BIND 10 trac834, updated. 41139644452bb11a162254b442ab611644ceb603 [trac834] really set edns on outgoing queries

BIND 10 source code commits bind10-changes at lists.isc.org
Mon May 23 14:23:21 UTC 2011


The branch, trac834 has been updated
       via  41139644452bb11a162254b442ab611644ceb603 (commit)
       via  c84b3ecae4d2d0b532c64c958857f8104dbae923 (commit)
       via  27ba6b2117e3ab88aedaa904292707871e131393 (commit)
       via  c37ebedf94c5dbbed3c685272a0cdc4bea67fb04 (commit)
       via  b0dfec1a5000ad22ef4dfa9c21c89e90b0e68673 (commit)
       via  496a4378cfcc8430dd1155bb3ae5448f27ebfdfa (commit)
       via  6e6eda44e9b1b7236e3baccc25e008eb674440aa (commit)
       via  27e122bfdd9edcc04e39cbe8a033d89ef36207d3 (commit)
       via  d04505cee4d9df2cb9cf9a2909a948589be4ff09 (commit)
       via  77d792c9d7c1a3f95d3e6a8b721ac79002cd7db1 (commit)
       via  82ea1075a4ae1ef8f6c0ba3cca5d6a1968a77f3f (commit)
       via  358e2303c565cb387aca660c2e55967b683792ff (commit)
       via  2ddb97d633c1721d74615b84d2c6ebd360b9bda3 (commit)
       via  74567fe1e92c8f10da3a639d235cdbc4c4d5cc9d (commit)
       via  cc3ccc1f474407507118ae0c53af307d0dd7bdf2 (commit)
       via  41521402ab646288ff1a4a12c5110d52dddeb4b1 (commit)
       via  5cb80378e05cc0ec208adfbe09e15efd04431267 (commit)
       via  0c7670c04135ba2ade5ffe241b66094aeb891f16 (commit)
       via  f0645fdb5d7be3c7d7090159847853f5a06ed7e4 (commit)
       via  df354bdb4031c1f67c03d71527105da4e35d1a6e (commit)
       via  b30c6c0843ae18a275f65e7ad5ab86bd78c82678 (commit)
       via  30d350e8cae28631a083c04a9ccf8d5bcaf69adb (commit)
       via  6c86102687c491bdac96577cabf98a0640ad8a60 (commit)
       via  37035a073be57c9f6d00f2558f74ce69b7067295 (commit)
       via  765bfaf3ccf1a96e981210c429d5beacb229b4ce (commit)
       via  938eb7ec8ac6bc670fcdc95a2189f4b13390e9cb (commit)
       via  50c678a05ecc181f4a63fd930bd345bce72dfc68 (commit)
       via  b5dc1d86b2a763f98d8414589a545fcbda09a36c (commit)
       via  bf4d941c69ed13ec03a2e179009780eb1ad11359 (commit)
       via  71ff1ab09693f1a90e46ba74cd5bbadf449161ea (commit)
       via  d2ee006cd5d5f3cf5ff56594fbf3d8955685d8a1 (commit)
       via  74a60943da1619dc598bbf4b440b78914ebe98a9 (commit)
       via  71d57323f77270278f75a57f63499c82f8f4ddd0 (commit)
       via  6f8d74e83a1c8073dada7288be92c2976c638e27 (commit)
       via  0034051f94a5e0e91e2574ec07f9b5374d39d6cd (commit)
       via  0346449357648e45f5b68f792cbf6dc914b16d9c (commit)
       via  89e3ffaa1fb56bcc76f626a64afcc25e506d8b54 (commit)
       via  fc97ca7de4ecd731aa6e470a7c68f5b26cbda7b0 (commit)
       via  78502c021478d97672232015b7df06a7d52e531b (commit)
       via  71eb80242fd144bddc06c98b3bdaa91341a65f26 (commit)
       via  0555ab65d0e43d03b2d40c95d833dd050eea6c23 (commit)
       via  23d63caf0cc09f19a01794458bf2457a67caac05 (commit)
       via  031eda633fe45496f47fad9d4b656a0100144f75 (commit)
       via  77def12e8d0d957d9fe587816b27b6df4f88ce90 (commit)
       via  080db7e6245ebf63f0b3104e92b99142c87fe291 (commit)
       via  b50e03318eeb6464f7143eb524eb7b8ed2a5d02a (commit)
       via  88504d121c5e08fff947b92e698a54d24d14c375 (commit)
       via  4bd053d4e1a4165c7b4b5d91a6f674e40250301a (commit)
       via  a2936cc155f8b5ce2afaa82820fa377a037f2be3 (commit)
       via  94cfeebfec6574350fb4980c2b0cc6a7d84ba4f7 (commit)
       via  47e5578077fa332f8476a13aa4ad6ba29e003a1a (commit)
       via  830c0ba6c96b009d1c9c4fa31dea7cf4f6de4e37 (commit)
       via  9e84764e4911a4ecf9b82df3beb6cd289eb68ada (commit)
       via  28465ec39050a2779fe98503c690ed4df2711e98 (commit)
       via  bcea2b3da4bca69194a2154b92f9f734edbe8322 (commit)
       via  a251c4f239e7b42856314412142cd9777f91dbf1 (commit)
       via  2360fc72c24eb39d32b0afd6a389cfe8f10cb2f9 (commit)
       via  fc9c42d22de8c2c5555573a1a3e29b2d30146a29 (commit)
       via  3303478b6f9943fd5514268bb1c0c42a638d107a (commit)
       via  d158640b970e5d8f0e5d4f8c6c278f03ee0e47e7 (commit)
       via  d11b5e89203a5340d4e5ca51c4c02db17c33dc1f (commit)
       via  7a1c4cc8e1baaf51a2058edd0a4179bd586345f3 (commit)
       via  de0694d2f4c7dba909eb922e3fa1a1269d3cbc78 (commit)
       via  bc0688b0e7846ec9bb38e4e014ed23be84876948 (commit)
       via  b8a7bf58c974c9ba4518fd894963cd66a19baf7e (commit)
       via  3a54f64afc94e9394a527872b957609d14002ff1 (commit)
       via  7c390c1149baab7bd33e741afcdefb827275d5cd (commit)
       via  b6982ea32af206b6ef661b492eea7b274af97bd2 (commit)
       via  62168918aceee04418765089cdc5fdfb34bf66a3 (commit)
       via  929a9cae2b351e67ac1953514a63b0c54095361c (commit)
       via  04ea273e2988cc405ae3ee7555a0f028258c17a5 (commit)
       via  58a5aabf65705e4107cc59ad25c76bbbcedc52bf (commit)
       via  43f5888605c770c012421a420766b01e1ad8a96b (commit)
       via  d1b5154a7c17058ff49aa67f389f52496228e4b6 (commit)
       via  5b495e880e559c413a80d0dcc741a5076f3f7eb4 (commit)
       via  141bf465a7b13f1e4c92a76ca2df208c8d375385 (commit)
       via  7a87432e627715d9062367e2321427a4510d5822 (commit)
       via  ac2e283bd92dcc5af494938d6cfed82e4074abde (commit)
       via  03fd43339b3ffd2537a1621d628d504cee13c9d5 (commit)
       via  6ed8870ee7ac32e786030403de4423b8d7647679 (commit)
       via  7a6f36fc9073def2a531a4090b97d223d5a5c69d (commit)
       via  7c576f2e3d986b0f58883776822323ff57535a3c (commit)
       via  201bae76d11706e9fe9c09491ed216c225a02e9d (commit)
       via  be4334aa0b66fd01f9b3f859c309545459dfab00 (commit)
       via  1440e71559ad3565dff46e9cac31f31e6748d8f2 (commit)
       via  a407cb3d58c78b93afe294be13e7b360b11fd542 (commit)
       via  1cccbc6845d795f8d8e2b0c7ba637fb28e179e71 (commit)
       via  0c81e90348e53e673a05e92e150cec0f598a2d4e (commit)
       via  882cc4d6b2b9f391e72fdc0bf8eb82bdb846ca61 (commit)
       via  081891b38f05f9a186814ab7d1cd5c572b8f777f (commit)
       via  4472e3c7cbfb5fd33ce575bd2666036d363b2ce2 (commit)
       via  04c0fbf9fa780b4a281c5982ec33e5632852cfa1 (commit)
       via  cd79c2fae07f7b1a8d2e2f501488de7a2d11eac5 (commit)
       via  76039741c19fa58e404879b334475b9ae01cd8dd (commit)
       via  dc19181b46dec42bc5db83861731656a5b45b899 (commit)
       via  224c7b9aeb3000e11790a2c667f0ee45c9481f17 (commit)
       via  94d43a69237b5d2bf671e384ff8b2b9a5ce445b4 (commit)
       via  c3e1e45419104bdb01dd385b22eae85bb8799611 (commit)
       via  946b527467c19236814cae6e35191ce19db3284a (commit)
       via  02e2f3a3c2ae669824d595bc9b42f37d9624b22c (commit)
       via  54210ba456b4e0822c5e333fd1f996bb35c6bee9 (commit)
       via  7a52a9a3618fd19ea9779eb0cef1a3e4f1c3d444 (commit)
       via  fd08a0dc40846f58aaa8a7df7726ac83e5e4c038 (commit)
       via  98f5e0e604e60fead409c28645b064510b8fc8de (commit)
       via  46629b17783d3ddf624002893af955d525f453a8 (commit)
       via  a1a58a7382e82256f3f6785b7bebfa4643cced67 (commit)
       via  928a439496c6040392cc03615c38aa3de45bfe87 (commit)
       via  8e28187a582820857ef2dae9b13637a3881f13ba (commit)
       via  4b3e621a4497ac99978d40b316b11581cf80d088 (commit)
       via  75340e4d2906762ecd088180087c9229a253e4ed (commit)
       via  1ce058332d84de9bc2f37344d0b49c24d3c30551 (commit)
       via  4e0adcf35398ec9f5c3a7a4b14e9a1aedcf9f66a (commit)
       via  87d5f96fe04dab6de30c733230669703a2429701 (commit)
       via  324cf344f3e0cd9e35e50076911fe7801a7d4690 (commit)
       via  d3da4f1f4f00d13962e6f23ff1272269569be5d4 (commit)
       via  71315bc901882a8bbb35a95c19781528560fcb82 (commit)
       via  3336f575aee4072d1d88b05f7db79712384ef2d8 (commit)
       via  f6e9a1186d00e023021f5853e5a7a1d7c3f838cf (commit)
       via  3bb68553bb39502b749265542c5b6d36ad80e32d (commit)
       via  ade0b1a890f1fe21c075d4fef332e3e35407f086 (commit)
       via  ff20711233b8bd6a5df5a896c0d2855222291a9e (commit)
       via  3e8ef1595dd2c7095540b22cca77e69991ad8ee1 (commit)
       via  c6827475447b07375cfdd2902c08519cd1cc9dde (commit)
       via  f15bdf8420351828159c0d7847d4f653388bf53c (commit)
       via  a234b20dc6617392deb8a1e00eb0eed0ff353c0a (commit)
       via  97a0938cfafb96358649b9a538b00fbb3ee42ea0 (commit)
       via  023527c23812b2f999c938ff1ee5b30434209297 (commit)
       via  86632c12308c3ed099d75eb828f740c526dd7ec0 (commit)
       via  dafe7a6038499cc0432f4dd6f968b7fb1ffb119b (commit)
       via  e93cfe3f6812d8a1fef103e34d9d1a6ee88dd8d7 (commit)
       via  a1420dabc6ace739cb21044184654717a32604a5 (commit)
       via  cd689c463a59fa5fee72d3f977835e0369eb3650 (commit)
       via  d1fdfd86c9b8e0120e557e2c7baaab542f9c2719 (commit)
       via  744fe91ac965c576cbe916ca39a0bef54afdcd3f (commit)
       via  c3f769ce6f0e3be367f7e0079a97a11e3f344761 (commit)
       via  ff36bea0314636d978f61923cc7292364c1808fa (commit)
       via  d686e00a5dd1efae29891e8056af324ea983d187 (commit)
       via  da57d4a08a2e14e5e6589138692674894f667f54 (commit)
       via  5aaa6c0f628ed7c2093ecdbac93a2c8cf6c94349 (commit)
       via  345b5986ff26015475b5e17506b3ca6cafaea8bd (commit)
       via  7b25152b5bbbaff6840f88ad7ff2684f8b8062a6 (commit)
       via  76a81d33b95b12341515cc6ca5718d72a242ab59 (commit)
       via  8339141a4a64043e82685f0e6793b592b7ac820a (commit)
       via  25c5c37094f9845be826f91bf5901068415891f6 (commit)
       via  9df5e254832c5c65ddf4a0895c09256e8386820f (commit)
       via  36af50328be059026859a09d402ff2d591789dfd (commit)
       via  f8c763ef2c9eb8343ead481093e2d0024e3f1cd2 (commit)
       via  f5278f2ac4becb33b93dc4c2fa7e6558a7daad8f (commit)
       via  c47f23e502e998d7885d4d3d679c1eacb1dab790 (commit)
       via  f80cdaf115a8ad80184240b283b243ac07bb9739 (commit)
       via  c2693bb84ea22e3b44617d729d8d2e8dbd99c51c (commit)
       via  2b521f9674a0d9aea7fb06d71b008e64c40922aa (commit)
       via  2f25f64f9f7a1021b67b9c37cfca41e86f5ae032 (commit)
       via  14f8767d89d62e0d573a1e6b31fbeea9272e7011 (commit)
       via  32872f1e745f45d1c0e84943cf57ad985a925f3e (commit)
       via  a82432e09cc7f3b22920d9baecba1f8e89332f37 (commit)
       via  fd51a1883a332c305fa4015a6210971d3956fc12 (commit)
       via  04611df9f5e34b2a8d6949b5b00d25a065c7c920 (commit)
       via  9eddc07cd32918f3b8e9ebd114d9c8f8f39a359b (commit)
       via  143b2c6769c64eb55d2f34305ad8e2b7ce681aa6 (commit)
       via  4569c1b87f5d04f663e1c8e2813d090a78dd9e40 (commit)
       via  76a1d7e547e9eecdc4aecfa3cf6cc4ba940ad725 (commit)
       via  ee53746391bcfdaa75bba0db87add3dc7becb84d (commit)
       via  92c0c95057cd98a5b8cf8099367a122684cf329b (commit)
       via  296ec6be00c208aa9ab8cbaa20376749e8b6ab49 (commit)
       via  82ead9ea724a5482c44e8a6235bcd4634eacce2c (commit)
       via  7deb4955ef8816885376e558e7f0eaf65e22b4d4 (commit)
       via  4a78ffbf8a2b9d1171415d7f0af1b7adc4e53481 (commit)
       via  b916d130e0799f457634cfba2b06fc1250db54a0 (commit)
       via  1ea71dc16928433c1243375bd9210d5fceb28fe6 (commit)
       via  e7a49bee8af14cf5d4e16e14cb5bdd3ba83385b9 (commit)
       via  ed62a7f4dde0264cd60e4b739c41be9c98bbe3e4 (commit)
       via  38932d7e76c4e35aca7382640e9e86360a389545 (commit)
       via  55b3152ebb03fbe946986a52732f79a68d926163 (commit)
       via  29d36377ec206cbe52274ee9a5a6e88ef27921d5 (commit)
       via  25b33e62902b5bb181405e2177d2fe935cfe6c75 (commit)
       via  a892818fb13a1839c82104523cb6cb359c970e88 (commit)
       via  df1ab797a9d1a2a188060c70071bb8fa7d6f1a01 (commit)
       via  6fc6ecda47f8556fc0a4daabc042b0b1a2d7d592 (commit)
       via  b653f950b906ecf4194d2a2cd07fa92ae47dd546 (commit)
       via  ceef68cd1223ae14d8412adbe18af2812ade8c2d (commit)
       via  879d981650dff5ee577712aa45aa9b363b039a04 (commit)
       via  e595402348d7766d7e3f7fd8d9f32bd8b144f747 (commit)
       via  33cd7d9232078f70aa380309a3615a1a9d743988 (commit)
       via  fb26d933e7af0cc07fe686ef88ef95b28cd10d2b (commit)
       via  48d2369e3a7c0e55f5c94973ab0191ddfbaa02c1 (commit)
       via  fe59cd140491dbc685932bd22440e28c703c1053 (commit)
       via  afd75a89d7aeba622b53c5b37e3f76572ef68c3a (commit)
       via  8d9debda3a88cb20d19d23dbdfe106b3132a4ead (commit)
       via  6eba2b45ef54d671c674d7d840dc99208eb5d00c (commit)
       via  4787c281a351b04b9570b8bb2d863db706a9d9c9 (commit)
       via  9bd9fa819f30aff560da9412ffa14d87e557ab69 (commit)
       via  d53bbaf239de6059dd0d8872f84d1a0db6ccb90c (commit)
       via  7b0d9b1dc03d9343f3ccfed2fb5876d7d9f048d5 (commit)
       via  d65686925bbd04cbbfa3ca2705f54696b76beb45 (commit)
       via  4f6b51bc00d3f37b8938951217cd1f3564bedcd8 (commit)
       via  b395258c708b49a5da8d0cffcb48d83294354ba3 (commit)
       via  569b2b6e5d84277316bce84c0e118ffd116ffe5e (commit)
       via  e5687a75c06966ab68ad453093fb6c7b9d8fe761 (commit)
       via  119678f768f09b13d6ecb715ad731d1dca8f05b0 (commit)
       via  4903410e45670b30d7283f5d69dc28c2069237d6 (commit)
       via  27a4c936d87d31952f6a8377e04cae1fb90edffd (commit)
       via  9eb7b41d5253c44e59987170a74e345b651c96bc (commit)
       via  7f642b767c8274a6f3344e4a5e1141e9e7f38924 (commit)
       via  7efc144e0eacc123544507d635630b7949052993 (commit)
       via  43db6eac145a6a9a59f6d892a9b9fd2384a12d51 (commit)
       via  ad6d052794693ec22f430109de624b8fd7ea212d (commit)
       via  a4f08f816c968fd9dc614f171b8925b5b7998da7 (commit)
       via  a7a3c9f8cc85f04267a5606f4413afcde7af1864 (commit)
       via  ea37ca8caa7c56fea957fc7aac066d5708675f28 (commit)
       via  4ff5a9f61d9ad1c96468556771562f1dbad7ec98 (commit)
       via  e93f054a2d0cf1c21d00112ccaa93d5d2432a677 (commit)
       via  c16b3ab523860ccca5e8e9648b58801c3eefae29 (commit)
       via  b734c55b73941125af327595ba39252add032791 (commit)
       via  daab0dcd59baee4b1e56eab640e29c9e8e947e80 (commit)
       via  00a15b4b06f9de757b30cd320fd56431980f8458 (commit)
       via  8bfccfb1fead0448e959126e07dad1a800880575 (commit)
       via  a09ced080782388e389ee6c669b9d36da65f9dc5 (commit)
       via  b21c74c08fbdd350bcd01b083fc3cf29a98e5a3a (commit)
       via  cabd3b127cf5ab2b916c5717992338316496de8b (commit)
       via  9a8870c515be763e8be63cdc28231883601867d4 (commit)
       via  fb1d629419b6c58b9c9f410e6c027c8769e0c9a3 (commit)
       via  0709f8b56df68cfe0c79ed98bfe7e9dd25ce0e1e (commit)
       via  40e06e655ce78197f0b52d8c5dc9c7516795362f (commit)
       via  80c0a2c3eec3ac5d3ac862f9b4c5926f0eece6ed (commit)
       via  11439c030741ce402c52ad9d3cd1a407d45a443e (commit)
       via  e564debcb683454296d3e3cf478748daa0b08cbc (commit)
       via  fba4ec1d7269284b48042b1a7ea084b531bf8d9c (commit)
       via  cccc20cac1d91951bd9b707c3dfb532e9ad8686b (commit)
       via  68c9545bb7d57933e514ef55779abfd06c38145b (commit)
       via  2cf390147f147dfab2c8c63c470177189799ed20 (commit)
       via  287ee379ad62f9043699c936dc1204b6a906f52c (commit)
       via  b5646b50e23e6049f233f755d7e143a09d4fb19c (commit)
       via  d4d910b28b3226d1330b7da1df170c406771b939 (commit)
       via  7bb5dc265a830d8993c9cb1da55194631e657587 (commit)
       via  1e3c154cd21cede83a8bbd7a559c20752b58ce24 (commit)
       via  434719dc9b7eeee0d0901fa6f5e1847bc40691c2 (commit)
       via  0ecb807011196eac01f281d40bc7c9d44565b364 (commit)
       via  fa321eca22c746101dd9cf67c7bc9da6de30483a (commit)
       via  a64f778b468ff7bd95461d1228aec66565602d57 (commit)
       via  eef87432f746406d467c647dd7302fc4cac8d53f (commit)
       via  ee2664ecf4fda60a78e97d39c4f69b4f22d5aa24 (commit)
       via  fb283c1a0e6f8cdacc9c326f00caef141b058f1f (commit)
       via  4c178871eba133fbbf56c2dac1dde1a28ad20477 (commit)
       via  ffa2f0672084c1f16e5784cdcdd55822f119feaa (commit)
       via  7c40e60eeaad7f2c1ea79f92e866dee08eafd5ab (commit)
       via  fcc1b5e13946c5e58e2bd0bf287f551e161f0544 (commit)
       via  b6d140b6169c130b06896d2b40df58752991a47d (commit)
       via  eab5008d28b04fdd7c0f4c93051fd3b1c1a416f7 (commit)
       via  313464eed2b54281b8b2357002cd7dfb9231ddf6 (commit)
       via  121d3e844ad6d8ed8aa21dd48c53095e2f770117 (commit)
       via  c3dad479414b01979693ba71c832aedd681f5044 (commit)
       via  a23491a635d7f74132fc0b91eac832275f8f1f87 (commit)
       via  9a2ca8e5de8a23018ebb0ac7fee819c065542ff1 (commit)
       via  284c8b457d8a8940265da1e4d0c7b1050806afbb (commit)
       via  7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8 (commit)
       via  5c497dfce7d23487c2aefe9907f942c39c4c5846 (commit)
       via  83717978e3941e4eb5d7dc90d26a88256efd3175 (commit)
       via  df0c3599c1f3ad957df20eb8cc04c33d1c958e4a (commit)
       via  40870d717a8017379cdb68db9ed15ca71faddd5f (commit)
       via  d846851699d5c76937533adf9ff9d948dfd593ca (commit)
       via  372a2f033edf044d3f515f3b5009d0c8fce3ce16 (commit)
       via  89fcb0f002447e2cc3148e212f1ecd4f6d1bd821 (commit)
       via  a437d4e26b81bb07181ff35a625c540703eee845 (commit)
       via  0338dd8c3ef74395235bc37533269fb252142263 (commit)
       via  28c50de2e9ef07250b54a3d99850ee353f511ffe (commit)
       via  297955d6928e3202c25d0f1fa17708c032c46a40 (commit)
       via  2979d921553eaaf59cfbe6b78bd726e09006ca9e (commit)
       via  db0ca2fbc64b390f261b5e36938c736321b171f9 (commit)
       via  7f0a7a5ff8d2452c4b48575a725f97e5981aff66 (commit)
       via  2aca19e705f02400a6b213ef84fa81c86dff0375 (commit)
       via  cf46f370333b15487f6c02f85749d90c2e0bd710 (commit)
       via  4fff42d6c9ae24effcae3f6eaa73a8a4eda5a38f (commit)
       via  25bc145bb597683411ece6ad7cb72fc0fabedeae (commit)
       via  df8ef3fffa7a4186d7ade60b514bb78acbb9b33c (commit)
       via  79b087eab39177799e38611661fd86125d9b8a67 (commit)
       via  efdf126e6e0fe75afa26d4d7cdcce663892a840c (commit)
       via  35a7c63a23646994af69a1a6d325ad11b4bc8354 (commit)
       via  a91fc737dd4c982194392b467b68c6c8383cec55 (commit)
       via  34c2d5bbe08e41b0802eb6ca58a8084595064803 (commit)
       via  4a2c0e7a8852496e9b8f9a56f5058cb1f55d3f55 (commit)
       via  c83d4bea0e9abc94b84315eb42c8ed7a879c8899 (commit)
       via  7e9ea719c8fda75f346eb87daae58cf06c8070e0 (commit)
       via  e4f2823d8b564c5b2c2f7029e5eb81be6b058d3c (commit)
       via  25301e86fb8aa4cb8d98933a0c3b7dcf46f8c4be (commit)
       via  1b967a5870088c3f4c7b5a3b8202e1b2e9572690 (commit)
       via  50ebc839b1c8389eb1b7b70f02758a9034138552 (commit)
       via  bb568b0fbb855dcf79681de5024c09b91251ccda (commit)
       via  04c515e17a08b41c9dbf241e3983148596353d2c (commit)
       via  45417c48a7d32fb6e3f7fdccc70ec2faa8441135 (commit)
       via  f1dfe74d6b9b2b8c4dc85dd39a43084dc2b73aa9 (commit)
       via  6daf339b7a83843a12d4938424063d1b96929924 (commit)
       via  9c3195a542df8d7e747e28d49d7abdc707781632 (commit)
       via  3ce5e0a2b96c84ae003ea372bb84ebb19ca355e8 (commit)
       via  9e8b5ec4233217fba5c7e9b17afd6c01e4fc7b79 (commit)
       via  cca71e70d0667d066ba5ab63c65b21d83cbb896c (commit)
       via  2d514a764119f29d3e2fbb04366d880df1866928 (commit)
       via  e22700fc2021180a0dab3f312df5fdabe9bc47e2 (commit)
       via  98d147ea68fc1e62b6e7e3bc74c80e9457b5249f (commit)
       via  96d1613a474602b833af953a364fb045fcfee776 (commit)
       via  6f8490fe9ce1d6dbef326d75f9eab79c09e83462 (commit)
       via  ac7ff7f2226bdba60809b70caa82659b77c6e2e6 (commit)
       via  677cebce1708ba85e46a0712d939176dc7ab7a94 (commit)
       via  f0fe344b15c3e1be2604201000e6c9fbe6a910bc (commit)
       via  5a4d69114ef60bbb86c4fc2190b78761ac4ccc3f (commit)
       via  776f5ebd79615b0c05f2009c09bf61c44c59343a (commit)
       via  314e299226288d66efe5e65d8e00fc041b688f35 (commit)
       via  0e3b55edc75e91ea11df51ecffae0ae4ff07fdac (commit)
       via  0261bbec3a5cd8770aee567aaebab2a4f93c2303 (commit)
       via  e997ff18a6bf1eeb23391e0957db0defdecd0213 (commit)
       via  9e183cb0529aeb9f0674b5727affa223d8fc9db5 (commit)
       via  31a6f34026c83594bd9f205df18eb290114d9ea1 (commit)
       via  e34dd62b8eca7abfbfd4851140d663efc43041f1 (commit)
       via  8320ec6eb230fe761ae4769367f10383e967655c (commit)
       via  38cddfdc23f6d2aa31be24173f9d7c1df2e3c4bc (commit)
       via  d033a50a7e32664848c360b160e9170cdcd79886 (commit)
       via  e2e13d0bd0856496a3571ba6b7f35f41e6534859 (commit)
       via  c8b7abc5751b171621be9edd5156dd2691ff60d1 (commit)
       via  b8422db8e0120d3998b15581dddcbfe4efe91a68 (commit)
       via  da16cc776443e1414f779d7402996c6949934765 (commit)
       via  d6db622c5649e745fb3c64218e36c41545c47aed (commit)
       via  cce60befee1e0c25e20449b9242112cc0a777089 (commit)
       via  89dd4548179485bdf76a84d289ab88ba65bd07bc (commit)
       via  364be72653933235d362a57c9342bae1c6e17b3a (commit)
       via  43f9ce0c56cd14c0349a8f3c3c9a5f4dc092f65a (commit)
       via  ebe0c4b1e66d359227bdd1bd47395fee7b957f14 (commit)
       via  d9b00f6ded6d0cfb41a0939cb613c1e7bd703a67 (commit)
       via  2c60d79949a79fc8f093f3447c949e7c63f83137 (commit)
       via  0ede9e8f8c0e1d89a01cdb1eccb5256363bda0cf (commit)
       via  64cee1a7ad8341b83954e022487744060b59d04a (commit)
       via  177b356c926307e94a95e6e2de7a3f0ee7124021 (commit)
       via  1867180c5e2263baf319514b5b765b8eb4049c08 (commit)
       via  6c554c8b4e37daeaa4182d05af69a40a0b78cea2 (commit)
       via  6eb7a93e81027bcf67435188c1ff7788965253cb (commit)
       via  cacab413e886e8c90691428e1e3f78b77814945e (commit)
       via  ea1f2d6e96715f0821df5d096be46b2454e6073a (commit)
       via  04f7331a44e0bfd48f52d06f6fd463c6652dd38f (commit)
       via  5b4feea19e2cc1bdf18ce52cf0062828ad9067c7 (commit)
       via  ec1ad752576f7f3541b1b57f906256c6a5ae0dc6 (commit)
       via  1ce2874170c85de79a896b1cc3077d9f3032d9e0 (commit)
       via  1151e49bcec0ac69fe01d084e10f106481337dea (commit)
       via  b92cca798d702273d63d56d9197782edeb927c8c (commit)
       via  abdf624576745fa0a4f37319e3c7dbd76047e2d2 (commit)
       via  28143beb0e57bbd4d62432b81edc8e179b95959f (commit)
       via  76705c8fc54809ece24609deda2d156a844d2bf5 (commit)
       via  47dc61713d6bcfc16410fdb657c41dbbef85fb2c (commit)
       via  a42b39784b65894e7dc164f1b7f2f887715f0c45 (commit)
       via  9713a50748616587ca32f17e9931c752aa1e5d3d (commit)
       via  fe141c14e201993b5e0efe848c2a47e0a4b553bc (commit)
       via  0310b8b77e6adb8671d1f9ebfe826e394e95f53f (commit)
       via  29170e28d19f35a874d84b88f7c0873c51e28f89 (commit)
       via  53d9f46923a22920c04d5bc4fc706ec202686b1b (commit)
       via  2842dda9275c1a471d70d3a571d810c8d715bf3a (commit)
       via  78bd2b77782510d02748254a8c79249e493b6024 (commit)
       via  daf48e860413d4c3229ce309253b29d1ad974c7a (commit)
       via  daa24430a497d145849a687f51252bfed16a2caf (commit)
       via  6d03a35ac6dec0508d30cd778fed48257fc6c0e1 (commit)
       via  87e4b9874ac16ccc5d236a2fcb8221942713e086 (commit)
       via  d9433ad4bd9aec1028b9b05aa55e9b083e35a4d4 (commit)
       via  9df42279a47eb617f586144dce8cce680598558a (commit)
       via  0640f80c7a62cf9c3e289f8290c5a3b44f4385f5 (commit)
       via  05c6223cf7f145ec6e96cffed0561a03387b7367 (commit)
       via  cc788af2c45043fbb98365d5fb85c1d16307dda2 (commit)
       via  fd45c40964a9557c0a6534c6d0cbe5c377d05066 (commit)
       via  475e26bae3b3c4c8823c4931638d0a7af0ac66cd (commit)
       via  f4ad75548592b2f3eeae22de5685cacbf5c82bae (commit)
       via  dabf205231ff9e720d8693800e311a89ace18488 (commit)
       via  ed5025a1322aec3c6aa2855ec807bdcb8e013f1d (commit)
       via  e4034daa010c24286b969cd9ad6d75c30895cd52 (commit)
       via  4903de33e8f5d16ed99b6ad6b22fac023e653f71 (commit)
       via  2bb4420b73b5485cbd05a221a414a40f9e7674b0 (commit)
       via  0660b35c79dce9ff27361fee48da8c174bf05cd5 (commit)
       via  3e37899f95fe561fee0a73fb5d85071065ef3c7d (commit)
       via  088bb8cbca563a17b97166bcbb799fd50bbbca4f (commit)
       via  f099c11348b7947c64f7467677e9afa58ca7023c (commit)
       via  ad134794bd3fdbb058fe5d50d8e92c71d03d47cc (commit)
       via  309bc10ee624106cf75165efd4251312deed3212 (commit)
       via  5cd716bd9844e154e6ca58a981787614a3a6fe6c (commit)
       via  adfd1014c34da20e272f058c9cce43130c637071 (commit)
       via  65874313065ddb02756d5ef06c8802c7540c17c7 (commit)
       via  98eab34d80219120219d064f6b3b9f0afce3e59a (commit)
       via  00e36b253bd643b007f89a8ccb3addac1a723eba (commit)
       via  7be4a7e7f859881a3e5a3f4268dbdbc3468b7214 (commit)
       via  abdb0ff5e8cdd781d7c4960bb51d8538f4e3b44e (commit)
       via  d4ab440d337cb9ef3f1301c3b655ed0a913cf257 (commit)
       via  33eb030ea0a6f980573c9a7ffff41c99535df98e (commit)
       via  6c274fd95d3c2bcc99113108f5a68aa0364f924c (commit)
       via  241c11e7b06b233585b52df53a9273ab8e0ad405 (commit)
       via  3427f489904a83ed1adb8e740aaaf1f6ba80267e (commit)
       via  dfddb7ba4637530a542b833ee14083421eeba826 (commit)
       via  1cbd51919237a6e65983be46e4f5a63d1877b1d3 (commit)
       via  81b2d1ceaf680d740f66250b848eea1db05c4a3b (commit)
       via  d743478f2b76e0f37381f64d5f4e90417260d67c (commit)
       via  bc436f1f6715aabcc62c468fa6cfd7d3bf694f29 (commit)
       via  0194e3a376aa9c1ec2c232b0f2fd9a6cf02e448d (commit)
       via  74472396fc8f91daedcd6a286b34b5cae8a5ab57 (commit)
       via  e5cae846407b0f627ea67ba687132c141c4de57b (commit)
       via  5542432e850b29dcd316842a61fcbc2903acbaab (commit)
       via  b963854734ff8ba78ccb14f2e5a481c9426881c6 (commit)
       via  ea46adf9f6bbdd78a06ae748d979986a75b9b8d2 (commit)
       via  ffbe8a099bece23efb94e3adbe8fdfff8cfb379e (commit)
       via  3c194549a61e68ed38bbcd90e69f1f954ff286f4 (commit)
       via  5a6f9f8c21674d8f70fe33de2b7d7e23c105e888 (commit)
       via  5573b0bc953d1a9589d2e0f06b8da58dadb64bc3 (commit)
       via  b1cb4c4a1421bb512d093690c95d27425b33e1e5 (commit)
       via  521c140da800fdb7a7c87e53e01270e02ae4bce2 (commit)
       via  583203a8ca082541bc2982752b20294bb972bdcc (commit)
       via  c32718be9f5409b6f72d98ddcd0b1ccd4c5c2293 (commit)
       via  2ec061bcb5fbdd5893377a233219af11a6309cf4 (commit)
       via  1096417815a2e2241aa059a24fada61108b2ca90 (commit)
       via  2463b96680bb3e9a76e50c38a4d7f1d38d810643 (commit)
       via  912b79387bbbe16f5a97513dce140d31917e091e (commit)
       via  a1703e5ae5fc9458c066fb4aab7666bf4e5fdb8a (commit)
       via  823fa0556364ad5bdcd26cb7a42999d502f3af02 (commit)
       via  e37bfa349bd0b7866a57519bf7f86dbb18c3a104 (commit)
       via  145a6173191e6cd39be3d495a6e5d0511dfe867a (commit)
       via  fb7877b06ba873d4fb222409dd92b4701ae11ffb (commit)
       via  21385dbdb72fe02275c859a88674a9d2166a0ed0 (commit)
       via  158af09a0032d47503a9e52102bc495b8d5bba46 (commit)
       via  e9f3843c953ce9a3e05c3dcc4b8df2a67a9d9e6d (commit)
       via  9f729b786ad2d12fde55cbaad5de72918fbe209e (commit)
       via  20336851f494ff1d9c8937400a99ed4d0203a340 (commit)
       via  246e56b3bb7792789b3aa891e21e580976d9e7be (commit)
       via  168bed01625dd25fc2c40bd6b402763849e840ec (commit)
       via  e831ffa2129fc5e013a0217f004896f6f40f258e (commit)
       via  4eda7bbc802b24730eb8ef9e5716fc47f19d5a00 (commit)
       via  fb4a0a36ba0d90409684e8042916341ce35c5f21 (commit)
       via  7b1677584cd0cc94825741792f9ed66f16029938 (commit)
       via  fe8babb0a2953fbe1755b79db136c0cae25682e2 (commit)
       via  9140fab9bab5f6502bd15d391fd51ac078b0b89b (commit)
       via  1241ddcffa16285d0a7bb01d6a8526e19fbb70cb (commit)
       via  fafa0c06f358f9cc32860535bef1c56d25f20775 (commit)
       via  bf1cf162e37ff391874569c82c6bef7e8b7e4f18 (commit)
       via  122d477847f80c7d77bec087a849b9e6743c17d3 (commit)
       via  e74f6d5e8f9abb081bde606bc46319488c7e546b (commit)
       via  f137e0fa3a387fcc13898ea6da6b61dcd80dc8ef (commit)
       via  457ef26144222d0eac25e93751ad8f0c8b12b8e5 (commit)
       via  572ac2cf62e18f7eb69d670b890e2a3443bfd6e7 (commit)
       via  e87e34cd12ac1e4b70bd55ea2fcae1bfd9ccfeeb (commit)
       via  9ce716d340a89f0212302af25ae75ba68bf69b75 (commit)
       via  4b5b7b0c63830075ce2b063c23a5efa5fd2b9cc7 (commit)
       via  0e2f20e8a4f5c57c8c9ed8601edeacf52c4a4ab9 (commit)
       via  ec02d3d35a79cf4acfe35dc7382ed69666d03f74 (commit)
       via  29025aa582a5d8771619e4de08c3c3fe4f0d0fd5 (commit)
       via  2a27eff879ad941873586006fc2b944fd7c9471d (commit)
       via  270059b1e812a686d706525a40873da3e5233611 (commit)
       via  8038f6efe5645a6100b9021b145f7b414efb6d86 (commit)
       via  084d1285d038d31067f8cdbb058d626acf03566d (commit)
       via  712d1db4df1cb12a3ade2f96d653535b77ea2718 (commit)
       via  cf456aa1546145ac403e75535e555d773b39ff20 (commit)
       via  006b2ea9dabd869bc05682b73b083ea815d520db (commit)
       via  c34d8eb763ceb840f65de77a22eb67c8b1ab6392 (commit)
       via  2aa47d167c58b6718706f8e037927b824ff0cf00 (commit)
       via  7ed21ab7e857037f18944e63fa5deac02ecf017a (commit)
       via  81c81d70342c7aacfb2689d86aa239e231c310cd (commit)
       via  9b16d3b4c04d35914b9eeba56a168d5039d7342b (commit)
       via  50eff6d6d5788193d055c038a5772bce2534628f (commit)
       via  e16c86b6229017d8b79f8bbe342976ca2b938c3c (commit)
       via  981abdeb847bfcee7c03d6c252d0859c1ed7a2b0 (commit)
       via  1781090510f9f7ad378497d65feaf94f5c32b262 (commit)
       via  5651434ffff461b28616ffec595ff8a941c6df04 (commit)
       via  27dc0ba25fb06503a6e9f5bfaa293b1db1cd5e78 (commit)
       via  ec9b5b21e964c7fb5eeeedb17af5a4f833289667 (commit)
       via  597a1d9a5adaee9c31156b0f8f07aac30dbf4e67 (commit)
       via  fe0c557fa06274df7610c0d07a6c6bb827a5cd3f (commit)
       via  604e90d1e0c928cc8d94146beea6e24fe2252eec (commit)
       via  dcf58b7836e854107438368905576de7d29e0e3b (commit)
       via  ea064b169fe62c3f71aaec4b5c6d677255f3621a (commit)
       via  5a906f923ec419895fc398ba3dcdf64842164d14 (commit)
       via  f4f11a9b1c09adb07e2d6b99a0bd342d5a75ea3f (commit)
       via  74e6966d7f8f8216dad871f1648cab977fb9fea2 (commit)
       via  f65cb09eef192590929e246311b33aa964c5a1a6 (commit)
       via  cf05a54b3c950aef906e577be39d792a17e53796 (commit)
       via  95689208a5f10f7f839abc57d7db9d73e0eca200 (commit)
       via  9303e9a05b5a48f80ea32531ae493724b04aa2be (commit)
       via  8ac28e2101ab399e885c178294635cacfe6573e1 (commit)
       via  0334c1798ea43061494a530d8bc274283f1f1fc7 (commit)
       via  dcd582cc0a7d02d69c3c7c28916980f71034f9b2 (commit)
       via  c6947d22cd80d5934ad53c91b74c640c8a64e57c (commit)
       via  40f4efbbd9f5685147cd1abf19d12c336bc1b8d9 (commit)
       via  a57662d6db020dd0b334472b5bb7ea88aefb6a7d (commit)
       via  122d9611bd552c3113eca8aa5e91d2b8a3018210 (commit)
       via  6ffefafd958806769b56e1e5972eab62b87a1135 (commit)
       via  36b32903369f9a3afda93e2537d369d2402a3bfc (commit)
       via  bb5efb65cb0114b5bf985fd1588e8b645d4c45aa (commit)
       via  54cc81d718e60a3e095fecefe502cdca9dad1776 (commit)
       via  1b666838b6c0fe265522b30971e878d9f0d21fde (commit)
       via  7ae7577211c77f31a9f30be122d245add72d893d (commit)
       via  0eea320309f86b8f1f95bed053078bdcf4c82071 (commit)
       via  20607bda887846e2745bac1d275c51874885f917 (commit)
       via  17106327efdf114e15b21cf8079f9191ab073648 (commit)
       via  8eb1d7a04312f7fa70ee3c986e66b6444a1dfde4 (commit)
       via  99c44efcd64b8262614354faaef2b5abb6fb644e (commit)
       via  af9f4f7fdaf88b906022bb808f44c6e586e702fc (commit)
       via  1ea4834d960f3d5f14ff8cee312448baab72e075 (commit)
       via  921ca1236dbf64fa1f73a03a6903b5a2fa82f84d (commit)
       via  f1ac03b8147047bee020fbc019d4969f16c75064 (commit)
       via  231b29911894b0f5ddbd0d1444d9dfdf9cb5abb3 (commit)
       via  06c4fa64bb59638af953e9b3961d23e173eab49f (commit)
       via  4e8ed21d6a2e80e81393e64d808bb07655f42cbf (commit)
       via  3b42967a83f4e15e1b1d07a159a600cb67628039 (commit)
       via  5012fabe00f1ebcbd2d67564df325fc69a529b5c (commit)
       via  262ac6c6fc61224d54705ed4c700dadb606fcb1c (commit)
       via  8eb32c279693c55b444cbacaa835c9d04ee3f242 (commit)
       via  160b06212023cfce40c1ff6f13c5307c4d4f6e50 (commit)
       via  8541053e6fffaf84127fddd2c0a25d0dcd5c635b (commit)
       via  5e89e6afd429bf91d66f2f70435342fa1de388a4 (commit)
       via  a37c25cdb88ceb49b518d27a324ad7523f936fb2 (commit)
       via  b1610a09098d7019c6701daf77c2b8b98eb03b75 (commit)
       via  04330565df2cc183a92f196772e03b05482046eb (commit)
       via  44f4b82933783502be198c0ab0a81020fb3fe510 (commit)
       via  3437b4fa8efb83ce5395ec159e85b38951e23504 (commit)
       via  4b65b6bdb511b88979d0b1c6f44161c223e1dc9d (commit)
       via  3f6620c5ba918a2a411aca9430fd8ac347e1aeca (commit)
       via  2018011dab54aaff10385ae4905c1a5706997062 (commit)
       via  b751b7e0cc08dca691029169909a54a0bd1e6b45 (commit)
       via  d7cf894e555a8aa8508f695fabac2061822d454d (commit)
       via  41361697fe474af2b511e922c18dc0b211f1344c (commit)
       via  0dc2e2582d63c42847400701a7c3c6b0fb2d6d9b (commit)
       via  4d55533790df1992aee5c088d4f91593d055c080 (commit)
       via  66c4f9e1df9c4c00d117323d016cca1c16c13e01 (commit)
       via  1eb73e619aae14a927a7970cc4cdd2a7fb1d362a (commit)
       via  c374a5c5a329a307346be02d5b884ab57e1cb8c1 (commit)
       via  cd3ce64ac0ac3e82ba905f3eea77f1040b7e69b8 (commit)
       via  3c348815b0ddc70deed6e5ffcdb3b6828edae961 (commit)
       via  660d7d782c81bc55b8cc009836c35d9ca3948063 (commit)
       via  316da90b500c8cb176bcecca78eb7e711022fdaf (commit)
       via  ecb22c0c225d8da3710f4f912648acf401183cfa (commit)
       via  75080dc8f887cad817ed9b1d20db97461704d1cf (commit)
       via  a9f80cc455747b38115c5279bafde024e78b5f30 (commit)
       via  def088d4e8387e8d04fc0fc0e56a9db39e3ccefa (commit)
       via  2c8303354db6a7d41b4c2e90181b5fcd5db40aee (commit)
       via  96b5b4c186fffb2a52891209bd8c95e92e45573e (commit)
       via  6f91ee90cd428b0e7eecd4cb99eefc0201f4360e (commit)
       via  24aa99548a4164d2c57adcf3829cc50f1fd34de5 (commit)
       via  f19053d9083026ad651b574f276313f5f2bd8dc6 (commit)
       via  bc88971bdb67728a22d029504bf18e778af26591 (commit)
       via  6e2078ecc6e3f91676631b3b3f9c4be7b5584853 (commit)
       via  3384859c8e15572519887abeb44d3ff295dbd178 (commit)
       via  a140e9b97e208ce30d0c3fb51f14dd248f307b1d (commit)
       via  f8a702716291db0b289aa211e5adac6fb2790cb7 (commit)
       via  390af5c81d043a9f4cc8e908365e7f0734bddb8f (commit)
       via  2df69541deceaa8a3bbbcc04d2087e94aa063d11 (commit)
       via  ed3c8e2f7a386b05b696d3ff79fa285ae7a050e9 (commit)
       via  047cdc39aa335b778d4ba9ecdacbd859d612807c (commit)
       via  f5bcf535de7b23fd48061b9ee37580e2ac761f16 (commit)
       via  1f16df990ddee676893ae701b8553fd42d6992a7 (commit)
       via  aa0ddfbb4f0aa61cfee383f5459c2183b353674b (commit)
       via  7bc6ee513da806b25cab12a32465122f33232128 (commit)
       via  a3e7ad9b4fb05fbed4cbeb6d6bbcfc8cc0443df3 (commit)
       via  87c6ef9942c9edcb37aa811e1c20357e6bd6bc4b (commit)
       via  95e81e5a713c145307034724994bd64bf35455ff (commit)
       via  4f1d8d0f2ce99880306f7926a23b28f1aa8e4fd9 (commit)
       via  3999bb246ea782310611471d3ff28cdd85bf4a0d (commit)
       via  10b62db1ae170eed2fb897335037d50c399b37e9 (commit)
       via  dbe0eeebf72c420712555c522be6d25ea857f7c1 (commit)
       via  ff81e1bf773d5d18656f75ed144f278cc0734a88 (commit)
       via  f155c3edec68515cccb5f5c4da611af08770ae4e (commit)
       via  ecfc86a4afb1d26fcd48054b0406e153daf571ee (commit)
       via  4e9bf13057eba0ccff7052f1859ab49b0a27c777 (commit)
       via  36dd3d4b0bdd8c40695ac186955196bd268db586 (commit)
       via  a7c4e0bc10a5430008d12081f4cb30d1d0d26723 (commit)
       via  3987357f56e0fc2feca75001b963a11f1b7120ff (commit)
       via  6cece2fc1d8a086b65421a583cf35b40f6ee1751 (commit)
       via  c20ca2440575e5cfc9d4a3dd582c9f56776452d6 (commit)
       via  e23c4b1e90ba1127a5b7eaef4add6f3b68fbc6fa (commit)
       via  a83e29a881af14dc61b366024e25f5ca68244220 (commit)
       via  bf0a9b3576da038ee53bd49360fe3bd8b01189fd (commit)
       via  4e47d5f6b692c63c907af6681a75024450884a88 (commit)
       via  400d3b61a32c0fc47c5f41a93ea649fbde6a5445 (commit)
       via  fac1bf01a628b3b922af67cdd94f05257b6eef9a (commit)
       via  34ba5055b70c9de09d406b3e51ad2e02b98f6439 (commit)
       via  0eacaf1a394d3674ca73c6531aca60dd952e0e3b (commit)
       via  238dca82160452df0eb732ce014166777380767e (commit)
       via  f6aa7d59569e492326499898a0e3f183c8748970 (commit)
       via  253d063204f1e0656c89650999c76f942b4840f6 (commit)
       via  ad04d070072126a8f221f67244e9a54e68b53955 (commit)
       via  817462f1ea1f1e9b4e05b2da90b8d311a7b59843 (commit)
       via  30ab4cfbd7f0744653248efc5635c68930359eea (commit)
       via  97feb3a88bae42f4051cd67384a4dc7dcd018c9a (commit)
       via  b78eefc13bc53a301327674a10d88cb917d6f28d (commit)
       via  34d2f102aedbdb6b818f8eb8deb1e00fe431dae4 (commit)
       via  6eab8b3fc5922c7b9c6403f4510b929544eafe30 (commit)
       via  e29c4f167f9d466eb9310989e836a0be428e5ace (commit)
       via  fb99e325e667a39ef88b6c8fab128a8df862a786 (commit)
       via  31b96198427b2c140556afcd61ff3809c43266f6 (commit)
       via  4578fa114fea13eae53713b5282f5e906a71fbf6 (commit)
       via  e58e69f00b57fbb7bdddfbd43e8b958ea50fd146 (commit)
       via  0a2a239a12af8c0ee54d62cb34d170c6cfdd33f9 (commit)
       via  0e519f4da5ef99475c3bf5941ed1ea553a7c9a6e (commit)
       via  1e3b465d617d7e7dc9c9ac2427e37a1b837369d9 (commit)
       via  429ade576746b5c5e1d9113ae57ee863276809b1 (commit)
       via  25fe349f4fb12f444c06fdc2117a4f62f1dda2f7 (commit)
       via  b91c7c259c85f29413e05898e8b74ca011835aa6 (commit)
       via  fcc5a1f450a3a0125e999a8bc9e1d26f207a8153 (commit)
       via  71d23aa4207048dc78531ce48e35e6a83a6b62ab (commit)
       via  bcc0502a221ec06331c2825c5e27874626b32cf1 (commit)
       via  6555863f88c4e9865baebe0b55db1f7b00b6214c (commit)
       via  d3dbda9445dcb699e48457e89b90c3be933ec2b9 (commit)
       via  992f3702aad9c83836af20d32e96313ff22cde3b (commit)
       via  111334856c3beb8cfad23ff60264604746dd1492 (commit)
       via  6ce4dde0aeb2a0aa3457f0037be5d549b3e9b966 (commit)
       via  cdf229b32e2138c7d451eead64d7fdc2d69e94b7 (commit)
       via  c3a18648a3d7f96325a529f87ed5824183fa0ce5 (commit)
       via  2e11f6cdbae2c29e12bbce2c9d14f1851439155f (commit)
       via  30872fc580a3cb357bdd34765eaecc1d61820b16 (commit)
       via  f2de716ada3aa2c0862f3d7d21ef10d28db90219 (commit)
       via  95b1c90380f6b12bf29939b7164fce8d5516d443 (commit)
       via  ca4c3ad8a436b2c5660959d266c82b692271c158 (commit)
       via  8fc7cdd216bead2a98f1c98a6b6dc7a8a3bea4f4 (commit)
       via  a2d07257bc12397054a57d4190cc61419e572278 (commit)
       via  051d8bf74c500b8e1f1d2eabb9bb384d01104d10 (commit)
       via  2e92b2f8a977a376fa38e3a51c9646ea9e83c4b8 (commit)
       via  ce281e646be9f0f273229d94ccd75bf7e08d17cf (commit)
       via  ca268cc4ca8f7505b996fa3076959b5ef3934658 (commit)
       via  c4d150ae4528f15fe8f05dbc85a1025abc92e78a (commit)
       via  ad3dfb04a335ed4c65722063bd351be51dae33b4 (commit)
       via  5861ae7cb08e698c7a6c6d053b644f04106ed7a3 (commit)
       via  778e7b5aa3c55ffc7947454459fd02263725303d (commit)
       via  bef9fc00a6c4e6c45922848d7f220ed262e83b1f (commit)
       via  d622e35a3d7b378f79dc4d587156cbfec3befed9 (commit)
       via  433ef14c7c54f255b302ff74213a24bdc298f2a0 (commit)
       via  5eeba2034481f043369f9a7f3f86ce606653387e (commit)
       via  86ab4d3fabd2e551f90603d81ff2bce2368ea7af (commit)
       via  865d62e9e58a3acf270f163a75ba713c134d82d2 (commit)
       via  8fdbc3e46da7c31b4a533bbfe5778bf7d68e1bbe (commit)
       via  aac391dda57b88507b8b10ac4bd1b068d3701b2d (commit)
       via  7e561fe2f8d44b9224cf107287f79df14584512b (commit)
       via  3b6ddc0b213a61abf826d87351d97de9145a3fc4 (commit)
       via  28b01ad5bf72472c824a7b8fc4a8dc394e22e462 (commit)
       via  745b08afcdce71ca9b50b2d5a7ffe5d4ffa66091 (commit)
       via  b509cbb77d31e388df68dfe52709d6edef93df3f (commit)
       via  d12560d1714fb3a07e56b6903141d82d6081148d (commit)
       via  150914707089969bde30fbc6276abc00f3211ba3 (commit)
       via  ba6927dc78e991f8a5c608beee4c9807895914cd (commit)
       via  21718d6ffdc3f782ffa1b5960088786da9b77e4e (commit)
       via  20f12e8672c45540cd72bb5df44cf21ff3b6732f (commit)
       via  583d7973d8f49c061dee13a14c89cf0846f84721 (commit)
       via  7b2536d7a654ecb24d98c3c0814c7384230e81df (commit)
       via  a3f3377467d511fb0e789957a4b7a9105e4fe0d2 (commit)
       via  e7d0dbd6ba745bab334aef6e747056c33f5edaa8 (commit)
       via  7c1e4d5e1e28e556b1d10a8df8d9486971a3f052 (commit)
       via  4929dc565823e49c94b1efea1543ba23d9745c9f (commit)
       via  34571fc51116f3e476e84c20e7fb7ba59393dab8 (commit)
       via  c7bb38c99c9afa049c7336ea3f827aa41a1b2ea0 (commit)
       via  1c269cbdc76f5dc2baeb43387c4d7ccc6dc863d2 (commit)
       via  a125177e363f66375aca5af53649b8e369af58e6 (commit)
       via  98e93921ae905aefef6646fc8839e3f4a30a37e1 (commit)
       via  1ec7e1ccd24b25501902e0fc29fddf400f2ebdb1 (commit)
       via  47b51ddc032a458b42454c3ed774bf26ef4254c1 (commit)
       via  c139d4bf6b30d7ad9325c7a621911c9455826f6b (commit)
       via  d8c55247d888cd9f5e2e474e49f8bd97b96623cf (commit)
       via  ba876505740d4782b58169848605af49325b11ed (commit)
       via  4d505b0cef54209575173d52e4f9a3e6e244dab3 (commit)
       via  6c611b5c04a5484df7269a603be4f00c4f7fa7f2 (commit)
       via  0355bddc92f6df66ef50b920edd6ec3b27920d61 (commit)
       via  69e7fd6b5782434c809f90d8060e148318ba3c7e (commit)
       via  56b5bef538df18c95ad5df3aaf7ebff4464de7c6 (commit)
       via  dec73bbd6dedb0068efe90ee8d77c020778b38db (commit)
       via  6ff2a83cb7a6c04a258e84818257fe6eda9634a6 (commit)
       via  682ea37cfb7e20366521fd48fc98826a21344942 (commit)
       via  e1e592789ebc8806b9a8767af95c41c1ec2d5a14 (commit)
       via  4f42307f123f7ed147b537430e0f2e9a1c665e8e (commit)
       via  afa5624c2c3503df1f152f82278f1b9dba19b533 (commit)
       via  342926bcc0d317101321ff9afe6cf61967472a6a (commit)
       via  8d3f576ca98cdd6e821cf76464cd342d42d941a3 (commit)
       via  13668e95ca6bbb07128babb14f1772bfefcb09a8 (commit)
       via  eddf905784249ab6949e6186f2676f9d627b089c (commit)
       via  b4111d2495797a6a9738df6dda3b9db696c5388b (commit)
       via  4a484575725500dd766516377eda41daaa17f402 (commit)
       via  ddfc6892916bc041e53b79a690abbed10ff99056 (commit)
       via  af0d35e501aab417b9b032069ae1cb8841debab4 (commit)
       via  cf5b24f110a927685226e8ef41378a847b002357 (commit)
       via  5a7c1928eb5b70c2a9739650961bd4e32b6b26ed (commit)
       via  238735e15837b8dcb878bbdb627ea4b61682db60 (commit)
       via  f9a697ab99914d58e7e135ca069b3d5a06c00511 (commit)
       via  d6c0273c617498a8bee3a813e013837e7c16b7e6 (commit)
       via  99fdcbeaa5ea2a5432fc47f39c5ed40f4850b843 (commit)
       via  a263e7d8bc90224bb6acf8b096d6ce8c87c8647a (commit)
       via  320bafb306878cd9f13ba9703a0d4573fb645341 (commit)
       via  0b53561c3b937c5d2585a3c62876b600800815bb (commit)
       via  e111d142cba584e410c5e385c10b714715f55dc4 (commit)
       via  ac453e66538072059954b8ca3e3d53bfc7c8cef3 (commit)
       via  3cc446d3ed8a1b6c899ee19faeda2c41a4b5bdb2 (commit)
       via  3e6c2a9c09722a48fe3e6c8a1ee35724a9397360 (commit)
       via  7a7299fb09d2a02023041d3fe7a92e22d17ab549 (commit)
       via  de3c708f962db8fe15287c9a5704d3aa8b257b03 (commit)
       via  9b90408108142c710c2adb403e61af374fe1b24c (commit)
       via  00cb2ff77044b185fe80dcf3f577a9b4793638b0 (commit)
       via  00b37501ae500c81657b1727dfff0105c2202f07 (commit)
       via  7b794844b6afc77cf05bb93828477fe5cc48408d (commit)
       via  75b29aaa4aabf843b0d80400eb2cf8c39c4dd8f0 (commit)
       via  d27da40718b797aca37ad5bab7215592a089627a (commit)
       via  7362cbdfc230a2f8deee2933b78e23bdb4892e98 (commit)
       via  48846bf7b70cc48e317aabc554a4dacef89b2d46 (commit)
       via  501462d7b9850ddca6a3d0a2c7043e3fa0923759 (commit)
       via  044c080dd3fc084f3ee7dcdcc70c8dc328bee9df (commit)
       via  1cd8ba5e307c77ae9bc2563569366c43623bbc75 (commit)
       via  8599f0c0c2ebe7043dd65458a2302837f7c43895 (commit)
       via  902005dceae646aefc03c2005e1ff2896efb909c (commit)
       via  22e21e72190a88d50dcca4c7ebf0394074d0adc3 (commit)
       via  cc259f459b92c5e5f5f374c99c7f1cde9900544b (commit)
       via  ba422c4d7e15abf64bc7e466d470243d3259e675 (commit)
       via  ff5a80a31953f5aa6f746e6c4e919519926da717 (commit)
       via  e04950d346768779e32c83268b6b68e0838680eb (commit)
       via  fa743a8d8303433152e7c93bfc8aca1a2aa9cf0e (commit)
       via  4434d7bef7a127ad8fb7e9dc6a43c9bd9e6601d1 (commit)
       via  c7a0fffa73e28d0d28b3706a9bc6b6e1ed9d2a7b (commit)
       via  344410fec60755f6b5cb2348ec9e7b67068f31ae (commit)
       via  e88330e1dbfed90776b634513372f71caa96ac5f (commit)
       via  6f9b0595718f8f7fd5324a6252207d29c40836b2 (commit)
       via  d11a387719a4ea69946801e4c865323f4b9016a3 (commit)
       via  88d4219ba95fa853b07c3397aeb4c2e6567e50c0 (commit)
       via  8da3cbf0ec4fcd563b8e779038a38811a77dece8 (commit)
       via  66bb0f76db68b8f96fc4ac819f9c07c7f8a404e6 (commit)
       via  26b876a067e285be526793254f9422067a89e071 (commit)
       via  be4ec3ec23084ca94e72a60ddb1a2d4250ade5cd (commit)
       via  d58451bac9dd51a562a24032d013e1eacc5a3fde (commit)
       via  6b09fa3b6e19b73f82940664802158baaca0297d (commit)
       via  1f7ffbad521f059f611876c27d8373f355ca8c40 (commit)
       via  0add6c7b1047219eda3f1d7fa13340da61cd96b5 (commit)
       via  3b1fef1e85522e061114beb6bd9013a51da16c08 (commit)
       via  3772748aa192829099877ac1c1e43e43b691df16 (commit)
       via  7dab055fe9854655b43338485ec8a960dea94080 (commit)
       via  78533f09dbf43b91578392dc8cee6700b3db7d2b (commit)
       via  5d8d976fe843af90f06dc9ff48408e96a51a0316 (commit)
      from  efea92bd3f50b23ed5d551cd7f140abe47959bfd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 41139644452bb11a162254b442ab611644ceb603
Author: Jelte Jansen <jelte at isc.org>
Date:   Mon May 23 16:13:51 2011 +0200

    [trac834] really set edns on outgoing queries
    
    put the code for it in a slightly better call, and update the tests. Also does not include setDNSSECAwareness, since that actively breaks the resolver right now (which is another issue)

commit c84b3ecae4d2d0b532c64c958857f8104dbae923
Merge: 27ba6b2117e3ab88aedaa904292707871e131393 c37ebedf94c5dbbed3c685272a0cdc4bea67fb04
Author: Jelte Jansen <jelte at isc.org>
Date:   Mon May 23 15:32:39 2011 +0200

    Merge branch 'master' into trac834

commit 27ba6b2117e3ab88aedaa904292707871e131393
Author: Jelte Jansen <jelte at isc.org>
Date:   Mon May 23 15:32:16 2011 +0200

    [trac834] revert previous patch for sync and redo

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |  683 ++-
 Makefile.am                                        |  450 +-
 README                                             |    4 +-
 configure.ac                                       |  116 +-
 doc/Doxyfile                                       |   10 +-
 doc/guide/bind10-guide.html                        |   44 +-
 doc/guide/bind10-guide.xml                         |   16 +-
 ext/asio/README                                    |    9 +-
 ext/asio/asio.hpp                                  |    2 +-
 ext/asio/asio/basic_datagram_socket.hpp            |   13 +-
 ext/asio/asio/basic_deadline_timer.hpp             |   13 +-
 ext/asio/asio/basic_io_object.hpp                  |    9 +-
 ext/asio/asio/basic_raw_socket.hpp                 |   15 +-
 ext/asio/asio/basic_serial_port.hpp                |   20 +-
 ext/asio/asio/basic_socket.hpp                     |   13 +-
 ext/asio/asio/basic_socket_acceptor.hpp            |    9 +-
 ext/asio/asio/basic_socket_iostream.hpp            |   17 +-
 ext/asio/asio/basic_socket_streambuf.hpp           |   19 +-
 ext/asio/asio/basic_stream_socket.hpp              |   13 +-
 ext/asio/asio/basic_streambuf.hpp                  |   38 +-
 ext/asio/asio/basic_streambuf_fwd.hpp              |   33 +
 ext/asio/asio/buffer.hpp                           |   22 +-
 ext/asio/asio/buffered_read_stream.hpp             |   15 +-
 ext/asio/asio/buffered_read_stream_fwd.hpp         |    6 +-
 ext/asio/asio/buffered_stream.hpp                  |   13 +-
 ext/asio/asio/buffered_stream_fwd.hpp              |    6 +-
 ext/asio/asio/buffered_write_stream.hpp            |   17 +-
 ext/asio/asio/buffered_write_stream_fwd.hpp        |    6 +-
 ext/asio/asio/buffers_iterator.hpp                 |   20 +-
 ext/asio/asio/completion_condition.hpp             |    8 +-
 ext/asio/asio/datagram_socket_service.hpp          |   12 +-
 ext/asio/asio/deadline_timer.hpp                   |   10 +-
 ext/asio/asio/deadline_timer_service.hpp           |   14 +-
 ext/asio/asio/detail/array_fwd.hpp                 |   25 +
 ext/asio/asio/detail/base_from_completion_cond.hpp |   17 +-
 ext/asio/asio/detail/bind_handler.hpp              |   31 +-
 ext/asio/asio/detail/buffer_resize_guard.hpp       |   12 +-
 ext/asio/asio/detail/buffer_sequence_adapter.hpp   |   20 +-
 ext/asio/asio/detail/buffered_stream_storage.hpp   |   14 +-
 ext/asio/asio/detail/call_stack.hpp                |   11 +-
 ext/asio/asio/detail/completion_handler.hpp        |   34 +-
 ext/asio/asio/detail/config.hpp                    |  205 +
 ext/asio/asio/detail/consuming_buffers.hpp         |   20 +-
 ext/asio/asio/detail/deadline_timer_service.hpp    |   76 +-
 ext/asio/asio/detail/descriptor_ops.hpp            |  171 +-
 ext/asio/asio/detail/descriptor_read_op.hpp        |  114 +
 ext/asio/asio/detail/descriptor_write_op.hpp       |  114 +
 ext/asio/asio/detail/dev_poll_reactor.hpp          |  366 +-
 ext/asio/asio/detail/dev_poll_reactor_fwd.hpp      |   19 +-
 ext/asio/asio/detail/epoll_reactor.hpp             |  426 +--
 ext/asio/asio/detail/epoll_reactor_fwd.hpp         |   26 +-
 ext/asio/asio/detail/event.hpp                     |   14 +-
 .../asio/detail/eventfd_select_interrupter.hpp     |  120 +-
 ext/asio/asio/detail/fd_set_adapter.hpp            |   15 +-
 ext/asio/asio/detail/fenced_block.hpp              |   34 +-
 ext/asio/asio/detail/gcc_arm_fenced_block.hpp      |   76 +
 ext/asio/asio/detail/gcc_hppa_fenced_block.hpp     |   58 +
 ext/asio/asio/detail/gcc_sync_fenced_block.hpp     |   61 +
 ext/asio/asio/detail/gcc_x86_fenced_block.hpp      |   18 +-
 ext/asio/asio/detail/handler_alloc_helpers.hpp     |  238 +-
 ext/asio/asio/detail/handler_invoke_helpers.hpp    |   14 +-
 ext/asio/asio/detail/hash_map.hpp                  |   35 +-
 ext/asio/asio/detail/impl/descriptor_ops.ipp       |  382 ++
 ext/asio/asio/detail/impl/dev_poll_reactor.hpp     |   77 +
 ext/asio/asio/detail/impl/dev_poll_reactor.ipp     |  338 +
 ext/asio/asio/detail/impl/epoll_reactor.hpp        |   75 +
 ext/asio/asio/detail/impl/epoll_reactor.ipp        |  390 ++
 .../detail/impl/eventfd_select_interrupter.ipp     |  125 +
 ext/asio/asio/detail/impl/kqueue_reactor.hpp       |   79 +
 ext/asio/asio/detail/impl/kqueue_reactor.ipp       |  385 ++
 .../asio/detail/impl/pipe_select_interrupter.ipp   |   96 +
 ext/asio/asio/detail/impl/posix_event.ipp          |   46 +
 ext/asio/asio/detail/impl/posix_mutex.ipp          |   46 +
 ext/asio/asio/detail/impl/posix_thread.ipp         |   74 +
 ext/asio/asio/detail/impl/posix_tss_ptr.ipp        |   46 +
 .../detail/impl/reactive_descriptor_service.ipp    |  136 +
 .../detail/impl/reactive_serial_port_service.ipp   |  151 +
 .../detail/impl/reactive_socket_service_base.ipp   |  212 +
 .../asio/detail/impl/resolver_service_base.ipp     |  106 +
 ext/asio/asio/detail/impl/select_reactor.hpp       |   84 +
 ext/asio/asio/detail/impl/select_reactor.ipp       |  273 +
 ext/asio/asio/detail/impl/service_registry.hpp     |   70 +
 ext/asio/asio/detail/impl/service_registry.ipp     |  164 +
 ext/asio/asio/detail/impl/socket_ops.ipp           | 2917 +++++++++
 .../asio/detail/impl/socket_select_interrupter.ipp |  151 +
 ext/asio/asio/detail/impl/strand_service.hpp       |  140 +
 ext/asio/asio/detail/impl/strand_service.ipp       |  106 +
 ext/asio/asio/detail/impl/task_io_service.hpp      |   60 +
 ext/asio/asio/detail/impl/task_io_service.ipp      |  354 +
 ext/asio/asio/detail/impl/throw_error.ipp          |   47 +
 ext/asio/asio/detail/impl/timer_queue.ipp          |   85 +
 ext/asio/asio/detail/impl/timer_queue_set.ipp      |  101 +
 ext/asio/asio/detail/impl/win_event.ipp            |   50 +
 .../asio/detail/impl/win_iocp_handle_service.ipp   |  452 ++
 ext/asio/asio/detail/impl/win_iocp_io_service.hpp  |  115 +
 ext/asio/asio/detail/impl/win_iocp_io_service.ipp  |  496 ++
 .../detail/impl/win_iocp_serial_port_service.ipp   |  180 +
 .../detail/impl/win_iocp_socket_service_base.ipp   |  575 ++
 ext/asio/asio/detail/impl/win_mutex.ipp            |   78 +
 ext/asio/asio/detail/impl/win_thread.ipp           |  138 +
 ext/asio/asio/detail/impl/win_tss_ptr.ipp          |   57 +
 ext/asio/asio/detail/impl/winsock_init.ipp         |   69 +
 ext/asio/asio/detail/io_control.hpp                |   14 +-
 ext/asio/asio/detail/kqueue_reactor.hpp            |  406 +-
 ext/asio/asio/detail/kqueue_reactor_fwd.hpp        |   23 +-
 ext/asio/asio/detail/local_free_on_block_exit.hpp  |   18 +-
 ext/asio/asio/detail/macos_fenced_block.hpp        |   20 +-
 ext/asio/asio/detail/mutex.hpp                     |   14 +-
 ext/asio/asio/detail/noncopyable.hpp               |   14 +-
 ext/asio/asio/detail/null_event.hpp                |   18 +-
 ext/asio/asio/detail/null_fenced_block.hpp         |    6 +-
 ext/asio/asio/detail/null_mutex.hpp                |   18 +-
 ext/asio/asio/detail/null_signal_blocker.hpp       |   28 +-
 ext/asio/asio/detail/null_thread.hpp               |   31 +-
 ext/asio/asio/detail/null_tss_ptr.hpp              |   18 +-
 ext/asio/asio/detail/object_pool.hpp               |  146 +
 ext/asio/asio/detail/old_win_sdk_compat.hpp        |   18 +-
 ext/asio/asio/detail/op_queue.hpp                  |   10 +-
 ext/asio/asio/detail/operation.hpp                 |   15 +-
 ext/asio/asio/detail/pipe_select_interrupter.hpp   |   84 +-
 ext/asio/asio/detail/pop_options.hpp               |   16 +-
 ext/asio/asio/detail/posix_event.hpp               |   44 +-
 ext/asio/asio/detail/posix_fd_set_adapter.hpp      |   19 +-
 ext/asio/asio/detail/posix_mutex.hpp               |   43 +-
 ext/asio/asio/detail/posix_signal_blocker.hpp      |   23 +-
 ext/asio/asio/detail/posix_thread.hpp              |   80 +-
 ext/asio/asio/detail/posix_tss_ptr.hpp             |   44 +-
 ext/asio/asio/detail/push_options.hpp              |   18 +-
 .../asio/detail/reactive_descriptor_service.hpp    |  549 +--
 ext/asio/asio/detail/reactive_null_buffers_op.hpp  |   83 +
 .../asio/detail/reactive_serial_port_service.hpp   |  186 +-
 ext/asio/asio/detail/reactive_socket_accept_op.hpp |  131 +
 .../asio/detail/reactive_socket_connect_op.hpp     |  101 +
 ext/asio/asio/detail/reactive_socket_recv_op.hpp   |  118 +
 .../asio/detail/reactive_socket_recvfrom_op.hpp    |  128 +
 ext/asio/asio/detail/reactive_socket_send_op.hpp   |  115 +
 ext/asio/asio/detail/reactive_socket_sendto_op.hpp |  118 +
 ext/asio/asio/detail/reactive_socket_service.hpp   | 1576 +-----
 .../asio/detail/reactive_socket_service_base.hpp   |  298 +
 ext/asio/asio/detail/reactor.hpp                   |   10 +-
 ext/asio/asio/detail/reactor_fwd.hpp               |   30 +-
 ext/asio/asio/detail/reactor_op.hpp                |   11 +-
 ext/asio/asio/detail/reactor_op_queue.hpp          |   13 +-
 ext/asio/asio/detail/regex_fwd.hpp                 |   31 +
 ext/asio/asio/detail/resolve_endpoint_op.hpp       |  116 +
 ext/asio/asio/detail/resolve_op.hpp                |  126 +
 ext/asio/asio/detail/resolver_service.hpp          |  401 +--
 ext/asio/asio/detail/resolver_service_base.hpp     |  123 +
 ext/asio/asio/detail/scoped_lock.hpp               |   10 +-
 ext/asio/asio/detail/select_interrupter.hpp        |   21 +-
 ext/asio/asio/detail/select_reactor.hpp            |  308 +-
 ext/asio/asio/detail/select_reactor_fwd.hpp        |   11 +-
 ext/asio/asio/detail/service_registry.hpp          |  197 +-
 ext/asio/asio/detail/service_registry_fwd.hpp      |   10 +-
 ext/asio/asio/detail/shared_ptr.hpp                |   38 +
 ext/asio/asio/detail/signal_blocker.hpp            |   24 +-
 ext/asio/asio/detail/signal_init.hpp               |   20 +-
 ext/asio/asio/detail/socket_holder.hpp             |   17 +-
 ext/asio/asio/detail/socket_ops.hpp                | 2051 +------
 ext/asio/asio/detail/socket_option.hpp             |   14 +-
 ext/asio/asio/detail/socket_select_interrupter.hpp |  156 +-
 ext/asio/asio/detail/socket_types.hpp              |   76 +-
 ext/asio/asio/detail/solaris_fenced_block.hpp      |   20 +-
 ext/asio/asio/detail/strand_service.hpp            |  204 +-
 ext/asio/asio/detail/task_io_service.hpp           |  381 +-
 ext/asio/asio/detail/task_io_service_fwd.hpp       |   11 +-
 ext/asio/asio/detail/task_io_service_operation.hpp |   18 +-
 ext/asio/asio/detail/thread.hpp                    |   14 +-
 ext/asio/asio/detail/throw_error.hpp               |   35 +-
 ext/asio/asio/detail/timer_op.hpp                  |   11 +-
 ext/asio/asio/detail/timer_queue.hpp               |  289 +-
 ext/asio/asio/detail/timer_queue_base.hpp          |   11 +-
 ext/asio/asio/detail/timer_queue_fwd.hpp           |   10 +-
 ext/asio/asio/detail/timer_queue_set.hpp           |   85 +-
 ext/asio/asio/detail/timer_scheduler.hpp           |   11 +-
 ext/asio/asio/detail/timer_scheduler_fwd.hpp       |   28 +-
 ext/asio/asio/detail/tss_ptr.hpp                   |   14 +-
 ext/asio/asio/detail/wait_handler.hpp              |   76 +
 ext/asio/asio/detail/weak_ptr.hpp                  |   39 +
 ext/asio/asio/detail/win_event.hpp                 |   40 +-
 ext/asio/asio/detail/win_fd_set_adapter.hpp        |   16 +-
 ext/asio/asio/detail/win_fenced_block.hpp          |   36 +-
 ext/asio/asio/detail/win_iocp_handle_read_op.hpp   |  101 +
 ext/asio/asio/detail/win_iocp_handle_service.hpp   |  573 +--
 ext/asio/asio/detail/win_iocp_handle_write_op.hpp  |   97 +
 ext/asio/asio/detail/win_iocp_io_service.hpp       |  599 +--
 ext/asio/asio/detail/win_iocp_io_service_fwd.hpp   |   30 +-
 ext/asio/asio/detail/win_iocp_null_buffers_op.hpp  |  112 +
 ext/asio/asio/detail/win_iocp_operation.hpp        |   19 +-
 ext/asio/asio/detail/win_iocp_overlapped_op.hpp    |   84 +
 ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp   |   72 +-
 .../asio/detail/win_iocp_serial_port_service.hpp   |  214 +-
 ext/asio/asio/detail/win_iocp_socket_accept_op.hpp |  158 +
 ext/asio/asio/detail/win_iocp_socket_recv_op.hpp   |  108 +
 .../asio/detail/win_iocp_socket_recvfrom_op.hpp    |  116 +
 ext/asio/asio/detail/win_iocp_socket_send_op.hpp   |  102 +
 ext/asio/asio/detail/win_iocp_socket_service.hpp   | 1806 +-----
 .../asio/detail/win_iocp_socket_service_base.hpp   |  385 ++
 ext/asio/asio/detail/win_mutex.hpp                 |   69 +-
 ext/asio/asio/detail/win_thread.hpp                |  153 +-
 ext/asio/asio/detail/win_tss_ptr.hpp               |   44 +-
 ext/asio/asio/detail/wince_thread.hpp              |   32 +-
 ext/asio/asio/detail/winsock_init.hpp              |  120 +-
 ext/asio/asio/detail/wrapped_handler.hpp           |   18 +-
 ext/asio/asio/error.hpp                            |   44 +-
 ext/asio/asio/error_code.hpp                       |   28 +-
 ext/asio/asio/handler_alloc_hook.hpp               |    8 +-
 ext/asio/asio/handler_invoke_hook.hpp              |    4 +-
 ext/asio/asio/impl/error.ipp                       |   33 +
 ext/asio/asio/impl/error_code.ipp                  |   97 +-
 ext/asio/asio/impl/io_service.hpp                  |  132 +
 ext/asio/asio/impl/io_service.ipp                  |  143 +-
 ext/asio/asio/impl/read.hpp                        |  386 ++
 ext/asio/asio/impl/read_at.hpp                     |  410 ++
 ext/asio/asio/impl/read_until.hpp                  |  902 +++
 ext/asio/asio/impl/serial_port_base.hpp            |   59 +
 ext/asio/asio/impl/serial_port_base.ipp            |  106 +-
 ext/asio/asio/impl/src.cpp                         |   25 +
 ext/asio/asio/impl/src.hpp                         |   65 +
 ext/asio/asio/impl/write.hpp                       |  396 ++
 ext/asio/asio/impl/write_at.hpp                    |  417 ++
 ext/asio/asio/io_service.hpp                       |  105 +-
 ext/asio/asio/ip/address.hpp                       |  207 +-
 ext/asio/asio/ip/address_v4.hpp                    |  175 +-
 ext/asio/asio/ip/address_v6.hpp                    |  305 +-
 ext/asio/asio/ip/basic_endpoint.hpp                |  235 +-
 ext/asio/asio/ip/basic_resolver.hpp                |   13 +-
 ext/asio/asio/ip/basic_resolver_entry.hpp          |   11 +-
 ext/asio/asio/ip/basic_resolver_iterator.hpp       |   18 +-
 ext/asio/asio/ip/basic_resolver_query.hpp          |   15 +-
 ext/asio/asio/ip/detail/endpoint.hpp               |  140 +
 ext/asio/asio/ip/detail/impl/endpoint.ipp          |  202 +
 ext/asio/asio/ip/detail/socket_option.hpp          |   17 +-
 ext/asio/asio/ip/host_name.hpp                     |   44 +-
 ext/asio/asio/ip/icmp.hpp                          |   13 +-
 ext/asio/asio/ip/impl/address.hpp                  |   53 +
 ext/asio/asio/ip/impl/address.ipp                  |  203 +
 ext/asio/asio/ip/impl/address_v4.hpp               |   53 +
 ext/asio/asio/ip/impl/address_v4.ipp               |  178 +
 ext/asio/asio/ip/impl/address_v6.hpp               |   53 +
 ext/asio/asio/ip/impl/address_v6.ipp               |  313 +
 ext/asio/asio/ip/impl/basic_endpoint.hpp           |   55 +
 ext/asio/asio/ip/impl/host_name.ipp                |   56 +
 ext/asio/asio/ip/multicast.hpp                     |   15 +-
 ext/asio/asio/ip/resolver_query_base.hpp           |   15 +-
 ext/asio/asio/ip/resolver_service.hpp              |   23 +-
 ext/asio/asio/ip/tcp.hpp                           |   15 +-
 ext/asio/asio/ip/udp.hpp                           |   13 +-
 ext/asio/asio/ip/unicast.hpp                       |   15 +-
 ext/asio/asio/ip/v6_only.hpp                       |   11 +-
 ext/asio/asio/is_read_buffered.hpp                 |   11 +-
 ext/asio/asio/is_write_buffered.hpp                |   11 +-
 ext/asio/asio/local/basic_endpoint.hpp             |  137 +-
 ext/asio/asio/local/connect_pair.hpp               |   30 +-
 ext/asio/asio/local/datagram_protocol.hpp          |   20 +-
 ext/asio/asio/local/detail/endpoint.hpp            |  133 +
 ext/asio/asio/local/detail/impl/endpoint.ipp       |  138 +
 ext/asio/asio/local/stream_protocol.hpp            |   20 +-
 ext/asio/asio/placeholders.hpp                     |    9 +-
 ext/asio/asio/posix/basic_descriptor.hpp           |   20 +-
 ext/asio/asio/posix/basic_stream_descriptor.hpp    |   24 +-
 ext/asio/asio/posix/descriptor_base.hpp            |   19 +-
 ext/asio/asio/posix/stream_descriptor.hpp          |   14 +-
 ext/asio/asio/posix/stream_descriptor_service.hpp  |   32 +-
 ext/asio/asio/raw_socket_service.hpp               |   12 +-
 ext/asio/asio/read.hpp                             |   17 +-
 ext/asio/asio/read_at.hpp                          |   17 +-
 ext/asio/asio/read_until.hpp                       |   21 +-
 ext/asio/asio/serial_port.hpp                      |   10 +-
 ext/asio/asio/serial_port_base.hpp                 |   71 +-
 ext/asio/asio/serial_port_service.hpp              |   23 +-
 ext/asio/asio/socket_acceptor_service.hpp          |    8 +-
 ext/asio/asio/socket_base.hpp                      |   11 +-
 ext/asio/asio/ssl.hpp                              |    2 +-
 ext/asio/asio/ssl/basic_context.hpp                |   16 +-
 ext/asio/asio/ssl/context.hpp                      |   11 +-
 ext/asio/asio/ssl/context_base.hpp                 |   15 +-
 ext/asio/asio/ssl/context_service.hpp              |   15 +-
 .../asio/ssl/detail/openssl_context_service.hpp    |   15 +-
 ext/asio/asio/ssl/detail/openssl_init.hpp          |   15 +-
 ext/asio/asio/ssl/detail/openssl_operation.hpp     |   22 +-
 .../asio/ssl/detail/openssl_stream_service.hpp     |   26 +-
 ext/asio/asio/ssl/detail/openssl_types.hpp         |   16 +-
 ext/asio/asio/ssl/stream.hpp                       |   17 +-
 ext/asio/asio/ssl/stream_base.hpp                  |   11 +-
 ext/asio/asio/ssl/stream_service.hpp               |   18 +-
 ext/asio/asio/strand.hpp                           |    9 +-
 ext/asio/asio/stream_socket_service.hpp            |   12 +-
 ext/asio/asio/streambuf.hpp                        |   10 +-
 ext/asio/asio/system_error.hpp                     |   11 +-
 ext/asio/asio/thread.hpp                           |    7 +-
 ext/asio/asio/time_traits.hpp                      |    6 +-
 ext/asio/asio/version.hpp                          |    4 +-
 ext/asio/asio/windows/basic_handle.hpp             |   22 +-
 .../asio/windows/basic_random_access_handle.hpp    |   24 +-
 ext/asio/asio/windows/basic_stream_handle.hpp      |   22 +-
 ext/asio/asio/windows/overlapped_ptr.hpp           |   26 +-
 ext/asio/asio/windows/random_access_handle.hpp     |   14 +-
 .../asio/windows/random_access_handle_service.hpp  |   30 +-
 ext/asio/asio/windows/stream_handle.hpp            |   14 +-
 ext/asio/asio/windows/stream_handle_service.hpp    |   31 +-
 ext/asio/asio/write.hpp                            |   17 +-
 ext/asio/asio/write_at.hpp                         |   17 +-
 src/bin/Makefile.am                                |    2 +-
 src/bin/auth/Makefile.am                           |    5 +-
 src/bin/auth/auth_config.cc                        |  347 +
 src/bin/auth/{config.h => auth_config.h}           |    0 
 src/bin/auth/auth_srv.cc                           |   11 +-
 src/bin/auth/auth_srv.h                            |   33 +-
 src/bin/auth/benchmarks/Makefile.am                |    3 +-
 src/bin/auth/benchmarks/query_bench.cc             |   11 +-
 src/bin/auth/common.cc                             |   36 +
 src/bin/auth/common.h                              |   11 +-
 src/bin/auth/config.cc                             |  347 -
 src/bin/auth/main.cc                               |   38 +-
 src/bin/auth/statistics.cc                         |    4 -
 src/bin/auth/tests/Makefile.am                     |    7 +-
 src/bin/auth/tests/auth_srv_unittest.cc            |    4 +-
 src/bin/auth/tests/command_unittest.cc             |    6 +-
 src/bin/auth/tests/common_unittest.cc              |   96 +
 src/bin/auth/tests/config_unittest.cc              |    5 +-
 src/bin/bind10/bind10.8                            |   49 +-
 src/bin/bind10/bind10.py.in                        |   27 +-
 src/bin/bind10/bind10.xml                          |   59 +-
 src/bin/bind10/bob.spec                            |    5 +
 src/bin/bind10/run_bind10.sh.in                    |    4 +-
 src/bin/bind10/tests/Makefile.am                   |    3 +-
 src/bin/bind10/tests/bind10_test.py.in             |   61 +-
 src/bin/cfgmgr/Makefile.am                         |    2 +-
 src/bin/cfgmgr/b10-cfgmgr.py.in                    |   47 +-
 src/bin/cfgmgr/plugins/Makefile.am                 |    5 +
 src/bin/cfgmgr/plugins/README                      |   34 +
 src/bin/cfgmgr/plugins/tests/Makefile.am           |   27 +
 src/bin/cfgmgr/plugins/tests/tsig_keys_test.py     |  103 +
 src/bin/cfgmgr/plugins/tsig_keys.py                |   50 +
 src/bin/cfgmgr/plugins/tsig_keys.spec              |   21 +
 src/bin/cfgmgr/tests/Makefile.am                   |    3 +-
 src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in         |   34 +
 .../cfgmgr/tests/testdata/plugins/testplugin.py    |   34 +
 src/bin/host/Makefile.am                           |   31 +-
 src/bin/host/README                                |   16 +-
 src/bin/host/b10-host.1                            |  122 +
 src/bin/host/b10-host.xml                          |  201 +
 src/bin/host/host.cc                               |   77 +-
 src/bin/msgq/tests/msgq_test.py                    |    4 +-
 src/bin/resolver/Makefile.am                       |    3 +
 src/bin/resolver/main.cc                           |    8 +-
 src/bin/resolver/resolver.cc                       |   28 +-
 src/bin/resolver/resolver.h                        |   44 +-
 src/bin/resolver/response_scrubber.cc              |   26 +-
 src/bin/resolver/response_scrubber.h               |    4 +-
 src/bin/resolver/tests/Makefile.am                 |    1 +
 src/bin/resolver/tests/resolver_config_unittest.cc |    6 +-
 .../resolver/tests/response_scrubber_unittest.cc   |    4 +-
 src/bin/sockcreator/Makefile.am                    |   18 +
 src/bin/sockcreator/README                         |   49 +
 src/bin/sockcreator/main.cc                        |   26 +
 src/bin/sockcreator/sockcreator.cc                 |  151 +
 src/bin/sockcreator/sockcreator.h                  |  100 +
 src/bin/sockcreator/tests/Makefile.am              |   25 +
 src/bin/sockcreator/tests/run_unittests.cc         |   22 +
 src/bin/sockcreator/tests/sockcreator_tests.cc     |  273 +
 src/bin/stats/Makefile.am                          |   30 +-
 src/bin/stats/b10-stats-httpd.8                    |  136 +
 src/bin/stats/b10-stats-httpd.xml                  |  221 +
 src/bin/stats/b10-stats.8                          |   25 +-
 src/bin/stats/b10-stats.xml                        |   22 +-
 src/bin/stats/run_b10-stats.sh.in                  |   33 -
 src/bin/stats/run_b10-stats_stub.sh.in             |   33 -
 src/bin/stats/stats-httpd-xml.tpl.in               |   24 +
 src/bin/stats/stats-httpd-xsd.tpl.in               |   38 +
 src/bin/stats/stats-httpd-xsl.tpl.in               |   56 +
 src/bin/stats/stats-httpd.spec.in                  |   54 +
 src/bin/stats/stats-schema.spec.in                 |   87 +
 src/bin/stats/stats.py.in                          |   36 +-
 src/bin/stats/stats.spec.in                        |   61 +
 src/bin/stats/stats.spec.pre.in                    |  140 -
 src/bin/stats/stats_httpd.py.in                    |  485 ++
 src/bin/stats/stats_stub.py.in                     |  154 -
 src/bin/stats/tests/Makefile.am                    |   10 +-
 src/bin/stats/tests/b10-stats-httpd_test.py        |  444 ++
 src/bin/stats/tests/b10-stats_stub_test.py         |  115 -
 src/bin/stats/tests/b10-stats_test.py              |   36 +-
 src/bin/stats/tests/fake_select.py                 |   43 +
 src/bin/stats/tests/fake_socket.py                 |   70 +
 src/bin/stats/tests/http/Makefile.am               |    2 +
 .../stats/tests/{isc/utils => http}/__init__.py    |    0 
 src/bin/stats/tests/http/server.py                 |   96 +
 src/bin/stats/tests/isc/cc/session.py              |   46 +-
 src/bin/stats/tests/isc/config/ccsession.py        |   59 +-
 src/bin/stats/tests/isc/util/process.py            |    5 +-
 src/bin/stats/tests/isc/utils/Makefile.am          |    2 -
 src/bin/stats/tests/isc/utils/process.py           |   18 -
 src/bin/stats/tests/stats_test.in                  |   31 -
 src/bin/xfrin/b10-xfrin.8                          |   43 +-
 src/bin/xfrin/b10-xfrin.xml                        |   46 +-
 src/bin/xfrin/tests/Makefile.am                    |    2 +-
 src/bin/xfrin/tests/xfrin_test.py                  |  555 ++-
 src/bin/xfrin/xfrin.py.in                          |  418 +-
 src/bin/xfrin/xfrin.spec                           |   45 +-
 src/bin/xfrout/tests/Makefile.am                   |    4 +-
 src/bin/xfrout/tests/xfrout_test.py                |  437 --
 src/bin/xfrout/tests/xfrout_test.py.in             |  469 ++
 src/bin/xfrout/xfrout.py.in                        |   41 +-
 src/bin/zonemgr/b10-zonemgr.8                      |   37 +-
 src/bin/zonemgr/b10-zonemgr.xml                    |   66 +-
 src/bin/zonemgr/tests/zonemgr_test.py              |  369 +-
 src/bin/zonemgr/zonemgr.py.in                      |  142 +-
 src/bin/zonemgr/zonemgr.spec.pre.in                |   38 +-
 src/cppcheck-suppress.lst                          |    8 +-
 src/lib/Makefile.am                                |    5 +-
 src/lib/asiodns/Makefile.am                        |   41 +
 src/lib/asiodns/README                             |  157 +
 src/lib/asiodns/asiodef.mes                        |   56 +
 src/lib/asiodns/asiodns.h                          |   23 +
 src/lib/asiodns/dns_answer.h                       |   77 +
 src/lib/asiodns/dns_lookup.h                       |   85 +
 src/lib/asiodns/dns_server.h                       |  157 +
 src/lib/asiodns/dns_service.cc                     |  201 +
 src/lib/asiodns/dns_service.h                      |  114 +
 src/lib/asiodns/io_fetch.cc                        |  429 ++
 src/lib/asiodns/io_fetch.h                         |  228 +
 src/lib/asiodns/tcp_server.cc                      |  244 +
 src/lib/asiodns/tcp_server.h                       |  124 +
 src/lib/asiodns/tests/Makefile.am                  |   50 +
 src/lib/asiodns/tests/dns_server_unittest.cc       |  503 ++
 src/lib/asiodns/tests/io_fetch_unittest.cc         |  731 +++
 src/lib/asiodns/tests/io_service_unittest.cc       |  118 +
 .../{asiolink => asiodns}/tests/run_unittests.cc   |    0 
 src/lib/asiodns/udp_server.cc                      |  325 +
 src/lib/asiodns/udp_server.h                       |  108 +
 src/lib/asiolink/Makefile.am                       |   13 -
 src/lib/asiolink/README                            |  160 -
 src/lib/asiolink/asiodef.cc                        |   37 -
 src/lib/asiolink/asiodef.h                         |   21 -
 src/lib/asiolink/asiodef.msg                       |   56 -
 src/lib/asiolink/asiolink.h                        |    9 -
 src/lib/asiolink/asiolink_utilities.h              |   61 -
 src/lib/asiolink/dns_answer.h                      |   73 -
 src/lib/asiolink/dns_lookup.h                      |   83 -
 src/lib/asiolink/dns_server.h                      |  155 -
 src/lib/asiolink/dns_service.cc                    |  200 -
 src/lib/asiolink/dns_service.h                     |  112 -
 src/lib/asiolink/dummy_io_cb.h                     |    2 +
 src/lib/asiolink/interval_timer.cc                 |    4 +-
 src/lib/asiolink/interval_timer.h                  |    6 +-
 src/lib/asiolink/io_address.cc                     |    4 +-
 src/lib/asiolink/io_address.h                      |    4 +-
 src/lib/asiolink/io_asio_socket.h                  |    9 +-
 src/lib/asiolink/io_endpoint.cc                    |    4 +-
 src/lib/asiolink/io_endpoint.h                     |    4 +-
 src/lib/asiolink/io_error.h                        |    4 +-
 src/lib/asiolink/io_fetch.cc                       |  386 --
 src/lib/asiolink/io_fetch.h                        |  179 -
 src/lib/asiolink/io_message.h                      |    4 +-
 src/lib/asiolink/io_service.cc                     |    4 +-
 src/lib/asiolink/io_service.h                      |    6 +-
 src/lib/asiolink/io_socket.cc                      |    6 +-
 src/lib/asiolink/io_socket.h                       |    2 +
 src/lib/asiolink/qid_gen.cc                        |   54 -
 src/lib/asiolink/qid_gen.h                         |   85 -
 src/lib/asiolink/simple_callback.h                 |    4 +-
 src/lib/asiolink/tcp_endpoint.h                    |    4 +-
 src/lib/asiolink/tcp_server.cc                     |  239 -
 src/lib/asiolink/tcp_server.h                      |  120 -
 src/lib/asiolink/tcp_socket.h                      |   16 +-
 src/lib/asiolink/tests/Makefile.am                 |   17 +-
 .../asiolink/tests/asiolink_utilities_unittest.cc  |   74 -
 src/lib/asiolink/tests/dns_server_unittest.cc      |  501 --
 src/lib/asiolink/tests/interval_timer_unittest.cc  |   28 +-
 src/lib/asiolink/tests/io_address_unittest.cc      |    2 +-
 src/lib/asiolink/tests/io_endpoint_unittest.cc     |    2 +-
 src/lib/asiolink/tests/io_fetch_unittest.cc        |  723 ---
 src/lib/asiolink/tests/io_service_unittest.cc      |  116 -
 src/lib/asiolink/tests/io_socket_unittest.cc       |    2 +-
 src/lib/asiolink/tests/qid_gen_unittest.cc         |   59 -
 src/lib/asiolink/tests/run_unittests.cc            |    1 -
 src/lib/asiolink/tests/tcp_endpoint_unittest.cc    |    2 +-
 src/lib/asiolink/tests/tcp_socket_unittest.cc      |    8 +-
 src/lib/asiolink/tests/udp_endpoint_unittest.cc    |    2 +-
 src/lib/asiolink/tests/udp_socket_unittest.cc      |    8 +-
 src/lib/asiolink/udp_endpoint.h                    |    4 +-
 src/lib/asiolink/udp_server.cc                     |  321 -
 src/lib/asiolink/udp_server.h                      |  106 -
 src/lib/asiolink/udp_socket.h                      |    6 +-
 src/lib/bench/benchmark_util.cc                    |    3 +-
 src/lib/bench/tests/Makefile.am                    |    1 +
 src/lib/bench/tests/loadquery_unittest.cc          |    3 +-
 src/lib/cache/Makefile.am                          |    1 +
 src/lib/cache/message_cache.h                      |    4 +-
 src/lib/cache/rrset_cache.h                        |    5 +-
 src/lib/cache/tests/Makefile.am                    |    2 +
 src/lib/cache/tests/cache_test_messagefromfile.h   |    4 +-
 src/lib/cache/tests/cache_test_sectioncount.h      |    2 +-
 src/lib/cache/tests/message_cache_unittest.cc      |    3 +-
 src/lib/cache/tests/message_entry_unittest.cc      |    2 +-
 src/lib/cc/Makefile.am                             |    1 +
 src/lib/cc/tests/Makefile.am                       |    1 -
 src/lib/config/Makefile.am                         |   20 +-
 src/lib/config/ccsession.cc                        |   82 +-
 src/lib/config/ccsession.h                         |   55 +-
 src/lib/config/config_log.cc                       |   26 +
 src/lib/config/config_log.h                        |   38 +
 src/lib/config/configdef.mes                       |   50 +
 src/lib/config/tests/Makefile.am                   |    1 +
 src/lib/config/tests/ccsession_unittests.cc        |  122 +-
 src/lib/config/tests/fake_session.cc               |    8 +-
 src/lib/config/tests/run_unittests.cc              |    7 +
 src/lib/cryptolink/Makefile.am                     |   14 +
 src/lib/cryptolink/crypto_hmac.cc                  |  281 +
 src/lib/cryptolink/crypto_hmac.h                   |  209 +
 src/lib/cryptolink/cryptolink.cc                   |   69 +
 src/lib/cryptolink/cryptolink.h                    |  208 +
 src/lib/cryptolink/tests/Makefile.am               |   26 +
 src/lib/cryptolink/tests/crypto_unittests.cc       |  756 +++
 src/lib/cryptolink/tests/run_unittests.cc          |   22 +
 src/lib/datasrc/Makefile.am                        |   15 +-
 src/lib/datasrc/cache.cc                           |   23 +-
 src/lib/datasrc/data_source.cc                     |  107 +-
 src/lib/datasrc/logger.cc                          |   23 +
 src/lib/datasrc/logger.h                           |   46 +
 src/lib/datasrc/memory_datasrc.cc                  |   60 +
 src/lib/datasrc/messagedef.mes                     |  498 ++
 src/lib/datasrc/query.cc                           |    2 +-
 src/lib/datasrc/sqlite3_datasrc.cc                 |   37 +-
 src/lib/datasrc/static_datasrc.cc                  |    5 +
 src/lib/datasrc/tests/Makefile.am                  |    6 +-
 src/lib/datasrc/tests/datasrc_unittest.cc          |   20 +-
 src/lib/datasrc/tests/logger_unittest.cc           |   31 +
 src/lib/datasrc/tests/query_unittest.cc            |    2 +-
 src/lib/datasrc/tests/rbtree_unittest.cc           |    2 +-
 src/lib/datasrc/tests/test_datasrc.cc              |    2 +-
 src/lib/dns/Makefile.am                            |   81 +-
 src/lib/dns/benchmarks/Makefile.am                 |   17 +
 src/lib/dns/benchmarks/README                      |   10 +
 .../benchmarks/benchmarkdata/rdatarender_data_com  |   32 +
 .../benchmarkdata/rdatarender_data_nxdomain        |   10 +
 .../benchmarks/benchmarkdata/rdatarender_data_org  |   22 +
 src/lib/dns/benchmarks/rdatarender_bench.cc        |  188 +
 src/lib/dns/buffer.h                               |  446 --
 src/lib/dns/dnssectime.cc                          |  211 -
 src/lib/dns/dnssectime.h                           |  145 -
 src/lib/dns/edns.cc                                |   30 +-
 src/lib/dns/edns.h                                 |   18 +-
 src/lib/dns/gen-rdatacode.py.in                    |   15 +-
 src/lib/dns/message.cc                             |  423 +-
 src/lib/dns/message.h                              |   65 +-
 src/lib/dns/messagerenderer.cc                     |   81 +-
 src/lib/dns/messagerenderer.h                      |  225 +-
 src/lib/dns/name.cc                                |    6 +-
 src/lib/dns/name.h                                 |   13 +-
 src/lib/dns/python/Makefile.am                     |   16 +-
 src/lib/dns/python/edns_python.cc                  |   18 +-
 src/lib/dns/python/message_python.cc               |  203 +-
 src/lib/dns/python/messagerenderer_python.cc       |  206 +-
 src/lib/dns/python/messagerenderer_python.h        |   52 +
 src/lib/dns/python/name_python.cc                  |  530 +-
 src/lib/dns/python/name_python.h                   |   84 +
 src/lib/dns/python/pydnspp.cc                      |   56 +-
 src/lib/dns/python/pydnspp_common.cc               |   18 +-
 src/lib/dns/python/pydnspp_common.h                |   29 +-
 src/lib/dns/python/pydnspp_towire.h                |  127 +
 src/lib/dns/python/question_python.cc              |    6 +-
 src/lib/dns/python/rcode_python.cc                 |  167 +-
 src/lib/dns/python/rcode_python.h                  |   57 +
 src/lib/dns/python/rdata_python.cc                 |    1 +
 src/lib/dns/python/rrclass_python.cc               |   12 +-
 src/lib/dns/python/rrset_python.cc                 |    9 +-
 src/lib/dns/python/rrttl_python.cc                 |    9 +-
 src/lib/dns/python/rrtype_python.cc                |   13 +-
 src/lib/dns/python/tests/Makefile.am               |    8 +-
 src/lib/dns/python/tests/edns_python_test.py       |   13 +-
 src/lib/dns/python/tests/message_python_test.py    |  114 +-
 .../python/tests/messagerenderer_python_test.py    |    5 +
 src/lib/dns/python/tests/name_python_test.py       |   19 +-
 src/lib/dns/python/tests/question_python_test.py   |    2 +-
 src/lib/dns/python/tests/rcode_python_test.py      |   19 +-
 src/lib/dns/python/tests/rrclass_python_test.py    |    9 +-
 src/lib/dns/python/tests/rrttl_python_test.py      |   10 +-
 src/lib/dns/python/tests/rrtype_python_test.py     |   16 +-
 src/lib/dns/python/tests/tsig_python_test.py       |  554 ++
 src/lib/dns/python/tests/tsig_rdata_python_test.py |   30 +
 src/lib/dns/python/tests/tsigerror_python_test.py  |   97 +
 src/lib/dns/python/tests/tsigkey_python_test.py    |   56 +-
 src/lib/dns/python/tests/tsigrecord_python_test.py |   44 +
 src/lib/dns/python/tsig_python.cc                  |  364 ++
 src/lib/dns/python/tsig_python.h                   |   47 +
 src/lib/dns/python/tsig_rdata_python.cc            |  369 ++
 src/lib/dns/python/tsig_rdata_python.h             |   57 +
 src/lib/dns/python/tsigerror_python.cc             |  370 ++
 src/lib/dns/python/tsigerror_python.h              |   52 +
 src/lib/dns/python/tsigerror_python_inc.cc         |   83 +
 src/lib/dns/python/tsigkey_python.cc               |  380 +-
 src/lib/dns/python/tsigkey_python.h                |   53 +
 src/lib/dns/python/tsigrecord_python.cc            |  311 +
 src/lib/dns/python/tsigrecord_python.h             |   53 +
 src/lib/dns/question.cc                            |    5 +-
 src/lib/dns/question.h                             |   16 +-
 src/lib/dns/rdata.cc                               |   14 +-
 src/lib/dns/rdata.h                                |   29 +-
 src/lib/dns/rdata/any_255/tsig_250.cc              |   25 +-
 src/lib/dns/rdata/ch_3/a_1.cc                      |    5 +-
 src/lib/dns/rdata/generic/cname_5.cc               |    5 +-
 src/lib/dns/rdata/generic/dname_39.cc              |    5 +-
 src/lib/dns/rdata/generic/dnskey_48.cc             |    8 +-
 src/lib/dns/rdata/generic/ds_43.cc                 |    9 +-
 src/lib/dns/rdata/generic/mx_15.cc                 |    5 +-
 src/lib/dns/rdata/generic/ns_2.cc                  |    5 +-
 src/lib/dns/rdata/generic/nsec3_50.cc              |   11 +-
 src/lib/dns/rdata/generic/nsec3param_51.cc         |    8 +-
 src/lib/dns/rdata/generic/nsec_47.cc               |    8 +-
 src/lib/dns/rdata/generic/opt_41.cc                |    5 +-
 src/lib/dns/rdata/generic/ptr_12.cc                |    5 +-
 src/lib/dns/rdata/generic/rp_17.cc                 |  125 +
 src/lib/dns/rdata/generic/rp_17.h                  |   88 +
 src/lib/dns/rdata/generic/rrsig_46.cc              |   10 +-
 src/lib/dns/rdata/generic/soa_6.cc                 |    5 +-
 src/lib/dns/rdata/generic/txt_16.cc                |    5 +-
 src/lib/dns/rdata/hs_4/a_1.cc                      |    5 +-
 src/lib/dns/rdata/in_1/a_1.cc                      |    5 +-
 src/lib/dns/rdata/in_1/aaaa_28.cc                  |    5 +-
 src/lib/dns/rdata/template.cc                      |    7 +-
 src/lib/dns/rdata/template.h                       |    2 +-
 src/lib/dns/rdatafields.cc                         |  223 +
 src/lib/dns/rdatafields.h                          |  427 ++
 src/lib/dns/rrclass-placeholder.h                  |   15 +-
 src/lib/dns/rrclass.cc                             |    5 +-
 src/lib/dns/rrparamregistry-placeholder.cc         |    1 +
 src/lib/dns/rrparamregistry.h                      |    4 +-
 src/lib/dns/rrset.cc                               |    9 +-
 src/lib/dns/rrset.h                                |   15 +-
 src/lib/dns/rrttl.cc                               |    5 +-
 src/lib/dns/rrttl.h                                |   15 +-
 src/lib/dns/rrtype-placeholder.h                   |   15 +-
 src/lib/dns/rrtype.cc                              |    6 +-
 src/lib/dns/tests/Makefile.am                      |   16 +-
 src/lib/dns/tests/base32hex_unittest.cc            |  159 -
 src/lib/dns/tests/base64_unittest.cc               |   93 -
 src/lib/dns/tests/buffer_unittest.cc               |  193 -
 src/lib/dns/tests/dnssectime_unittest.cc           |  163 -
 src/lib/dns/tests/edns_unittest.cc                 |    3 +-
 src/lib/dns/tests/hex_unittest.cc                  |  120 -
 src/lib/dns/tests/message_unittest.cc              |  195 +-
 src/lib/dns/tests/messagerenderer_unittest.cc      |    4 +-
 src/lib/dns/tests/name_unittest.cc                 |    3 +-
 src/lib/dns/tests/question_unittest.cc             |    3 +-
 src/lib/dns/tests/rdata_cname_unittest.cc          |    3 +-
 src/lib/dns/tests/rdata_dname_unittest.cc          |    3 +-
 src/lib/dns/tests/rdata_dnskey_unittest.cc         |    3 +-
 src/lib/dns/tests/rdata_ds_unittest.cc             |    3 +-
 src/lib/dns/tests/rdata_in_a_unittest.cc           |    3 +-
 src/lib/dns/tests/rdata_in_aaaa_unittest.cc        |    3 +-
 src/lib/dns/tests/rdata_mx_unittest.cc             |    3 +-
 src/lib/dns/tests/rdata_ns_unittest.cc             |    3 +-
 src/lib/dns/tests/rdata_nsec3_unittest.cc          |    6 +-
 src/lib/dns/tests/rdata_nsec3param_unittest.cc     |    8 +-
 src/lib/dns/tests/rdata_nsec_unittest.cc           |    3 +-
 src/lib/dns/tests/rdata_opt_unittest.cc            |    3 +-
 src/lib/dns/tests/rdata_ptr_unittest.cc            |    3 +-
 src/lib/dns/tests/rdata_rp_unittest.cc             |  163 +
 src/lib/dns/tests/rdata_rrsig_unittest.cc          |    5 +-
 src/lib/dns/tests/rdata_soa_unittest.cc            |    3 +-
 src/lib/dns/tests/rdata_tsig_unittest.cc           |    3 +-
 src/lib/dns/tests/rdata_txt_unittest.cc            |    3 +-
 src/lib/dns/tests/rdata_unittest.cc                |    3 +-
 src/lib/dns/tests/rdata_unittest.h                 |    4 +-
 src/lib/dns/tests/rdatafields_unittest.cc          |  380 ++
 src/lib/dns/tests/rrclass_unittest.cc              |    3 +-
 src/lib/dns/tests/rrparamregistry_unittest.cc      |    1 +
 src/lib/dns/tests/rrset_unittest.cc                |    3 +-
 src/lib/dns/tests/rrttl_unittest.cc                |    3 +-
 src/lib/dns/tests/rrtype_unittest.cc               |    3 +-
 src/lib/dns/tests/run_unittests.cc                 |    3 +
 src/lib/dns/tests/sha1_unittest.cc                 |  108 -
 src/lib/dns/tests/testdata/Makefile.am             |   41 +-
 src/lib/dns/tests/testdata/gen-wiredata.py.in      |  140 +-
 src/lib/dns/tests/testdata/message_fromWire12.spec |   21 +
 src/lib/dns/tests/testdata/message_fromWire13.spec |   20 +
 src/lib/dns/tests/testdata/message_fromWire14.spec |   21 +
 src/lib/dns/tests/testdata/message_fromWire15.spec |   22 +
 src/lib/dns/tests/testdata/message_fromWire16.spec |   21 +
 src/lib/dns/tests/testdata/message_toText1.spec    |   24 +
 src/lib/dns/tests/testdata/message_toText1.txt     |   14 +
 src/lib/dns/tests/testdata/message_toText2.spec    |   14 +
 src/lib/dns/tests/testdata/message_toText2.txt     |    8 +
 src/lib/dns/tests/testdata/message_toText3.spec    |   31 +
 src/lib/dns/tests/testdata/message_toText3.txt     |   17 +
 src/lib/dns/tests/testdata/message_toWire2.spec    |   21 +
 src/lib/dns/tests/testdata/message_toWire3.spec    |   22 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec |    6 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec |   12 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec |    7 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec |    7 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec |    7 +
 src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec |    7 +
 src/lib/dns/tests/testdata/rdata_rp_toWire1.spec   |    8 +
 src/lib/dns/tests/testdata/rdata_rp_toWire2.spec   |   14 +
 src/lib/dns/tests/testdata/rdatafields1.spec       |   10 +
 src/lib/dns/tests/testdata/rdatafields2.spec       |   11 +
 src/lib/dns/tests/testdata/rdatafields3.spec       |   11 +
 src/lib/dns/tests/testdata/rdatafields4.spec       |    7 +
 src/lib/dns/tests/testdata/rdatafields5.spec       |   12 +
 src/lib/dns/tests/testdata/rdatafields6.spec       |   13 +
 src/lib/dns/tests/testdata/tsig_verify1.spec       |   19 +
 src/lib/dns/tests/testdata/tsig_verify10.spec      |   22 +
 src/lib/dns/tests/testdata/tsig_verify2.spec       |   32 +
 src/lib/dns/tests/testdata/tsig_verify3.spec       |   26 +
 src/lib/dns/tests/testdata/tsig_verify4.spec       |   27 +
 src/lib/dns/tests/testdata/tsig_verify5.spec       |   26 +
 src/lib/dns/tests/testdata/tsig_verify6.spec       |   21 +
 src/lib/dns/tests/testdata/tsig_verify7.spec       |   21 +
 src/lib/dns/tests/testdata/tsig_verify8.spec       |   23 +
 src/lib/dns/tests/testdata/tsig_verify9.spec       |   21 +
 src/lib/dns/tests/testdata/tsigrecord_toWire1.spec |   16 +
 src/lib/dns/tests/testdata/tsigrecord_toWire2.spec |   19 +
 src/lib/dns/tests/tsig_unittest.cc                 |  907 +++
 src/lib/dns/tests/tsigerror_unittest.cc            |  116 +
 src/lib/dns/tests/tsigkey_unittest.cc              |  141 +-
 src/lib/dns/tests/tsigrecord_unittest.cc           |  159 +
 src/lib/dns/tsig.cc                                |  453 ++
 src/lib/dns/tsig.h                                 |  394 ++
 src/lib/dns/tsigerror.cc                           |   68 +
 src/lib/dns/tsigerror.h                            |  338 +
 src/lib/dns/tsigkey.cc                             |  143 +-
 src/lib/dns/tsigkey.h                              |   79 +-
 src/lib/dns/tsigrecord.cc                          |  147 +
 src/lib/dns/tsigrecord.h                           |  308 +
 src/lib/dns/util/README                            |   31 -
 src/lib/dns/util/base32hex.h                       |   61 -
 src/lib/dns/util/base64.h                          |   76 -
 src/lib/dns/util/base_n.cc                         |  398 --
 src/lib/dns/util/hex.h                             |   62 -
 src/lib/dns/util/sha1.cc                           |  484 --
 src/lib/dns/util/sha1.h                            |   84 -
 src/lib/log/Makefile.am                            |    8 +-
 src/lib/log/README                                 |  119 +-
 src/lib/log/compiler/Makefile.am                   |    2 +
 src/lib/log/compiler/message.cc                    |   59 +-
 src/lib/log/filename.cc                            |  138 -
 src/lib/log/filename.h                             |  161 -
 src/lib/log/log_formatter.cc                       |   42 +
 src/lib/log/log_formatter.h                        |  150 +
 src/lib/log/logger.cc                              |   66 +-
 src/lib/log/logger.h                               |   25 +-
 src/lib/log/logger_impl.cc                         |   23 +-
 src/lib/log/logger_impl.h                          |   62 +-
 src/lib/log/logger_impl_log4cxx.cc                 |    3 +-
 src/lib/log/logger_support.cc                      |   89 +-
 src/lib/log/logger_support.h                       |   31 +
 src/lib/log/macros.h                               |   50 +
 src/lib/log/message_exception.cc                   |   26 -
 src/lib/log/message_exception.h                    |   37 +-
 src/lib/log/message_reader.cc                      |  190 +-
 src/lib/log/message_reader.h                       |   19 +-
 src/lib/log/messagedef.cc                          |   70 +-
 src/lib/log/messagedef.h                           |   14 +-
 src/lib/log/messagedef.mes                         |  202 +-
 src/lib/log/strutil.cc                             |  135 -
 src/lib/log/strutil.h                              |  145 -
 src/lib/log/tests/Makefile.am                      |    6 +-
 src/lib/log/tests/filename_unittest.cc             |  179 -
 src/lib/log/tests/log_formatter_unittest.cc        |  125 +
 src/lib/log/tests/logger_support_test.cc           |   18 +-
 src/lib/log/tests/message_dictionary_unittest.cc   |    4 +-
 src/lib/log/tests/message_reader_unittest.cc       |   47 +-
 src/lib/log/tests/run_time_init_test.sh.in         |   41 +-
 src/lib/log/tests/strutil_unittest.cc              |  214 -
 src/lib/nsas/Makefile.am                           |   35 +-
 src/lib/nsas/glue_hints.cc                         |    2 +-
 src/lib/nsas/hash_deleter.h                        |    5 +-
 src/lib/nsas/hash_table.h                          |    9 +-
 src/lib/nsas/locks.h                               |  116 -
 src/lib/nsas/lru_list.h                            |  260 -
 src/lib/nsas/nameserver_address_store.cc           |   17 +-
 src/lib/nsas/nameserver_address_store.h            |   10 +-
 src/lib/nsas/nameserver_entry.cc                   |   28 +-
 src/lib/nsas/nameserver_entry.h                    |    5 +-
 src/lib/nsas/nsas_entry.h                          |   10 +-
 src/lib/nsas/nsas_log.cc                           |   26 +
 src/lib/nsas/nsas_log.h                            |   53 +
 src/lib/nsas/nsasdef.mes                           |   61 +
 src/lib/nsas/random_number_generator.h             |  207 -
 src/lib/nsas/tests/Makefile.am                     |    5 +-
 src/lib/nsas/tests/address_entry_unittest.cc       |    2 +-
 src/lib/nsas/tests/hash_deleter_unittest.cc        |    3 +-
 src/lib/nsas/tests/lru_list_unittest.cc            |  318 -
 .../tests/nameserver_address_store_unittest.cc     |  310 +-
 src/lib/nsas/tests/nameserver_address_unittest.cc  |    7 +-
 src/lib/nsas/tests/nameserver_entry_unittest.cc    |   10 +-
 src/lib/nsas/tests/nsas_test.h                     |  149 +-
 .../nsas/tests/random_number_generator_unittest.cc |  309 -
 src/lib/nsas/tests/run_unittests.cc                |    9 +
 src/lib/nsas/tests/zone_entry_unittest.cc          |    3 +-
 src/lib/nsas/zone_entry.cc                         |    6 +-
 src/lib/nsas/zone_entry.h                          |   13 +-
 src/lib/python/Makefile.am                         |    1 +
 src/lib/python/bind10_config.py.in                 |   38 +-
 src/lib/python/isc/config/ccsession.py             |    3 +
 src/lib/python/isc/config/cfgmgr.py                |   59 +-
 src/lib/python/isc/config/config_data.py           |   13 +-
 src/lib/python/isc/config/tests/ccsession_test.py  |   13 +-
 src/lib/python/isc/config/tests/cfgmgr_test.py     |   71 +
 .../python/isc/config/tests/config_data_test.py    |   25 +-
 .../isc/config/tests/unittest_fakesession.py       |    9 +-
 src/lib/python/isc/notify/notify_out.py            |    8 +-
 src/lib/python/isc/notify/tests/Makefile.am        |    2 +-
 src/lib/python/isc/notify/tests/notify_out_test.py |   50 +-
 src/lib/python/isc/testutils/Makefile.am           |    2 +-
 src/lib/python/isc/testutils/tsigctx_mock.py       |   53 +
 src/lib/python/isc/util/Makefile.am                |    2 +-
 src/lib/python/isc/util/file.py                    |   29 +
 src/lib/python/isc/util/tests/Makefile.am          |    2 +-
 src/lib/python/isc/util/tests/file_test.py         |   32 +
 src/lib/resolve/recursive_query.cc                 |  359 +-
 src/lib/resolve/recursive_query.h                  |   83 +-
 src/lib/resolve/resolver_callback.h                |    8 +-
 src/lib/resolve/tests/Makefile.am                  |    1 +
 src/lib/resolve/tests/recursive_query_unittest.cc  |  257 +-
 .../resolve/tests/recursive_query_unittest_2.cc    |   35 +-
 .../resolve/tests/resolver_callback_unittest.cc    |    8 +-
 src/lib/server_common/Makefile.am                  |    3 +
 src/lib/server_common/keyring.cc                   |   61 +
 src/lib/server_common/keyring.h                    |   96 +
 src/lib/server_common/portconfig.cc                |   26 +-
 src/lib/server_common/portconfig.h                 |    6 +-
 src/lib/server_common/tests/Makefile.am            |    9 +-
 src/lib/server_common/tests/data_path.h.in         |   16 +
 src/lib/server_common/tests/keyring_test.cc        |  132 +
 src/lib/server_common/tests/portconfig_unittest.cc |    6 +-
 src/lib/server_common/tests/testdata/spec.spec     |    6 +
 src/lib/testutils/mockups.h                        |    4 +-
 src/lib/testutils/srv_test.cc                      |    7 +-
 src/lib/testutils/srv_test.h                       |    6 +-
 src/lib/util/Makefile.am                           |   30 +
 src/lib/util/buffer.h                              |  524 ++
 .../{dns/util => util/encode}/base16_from_binary.h |    0 
 src/lib/util/encode/base32hex.h                    |   64 +
 .../util => util/encode}/base32hex_from_binary.h   |    0 
 src/lib/util/encode/base64.h                       |   79 +
 src/lib/util/encode/base_n.cc                      |  398 ++
 .../{dns/util => util/encode}/binary_from_base16.h |    0 
 .../util => util/encode}/binary_from_base32hex.h   |    0 
 src/lib/util/encode/hex.h                          |   65 +
 src/lib/util/filename.cc                           |  137 +
 src/lib/util/filename.h                            |  161 +
 src/lib/util/hash/sha1.cc                          |  492 ++
 src/lib/util/hash/sha1.h                           |   91 +
 src/lib/util/io/Makefile.am                        |   18 +
 src/lib/util/io/fd.cc                              |   70 +
 src/lib/util/io/fd.h                               |   61 +
 src/lib/util/io/fd_share.cc                        |  139 +
 src/lib/util/io/fd_share.h                         |   65 +
 src/lib/util/io/fdshare_python.cc                  |   97 +
 src/lib/util/io/tests/Makefile.am                  |   25 +
 src/lib/util/io/tests/fd_share_tests.cc            |   74 +
 src/lib/util/io/tests/fd_tests.cc                  |   66 +
 src/lib/util/io/tests/run_unittests.cc             |   22 +
 src/lib/util/io_utilities.h                        |   63 +
 src/lib/util/locks.h                               |  115 +
 src/lib/util/lru_list.h                            |  260 +
 src/lib/util/python/mkpywrapper.py.in              |  100 +
 src/lib/util/python/pycppwrapper_util.h            |  308 +
 src/lib/util/python/wrapper_template.cc            |  309 +
 src/lib/util/python/wrapper_template.h             |   59 +
 src/lib/util/pyunittests/Makefile.am               |   14 +
 src/lib/util/pyunittests/pyunittests_util.cc       |   84 +
 src/lib/util/random/qid_gen.cc                     |   57 +
 src/lib/util/random/qid_gen.h                      |   87 +
 src/lib/util/random/random_number_generator.h      |  208 +
 src/lib/util/strutil.cc                            |  137 +
 src/lib/util/strutil.h                             |  147 +
 src/lib/util/tests/Makefile.am                     |   41 +
 src/lib/util/tests/base32hex_unittest.cc           |  159 +
 src/lib/util/tests/base64_unittest.cc              |   93 +
 src/lib/util/tests/buffer_unittest.cc              |  242 +
 src/lib/util/tests/filename_unittest.cc            |  179 +
 src/lib/util/tests/hex_unittest.cc                 |  120 +
 src/lib/util/tests/io_utilities_unittest.cc        |   73 +
 src/lib/util/tests/lru_list_unittest.cc            |  428 ++
 src/lib/util/tests/qid_gen_unittest.cc             |   60 +
 .../util/tests/random_number_generator_unittest.cc |  311 +
 src/lib/{log => util}/tests/run_unittests.cc       |    0 
 src/lib/util/tests/sha1_unittest.cc                |  109 +
 src/lib/util/tests/strutil_unittest.cc             |  215 +
 src/lib/util/tests/time_utilities_unittest.cc      |  161 +
 src/lib/util/time_utilities.cc                     |  207 +
 src/lib/util/time_utilities.h                      |  173 +
 src/lib/util/unittests/Makefile.am                 |   10 +
 src/lib/util/unittests/README                      |    5 +
 src/lib/util/unittests/fork.cc                     |  145 +
 src/lib/util/unittests/fork.h                      |   52 +
 src/lib/util/unittests/newhook.cc                  |   51 +
 src/lib/util/unittests/newhook.h                   |   82 +
 src/lib/util/unittests/resolver.h                  |  193 +
 src/lib/util/unittests/testdata.cc                 |   61 +
 src/lib/util/unittests/testdata.h                  |   54 +
 src/lib/util/unittests/textdata.h                  |  103 +
 src/lib/xfr/Makefile.am                            |   14 +-
 src/lib/xfr/fd_share.cc                            |  137 -
 src/lib/xfr/fd_share.h                             |   42 -
 src/lib/xfr/fdshare_python.cc                      |   84 -
 src/lib/xfr/python_xfr.cc                          |   32 -
 src/lib/xfr/xfrout_client.cc                       |    5 +-
 tests/Makefile.am                                  |    2 +-
 tests/tools/Makefile.am                            |    1 +
 tests/tools/badpacket/Makefile.am                  |   33 +
 tests/tools/badpacket/README                       |   53 +
 tests/tools/badpacket/badpacket.cc                 |   62 +
 tests/tools/badpacket/command_options.cc           |  333 +
 tests/tools/badpacket/command_options.h            |  162 +
 tests/tools/badpacket/header_flags.h               |  102 +
 tests/tools/badpacket/option_info.cc               |  114 +
 tests/tools/badpacket/option_info.h                |  174 +
 tests/tools/badpacket/scan.cc                      |  312 +
 tests/tools/badpacket/scan.h                       |  198 +
 tests/tools/badpacket/tests/Makefile.am            |   32 +
 .../badpacket/tests/command_options_unittest.cc    |  300 +
 .../tools/badpacket/tests/header_flags_unittest.cc |  141 +
 .../tools/badpacket/tests/option_info_unittest.cc  |  161 +
 tests/tools/badpacket/tests/run_unittests.cc       |   24 +
 tests/tools/badpacket/version.h                    |   26 +
 tools/query_cmp/README                             |   27 +
 tools/query_cmp/queries/dquery01                   |  394 ++
 tools/query_cmp/queries/dquery01_no-type           |  316 +
 tools/query_cmp/queries/dquery01_non-terminal      |  317 +
 tools/query_cmp/queries/dquery01_nxdomain          |  316 +
 tools/query_cmp/src/lib/compare_rrset.py           |  285 +
 tools/query_cmp/src/lib/handledns.py               |  284 +
 tools/query_cmp/src/lib/read_query.py              |   93 +
 tools/query_cmp/src/query_two_server.py            |  102 +
 tools/query_cmp/zonefile/example.com.txt           | 1298 ++++
 tools/query_cmp/zonefile/example.com.txt.signed    | 6858 ++++++++++++++++++++
 932 files changed, 68904 insertions(+), 27219 deletions(-)
 create mode 100644 ext/asio/asio/basic_streambuf_fwd.hpp
 create mode 100644 ext/asio/asio/detail/array_fwd.hpp
 create mode 100644 ext/asio/asio/detail/config.hpp
 create mode 100644 ext/asio/asio/detail/descriptor_read_op.hpp
 create mode 100644 ext/asio/asio/detail/descriptor_write_op.hpp
 create mode 100644 ext/asio/asio/detail/gcc_arm_fenced_block.hpp
 create mode 100644 ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
 create mode 100644 ext/asio/asio/detail/gcc_sync_fenced_block.hpp
 create mode 100644 ext/asio/asio/detail/impl/descriptor_ops.ipp
 create mode 100644 ext/asio/asio/detail/impl/dev_poll_reactor.hpp
 create mode 100644 ext/asio/asio/detail/impl/dev_poll_reactor.ipp
 create mode 100644 ext/asio/asio/detail/impl/epoll_reactor.hpp
 create mode 100644 ext/asio/asio/detail/impl/epoll_reactor.ipp
 create mode 100644 ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
 create mode 100644 ext/asio/asio/detail/impl/kqueue_reactor.hpp
 create mode 100644 ext/asio/asio/detail/impl/kqueue_reactor.ipp
 create mode 100644 ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
 create mode 100644 ext/asio/asio/detail/impl/posix_event.ipp
 create mode 100644 ext/asio/asio/detail/impl/posix_mutex.ipp
 create mode 100644 ext/asio/asio/detail/impl/posix_thread.ipp
 create mode 100644 ext/asio/asio/detail/impl/posix_tss_ptr.ipp
 create mode 100644 ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
 create mode 100644 ext/asio/asio/detail/impl/resolver_service_base.ipp
 create mode 100644 ext/asio/asio/detail/impl/select_reactor.hpp
 create mode 100644 ext/asio/asio/detail/impl/select_reactor.ipp
 create mode 100644 ext/asio/asio/detail/impl/service_registry.hpp
 create mode 100644 ext/asio/asio/detail/impl/service_registry.ipp
 create mode 100644 ext/asio/asio/detail/impl/socket_ops.ipp
 create mode 100644 ext/asio/asio/detail/impl/socket_select_interrupter.ipp
 create mode 100644 ext/asio/asio/detail/impl/strand_service.hpp
 create mode 100644 ext/asio/asio/detail/impl/strand_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/task_io_service.hpp
 create mode 100644 ext/asio/asio/detail/impl/task_io_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/throw_error.ipp
 create mode 100644 ext/asio/asio/detail/impl/timer_queue.ipp
 create mode 100644 ext/asio/asio/detail/impl/timer_queue_set.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_event.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_iocp_io_service.hpp
 create mode 100644 ext/asio/asio/detail/impl/win_iocp_io_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_mutex.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_thread.ipp
 create mode 100644 ext/asio/asio/detail/impl/win_tss_ptr.ipp
 create mode 100644 ext/asio/asio/detail/impl/winsock_init.ipp
 create mode 100644 ext/asio/asio/detail/object_pool.hpp
 create mode 100644 ext/asio/asio/detail/reactive_null_buffers_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_accept_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_connect_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_recv_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_send_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_sendto_op.hpp
 create mode 100644 ext/asio/asio/detail/reactive_socket_service_base.hpp
 create mode 100644 ext/asio/asio/detail/regex_fwd.hpp
 create mode 100644 ext/asio/asio/detail/resolve_endpoint_op.hpp
 create mode 100644 ext/asio/asio/detail/resolve_op.hpp
 create mode 100644 ext/asio/asio/detail/resolver_service_base.hpp
 create mode 100644 ext/asio/asio/detail/shared_ptr.hpp
 create mode 100644 ext/asio/asio/detail/wait_handler.hpp
 create mode 100644 ext/asio/asio/detail/weak_ptr.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_handle_read_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_handle_write_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_overlapped_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_socket_send_op.hpp
 create mode 100644 ext/asio/asio/detail/win_iocp_socket_service_base.hpp
 create mode 100644 ext/asio/asio/impl/error.ipp
 create mode 100644 ext/asio/asio/impl/io_service.hpp
 create mode 100644 ext/asio/asio/impl/read.hpp
 create mode 100644 ext/asio/asio/impl/read_at.hpp
 create mode 100644 ext/asio/asio/impl/read_until.hpp
 create mode 100644 ext/asio/asio/impl/serial_port_base.hpp
 create mode 100644 ext/asio/asio/impl/src.cpp
 create mode 100644 ext/asio/asio/impl/src.hpp
 create mode 100644 ext/asio/asio/impl/write.hpp
 create mode 100644 ext/asio/asio/impl/write_at.hpp
 create mode 100644 ext/asio/asio/ip/detail/endpoint.hpp
 create mode 100644 ext/asio/asio/ip/detail/impl/endpoint.ipp
 create mode 100644 ext/asio/asio/ip/impl/address.hpp
 create mode 100644 ext/asio/asio/ip/impl/address.ipp
 create mode 100644 ext/asio/asio/ip/impl/address_v4.hpp
 create mode 100644 ext/asio/asio/ip/impl/address_v4.ipp
 create mode 100644 ext/asio/asio/ip/impl/address_v6.hpp
 create mode 100644 ext/asio/asio/ip/impl/address_v6.ipp
 create mode 100644 ext/asio/asio/ip/impl/basic_endpoint.hpp
 create mode 100644 ext/asio/asio/ip/impl/host_name.ipp
 create mode 100644 ext/asio/asio/local/detail/endpoint.hpp
 create mode 100644 ext/asio/asio/local/detail/impl/endpoint.ipp
 create mode 100644 src/bin/auth/auth_config.cc
 rename src/bin/auth/{config.h => auth_config.h} (100%)
 create mode 100644 src/bin/auth/common.cc
 delete mode 100644 src/bin/auth/config.cc
 create mode 100644 src/bin/auth/tests/common_unittest.cc
 mode change 100644 => 100755 src/bin/bind10/run_bind10.sh.in
 create mode 100644 src/bin/cfgmgr/plugins/Makefile.am
 create mode 100644 src/bin/cfgmgr/plugins/README
 create mode 100644 src/bin/cfgmgr/plugins/tests/Makefile.am
 create mode 100644 src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
 create mode 100644 src/bin/cfgmgr/plugins/tsig_keys.py
 create mode 100644 src/bin/cfgmgr/plugins/tsig_keys.spec
 create mode 100644 src/bin/cfgmgr/tests/testdata/plugins/testplugin.py
 create mode 100644 src/bin/host/b10-host.1
 create mode 100644 src/bin/host/b10-host.xml
 create mode 100644 src/bin/sockcreator/Makefile.am
 create mode 100644 src/bin/sockcreator/README
 create mode 100644 src/bin/sockcreator/main.cc
 create mode 100644 src/bin/sockcreator/sockcreator.cc
 create mode 100644 src/bin/sockcreator/sockcreator.h
 create mode 100644 src/bin/sockcreator/tests/Makefile.am
 create mode 100644 src/bin/sockcreator/tests/run_unittests.cc
 create mode 100644 src/bin/sockcreator/tests/sockcreator_tests.cc
 create mode 100644 src/bin/stats/b10-stats-httpd.8
 create mode 100644 src/bin/stats/b10-stats-httpd.xml
 delete mode 100644 src/bin/stats/run_b10-stats.sh.in
 delete mode 100644 src/bin/stats/run_b10-stats_stub.sh.in
 create mode 100644 src/bin/stats/stats-httpd-xml.tpl.in
 create mode 100644 src/bin/stats/stats-httpd-xsd.tpl.in
 create mode 100644 src/bin/stats/stats-httpd-xsl.tpl.in
 create mode 100644 src/bin/stats/stats-httpd.spec.in
 create mode 100644 src/bin/stats/stats-schema.spec.in
 mode change 100755 => 100644 src/bin/stats/stats.py.in
 create mode 100644 src/bin/stats/stats.spec.in
 delete mode 100644 src/bin/stats/stats.spec.pre.in
 create mode 100644 src/bin/stats/stats_httpd.py.in
 delete mode 100755 src/bin/stats/stats_stub.py.in
 create mode 100644 src/bin/stats/tests/b10-stats-httpd_test.py
 delete mode 100644 src/bin/stats/tests/b10-stats_stub_test.py
 create mode 100644 src/bin/stats/tests/fake_select.py
 create mode 100644 src/bin/stats/tests/fake_socket.py
 create mode 100644 src/bin/stats/tests/http/Makefile.am
 rename src/bin/stats/tests/{isc/utils => http}/__init__.py (100%)
 create mode 100644 src/bin/stats/tests/http/server.py
 delete mode 100644 src/bin/stats/tests/isc/utils/Makefile.am
 delete mode 100644 src/bin/stats/tests/isc/utils/process.py
 delete mode 100644 src/bin/stats/tests/stats_test.in
 delete mode 100644 src/bin/xfrout/tests/xfrout_test.py
 create mode 100644 src/bin/xfrout/tests/xfrout_test.py.in
 create mode 100644 src/lib/asiodns/Makefile.am
 create mode 100644 src/lib/asiodns/README
 create mode 100644 src/lib/asiodns/asiodef.mes
 create mode 100644 src/lib/asiodns/asiodns.h
 create mode 100644 src/lib/asiodns/dns_answer.h
 create mode 100644 src/lib/asiodns/dns_lookup.h
 create mode 100644 src/lib/asiodns/dns_server.h
 create mode 100644 src/lib/asiodns/dns_service.cc
 create mode 100644 src/lib/asiodns/dns_service.h
 create mode 100644 src/lib/asiodns/io_fetch.cc
 create mode 100644 src/lib/asiodns/io_fetch.h
 create mode 100644 src/lib/asiodns/tcp_server.cc
 create mode 100644 src/lib/asiodns/tcp_server.h
 create mode 100644 src/lib/asiodns/tests/Makefile.am
 create mode 100644 src/lib/asiodns/tests/dns_server_unittest.cc
 create mode 100644 src/lib/asiodns/tests/io_fetch_unittest.cc
 create mode 100644 src/lib/asiodns/tests/io_service_unittest.cc
 copy src/lib/{asiolink => asiodns}/tests/run_unittests.cc (100%)
 create mode 100644 src/lib/asiodns/udp_server.cc
 create mode 100644 src/lib/asiodns/udp_server.h
 delete mode 100644 src/lib/asiolink/asiodef.cc
 delete mode 100644 src/lib/asiolink/asiodef.h
 delete mode 100644 src/lib/asiolink/asiodef.msg
 delete mode 100644 src/lib/asiolink/asiolink_utilities.h
 delete mode 100644 src/lib/asiolink/dns_answer.h
 delete mode 100644 src/lib/asiolink/dns_lookup.h
 delete mode 100644 src/lib/asiolink/dns_server.h
 delete mode 100644 src/lib/asiolink/dns_service.cc
 delete mode 100644 src/lib/asiolink/dns_service.h
 delete mode 100644 src/lib/asiolink/io_fetch.cc
 delete mode 100644 src/lib/asiolink/io_fetch.h
 delete mode 100644 src/lib/asiolink/qid_gen.cc
 delete mode 100644 src/lib/asiolink/qid_gen.h
 delete mode 100644 src/lib/asiolink/tcp_server.cc
 delete mode 100644 src/lib/asiolink/tcp_server.h
 delete mode 100644 src/lib/asiolink/tests/asiolink_utilities_unittest.cc
 delete mode 100644 src/lib/asiolink/tests/dns_server_unittest.cc
 delete mode 100644 src/lib/asiolink/tests/io_fetch_unittest.cc
 delete mode 100644 src/lib/asiolink/tests/io_service_unittest.cc
 delete mode 100644 src/lib/asiolink/tests/qid_gen_unittest.cc
 delete mode 100644 src/lib/asiolink/udp_server.cc
 delete mode 100644 src/lib/asiolink/udp_server.h
 create mode 100644 src/lib/config/config_log.cc
 create mode 100644 src/lib/config/config_log.h
 create mode 100644 src/lib/config/configdef.mes
 create mode 100644 src/lib/cryptolink/Makefile.am
 create mode 100644 src/lib/cryptolink/crypto_hmac.cc
 create mode 100644 src/lib/cryptolink/crypto_hmac.h
 create mode 100644 src/lib/cryptolink/cryptolink.cc
 create mode 100644 src/lib/cryptolink/cryptolink.h
 create mode 100644 src/lib/cryptolink/tests/Makefile.am
 create mode 100644 src/lib/cryptolink/tests/crypto_unittests.cc
 create mode 100644 src/lib/cryptolink/tests/run_unittests.cc
 create mode 100644 src/lib/datasrc/logger.cc
 create mode 100644 src/lib/datasrc/logger.h
 create mode 100644 src/lib/datasrc/messagedef.mes
 create mode 100644 src/lib/datasrc/tests/logger_unittest.cc
 create mode 100644 src/lib/dns/benchmarks/Makefile.am
 create mode 100644 src/lib/dns/benchmarks/README
 create mode 100644 src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com
 create mode 100644 src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain
 create mode 100644 src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org
 create mode 100644 src/lib/dns/benchmarks/rdatarender_bench.cc
 delete mode 100644 src/lib/dns/buffer.h
 delete mode 100644 src/lib/dns/dnssectime.cc
 delete mode 100644 src/lib/dns/dnssectime.h
 create mode 100644 src/lib/dns/python/messagerenderer_python.h
 create mode 100644 src/lib/dns/python/name_python.h
 create mode 100644 src/lib/dns/python/pydnspp_towire.h
 create mode 100644 src/lib/dns/python/rcode_python.h
 create mode 100644 src/lib/dns/python/tests/tsig_python_test.py
 create mode 100644 src/lib/dns/python/tests/tsig_rdata_python_test.py
 create mode 100644 src/lib/dns/python/tests/tsigerror_python_test.py
 create mode 100644 src/lib/dns/python/tests/tsigrecord_python_test.py
 create mode 100644 src/lib/dns/python/tsig_python.cc
 create mode 100644 src/lib/dns/python/tsig_python.h
 create mode 100644 src/lib/dns/python/tsig_rdata_python.cc
 create mode 100644 src/lib/dns/python/tsig_rdata_python.h
 create mode 100644 src/lib/dns/python/tsigerror_python.cc
 create mode 100644 src/lib/dns/python/tsigerror_python.h
 create mode 100644 src/lib/dns/python/tsigerror_python_inc.cc
 create mode 100644 src/lib/dns/python/tsigkey_python.h
 create mode 100644 src/lib/dns/python/tsigrecord_python.cc
 create mode 100644 src/lib/dns/python/tsigrecord_python.h
 create mode 100644 src/lib/dns/rdata/generic/rp_17.cc
 create mode 100644 src/lib/dns/rdata/generic/rp_17.h
 create mode 100644 src/lib/dns/rdatafields.cc
 create mode 100644 src/lib/dns/rdatafields.h
 delete mode 100644 src/lib/dns/tests/base32hex_unittest.cc
 delete mode 100644 src/lib/dns/tests/base64_unittest.cc
 delete mode 100644 src/lib/dns/tests/buffer_unittest.cc
 delete mode 100644 src/lib/dns/tests/dnssectime_unittest.cc
 delete mode 100644 src/lib/dns/tests/hex_unittest.cc
 create mode 100644 src/lib/dns/tests/rdata_rp_unittest.cc
 create mode 100644 src/lib/dns/tests/rdatafields_unittest.cc
 delete mode 100644 src/lib/dns/tests/sha1_unittest.cc
 create mode 100644 src/lib/dns/tests/testdata/message_fromWire12.spec
 create mode 100644 src/lib/dns/tests/testdata/message_fromWire13.spec
 create mode 100644 src/lib/dns/tests/testdata/message_fromWire14.spec
 create mode 100644 src/lib/dns/tests/testdata/message_fromWire15.spec
 create mode 100644 src/lib/dns/tests/testdata/message_fromWire16.spec
 create mode 100644 src/lib/dns/tests/testdata/message_toText1.spec
 create mode 100644 src/lib/dns/tests/testdata/message_toText1.txt
 create mode 100644 src/lib/dns/tests/testdata/message_toText2.spec
 create mode 100644 src/lib/dns/tests/testdata/message_toText2.txt
 create mode 100644 src/lib/dns/tests/testdata/message_toText3.spec
 create mode 100644 src/lib/dns/tests/testdata/message_toText3.txt
 create mode 100644 src/lib/dns/tests/testdata/message_toWire2.spec
 create mode 100644 src/lib/dns/tests/testdata/message_toWire3.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_toWire1.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_rp_toWire2.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields1.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields2.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields3.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields4.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields5.spec
 create mode 100644 src/lib/dns/tests/testdata/rdatafields6.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify1.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify10.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify2.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify3.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify4.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify5.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify6.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify7.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify8.spec
 create mode 100644 src/lib/dns/tests/testdata/tsig_verify9.spec
 create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
 create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
 create mode 100644 src/lib/dns/tests/tsig_unittest.cc
 create mode 100644 src/lib/dns/tests/tsigerror_unittest.cc
 create mode 100644 src/lib/dns/tests/tsigrecord_unittest.cc
 create mode 100644 src/lib/dns/tsig.cc
 create mode 100644 src/lib/dns/tsig.h
 create mode 100644 src/lib/dns/tsigerror.cc
 create mode 100644 src/lib/dns/tsigerror.h
 create mode 100644 src/lib/dns/tsigrecord.cc
 create mode 100644 src/lib/dns/tsigrecord.h
 delete mode 100644 src/lib/dns/util/README
 delete mode 100644 src/lib/dns/util/base32hex.h
 delete mode 100644 src/lib/dns/util/base64.h
 delete mode 100644 src/lib/dns/util/base_n.cc
 delete mode 100644 src/lib/dns/util/hex.h
 delete mode 100644 src/lib/dns/util/sha1.cc
 delete mode 100644 src/lib/dns/util/sha1.h
 delete mode 100644 src/lib/log/filename.cc
 delete mode 100644 src/lib/log/filename.h
 create mode 100644 src/lib/log/log_formatter.cc
 create mode 100644 src/lib/log/log_formatter.h
 create mode 100644 src/lib/log/macros.h
 delete mode 100644 src/lib/log/message_exception.cc
 delete mode 100644 src/lib/log/strutil.cc
 delete mode 100644 src/lib/log/strutil.h
 delete mode 100644 src/lib/log/tests/filename_unittest.cc
 create mode 100644 src/lib/log/tests/log_formatter_unittest.cc
 delete mode 100644 src/lib/log/tests/strutil_unittest.cc
 delete mode 100644 src/lib/nsas/locks.h
 delete mode 100644 src/lib/nsas/lru_list.h
 create mode 100644 src/lib/nsas/nsas_log.cc
 create mode 100644 src/lib/nsas/nsas_log.h
 create mode 100644 src/lib/nsas/nsasdef.mes
 delete mode 100644 src/lib/nsas/random_number_generator.h
 delete mode 100644 src/lib/nsas/tests/lru_list_unittest.cc
 delete mode 100644 src/lib/nsas/tests/random_number_generator_unittest.cc
 create mode 100644 src/lib/python/isc/testutils/tsigctx_mock.py
 create mode 100644 src/lib/python/isc/util/file.py
 create mode 100644 src/lib/python/isc/util/tests/file_test.py
 create mode 100644 src/lib/server_common/keyring.cc
 create mode 100644 src/lib/server_common/keyring.h
 create mode 100644 src/lib/server_common/tests/data_path.h.in
 create mode 100644 src/lib/server_common/tests/keyring_test.cc
 create mode 100644 src/lib/server_common/tests/testdata/spec.spec
 create mode 100644 src/lib/util/Makefile.am
 create mode 100644 src/lib/util/buffer.h
 rename src/lib/{dns/util => util/encode}/base16_from_binary.h (100%)
 create mode 100644 src/lib/util/encode/base32hex.h
 rename src/lib/{dns/util => util/encode}/base32hex_from_binary.h (100%)
 create mode 100644 src/lib/util/encode/base64.h
 create mode 100644 src/lib/util/encode/base_n.cc
 rename src/lib/{dns/util => util/encode}/binary_from_base16.h (100%)
 rename src/lib/{dns/util => util/encode}/binary_from_base32hex.h (100%)
 create mode 100644 src/lib/util/encode/hex.h
 create mode 100644 src/lib/util/filename.cc
 create mode 100644 src/lib/util/filename.h
 create mode 100644 src/lib/util/hash/sha1.cc
 create mode 100644 src/lib/util/hash/sha1.h
 create mode 100644 src/lib/util/io/Makefile.am
 create mode 100644 src/lib/util/io/fd.cc
 create mode 100644 src/lib/util/io/fd.h
 create mode 100644 src/lib/util/io/fd_share.cc
 create mode 100644 src/lib/util/io/fd_share.h
 create mode 100644 src/lib/util/io/fdshare_python.cc
 create mode 100644 src/lib/util/io/tests/Makefile.am
 create mode 100644 src/lib/util/io/tests/fd_share_tests.cc
 create mode 100644 src/lib/util/io/tests/fd_tests.cc
 create mode 100644 src/lib/util/io/tests/run_unittests.cc
 create mode 100644 src/lib/util/io_utilities.h
 create mode 100644 src/lib/util/locks.h
 create mode 100644 src/lib/util/lru_list.h
 create mode 100755 src/lib/util/python/mkpywrapper.py.in
 create mode 100644 src/lib/util/python/pycppwrapper_util.h
 create mode 100644 src/lib/util/python/wrapper_template.cc
 create mode 100644 src/lib/util/python/wrapper_template.h
 create mode 100644 src/lib/util/pyunittests/Makefile.am
 create mode 100644 src/lib/util/pyunittests/pyunittests_util.cc
 create mode 100644 src/lib/util/random/qid_gen.cc
 create mode 100644 src/lib/util/random/qid_gen.h
 create mode 100644 src/lib/util/random/random_number_generator.h
 create mode 100644 src/lib/util/strutil.cc
 create mode 100644 src/lib/util/strutil.h
 create mode 100644 src/lib/util/tests/Makefile.am
 create mode 100644 src/lib/util/tests/base32hex_unittest.cc
 create mode 100644 src/lib/util/tests/base64_unittest.cc
 create mode 100644 src/lib/util/tests/buffer_unittest.cc
 create mode 100644 src/lib/util/tests/filename_unittest.cc
 create mode 100644 src/lib/util/tests/hex_unittest.cc
 create mode 100644 src/lib/util/tests/io_utilities_unittest.cc
 create mode 100644 src/lib/util/tests/lru_list_unittest.cc
 create mode 100644 src/lib/util/tests/qid_gen_unittest.cc
 create mode 100644 src/lib/util/tests/random_number_generator_unittest.cc
 copy src/lib/{log => util}/tests/run_unittests.cc (100%)
 create mode 100644 src/lib/util/tests/sha1_unittest.cc
 create mode 100644 src/lib/util/tests/strutil_unittest.cc
 create mode 100644 src/lib/util/tests/time_utilities_unittest.cc
 create mode 100644 src/lib/util/time_utilities.cc
 create mode 100644 src/lib/util/time_utilities.h
 create mode 100644 src/lib/util/unittests/Makefile.am
 create mode 100644 src/lib/util/unittests/README
 create mode 100644 src/lib/util/unittests/fork.cc
 create mode 100644 src/lib/util/unittests/fork.h
 create mode 100644 src/lib/util/unittests/newhook.cc
 create mode 100644 src/lib/util/unittests/newhook.h
 create mode 100644 src/lib/util/unittests/resolver.h
 create mode 100644 src/lib/util/unittests/testdata.cc
 create mode 100644 src/lib/util/unittests/testdata.h
 create mode 100644 src/lib/util/unittests/textdata.h
 delete mode 100644 src/lib/xfr/fd_share.cc
 delete mode 100644 src/lib/xfr/fd_share.h
 delete mode 100644 src/lib/xfr/fdshare_python.cc
 delete mode 100644 src/lib/xfr/python_xfr.cc
 create mode 100644 tests/tools/Makefile.am
 create mode 100644 tests/tools/badpacket/Makefile.am
 create mode 100644 tests/tools/badpacket/README
 create mode 100644 tests/tools/badpacket/badpacket.cc
 create mode 100644 tests/tools/badpacket/command_options.cc
 create mode 100644 tests/tools/badpacket/command_options.h
 create mode 100644 tests/tools/badpacket/header_flags.h
 create mode 100644 tests/tools/badpacket/option_info.cc
 create mode 100644 tests/tools/badpacket/option_info.h
 create mode 100644 tests/tools/badpacket/scan.cc
 create mode 100644 tests/tools/badpacket/scan.h
 create mode 100644 tests/tools/badpacket/tests/Makefile.am
 create mode 100644 tests/tools/badpacket/tests/command_options_unittest.cc
 create mode 100644 tests/tools/badpacket/tests/header_flags_unittest.cc
 create mode 100644 tests/tools/badpacket/tests/option_info_unittest.cc
 create mode 100644 tests/tools/badpacket/tests/run_unittests.cc
 create mode 100644 tests/tools/badpacket/version.h
 create mode 100644 tools/query_cmp/README
 create mode 100644 tools/query_cmp/queries/dquery01
 create mode 100644 tools/query_cmp/queries/dquery01_no-type
 create mode 100644 tools/query_cmp/queries/dquery01_non-terminal
 create mode 100644 tools/query_cmp/queries/dquery01_nxdomain
 create mode 100755 tools/query_cmp/src/lib/compare_rrset.py
 create mode 100755 tools/query_cmp/src/lib/handledns.py
 create mode 100755 tools/query_cmp/src/lib/read_query.py
 create mode 100755 tools/query_cmp/src/query_two_server.py
 create mode 100644 tools/query_cmp/zonefile/example.com.txt
 create mode 100644 tools/query_cmp/zonefile/example.com.txt.signed

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 0c92bb8..e44caa2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,75 +1,299 @@
-  211.  [func]		shane
+243.	[func]*		feng
+	Add optional hmac algorithm SHA224/384/812.
+	(Trac#782,git 77d792c9d7c1a3f95d3e6a8b721ac79002cd7db1).
+
+bind10-devel-20110519 released on May 19, 2011
+
+242.	[func]		jinmei
+	xfrin: added support for TSIG verify.  This change completes TSIG
+	support in b10-xfrin.
+	(Trac #914, git 78502c021478d97672232015b7df06a7d52e531b)
+
+241.	[func]		jinmei
+	pydnspp: added python extension for the TSIG API introduced in
+	change 235.
+	(Trac #905, git 081891b38f05f9a186814ab7d1cd5c572b8f777f)
+	(Trac #915, git 0555ab65d0e43d03b2d40c95d833dd050eea6c23)
+
+240.	[func]*		jelte
+	Updated configuration options to Xfrin, so that you can specify
+	a master address, port, and TSIG key per zone. Still only one per
+	zone at this point, and TSIG keys are (currently) only specified
+	by their full string representation. This replaces the
+	Xfrin/master_addr, Xfrin/master_port, and short-lived
+	Xfrin/tsig_key configurations with a Xfrin/zones list.
+	(Trac #811, git 88504d121c5e08fff947b92e698a54d24d14c375)
+
+239.	[bug]		jerry
+	src/bin/xfrout: If a zone doesn't have notify slaves (only has
+	one apex ns record - the primary master name server) will cause
+	b10-xfrout uses 100% of CPU.
+	(Trac #684, git d11b5e89203a5340d4e5ca51c4c02db17c33dc1f)
+
+238.	[func]		zhang likun
+	Implement the simplest forwarder, which pass everything through
+	except QID, port number. The response will not be cached.
+	(Trac #598_new, git 8e28187a582820857ef2dae9b13637a3881f13ba)
+
+237.	[bug]		naokikambe
+	Resolved that the stats module wasn't configurable in bindctl in
+	spite of its having configuration items. The configuration part
+	was removed from the original spec file "stats.spec" and was
+	placed in a new spec file "stats-schema.spec". Because it means
+	definitions of statistics items. The command part is still
+	there. Thus stats module currently has no its own configuration,
+	and the items in "stats-schema.spec" are neither visible nor
+	configurable through bindctl. "stats-schema.spec" is shared with
+	stats module and stats-httpd module, and maybe with other
+	statistical modules in future. "stats.spec" has own configuration
+	and commands of stats module, if it requires.
+	(Trac#719, git a234b20dc6617392deb8a1e00eb0eed0ff353c0a)
+
+236.	[func]		jelte
+	C++ client side of configuration now uses BIND10 logging system.
+	It also has improved error handling when communicating with the
+	rest of the system.
+	(Trac #743, git 86632c12308c3ed099d75eb828f740c526dd7ec0)
+
+235.	[func]		jinmei
+	libdns++: added support for TSIG signing and verification.  It can
+	be done using a newly introduced TSIGContext class.
+	Note: we temporarily disabled support for truncated signature
+	and modified some part of the code introduced in #226 accordingly.
+	We plan to fix this pretty soon.
+	(Trac #812, git ebe0c4b1e66d359227bdd1bd47395fee7b957f14)
+	(Trac #871, git 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8)
+	(Trac #813, git ffa2f0672084c1f16e5784cdcdd55822f119feaa)
+	(Trac #893, git 5aaa6c0f628ed7c2093ecdbac93a2c8cf6c94349)
+
+234.	[func]		jerry
+	src/bin/xfrin: update xfrin to use TSIG. Currently it only supports
+	sending a signed TSIG request or SOA request.
+	(Trac #815, git a892818fb13a1839c82104523cb6cb359c970e88)
+
+233.	[func]		stephen
+	Added new-style logging statements to the NSAS code.
+	(Trac #745, git ceef68cd1223ae14d8412adbe18af2812ade8c2d)
+
+232.	[func]		stephen
+	To facilitate the writing of extended descriptions in
+	message files, altered the message file format.  The message
+	is now flagged with a "%" as the first non-blank character
+	in the line and the lines in the extended description are
+	no longer preceded by a "+".
+	(Trac #900, git b395258c708b49a5da8d0cffcb48d83294354ba3)
+
+231.	[func]*		vorner
+    The logging interface changed slightly. We use
+	logger.foo(MESSAGE_ID).arg(bar); instead of logger.foo(MESSAGE_ID,
+	bar); internally. The message definitions use '%1,%2,...'
+	instead of '%s,%d', which allows us to cope better with
+	mismatched placeholders and allows reordering of them in
+	case of translation.
+	(Trac901, git 4903410e45670b30d7283f5d69dc28c2069237d6)
+
+230.	[bug]		naokikambe
+	Removed too repeated verbose messages in two cases of:
+	 - when auth sends statistics data to stats
+	 - when stats receives statistics data from other modules
+	(Trac#620, git 0ecb807011196eac01f281d40bc7c9d44565b364)
+
+229.	[doc]		jreed
+	Add manual page for b10-host.
+	(git a437d4e26b81bb07181ff35a625c540703eee845)
+
+228.	[func]*		jreed
+	The host tool is renamed to b10-host. While the utility is
+	a work in progress, it is expected to now be shipped with
+	tarballs. Its initial goal was to be a host(1) clone,
+	rewritten in C++ from scratch and using BIND 10's libdns++.
+	It now supports the -a (any), -c class, -d (verbose) switches
+	and has improved output.
+	(Trac #872, git d846851699d5c76937533adf9ff9d948dfd593ca)
+
+227.	[build]		jreed
+	Add missing libdns++ rdata files for the distribution (this
+	fixes distcheck error). Change three generated libdns++
+	headers to "nodist" so they aren't included in the distribution
+	(they were mistakenly included in last tarball).
+
+226.	[func]*		jelte
+	Introduced an API for cryptographic operations. Currently it only
+	supports HMAC, intended for use with TSIG. The current
+	implementation uses Botan as the backend library.
+	This introduces a new dependency, on Botan.  Currently only Botan
+	1.8.x works; older or newer versions don't.
+	(Trac #781, git 9df42279a47eb617f586144dce8cce680598558a)
+
+225.	[func]		naokikambe
+	Added the HTTP/XML interface (b10-stats-httpd) to the
+	statistics feature in BIND 10. b10-stats-httpd is a standalone
+	HTTP server and it requests statistics data to the stats
+	daemon (b10-stats) and sends it to HTTP clients in XML
+	format. Items of the data collected via b10-stats-httpd
+	are almost equivalent to ones which are collected via
+	bindctl. Since it also can send XSL (Extensible Stylesheet
+	Language) document and XSD (XML Schema definition) document,
+	XML document is human-friendly to view through web browsers
+	and its data types are strictly defined.
+	(Trac #547, git 1cbd51919237a6e65983be46e4f5a63d1877b1d3)
+
+224.	[bug]		jinmei
+	b10-auth, src/lib/datasrc: inconsistency between the hot spot
+	cache and actual data source could cause a crash while query
+	processing.  The crash could happen, e.g., when an sqlite3 DB file
+	is being updated after a zone transfer while b10-auth handles a
+	query using the corresponding sqlite3 data source.
+	(Trac #851, git 2463b96680bb3e9a76e50c38a4d7f1d38d810643)
+
+223.	[bug]		feng
+	If ip address or port isn't usable for name server, name
+	server process won't exist and give end user chance to
+	reconfigure them.
+	(Trac #775, git 572ac2cf62e18f7eb69d670b890e2a3443bfd6e7)
+
+222.	[bug]*		jerry
+	src/lib/zonemgr: Fix a bug that xfrin not checking for new
+	copy of zone on startup.  Imposes some random jitters to
+	avoid many zones need to do refresh at the same time. This
+	removed the Zonemgr/jitter_scope setting and introduced
+	Zonemgr/refresh_jitter and Zonemgr/reload_jitter.
+	(Trac #387, git 1241ddcffa16285d0a7bb01d6a8526e19fbb70cb)
+
+221.	[func]*		jerry
+	src/lib/util: Create C++ utility library.
+	(Trac #749, git 084d1285d038d31067f8cdbb058d626acf03566d)
+
+220.	[func]		stephen
+	Added the 'badpacket' program for testing; it sends a set of
+	(potentially) bad packets to a nameserver and prints the responses.
+	(Trac #703, git 1b666838b6c0fe265522b30971e878d9f0d21fde)
+
+219.	[func]		ocean
+	src/lib: move some dns related code out of asiolink library to
+	asiodns library
+	(Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c)
+
+218.	[func]		jinmei
+	src/lib/dns: added support for RP RDATA.
+	(Trac #806, git 4e47d5f6b692c63c907af6681a75024450884a88)
+
+217.	[bug]		jerry
+	src/lib/dns/python: Use a signed version of larger size of
+	integer and perform more strict range checks with
+	PyArg_ParseTuple() in case of overflows.
+	(Trac #363, git ce281e646be9f0f273229d94ccd75bf7e08d17cf)
+
+216.	[func]		vorner
+	The BIND10_XFROUT_SOCKET_FILE environment variable can be
+	used to specify which socket should be used for communication
+	between b10-auth and b10-xfrout. Mostly for testing reasons.
+	(Trac #615, git 28b01ad5bf72472c824a7b8fc4a8dc394e22e462)
+
+215.	[func]		vorner
+	A new process, b10-sockcreator, is added, which will create
+	sockets for the rest of the system.  It is the only part
+	which will need to keep the root privileges. However, only
+	the process exists, nothing can talk to it yet.
+	(Trac #366, git b509cbb77d31e388df68dfe52709d6edef93df3f)
+
+214.	[func]*		vorner
+	Zone manager no longer thinks it is secondary master for
+	all zones in the database. They are listed in
+	Zonemgr/secondary_zones configuration variable (in the form
+	[{"name": "example.com", "class": "IN"}]).
+	(Trac #670, git 7c1e4d5e1e28e556b1d10a8df8d9486971a3f052)
+
+213.	[bug]		naokikambe
+	Solved incorrect datetime of "bind10.boot_time" and also
+	added a new command "sendstats" for Bob. This command is
+	to send statistics data to the stats daemon immediately.
+	The solved problem is that statistics data doesn't surely
+	reach to the daemon because Bob sent statistics data to
+	the daemon while it is starting. So the daemon invokes the
+	command for Bob after it starts up. This command is also
+	useful for resending statistics data via bindctl manually.
+	(Trac #521, git 1c269cbdc76f5dc2baeb43387c4d7ccc6dc863d2)
+
+212.	[bug]		naokikambe
+	Fixed that the ModuleCCSession object may group_unsubscribe in the
+	closed CC session in being deleted.
+	(Trac #698, git 0355bddc92f6df66ef50b920edd6ec3b27920d61)
+
+211.	[func]		shane
 	Implement "--brittle" option, which causes the server to exit
-        if any of BIND 10's processes dies.
+	if any of BIND 10's processes dies.
 	(Trac #788, git 88c0d241fe05e5ea91b10f046f307177cc2f5bc5)
 
-  210.  [bug]		jerry
+210.	[bug]		jerry
 	src/bin/auth: fixed a bug where type ANY queries don't provide
 	additional glue records for ANSWER section.
 	(Trac #699, git 510924ebc57def8085cc0e5413deda990b2abeee)
 
-  209.  [func]		jelte
+bind10-devel-20110322 released on March 22, 2011
+
+209.	[func]		jelte
 	Resolver now uses the NSAS when looking for a nameserver to
 	query for any specific zone. This also includes keeping track of
 	the RTT for that nameserver.
 	(Trac #495, git 76022a7e9f3ff339f0f9f10049aa85e5784d72c5)
 
-  208.  [bug]*		jelte
+208.	[bug]*		jelte
 	Resolver now answers REFUSED on queries that are not for class IN.
 	This includes the various CH TXT queries, which will be added
 	later.
 	(git 012f9e78dc611c72ea213f9bd6743172e1a2ca20)
 
-  207.  [func]		jelte
+207.	[func]		jelte
 	Resolver now starts listening on localhost:53 if no configuration
 	is set.
 	(Trac #471, git 1960b5becbba05570b9c7adf5129e64338659f07)
 
-  206.  [func]		shane
+206.	[func]		shane
 	Add the ability to list the running BIND 10 processes using the
 	command channel. To try this, use "Boss show_processes".
 	(Trac #648, git 451bbb67c2b5d544db2f7deca4315165245d2b3b)
 
-  205.	[bug]		jinmei
+205.	[bug]		jinmei
 	b10-auth, src/lib/datasrc: fixed a bug where b10-auth could return
 	an empty additional section for delegation even if some glue is
 	crucial when it fails to find some other glue records in its data
 	source.
 	(Trac #646, git 6070acd1c5b2f7a61574eda4035b93b40aab3e2b)
 
-  204.	[bug]		jinmei
+204.	[bug]		jinmei
 	b10-auth, src/lib/datasrc: class ANY queries were not handled
 	correctly in the generic data source (mainly for sqlite3).  It
 	could crash b10-auth in the worst case, and could result in
 	incorrect responses in some other cases.
 	(Trac #80, git c65637dd41c8d94399bd3e3cee965b694b633339)
 
-  203.  [bug]		zhang likun
+203.	[bug]		zhang likun
 	Fix resolver cache memory leak: when cache is destructed, rrset
 	and message entries in it are not destructed properly.
 	(Trac #643, git aba4c4067da0dc63c97c6356dc3137651755ffce)
 
-  202.  [func]    vorner
+202.	[func]		vorner
 	It is possible to specify a different directory where we look for
 	configuration files (by -p) and different configuration file to
 	use (-c).  Also, it is possible to specify the port on which
 	cmdctl should listen (--cmdctl-port).
 	(Trac #615, git 5514dd78f2d61a222f3069fc94723ca33fb3200b)
 
-  201.  [bug]           jerry
+201.	[bug]		jerry
 	src/bin/bindctl: bindctl doesn't show traceback on shutdown.
 	(Trac #588, git 662e99ef050d98e86614c4443326568a0b5be437)
 
-  200.  [bug]           Jelte
+200.	[bug]		Jelte
 	Fixed a bug where incoming TCP connections were not closed.
 	(Trac #589, git 1d88daaa24e8b1ab27f28be876f40a144241e93b)
 
-  199.  [func]           ocean
+199.	[func]		ocean
 	Cache negative responses (NXDOMAIN/NODATA) from authoritative
 	server for recursive resolver.
 	(Trac #493, git f8fb852bc6aef292555063590c361f01cf29e5ca)
 
-  198.	[bug]		jinmei
+198.	[bug]		jinmei
 	b10-auth, src/lib/datasrc: fixed a bug where hot spot cache failed
 	to reuse cached SOA for negative responses.  Due to this bug
 	b10-auth returned SERVFAIL when it was expected to return a
@@ -77,42 +301,42 @@
 	the zone.
 	(Trac #626, git 721a53160c15e8218f6798309befe940b9597ba0)
 
-  197.  [bug]		zhang likun
+197.	[bug]		zhang likun
 	Remove expired message and rrset entries when looking up them
 	in cache, touch or remove the rrset entry in cache properly
 	when doing lookup or update.
 	(Trac #661, git 9efbe64fe3ff22bb5fba46de409ae058f199c8a7)
 
-  196.	[bug]		jinmei
+196.	[bug]		jinmei
 	b10-auth, src/lib/datasrc: the backend of the in-memory data
 	source could not handle the root name.  As a result b10-auth could
 	not work as a root server when using the in-memory data source.
 	(Trac #683, git 420ec42bd913fb83da37b26b75faae49c7957c46)
 
-  195.  [func]      stephen
+195.	[func]		stephen
 	Resolver will now re-try a query over TCP if a response to a UDP
 	query has the TC bit set.
 	(Trac #499, git 4c05048ba059b79efeab53498737abe94d37ee07)
 
-  194.  [bug]       vorner
+194.	[bug]		vorner
 	Solved a 100% CPU usage problem after switching addresses in b10-auth
 	(and possibly, but unconfirmed, in b10-resolver). It was caused by
 	repeated reads/accepts on closed socket (the bug was in the code for a
 	long time, recent changes made it show).
 	(Trac #657, git e0863720a874d75923ea66adcfbf5b2948efb10a)
 
-  193.	[func]*		jreed
+193.	[func]*		jreed
 	Listen on the IPv6 (::) and IPv4 (0.0.0.0) wildcard addresses
 	for b10-auth. This returns to previous behavior prior to
 	change #184. Document the listen_on configuration in manual.
 	(Trac #649, git 65a77d8fde64d464c75917a1ab9b6b3f02640ca6)
 
-  192.	[func]*		jreed
+192.	[func]*		jreed
 	Listen on standard domain port 53 for b10-auth and
 	b10-resolver.
 	(Trac #617, #618, git 137a6934a14cf0c5b5c065e910b8b364beb0973f)
 
-  191.	[func]		jinmei
+191.	[func]		jinmei
 	Imported system test framework of BIND 9.  It can be run by
 	'make systest' at the top source directory.  Notes: currently it
 	doesn't work when built in a separate tree.  It also requires
@@ -122,51 +346,51 @@
 	to the specified file.
 	(Trac #606, git 6ac000df85625f5921e8895a1aafff5e4be3ba9c)
 
-  190.	[func]		jelte
+190.	[func]		jelte
 	Resolver now sets random qids on outgoing queries using
 	the boost::mt19937 prng.
 	(Trac #583, git 5222b51a047d8f2352bc9f92fd022baf1681ed81)
 
-  189.	[bug]		jreed
+189.	[bug]		jreed
 	Do not install the log message compiler.
 	(Trac #634, git eb6441aca464980d00e3ff827cbf4195c5a7afc5)
 
-  188.  [bug]		zhang likun
+188.	[bug]		zhang likun
 	Make the rrset trust level ranking algorithm used by
 	isc::cache::MessageEntry::getRRsetTrustLevel() follow RFC2181
 	section 5.4.1.
 	(Trac #595 git 19197b5bc9f2955bd6a8ca48a2d04472ed696e81)
 
-  187.  [bug]		zhang likun
+187.	[bug]		zhang likun
 	Fix the assert error in class isc::cache::RRsetCache by adding the
 	check for empty pointer and test case for it.
 	(Trac #638, git 54e61304131965c4a1d88c9151f8697dcbb3ce12)
 
-  186.  [bug]		jelte
+186.	[bug]		jelte
 	b10-resolver could stop with an assertion failure on certain kinds
 	of messages (there was a problem in error message creation). This
 	fixes that.
 	(Trac #607, git 25a5f4ec755bc09b54410fcdff22691283147f32)
 
-  185.  [bug]        vorner
+185.	[bug]		vorner
 	Tests use port from private range (53210), lowering chance of
 	a conflict with something else (eg. running bind 10).
 	(Trac #523, git 301da7d26d41e64d87c0cf72727f3347aa61fb40)
 
-  184.  [func]*      vorner
+184.	[func]*		vorner
 	Listening address and port configuration of b10-auth is the same as
 	for b10-resolver now. That means, it is configured through bindctl
 	at runtime, in the Auth/listen_on list, not through command line
 	arguments.
 	(Trac #575, #576, git f06ce638877acf6f8e1994962bf2dbfbab029edf)
 
-  183.  [bug]      jerry
+183.	[bug]		jerry
 	src/bin/xfrout: Enable parallel sessions between xfrout server and
 	muti-Auth. The session needs to be created only on the first time
 	or if an error occur.
 	(Trac #419, git 1d60afb59e9606f312caef352ecb2fe488c4e751)
 
-  182.	[func]		jinmei
+182.	[func]		jinmei
 	Support cppcheck for static code check on C++ code.  If cppcheck
 	is available, 'make cppcheck' on the top source directory will run
 	the checker and should cleanly complete with an exit code of 0
@@ -176,46 +400,46 @@
 	the git repository.
 	(Trac #613, git b973f67520682b63ef38b1451d309be9f4f4b218)
 
-  181.  [func]      feng
+181.	[func]		feng
 	Add stop interface into dns server, so we can stop each running
 	server individually. With it, user can reconfigure her running server
 	with different ip address or port.
 	(Trac #388, git 6df94e2db856c1adc020f658cc77da5edc967555)
 
-  180.  [build]     jreed
+180.	[build]		jreed
 	Fix custom DESTDIR for make install. Patch from Jan Engelhardt.
 	(Trac #629, git 5ac67ede03892a5eacf42ce3ace1e4e376164c9f)
 
 bind10-devel-20110224 released on February 24, 2011
 
-  179.  [func]      vorner
+179.	[func]		vorner
 	It is possible to start and stop resolver and authoritative
 	server without restart of the whole system. Change of the
 	configuration (Boss/start_auth and Boss/start_resolver) is
 	enough.
 	(Trac #565, git 0ac0b4602fa30852b0d86cc3c0b4730deb1a58fe)
 
-  178.  [func]      jelte
+178.	[func]		jelte
 	Resolver now makes (limited) use of the cache
 	(Trac #491, git 8b41f77f0099ddc7ca7d34d39ad8c39bb1a8363c)
 
-  177.  [func]      stephen
+177.	[func]		stephen
 	The upstream fetch code in asiolink is now protocol agnostic to
 	allow for the addition of fallback to TCP if a fetch response
 	indicates truncation.
 	(Trac #554, git 9739cbce2eaffc7e80640db58a8513295cf684de)
 
-  176.  [func]      zhang likun
+176.	[func]		likun
 	src/lib/cache: Rename one interface: from lookupClosestRRset()
 	to lookupDeepestNS(), and remove one parameter of it.
 	(Trac #492, git ecbfb7cf929d62a018dd4cdc7a841add3d5a35ae)
 
-  175.	[bug]		jerry
+175.	[bug]		jerry
 	src/bin/xfrout: Xfrout use the case-sensitive mode to compress
 	names in an AXFR massage.
 	(Trac #253, git 004e382616150f8a2362e94d3458b59bb2710182)
 
-  174.	[bug]*		jinmei
+174.	[bug]*		jinmei
 	src/lib/dns: revised dnssectime functions so that they don't rely
 	on the time_t type (whose size varies on different systems, which
 	can lead to subtle bugs like some form of "year 2038 problem").
@@ -224,74 +448,74 @@ bind10-devel-20110224 released on February 24, 2011
 	should be minimal because these functions are mostly private.
 	(Trac #61, git 09ece8cdd41c0f025e8b897b4883885d88d4ba5d)
 
-  173.	[bug]		jerry
+173.	[bug]		jerry
 	python/isc/notify: A notify_out test fails without network
 	connectivity, encapsulate the socket behavior using a mock
 	socket class to fix it.
 	(Trac #346, git 319debfb957641f311102739a15059f8453c54ce)
 
-  172.  [func]      jelte
+172.	[func]		jelte
 	Improved the bindctl cli in various ways, mainly concerning
 	list and map item addressing, the correct display of actual values,
 	and internal help.
 	(Trac #384, git e5fb3bc1ed5f3c0aec6eb40a16c63f3d0fc6a7b2)
 
-  171.  [func]      feng, jerry, jinmei, vorner
+171.	[func]		vorner
 	b10-auth, src/lib/datasrc: in memory data source now works as a
 	complete data source for authoritative DNS servers and b10-auth
 	uses it.  It still misses major features, however, including
 	DNSSEC support and zone transfer.
-	(Last trac #553, but many more,
+	(Last Trac #553, but many more,
 	git 6f031a09a248e7684723c000f3e8cc981dcdb349)
 
-  170.	[bug]		jinmei
+170.	[bug]		jinmei
 	Tightened validity checks in the NSEC3 constructors, both "from
 	"text" and "from wire".  Specifically, wire data containing
 	invalid type bitmaps or invalid lengths of salt or hash is now
 	correctly rejected.
 	(Trac #117, git 9c690982f24fef19c747a72f43c4298333a58f48)
 
-  169.  [func]      zhang likun, jelte
+169.	[func]		jelte
 	Added a basic implementation for a resolver cache (though not
 	used yet).
 	(Trac #449, git 8aa3b2246ae095bbe7f855fd11656ae3bdb98986)
 
-  168.  [bug]       vorner
+168.	[bug]		vorner
 	Boss no longer has the -f argument, which was undocumented and
 	stayed as a relict of previous versions, currently causing only
 	strange behaviour.
 	(Trac #572, git 17f237478961005707d649a661cc72a4a0d612d4)
 
-  167.  [bug]           naokikambe
+167.	[bug]		naokikambe
 	Fixed failure of termination of msgq_test.py with python3
-	coverage(3.3.1)
+	coverage (3.3.1).
 	(Trac #573, git 0e6a18e12f61cc482e07078776234f32605312e5)
 
-  166.  [func]      jelte
+166.	[func]		jelte
 	The resolver now sends back a SERVFAIL when there is a client
 	timeout (timeout_client config setting), but it will not stop
 	resolving (until there is a lookup timeout or a result).
 	(Trac #497 and #489, git af0e5cd93bebb27cb5c4457f7759d12c8bf953a6)
 
-  165.  [func]      jelte
+165.	[func]		jelte
 	The resolver now handles CNAMEs, it will follow them, and include
 	them in the answer. The maximum length of CNAME chains that is
 	supported is 16.
 	(Trac #497, git af0e5cd93bebb27cb5c4457f7759d12c8bf953a6)
 
-  164.  [bug]           y-aharen
+164.	[bug]		y-aharen
 	IntervalTimer: Modified the interface to accept interval in
 	milliseconds. It shortens the time of the tests of IntervalTimer.
 	(Trac #452, git c9f6acc81e24c4b8f0eb351123dc7b43f64e0914)
 
-  163.  [func]      vorner
+163.	[func]		vorner
 	The pimpl design pattern is used in UDPServer, with a shared
 	pointer. This makes it smaller to copy (which is done a lot as a
 	sideeffect of being coroutine) and speeds applications of this
 	class (notably b10-auth) up by around 10%.
 	(Trac #537, git 94cb95b1d508541201fc064302ba836164d3cbe6)
 
-  162.  [func]		stephen
+162.	[func]		stephen
 	Added C++ logging, allowing logging at different severities.
 	Code specifies the message to be logged via a symbol, and the
 	logging code picks up the message from an in-built dictionary.
@@ -300,13 +524,13 @@ bind10-devel-20110224 released on February 24, 2011
 	to create message header files and supply the default messages.
 	(Trac #438, git 7b1606cea7af15dc71f5ec1d70d958b00aa98af7)
 
-  161.  [func]		stephen
+161.	[func]		stephen
 	Added ResponseScrubber class to examine response from
 	a server and to remove out-of-bailiwick RRsets.  Also
 	does cross-section checks to ensure consistency.
 	(Trac #496, git b9296ca023cc9e76cda48a7eeebb0119166592c5)
 
-  160.  [func]		jelte
+160.	[func]		jelte
   	Updated the resolver to take 3 different timeout values;
 	timeout_query for outstanding queries we sent while resolving
 	timeout_client for sending an answer back to the client
@@ -314,14 +538,14 @@ bind10-devel-20110224 released on February 24, 2011
 	(currently 2 and 3 have the same final effect)
 	(Trac #489, git 578ea7f4ba94dc0d8a3d39231dad2be118e125a2)
 
-  159.	[func]		smann
+159.	[func]		smann
 	The resolver now has a configurable set of root servers to start
 	resolving at (called root_addresses). By default these are not
 	(yet) filled in. If empty, a hardcoded address for f-root will be
 	used right now.
 	(Trac #483, git a07e078b4feeb01949133fc88c9939254c38aa7c)
 
-  158.	[func]		jelte
+158.	[func]		jelte
 	The Resolver module will now do (very limited) resolving, if not
 	set to forwarding mode (i.e. if the configuration option
 	forward_addresses is left empty). It only supports referrals that
@@ -329,24 +553,24 @@ bind10-devel-20110224 released on February 24, 2011
 	of authoritative answers.
 	(Trac #484, git 7b84de4c0e11f4a070e038ca4f093486e55622af)
 
-  157.  [bug]       vorner
+157.	[bug]		vorner
 	One frozen process no longer freezes the whole b10-msgq. It caused the
 	whole system to stop working.
 	(Trac #420, git 93697f58e4d912fa87bc7f9a591c1febc9e0d139)
 
-  156.	[func]		stephen
+156.	[func]		stephen
 	Added ResponseClassifier class to examine response from
 	a server and classify it into one of several categories.
 	(Trac #487, git 18491370576e7438c7893f8551bbb8647001be9c)
 
 bind10-devel-20110120 released on January 20, 2011
 
-  155.	[doc]		jreed
+155.	[doc]		jreed
 	Miscellaneous documentation improvements for man pages and
 	the guide, including auth, resolver, stats, xfrout, and
 	zonemgr.  (git c14c4741b754a1eb226d3bdc3a7abbc4c5d727c0)
 
-  154.	[bug]		jinmei
+154.	[bug]		jinmei
 	b10-xfrin/b10-zonemgr: Fixed a bug where these programs didn't
 	receive command responses from CC sessions.  Eventually the
 	receive buffer became full, and many other components that rely
@@ -355,12 +579,12 @@ bind10-devel-20110120 released on January 20, 2011
 	to revisit it for cleaner fix later.
 	(Trac #516, git 62c72fcdf4617e4841e901408f1e7961255b8194)
 
-  153.	[bug]		jelte
+153.	[bug]		jelte
 	b10-cfgmgr: Fixed a bug where configuration updates sometimes
 	lost previous settings in the configuration manager.
 	(Trac #427, git 2df894155657754151e0860e2ca9cdbed7317c70)
 
-  152.	[func]*		jinmei
+152.	[func]*		jinmei
 	b10-auth: Added new configuration variable "statistics-interval"
 	to allow the user to change the timer interval for periodic
 	statistics updates.  The update can also be disabled by setting
@@ -369,46 +593,47 @@ bind10-devel-20110120 released on January 20, 2011
 	sending statistics and stop responding to queries as a result.
 	(Trac #513, git 285c5ee3d5582ed6df02d1aa00387f92a74e3695)
 
-  151.  [bug]		smann
+151.	[bug]		smann
 	lib/log/dummylog.h: 
-	lib/log/dummylog.cc: Modify dlog so that it takes an optional 2nd
-        argument of type bool (true or false). This flag, if set, will cause
-        the message to be printed whether or not -v is chosen.
-        (trac #432, git 880220478c3e8702d56d761b1e0b21b77d08ee5a)
+	lib/log/dummylog.cc: Modify dlog so that it takes an optional
+	2nd argument of type bool (true or false). This flag, if
+	set, will cause the message to be printed whether or not
+	-v is chosen.
+        (Trac #432, git 880220478c3e8702d56d761b1e0b21b77d08ee5a)
 
-  150.  [bug]		jelte
+150.	[bug]		jelte
 	b10-cfgmgr: No longer save the configuration on exit. Configuration
 	is already saved if it is changed successfully, so writing it on
 	exit (and hence, when nothing has changed too) is unnecessary and
 	may even cause problems.
 	(Trac #435, git fd7baa38c08d54d5b5f84930c1684c436d2776dc)
 
-  149.  [bug]		jelte
+149.	[bug]		jelte
 	bindctl: Check if the user session has disappeared (either by a
 	timeout or by a server restart), and reauthenticate if so. This
 	fixes the 'cmdctl not running' problem.
-        (trac #431, git b929be82fec5f92e115d8985552f84b4fdd385b9)
+        (Trac #431, git b929be82fec5f92e115d8985552f84b4fdd385b9)
 
-  148.	[func]		jelte
+148.	[func]		jelte
 	bindctl: Command results are now pretty-printed (i.e. printed in
 	a more readable form). Empty results are no longer printed at all
 	(used to print '{}'), and the message
 	'send the command to cmd-ctrl' has also been removed.
 	(git 3954c628c13ec90722a2d8816f52a380e0065bae)
 
-  147.	[bug]		jinmei
+147.	[bug]		jinmei
 	python/isc/config: Fixed a bug that importing custom configuration
 	(in b10-config.db) of a remote module didn't work.
 	(Trac #478, git ea4a481003d80caf2bff8d0187790efd526d72ca)
 
-  146.	[func]		jelte
+146.	[func]		jelte
 	Command arguments were not validated internally against their
 	specifications. This change fixes that (on the C++ side, Python
 	side depends on an as yet planned addition). Note: this is only
 	an added internal check, the cli already checks format.
 	(Trac #473, git 5474eba181cb2fdd80e2b2200e072cd0a13a4e52)
 
-  145.	[func]*		jinmei
+145.	[func]*		jinmei
 	b10-auth: added a new command 'loadzone' for (re)loading a
 	specific zone.  The command syntax is generic but it is currently
 	only feasible for class IN in memory data source.  To reload a
@@ -417,7 +642,7 @@ bind10-devel-20110120 released on January 20, 2011
 	(Trac #467 git 4f7e1f46da1046de527ab129a88f6aad3dba7562
 	from 1d7d3918661ba1c6a8b1e40d8fcbc5640a84df12)
 
-  144.	[build]		jinmei
+144.	[build]		jinmei
 	Introduced a workaround for clang++ build on FreeBSD (and probably
 	some other OSes).  If building BIND 10 fails with clang++ due to
 	a link error about "__dso_handle", try again from the configure
@@ -428,23 +653,23 @@ bind10-devel-20110120 released on January 20, 2011
 	variable by hand.
 	(Trac #474, git cfde436fbd7ddf3f49cbbd153999656e8ca2a298)
 
-  143.	[build]		jinmei
+143.	[build]		jinmei
 	Fixed build problems with clang++ in unit tests due to recent
 	changes.  No behavior change. (Trac #448, svn r4133)
 
-  142.	[func]		jinmei
+142.	[func]		jinmei
 	b10-auth: updated query benchmark so that it can test in memory
 	data source.  Also fixed a bug that the output buffer isn't
 	cleared after query processing, resulting in misleading results
 	or program crash.  This is a regression due to change #135.
 	(Trac #465, svn r4103)
 
-  141.	[bug]		jinmei
+141.	[bug]		jinmei
 	b10-auth: Fixed a bug that the authoritative server includes
 	trailing garbage data in responses.  This is a regression due to
 	change #135. (Trac #462, svn r4081)
 
-  140.  [func]		y-aharen
+140.	[func]		y-aharen
 	src/bin/auth: Added a feature to count queries and send counter
 	values to statistics periodically. To support it, added wrapping
 	class of asio::deadline_timer to use as interval timer.
@@ -455,14 +680,14 @@ bind10-devel-20110120 released on January 20, 2011
 	counters to b10-stats immediately.
 	(Trac #347, svn r4026)
 
-  139.  [build]		jreed
+139.	[build]		jreed
 	Introduced configure option and make targets for generating
 	Python code coverage report. This adds new make targets:
 	report-python-coverage and clean-python-coverage. The C++
 	code coverage targets were renamed to clean-cpp-coverage
 	and report-cpp-coverage. (Trac #362, svn r4023)
 
-  138.	[func]*		jinmei
+138.	[func]*		jinmei
 	b10-auth: added a configuration interface to support in memory
 	data sources.  For example, the following command to bindctl
 	will configure a memory data source containing the "example.com"
@@ -479,70 +704,70 @@ bind10-devel-20110120 released on January 20, 2011
 	future versions.
 	(Trac #446, svn r3998)
 
-  137.	[bug]		jreed
+137.	[bug]		jreed
 	Fix run_*.sh scripts that are used for development testing
 	so they use a msgq socket file in the build tree.
 	(Trac #226, svn r3989)
 
-  136.  [bug]       jelte
+136.	[bug]		jelte
   	bindctl (and the configuration manager in general) now no longer
 	accepts 'unknown' data; i.e. data for modules that it does not know
 	about, or configuration items that are not specified in the .spec
 	files.
 	(Trac #202, svn r3967)
 
-  135.  [func]      each
+135.	[func]		each
 	Add b10-resolver. This is an example recursive server that
 	currently does forwarding only and no caching.
 	(Trac #327, svn r3903)
 
-  134.  [func]      vorner
+134.	[func]		vorner
 	b10-resolver supports timeouts and retries in forwarder mode.
 	(Trac #401, svn r3660)
 
-  133.  [func]      vorner
+133.	[func]		vorner
 	New temporary logging function available in isc::log. It is used by
 	b10-resolver.
 	(Trac #393, r3602)
 
-  132.  [func]      vorner
+132.	[func]		vorner
 	The b10-resolver is configured through config manager.
 	It has "listen_on" and "forward_addresses" options.
 	(Trac #389, r3448)
 
-  131.  [func]    feng, jerry
+131.	[func]		jerry
 	src/lib/datasrc: Introduced two template classes RBTree and RBNode
 	to provide the generic map with domain name as key and anything as
 	the value. Because of some unresolved design issue, the new classes
 	are only intended to be used by memory zone and zone table.
 	(Trac #397, svn r3890)
 
-  130.	[func]		jerry
+130.	[func]		jerry
 	src/lib/datasrc: Introduced a new class MemoryDataSrc to provide
 	the general interface for memory data source.  For the initial
 	implementation, we don't make it a derived class of AbstractDataSrc
-	because the interface is so different(we'll eventually consider this
-	as part of the generalization work).
+	because the interface is so different (we'll eventually
+	consider this as part of the generalization work).
 	(Trac #422, svn r3866)
 
-  129.	[func]		jinmei
+129.	[func]		jinmei
 	src/lib/dns: Added new functions masterLoad() for loading master
 	zone files.  The initial implementation can only parse a limited
 	form of master files, but BIND 9's named-compilezone can convert
 	any valid zone file into the acceptable form.
 	(Trac #423, svn r3857)
 
-  128.  [build]     vorner
+128.	[build]		vorner
 	Test for query name = '.', type = DS to authoritative nameserver
 	for root zone was added.
 	(Trac #85, svn r3836)
 
-  127.  [bug]       stephen
+127.	[bug]		stephen
 	During normal operation process termination and resurrection messages
 	are now output regardless of the state of the verbose flag.
 	(Trac #229, svn r3828)
 
-  126.  [func]      stephen, vorner, ocean
+126.	[func]		ocean
 	The Nameserver Address Store (NSAS) component has been added. It takes
 	care of choosing an IP address of a nameserver when a zone needs to be
 	contacted.
@@ -550,38 +775,38 @@ bind10-devel-20110120 released on January 20, 2011
 
 bind10-devel-20101201 released on December 01, 2010
 
-  125.  [func]		jelte
+125.	[func]		jelte
 	Added support for addressing individual list items in bindctl
 	configuration commands; If you have an element that is a list, you
-	can use foo[X] to address a specific item, where X is an integer
+	can use foo[X]		integer
 	(starting at 0)
 	(Trac #405, svn r3739)
 
-  124.  [bug]		jreed
+124.	[bug]		jreed
 	Fix some wrong version reporting. Now also show the version
 	for the component and BIND 10 suite. (Trac #302, svn r3696)
 
-  123.  [bug]		jelte
+123.	[bug]		jelte
 	src/bin/bindctl printed values had the form of python literals
 	(e.g. 'True'), while the input requires valid JSON (e.g. 'true').
 	Output changed to JSON format for consistency. (svn r3694)
 
-  122.  [func]		stephen
+122.	[func]		stephen
 	src/bin/bind10: Added configuration options to Boss to determine
 	whether to start the authoritative server, recursive server (or
 	both). A dummy program has been provided for test purposes.
 	(Trac #412, svn r3676)
 
-  121.  [func]		jinmei
+121.	[func]		jinmei
 	src/lib/dns: Added support for TSIG RDATA.  At this moment this is
 	not much of real use, however, because no protocol support was
 	added yet.  It will soon be added. (Trac #372, svn r3649)
 
-  120.  [func]		jinmei
+120.	[func]		jinmei
 	src/lib/dns: introduced two new classes, TSIGKey and TSIGKeyRing,
 	to manage TSIG keys. (Trac #381, svn r3622)
 
-  119.	[bug]		jinmei
+119.	[bug]		jinmei
 	The master file parser of the python datasrc module incorrectly
 	regarded a domain name beginning with a decimal number as a TTL
 	specification.  This confused b10-loadzone and had it reject to
@@ -591,158 +816,158 @@ bind10-devel-20101201 released on December 01, 2010
 	from a TTL specification.  This is part of a more general issue
 	and will be addressed in Trac #413. (Trac #411, svn r3599)
 
-  118.	[func]		jinmei
+118.	[func]		jinmei
 	src/lib/dns: changed the interface of
 	AbstractRRset::getRdataIterator() so that the internal
 	cursor would point to the first RDATA automatically.  This
 	will be a more intuitive and less error prone behavior.
 	This is a backward compatible change. (Trac #410, r3595)
 
-  117.  [func]		jinmei
+117.	[func]		jinmei
 	src/lib/datasrc: added new zone and zone table classes for the
 	support of in memory data source.  This is an intermediate step to
 	the bigger feature, and is not yet actually usable in practice.
 	(Trac #399, svn r3590)
 
-  116.	[bug]		jerry
+116.	[bug]		jerry
 	src/bin/xfrout: Xfrout and Auth will communicate by long tcp
 	connection, Auth needs to make a new connection only on the first
 	time or if an error occurred.
 	(Trac #299, svn r3482)
 
-  115.	[func]*		jinmei
+115.	[func]*		jinmei
 	src/lib/dns: Changed DNS message flags and section names from
 	separate classes to simpler enums, considering the balance between
 	type safety and usability.  API has been changed accordingly.
 	More documentation and tests were provided with these changes.
 	(Trac #358, r3439)
 
-  114.	[build]		jinmei
+114.	[build]		jinmei
 	Supported clang++.  Note: Boost >= 1.44 is required.
 	(Trac #365, svn r3383)
 
-  113.	[func]*		zhanglikun
+113.	[func]*		zhanglikun
 	Folder name 'utils'(the folder in /src/lib/python/isc/) has been
 	renamed	to 'util'. Programs that used 'import isc.utils.process'
 	now need to use 'import isc.util.process'. The folder
 	/src/lib/python/isc/Util is removed since it isn't used by any
 	program. (Trac #364, r3382)
 
-  112.	[func]		zhang likun
+112.	[func]		zhang likun
 	Add one mixin class to override the naive serve_forever() provided
 	in python library socketserver. Instead of polling for shutdown
 	every poll_interval seconds, one socketpair is used to wake up
 	the waiting server. (Trac #352, svn r3366)
 
-  111.	[bug]*   zhanglikun, Michal Vaner
+111.	[bug]*		Vaner
 	Make sure process xfrin/xfrout/zonemgr/cmdctl can be stopped
 	properly when user enter "ctrl+c" or 'Boss shutdown' command
 	through bindctl.  The ZonemgrRefresh.run_timer and
 	NotifyOut.dispatcher spawn a thread themselves.
 	(Trac #335, svn r3273)
 
-  110.  [func]      Michal Vaner
+110.	[func]		Vaner
 	Added isc.net.check module to check ip addresses and ports for
 	correctness and isc.net.addr to hold IP address. The bind10, xfrin
 	and cmdctl programs are modified to use it.
 	(Trac #353, svn r3240)
 
-  109.  [func]		naokikambe
+109.	[func]		naokikambe
 	Added the initial version of the stats module for the statistics
 	feature of BIND 10, which supports the restricted features and
 	items and reports via bindctl command. (Trac #191, r3218)
 	Added the document of the stats module, which is about how stats
 	module collects the data (Trac #170, [wiki:StatsModule])
 
-  108.	[func]		jerry
+108.	[func]		jerry
 	src/bin/zonemgr: Provide customizable configurations for
 	lowerbound_refresh, lowerbound_retry, max_transfer_timeout and
 	jitter_scope. (Trac #340, r3205)
 
-  107.  [func]       zhang likun
+107.	[func]		likun
 	Remove the parameter 'db_file' for command 'retransfer' of
 	xfrin module. xfrin.spec will not be generated by script.
 	(Trac #329, r3171)
 
-  106.  [bug]       zhang likun
+106.	[bug]		likun
 	When xfrin can't connect with one zone's master, it should tell
 	the bad news to zonemgr, so that zonemgr can reset the timer for
 	that zone. (Trac #329, r3170)
 
-  105.  [bug]       Michal Vaner
+105.	[bug]		Vaner
 	Python processes: they no longer take 100% CPU while idle
 	due to a busy loop in reading command session in a nonblocking way.
 	(Trac #349, svn r3153), (Trac #382, svn r3294)
 
-  104.	[bug]		jerry
+104.	[bug]		jerry
 	bin/zonemgr: zonemgr should be attempting to refresh expired zones.
 	(Trac #336, r3139)
  
-  103.	[bug]		jerry
+103.	[bug]		jerry
 	lib/python/isc/log: Fixed an issue with python logging,
 	python log shouldn't die with OSError. (Trac #267, r3137)
  
-  102.	[build]		jinmei
+102.	[build]		jinmei
 	Disable threads in ASIO to minimize build time dependency.
 	(Trac #345, r3100)
 
-  101.	[func]		jinmei
+101.	[func]		jinmei
 	src/lib/dns: Completed Opcode and Rcode implementation with more
 	tests and documentation.  API is mostly the same but the
 	validation was a bit tightened. (Trac #351, svn r3056)
 
-  100.  [func]      Michal Vaner
+100.	[func]		Vaner
 	Python processes: support naming of python processes so
 	they're not all called python3.
 	(Trac #322, svn r3052)
 
-  99.	[func]*		jinmei
+99.	[func]*		jinmei
 	Introduced a separate EDNS class to encapsulate EDNS related
 	information more cleanly.  The related APIs are changed a bit,
 	although it won't affect most of higher level applications.
 	(Trac #311, svn r3020)
 
-  98.	[build]		jinmei
+98.	[build]		jinmei
 	The ./configure script now tries to search some common include
 	paths for boost header files to minimize the need for explicit
 	configuration with --with-boost-include. (Trac #323, svn r3006)
 
-  97.	[func]		jinmei
+97.	[func]		jinmei
 	Added a micro benchmark test for query processing of b10-auth.
 	(Trac #308, svn r2982)
 
-  96.	[bug]		jinmei
+96.	[bug]		jinmei
 	Fixed two small issues with configure: Do not set CXXFLAGS so that
 	it can be customized; Make sure --disable-static works.
 	(Trac #325, r2976)
 
 bind10-devel-20100917 released on September 17, 2010 
 
-  95.	[doc]		jreed
+95.	[doc]		jreed
 	Add b10-zonemgr manual page. Update other docs to introduce
 	this secondary manager. (Trac #341, svn r2951)
 
-  95.	[bug]		jreed
+95.	[bug]		jreed
 	bin/xfrout and bin/zonemgr: Fixed some stderr output.
 	(Trac #342, svn r2949)
 
-  94.	[bug]		jelte
+94.	[bug]		jelte
   	bin/xfrout:  Fixed a problem in xfrout where only 2 or 3 RRs
 	were used per DNS message in the xfrout stream.
 	(Trac #334, r2931)
 
-  93.	[bug]		jinmei
+93.	[bug]		jinmei
 	lib/datasrc: A DS query could crash the library (and therefore,
 	e.g. the authoritative server) if some RR of the same apex name
 	is stored in the hot spot cache. (Trac #307, svn r2923)
 
-  92.	[func]*		jelte
+92.	[func]*		jelte
 	libdns_python (the python wrappers for libdns++) has been renamed
 	to pydnspp (Python DNS++). Programs and libraries that used
 	'import libdns_python' now need to use 'import pydnspp'.
 	(Trac #314, r2902)
 
-  91.	[func]*		jinmei
+91.	[func]*		jinmei
 	lib/cc: Use const pointers and const member functions for the API
 	as much as possible for safer operations.  Basically this does not
 	change the observable behavior, but some of the API were changed
@@ -750,36 +975,36 @@ bind10-devel-20100917 released on September 17, 2010
 	copies, but at this moment the overhead is deemed acceptable.
 	(Trac #310, r2803)
 
-  90.	[build]		jinmei
+90.	[build]		jinmei
 	(Darwin/Mac OS X specific) Specify DYLD_LIBRARY_PATH for tests and
 	experimental run under the source tree.  Without this loadable
 	python modules refer to installation paths, which may confuse the
 	operation due to version mismatch or even trigger run time errors
 	due to missing libraries. (Trac #313, r2782)
 
-  89.	[build]		jinmei
+89.	[build]		jinmei
 	Generate b10-config.db for tests at build time so that the source
 	tree does not have to be writable. (Trac #315, r2776)
 
-  88.   [func]		jelte
+88.	[func]		jelte
 	Blocking reads on the msgq command channel now have a timeout
 	(defaults to 4 seconds, modifiable as needed by modules).
 	Because of this, modules will no longer block indefinitely
 	if they are waiting for a message that is not sent for whatever
 	reason. (Trac #296, r2761)
 
-  87.   [func]		zhanglikun
+87.	[func]		zhanglikun
 	lib/python/isc/notifyout: Add the feature of notify-out, when 
 	zone axfr/ixfr finishing, the server will notify its slaves.
 	(Trac #289, svn r2737)
 
-  86.	[func]		jerry
+86.	[func]		jerry
 	bin/zonemgr: Added zone manager module. The zone manager is one 
 	of the co-operating processes of BIND10, which keeps track of 
 	timers and other information necessary for BIND10 to act as a 
 	slave. (Trac #215, svn r2737)
 
-  85.	[build]*	jinmei
+85.	[build]*		jinmei
 	Build programs using dynamic link by default.  A new configure
 	option --enable-static-link is provided to force static link for
 	executable programs.  Statically linked programs can be run on a
@@ -788,34 +1013,34 @@ bind10-devel-20100917 released on September 17, 2010
 
 bind10-devel-20100812 released on August 12, 2010
 
-  84.	[bug]		jinmei, jerry
+84.	[bug]		jinmei, jerry
 	This is a quick fix patch for the issue: AXFR fails half the 
 	time because of connection problems. xfrout client will make
 	a new connection every time. (Trac #299, svn r2697)
 
-  83.	[build]*	jreed
+83.	[build]*		jreed
 	The configure --with-boost-lib option is removed. It was not
 	used since the build included ASIO. (svn r2684)
 
-  82.	[func]		jinmei
+82.	[func]		jinmei
 	bin/auth: Added -u option to change the effective process user
 	of the authoritative server after invocation.  The same option to
 	the boss process will be propagated to b10-auth, too.
 	(Trac #268, svn r2675)
 
-  81.	[func]		jinmei
+81.	[func]		jinmei
 	Added a C++ framework for micro benchmark tests.  A supplemental
 	library functions to build query data for the tests were also
 	provided. (Trac #241, svn r2664)
 
-  80.	[bug]		jelte
+80.	[bug]		jelte
 	bindctl no longer accepts configuration changes for unknown or
 	non-running modules (for the latter, this is until we have a
 	way to verify those options, at which point it'll be allowed
 	again).
 	(Trac #99, r2657)
 
-  79.	[func]		feng, jinmei
+79.	[func]		feng, jinmei
 	Refactored the ASIO link interfaces to move incoming XFR and
 	NOTIFY processing to the auth server class.  Wrapper classes for
 	ASIO specific concepts were also provided, so that other BIND 10
@@ -827,7 +1052,7 @@ bind10-devel-20100812 released on August 12, 2010
 	Note: Right now, NOTIFY doesn't actually trigger subsequent zone
 	transfer due to security reasons. (Trac #221, r2565)
 
-  78.	[bug]		jinmei
+78.	[bug]		jinmei
 	lib/dns: Fixed miscellaneous bugs in the base32 (hex) and hex
 	(base16) implementation, including incorrect padding handling,
 	parser failure in decoding with a SunStudio build, missing
@@ -838,44 +1063,44 @@ bind10-devel-20100812 released on August 12, 2010
 	libdns++, so we don't consider it a backward incompatible change.
 	(Trac #256, r2549)
 
-  77.	[func]		zhanglikun
+77.	[func]		zhanglikun
 	Make error message be more friendly when running cmdctl and it's 
-	already running(listening on same port)(Trac #277, r2540)
+	already running (listening on same port)(Trac #277, r2540)
 
-  76.	[bug]		jelte
+76.	[bug]		jelte
 	Fixed a bug in the handling of 'remote' config modules (i.e.
 	modules that peek at the configuration of other modules), where
 	they answered 'unknown command' to commands for those other
 	modules. (Trac #278, r2506)
 
-  75.	[bug]		jinmei
+75.	[bug]		jinmei
 	Fixed a bug in the sqlite3 data source where temporary strings
 	could be referenced after destruction.  It caused various lookup
 	failures with SunStudio build. (Trac #288, r2494)
 
-  74.	[func]*		jinmei
+74.	[func]*		jinmei
 	Refactored the cc::Session class by introducing an abstract base
 	class.  Test code can use their own derived mock class so that
 	tests can be done without establishing a real CC session.  This
 	change also modified some public APIs, mainly in the config
 	module. (Trac #275, r2459)
 
-  73.	[bug]		jelte
+73.	[bug]		jelte
   	Fixed a bug where in bindctl, locally changed settings were
 	reset when the list of running modules is updated. (Trac #285,
 	r2452)
 
-  72.	[build]		jinmei
+72.	[build]		jinmei
 	Added -R when linking python wrapper modules to libpython when
 	possible.  This helps build BIND 10 on platforms that install
 	libpython whose path is unknown to run-time loader.  NetBSD is a
 	known such platform. (Trac #148, r2427)
 
-  71.  [func]		each
+71.	[func]		each
   	Add "-a" (address) option to bind10 to specify an address for
 	the auth server to listen on.
 
-  70.  [func]		each
+70.	[func]		each
   	Added a hot-spot cache to libdatasrc to speed up access to
 	repeatedly-queried data and reduce the number of queries to
 	the underlying database; this should substantially improve
@@ -885,22 +1110,22 @@ bind10-devel-20100812 released on August 12, 2010
 
 bind10-devel-20100701 released on July 1, 2010
 
-  69.  [func]*		jelte
+69.	[func]*		jelte
 	Added python wrappers for libdns++ (isc::dns), and libxfr. This
 	removes the dependency on Boost.Python. The wrappers don't
 	completely implement all functionality, but the high-level API
 	is wrapped, and current modules use it now.
 	(Trac #181, svn r2361)
 
-  68.  [func]		zhanglikun
-	Add options -c(--certificate-chain) to bindctl. Override class
+68.	[func]		zhanglikun
+	Add options -c (--certificate-chain) to bindctl. Override class
 	HTTPSConnection to support server certificate validation.
 	Add support to cmdctl.spec file, now there are three configurable 
 	items for cmdctl: 'key_file', 'cert_file' and 'accounts_file', 
 	all of them can be changed in runtime.
 	(Trac #127, svn r2357)
 
-  67.  [func]		zhanglikun
+67.	[func]		zhanglikun
 	Make bindctl's command parser only do minimal check.
 	Parameter value can be a sequence of non-space characters,
 	or a string surrounded by quotation marks (these marks can
@@ -911,13 +1136,13 @@ bind10-devel-20100701 released on July 1, 2010
 	avoid using Exception to catch all exceptions.
 	(Trac #220, svn r2356)
 
-  66.  [bug]		each
+66.	[bug]		each
 	Check for duplicate RRsets before inserting data into a message
 	section; this, among other things, will prevent multiple copies
 	of the same CNAME from showing up when there's a loop. (Trac #69,
 	svn r2350)
     
-  65.  [func]		shentingting
+65.	[func]		shentingting
 	Various loadzone improvements: allow optional comment for
 	$TTL, allow optional origin and comment for $INCLUDE, allow
 	optional comment for $ORIGIN, support BIND9 extension of
@@ -928,71 +1153,71 @@ bind10-devel-20100701 released on July 1, 2010
 	formats to load.
 	(Trac #197, #199, #244, #161, #198, #174, #175, svn r2340)
 
-  64.  [func]		jerry
+64.	[func]		jerry
 	Added python logging framework. It is for testing and
 	experimenting with logging ideas. Currently, it supports
 	three channels (file, syslog and stderr) and five levels
 	(debug, info, warning, error and critical).
 	(Trac #176, svn r2338)
 
-  63.  [func]		shane
+63.	[func]		shane
 	Added initial support for setuid(), using the "-u" flag. This will
 	be replaced in the future, but for now provides a reasonable 
 	starting point.
 	(Trac #180, svn r2330)
 
-  62.  [func]		jelte
+62.	[func]		jelte
 	bin/xfrin: Use the database_file as configured in Auth to transfers
 	bin/xfrout: Use the database_file as configured in Auth to transfers
 
-  61.  [bug]		jelte
+61.	[bug]		jelte
 	bin/auth: Enable b10-auth to be launched in source tree
 	(i.e. use a zone database file relative to that)
 
-  60.	[build]		jinmei
+60.	[build]		jinmei
 	Supported SunStudio C++ compiler.  Note: gtest still doesn't work.
 	(Trac #251, svn r2310)
 
-  59.	[bug]		jinmei
+59.	[bug]		jinmei
 	lib/datasrc,bin/auth: The authoritative server could return a
 	SERVFAIL with a partial answer if it finds a data source broken
 	while looking for an answer.  This can happen, for example, if a
 	zone that doesn't have an NS RR is configured and loaded as a
 	sqlite3 data source. (Trac #249, r2286)
 
-  58.	[bug]		jinmei
+58.	[bug]		jinmei
 	Worked around an interaction issue between ASIO and standard C++
 	library headers.  Without this ASIO didn't work: sometimes the
 	application crashes, sometimes it blocked in the ASIO module.
 	(Trac #248, svn r2187, r2190)
 
-  57.	[func]		jinmei
+57.	[func]		jinmei
 	lib/datasrc: used a simpler version of Name::split (change 31) for
 	better readability.  No behavior change. (Trac #200, svn r2159)
 
-  56.	[func]*		jinmei
+56.	[func]*		jinmei
 	lib/dns: renamed the library name to libdns++ to avoid confusion
 	with the same name of library of BIND 9.
 	(Trac #190, svn r2153)
 
-  55.	[bug]		shane
+55.	[bug]		shane
 	bin/xfrout: xfrout exception on Ctrl-C now no longer generates
 	exception for 'Interrupted system call'
-	(Track #136, svn r2147)
+	(Trac #136, svn r2147)
 
-  54.	[bug]		zhanglikun
+54.	[bug]		zhanglikun
 	bin/xfrout: Enable b10-xfrout can be launched in source
 	code tree.
 	(Trac #224, svn r2103)
 
-  53.	[bug]		zhanglikun
+53.	[bug]		zhanglikun
 	bin/bindctl: Generate a unique session ID by using 
 	socket.gethostname() instead of socket.gethostbyname(), 
 	since the latter one could make bindctl	stall if its own 
 	host name can't be resolved.
 	(Trac #228, svn r2096)
 
-  52.	[func]		zhanglikun
+52.	[func]		zhanglikun
 	bin/xfrout: When xfrout is launched, check whether the
 	socket file is being used by one running xfrout process, 
 	if it is, exit from python.	If the file isn't a socket file 
@@ -1002,210 +1227,210 @@ bind10-devel-20100701 released on July 1, 2010
 
 bind10-devel-20100602 released on June 2, 2010
 
-  51.   [build]		jelte
+51.	[build]		jelte
 	lib/python: Add bind10_config.py module for paths and
 	possibly other configure-time variables. Allow some components
 	to find spec files in build tree when ran from source.
 	(Trac #223)
 
-  50.	[bug]		zhanglikun
+50.	[bug]		zhanglikun
 	bin/xfrin: a regression in xfrin: it can't communicate with 
 	a remote server. (Trac #218, svn r2038)
 
-  49.	[func]*		jelte
+49.	[func]*		jelte
 	Use unix domain sockets for msgq. For b10-msgq, the command
 	line options --msgq-port and -m were removed. For bind10,
 	the -msgq-port option was removed, and the -m command line
 	option was changed to be a filename (instead of port number).
 	(Trac #183, svn r2009)
 
-  48.	[func]		jelte
+48.	[func]		jelte
 	bin/auth: Use asio's io_service for the msgq handling.
 	(svn r2007)
 
-  47.	[func]		zhanglikun
+47.	[func]		zhanglikun
 	bin/cmdctl: Add value/type check for commands sent to
 	cmdctl. (Trac #201, svn r1959)
 
-  46.	[func]		zhanglikun
+46.	[func]		zhanglikun
 	lib/cc: Fix real type data encoding/decoding. (Trac #193,
 	svn r1959)
 
-  45.	[func]		zhanglikun
+45.	[func]		zhanglikun
 	bin/bind10: Pass verbose option to more modules. (Trac
 	#205, svn r1957)
 
-  44.   [build]         jreed
+44.	[build]		jreed
 	Install headers for libdns and libexception. (Trac #68,
 	svn r1941)
 
-  43.   [func]          jelte
+43.	[func]		jelte
 	lib/cc: Message queuing on cc channel. (Trac #58, svn r1870)
 
-  42.   [func]          jelte
+42.	[func]		jelte
 	lib/python/isc/config:      Make temporary file with python
 	tempfile module instead of manual with fixed name. (Trac
 	#184, svn r1859)
 
-  41.   [func]          jelte
+41.	[func]		jelte
 	Module descriptions in spec files. (Trac #90, svn r1856)
 
-  40.   [build]         jreed
+40.	[build]		jreed
 	Report detected features and configure settings at end of
 	configure output. (svn r1836)
 
-  39.   [func]*         each
+39.	[func]*		each
 	Renamed libauth to libdatasrc.
 
-  38.   [bug]           zhanglikun
+38.	[bug]		zhanglikun
 	Send command 'shutdown' to Xfrin and Xfrout when boss receive SIGINT.
 	Remove unused socket file when Xfrout process exits. Make sure Xfrout
 	exit by itself when it receives SIGINT, instead of being killed by the
 	signal SIGTERM or SIGKILL sent from boss.
 	(Trac #135, #151, #134, svn r1797)
 
-  37.   [build]         jinmei
+37.	[build]		jinmei
 	Check for the availability of python-config. (Trac #159,
 	svn r1794)
 
-  36.	[func]		shane
+36.	[func]		shane
 	bin/bind10:	Miscellaneous code cleanups and improvements.
 	(Trac #40, svn r2012)
 
-  35.	[bug]		jinmei
+35.	[bug]		jinmei
 	bin/bindctl: fixed a bug that it didn't accept IPv6 addresses as
 	command arguments. (Trac #219, svn r2022)
 
-  34.	[bug]		jinmei
+34.	[bug]		jinmei
 	bin/xfrin: fixed several small bugs with many additional unit
 	tests.  Fixes include: IPv6 transport support, resource leak,
 	and non IN class support. (Trac #185, svn r2000)
 
-  33.   [bug]           each
+33.	[bug]		each
 	bin/auth: output now prepended with "[b10-auth]" (Trac
 	#109, svn r1985)
 
-  32.	[func]*		each
+32.	[func]*		each
 	bin/auth: removed custom query-processing code, changed
         boost::asio code to use plain asio instead, and added asio
         headers to the source tree.  This allows building without
         using an external boost library. (Trac #163, svn r1983)
 
-  31.	[func]		jinmei
+31.	[func]		jinmei
 	lib/dns: added a separate signature for Name::split() as a
 	convenient wrapper for common usage. (Trac #49, svn r1903)
 
-  30.	[bug]		jinmei
+30.	[bug]		jinmei
 	lib/dns: parameter validation of Name::split() was not sufficient,
 	and invalid parameters could cause integer overflow and make the
 	library crash. (Trac #177, svn r1806)
 
 bind10-devel-20100421 released on April 21, 2010
 
-  29.	[build]
+29.	[build]		jreed
 	Enable Python unit tests for "make check". (svn r1762)
 
-  28.	[bug]
+28.	[bug]		jreed
 	Fix msgq CC test so it can find its module. (svn r1751)
 
-  27.	[build]
+27.	[build]		jelte
 	Add missing copyright license statements to various source
 	files. (svn r1750)
 
-  26.	[func]
+26.	[func]		jelte
 	Use PACKAGE_STRING (name + version) from config.h instead
 	of hard-coded value in CH TXT version.bind replies (Trac
 	#114, svn r1749)
 
-  25.	[func]*
+25.	[func]*		jreed
 	Renamed msgq to b10-msgq. (Trac #25, svn r1747, r1748)
 
-  24.	[func]
+24.	[func]		jinmei
 	Support case-sensitive name compression in MessageRenderer.
 	(Trac #142, svn r1704)
 
-  23.	[func]
+23.	[func]		jinmei
 	Support a simple name with possible compression. (svn r1701)
 
-  22.	[func]
+22.	[func]		zhanglikun
 	b10-xfrout for AXFR-out support added. (svn r1629, r1630)
 
-  21.	[bug]
+21.	[bug]		zhanglikun
 	Make log message more readable when xfrin failed. (svn
 	r1697)
 
-  20.	[bug]
+20.	[bug]		jinmei
 	Keep stderr for child processes if -v is specified. (svn
 	r1690, r1698)
 
-  19.	[bug]
+19.	[bug]		jinmei
 	Allow bind10 boss to pass environment variables from parent.
 	(svn r1689)
 
-  18.	[bug]
+18.	[bug]		jinmei
 	Xfrin warn if bind10_dns load failed. (svn r1688)
 
-  17.	[bug]
+17.	[bug]		jinmei
 	Use sqlite3_ds.load() in xfrin module and catch Sqlite3DSError
 	explicitly. (svn r1684)
 
-  16.	[func]*
+16.	[func]*		zhanglikun
 	Removed print_message and print_settings configuration
 	commands from Xfrin. (Trac #136, svn r1682)
 
-  15.	[func]*
+15.	[func]*		jinmei
 	Changed zone loader/updater so trailing dot is not required.
 	(svn r1681)
 
-  14.	[bug]
+14.	[bug]		shane
 	Change shutdown to actually SIGKILL properly. (svn r1675)
 
-  13.	[bug]
+13.	[bug]		jinmei
 	Don't ignore other RRs than SOA even if the second SOA is
 	found. (svn r1674)
 
-  12.	[build]
+12.	[build]		jreed
 	Fix tests and testdata so can be used from a read-only
 	source directory.
 
-  11.	[build]
+11.	[build]		jreed
 	Make sure python tests scripts are included in tarball.
 	(svn r1648)
 
-  10.	[build]
+10.	[build]		jinmei
 	Improve python detection for configure. (svn r1622)
 
-   9.	[build]
+9.	[build]		jinmei
 	Automake the python binding of libdns. (svn r1617)
 
-   8.	[bug]
+8.	[bug]		zhanglikun
 	Fix log errors which may cause xfrin module to crash. (svn
 	r1613)
 
-   7.	[func]
+7.	[func]		zhanglikun
 	New API for inserting zone data to sqlite3 database for
 	AXFR-in. (svn r1612, r1613)
 
-   6.	[bug]
+6.	[bug]		jreed
 	More code review, miscellaneous cleanups, style guidelines,
 	and new and improved unit tests added.
 
-   5.	[doc]
+5.	[doc]		jreed
 	Manual page cleanups and improvements.
 
-   4.	[bug]
+4.	[bug]		jinmei
 	NSEC RDATA fixes for buffer overrun lookups, incorrect
 	boundary checks, spec-non-conformant behaviors. (svn r1611)
 
-   3.	[bug]
+3.	[bug]		jelte
 	Remove a re-raise of an exception that should only have
 	been included in an error answer on the cc channel. (svn
 	r1601)
 
-   2.	[bug]
+2.	[bug]		mgraff
 	Removed unnecessary sleep() from ccsession.cc. (svn r1528)
 
-   1.	[build]*
+1.	[build]*		jreed
 	The configure --with-boostlib option changed to --with-boost-lib.
 
 bind10-devel-20100319 released on March 19, 2010
@@ -1224,10 +1449,10 @@ LEGEND
 	unless it's deemed to be impossible or very hard to keep
 	compatibility to fix the bug.
 [build] compilation and installation infrastructure change.
-[doc] update to documentation.  This shouldn't change run time behavior.
+[doc] update to documentation. This shouldn't change run time behavior.
 [func] new feature.  In some cases this may be a backward incompatible
 	change, which would require a bump of major version.
-[security] security hole fix.  This is no different than a general bug fix
-	except that it will be handled as confidential and will cause 
+[security] security hole fix. This is no different than a general bug
+	fix except that it will be handled as confidential and will cause
 	security patch releases.
 *: Backward incompatible or operational change.
diff --git a/Makefile.am b/Makefile.am
index e31a1a5..bab6679 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -84,214 +84,310 @@ systest:
 
 #### include external sources in the distributed tarball:
 EXTRA_DIST = ext/asio/README
-EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
-EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
-EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
-EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
-EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
-EXTRA_DIST += ext/asio/asio/impl/write.ipp
-EXTRA_DIST += ext/asio/asio/impl/read.ipp
-EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
-EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
-EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
-EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
-EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
-EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
-EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
-EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
-EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
-EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
-EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
-EXTRA_DIST += ext/asio/asio/detail/event.hpp
-EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
+EXTRA_DIST += ext/asio/README
+EXTRA_DIST += ext/asio/asio.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket.hpp
+EXTRA_DIST += ext/asio/asio/streambuf.hpp
+EXTRA_DIST += ext/asio/asio/thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/wait_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolve_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
 EXTRA_DIST += ext/asio/asio/detail/null_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
+EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
 EXTRA_DIST += ext/asio/asio/detail/task_io_service_operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_write_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/event.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recv_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
 EXTRA_DIST += ext/asio/asio/detail/local_free_on_block_exit.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
-EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
-EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
-EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
-EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
-EXTRA_DIST += ext/asio/asio/detail/operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
-EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
 EXTRA_DIST += ext/asio/asio/detail/signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolver_service_base.hpp
 EXTRA_DIST += ext/asio/asio/detail/socket_holder.hpp
-EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
 EXTRA_DIST += ext/asio/asio/detail/select_reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_arm_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
+EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
 EXTRA_DIST += ext/asio/asio/detail/reactor_op_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
 EXTRA_DIST += ext/asio/asio/detail/buffer_sequence_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
-EXTRA_DIST += ext/asio/asio/detail/thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_send_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/shared_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
+EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
 EXTRA_DIST += ext/asio/asio/detail/null_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_sync_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
+EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
+EXTRA_DIST += ext/asio/asio/detail/weak_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
 EXTRA_DIST += ext/asio/asio/detail/service_id.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/regex_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_sendto_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service_base.hpp
 EXTRA_DIST += ext/asio/asio/detail/throw_error.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
-EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_accept_op.hpp
 EXTRA_DIST += ext/asio/asio/detail/wrapped_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
-EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/object_pool.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolve_endpoint_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/array_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/config.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
 EXTRA_DIST += ext/asio/asio/detail/win_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_send_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_read_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_connect_op.hpp
 EXTRA_DIST += ext/asio/asio/detail/timer_queue_base.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_write_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_mutex.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_event.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_tss_ptr.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/winsock_init.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_mutex.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/socket_ops.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/socket_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_thread.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_event.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue_set.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_tss_ptr.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/resolver_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_thread.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/throw_error.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/descriptor_ops.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.ipp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
 EXTRA_DIST += ext/asio/asio/detail/timer_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
-EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
-EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_read_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
 EXTRA_DIST += ext/asio/asio/ssl/context_base.hpp
 EXTRA_DIST += ext/asio/asio/ssl/context.hpp
 EXTRA_DIST += ext/asio/asio/ssl/context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
 EXTRA_DIST += ext/asio/asio/ssl/basic_context.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
 EXTRA_DIST += ext/asio/asio/ssl/stream_base.hpp
-EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
-EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/error.hpp
+EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
+EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
+EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/placeholders.hpp
+EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/detail/impl/endpoint.ipp
+EXTRA_DIST += ext/asio/asio/local/detail/endpoint.hpp
+EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
+EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
+EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
+EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/socket_base.hpp
+EXTRA_DIST += ext/asio/asio/io_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
+EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/error_code.hpp
+EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
+EXTRA_DIST += ext/asio/asio/read_until.hpp
+EXTRA_DIST += ext/asio/asio/basic_streambuf_fwd.hpp
+EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
+EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
+EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
+EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
+EXTRA_DIST += ext/asio/asio/time_traits.hpp
+EXTRA_DIST += ext/asio/asio/completion_condition.hpp
 EXTRA_DIST += ext/asio/asio/posix/basic_stream_descriptor.hpp
 EXTRA_DIST += ext/asio/asio/posix/basic_descriptor.hpp
 EXTRA_DIST += ext/asio/asio/posix/descriptor_base.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
+EXTRA_DIST += ext/asio/asio/write.hpp
+EXTRA_DIST += ext/asio/asio/write_at.hpp
+EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
+EXTRA_DIST += ext/asio/asio/serial_port.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/read.hpp
+EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
+EXTRA_DIST += ext/asio/asio/buffer.hpp
+EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
+EXTRA_DIST += ext/asio/asio/impl/serial_port_base.hpp
+EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/read.ipp
+EXTRA_DIST += ext/asio/asio/impl/error.ipp
+EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
+EXTRA_DIST += ext/asio/asio/impl/io_service.hpp
+EXTRA_DIST += ext/asio/asio/impl/src.hpp
+EXTRA_DIST += ext/asio/asio/impl/src.cpp
+EXTRA_DIST += ext/asio/asio/impl/read_until.hpp
+EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
+EXTRA_DIST += ext/asio/asio/impl/write.hpp
+EXTRA_DIST += ext/asio/asio/impl/write_at.hpp
+EXTRA_DIST += ext/asio/asio/impl/write.ipp
+EXTRA_DIST += ext/asio/asio/impl/read.hpp
+EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
+EXTRA_DIST += ext/asio/asio/impl/read_at.hpp
+EXTRA_DIST += ext/asio/asio/strand.hpp
+EXTRA_DIST += ext/asio/asio/version.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
+EXTRA_DIST += ext/asio/asio/ip/address.hpp
+EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
 EXTRA_DIST += ext/asio/asio/ip/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/ip/detail/impl/endpoint.ipp
+EXTRA_DIST += ext/asio/asio/ip/detail/endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/udp.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
 EXTRA_DIST += ext/asio/asio/ip/v6_only.hpp
 EXTRA_DIST += ext/asio/asio/ip/address_v4.hpp
-EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
+EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
 EXTRA_DIST += ext/asio/asio/ip/multicast.hpp
+EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
+EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
 EXTRA_DIST += ext/asio/asio/ip/unicast.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
-EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
-EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
 EXTRA_DIST += ext/asio/asio/ip/resolver_service.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
-EXTRA_DIST += ext/asio/asio/ip/address.hpp
-EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
-EXTRA_DIST += ext/asio/asio/ip/udp.hpp
 EXTRA_DIST += ext/asio/asio/ip/icmp.hpp
-EXTRA_DIST += ext/asio/asio/error.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket.hpp
-EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
-EXTRA_DIST += ext/asio/asio/system_error.hpp
-EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
-EXTRA_DIST += ext/asio/asio/read_at.hpp
-EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
-EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
-EXTRA_DIST += ext/asio/asio/placeholders.hpp
-EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
-EXTRA_DIST += ext/asio/asio/thread.hpp
-EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/host_name.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.ipp
 EXTRA_DIST += ext/asio/asio/handler_invoke_hook.hpp
-EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
-EXTRA_DIST += ext/asio/asio/buffer.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
-EXTRA_DIST += ext/asio/asio/write_at.hpp
-EXTRA_DIST += ext/asio/asio/completion_condition.hpp
-EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/socket_base.hpp
-EXTRA_DIST += ext/asio/asio/serial_port.hpp
-EXTRA_DIST += ext/asio/asio/error_code.hpp
-EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
-EXTRA_DIST += ext/asio/asio/version.hpp
-EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
-EXTRA_DIST += ext/asio/asio/io_service.hpp
-EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
-EXTRA_DIST += ext/asio/asio/streambuf.hpp
-EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
-EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
-EXTRA_DIST += ext/asio/asio/write.hpp
-EXTRA_DIST += ext/asio/asio/strand.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
-EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
-EXTRA_DIST += ext/asio/asio/ssl.hpp
+EXTRA_DIST += ext/asio/asio/read_at.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/system_error.hpp
 EXTRA_DIST += ext/asio/asio/deadline_timer.hpp
-EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
-EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
-EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
-EXTRA_DIST += ext/asio/asio/read.hpp
-EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
 EXTRA_DIST += ext/asio/asio/stream_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/time_traits.hpp
-EXTRA_DIST += ext/asio/asio/read_until.hpp
-EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
-EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
-EXTRA_DIST += ext/asio/asio.hpp
 EXTRA_DIST += ext/coroutine/coroutine.h
diff --git a/README b/README
index 5320a6e..a6509da 100644
--- a/README
+++ b/README
@@ -19,7 +19,9 @@ backends), b10-resolver recursive or forwarding DNS server, b10-cmdctl
 remote control daemon, b10-cfgmgr configuration manager, b10-xfrin
 AXFR inbound service, b10-xfrout outgoing AXFR service, b10-zonemgr
 secondary manager, b10-stats statistics collection and reporting
-daemon, and a new libdns++ library for C++ with a python wrapper.
+daemon, b10-stats-httpd for HTTP access to XML-formatted stats,
+b10-host DNS lookup utility, and a new libdns++ library for C++
+with a python wrapper.
 
 Documentation is included and also available via the BIND 10
 website at http://bind10.isc.org/
diff --git a/configure.ac b/configure.ac
index 1c063c4..2324b21 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT(bind10-devel, 20110322, bind10-dev at isc.org)
+AC_INIT(bind10-devel, 20110519, bind10-dev at isc.org)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE
 AC_CONFIG_HEADERS([config.h])
@@ -374,6 +374,79 @@ if test "$lcov" != "no"; then
 fi
 AC_SUBST(USE_LCOV)
 
+# Check for Botan
+botan_path="yes"
+AC_ARG_WITH([botan],
+  AC_HELP_STRING([--with-botan=PATH],
+    [specify exact directory of Botan library]),
+    [botan_path="$withval"])
+if test "${botan_path}" == "no" ; then
+    AC_MSG_ERROR([Need botan for libcryptolink])
+fi
+if test "${botan_path}" != "yes" ; then
+    if test -x "${botan_path}/bin/botan-config" ; then
+        BOTAN_CONFIG="${botan_path}/bin/botan-config"
+    else
+        AC_MSG_ERROR([${botan_path}/bin/botan-config not found])
+    fi
+else
+        AC_PATH_PROG([BOTAN_CONFIG], [botan-config])
+fi
+
+if test -x "${BOTAN_CONFIG}" ; then
+    BOTAN_LDFLAGS=`${BOTAN_CONFIG} --libs`
+    # We expect botan-config --libs to contain -L<path_to_libbotan>, but
+    # this is not always the case.  As a heuristics workaround we add
+    # -L`botan-config --prefix/lib` in this case.  Same for BOTAN_INCLUDES
+    # (but using include instead of lib) below.
+    echo ${BOTAN_LDFLAGS} | grep -- -L > /dev/null || \
+	    BOTAN_LDFLAGS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LDFLAGS}"
+    BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
+    echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
+	    BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
+    # See python_rpath for some info on why we do this
+    if test $rpath_available = yes; then
+        BOTAN_RPATH=
+        for flag in ${BOTAN_LDFLAGS}; do
+                BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne 's/^\(\-L\)/-R/p'`"
+        done
+	AC_SUBST(BOTAN_RPATH)
+
+	# According to the libtool manual, it should be sufficient if we
+	# specify the "-R libdir" in our wrapper library of botan (no other
+	# programs will need libbotan directly); "libdir" should be added to
+	# the program's binary image.  But we've seen in our build environments
+	# that (some versions of?) libtool doesn't propagate -R as documented,
+	# and it caused a linker error at run time.  To work around this, we
+	# also add the rpath to the global LDFLAGS.
+        LDFLAGS="$BOTAN_RPATH $LDFLAGS"
+    fi
+
+    AC_SUBST(BOTAN_LDFLAGS)
+    AC_SUBST(BOTAN_INCLUDES)
+fi
+
+CPPFLAGS_SAVED=$CPPFLAGS
+CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS"
+LDFLAGS_SAVED="$LDFLAGS"
+LDFLAGS="$BOTAN_LDFLAGS $LDFLAGS"
+
+AC_CHECK_HEADERS([botan/botan.h],,AC_MSG_ERROR([Missing required header files.]))
+AC_LINK_IFELSE(
+        [AC_LANG_PROGRAM([#include <botan/botan.h>
+                          #include <botan/hash.h>
+                         ],
+                         [using namespace Botan;
+                          LibraryInitializer::initialize();
+                          HashFunction *h = get_hash("MD5");
+                         ])],
+        [AC_MSG_RESULT([checking for Botan library... yes])],
+        [AC_MSG_RESULT([checking for Botan library... no])
+         AC_MSG_ERROR([Needs Botan library 1.8 or higher])]
+)
+CPPFLAGS=$CPPFLAGS_SAVED
+LDFLAGS=$LDFLAGS_SAVED
+
 #
 # Configure Boost header path
 #
@@ -612,6 +685,8 @@ AC_CONFIG_FILES([Makefile
                  src/bin/bindctl/Makefile
                  src/bin/bindctl/tests/Makefile
                  src/bin/cfgmgr/Makefile
+                 src/bin/cfgmgr/plugins/Makefile
+                 src/bin/cfgmgr/plugins/tests/Makefile
                  src/bin/cfgmgr/tests/Makefile
                  src/bin/host/Makefile
                  src/bin/loadzone/Makefile
@@ -624,6 +699,8 @@ AC_CONFIG_FILES([Makefile
                  src/bin/auth/benchmarks/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
+                 src/bin/sockcreator/Makefile
+                 src/bin/sockcreator/tests/Makefile
                  src/bin/xfrin/Makefile
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrout/Makefile
@@ -637,11 +714,14 @@ AC_CONFIG_FILES([Makefile
                  src/bin/stats/tests/isc/config/Makefile
                  src/bin/stats/tests/isc/util/Makefile
                  src/bin/stats/tests/testdata/Makefile
+                 src/bin/stats/tests/http/Makefile
                  src/bin/usermgr/Makefile
                  src/bin/tests/Makefile
                  src/lib/Makefile
                  src/lib/asiolink/Makefile
                  src/lib/asiolink/tests/Makefile
+                 src/lib/asiodns/Makefile
+                 src/lib/asiodns/tests/Makefile
                  src/lib/bench/Makefile
                  src/lib/bench/example/Makefile
                  src/lib/bench/tests/Makefile
@@ -667,11 +747,14 @@ AC_CONFIG_FILES([Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/config/tests/testdata/Makefile
+                 src/lib/cryptolink/Makefile
+                 src/lib/cryptolink/tests/Makefile
                  src/lib/dns/Makefile
                  src/lib/dns/tests/Makefile
                  src/lib/dns/tests/testdata/Makefile
                  src/lib/dns/python/Makefile
                  src/lib/dns/python/tests/Makefile
+                 src/lib/dns/benchmarks/Makefile
                  src/lib/exceptions/Makefile
                  src/lib/exceptions/tests/Makefile
                  src/lib/datasrc/Makefile
@@ -690,8 +773,17 @@ AC_CONFIG_FILES([Makefile
                  src/lib/cache/tests/Makefile
                  src/lib/server_common/Makefile
                  src/lib/server_common/tests/Makefile
+                 src/lib/util/Makefile
+                 src/lib/util/io/Makefile
+                 src/lib/util/io/tests/Makefile
+                 src/lib/util/unittests/Makefile
+                 src/lib/util/pyunittests/Makefile
+                 src/lib/util/tests/Makefile
                  tests/Makefile
                  tests/system/Makefile
+                 tests/tools/Makefile
+                 tests/tools/badpacket/Makefile
+                 tests/tools/badpacket/tests/Makefile
                ])
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
@@ -706,6 +798,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/xfrout/xfrout.py
            src/bin/xfrout/xfrout.spec.pre
            src/bin/xfrout/tests/xfrout_test
+           src/bin/xfrout/tests/xfrout_test.py
            src/bin/xfrout/run_b10-xfrout.sh
            src/bin/resolver/resolver.spec.pre
            src/bin/resolver/spec_config.h.pre
@@ -714,11 +807,13 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
            src/bin/stats/stats.py
-           src/bin/stats/stats_stub.py
-           src/bin/stats/stats.spec.pre
-           src/bin/stats/run_b10-stats.sh
-           src/bin/stats/run_b10-stats_stub.sh
-           src/bin/stats/tests/stats_test
+           src/bin/stats/stats_httpd.py
+           src/bin/stats/stats.spec
+           src/bin/stats/stats-schema.spec
+           src/bin/stats/stats-httpd.spec
+           src/bin/stats/stats-httpd-xml.tpl
+           src/bin/stats/stats-httpd-xsd.tpl
+           src/bin/stats/stats-httpd-xsl.tpl
            src/bin/bind10/bind10.py
            src/bin/bind10/run_bind10.sh
            src/bin/bind10/tests/bind10_test.py
@@ -748,6 +843,8 @@ AC_OUTPUT([doc/version.ent
            src/lib/cc/session_config.h.pre
            src/lib/cc/tests/session_unittests_config.h
            src/lib/log/tests/run_time_init_test.sh
+           src/lib/util/python/mkpywrapper.py
+           src/lib/server_common/tests/data_path.h
            tests/system/conf.sh
            tests/system/glue/setup.sh
            tests/system/glue/nsx1/b10-config.db
@@ -757,9 +854,6 @@ AC_OUTPUT([doc/version.ent
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
            chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
-           chmod +x src/bin/stats/tests/stats_test
-           chmod +x src/bin/stats/run_b10-stats.sh
-           chmod +x src/bin/stats/run_b10-stats_stub.sh
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/xfrin/tests/xfrin_test
@@ -776,6 +870,7 @@ AC_OUTPUT([doc/version.ent
            chmod +x src/lib/dns/gen-rdatacode.py
            chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
            chmod +x src/lib/log/tests/run_time_init_test.sh
+           chmod +x src/lib/util/python/mkpywrapper.py
            chmod +x tests/system/conf.sh
           ])
 AC_OUTPUT
@@ -798,12 +893,15 @@ Flags:
   DEFS:          $DEFS
   CPPFLAGS:      $CPPFLAGS
   CXXFLAGS:      $CXXFLAGS
+  LDFLAGS:       $LDFLAGS
   B10_CXXFLAGS:  $B10_CXXFLAGS
 dnl includes too
   Python:        ${PYTHON_INCLUDES}
                  ${PYTHON_LDFLAGS}
                  ${PYTHON_LIB}
   Boost:         ${BOOST_INCLUDES}
+  Botan:         ${BOTAN_INCLUDES}
+                 ${BOTAN_LDFLAGS}
   SQLite:        $SQLITE_CFLAGS
                  $SQLITE_LIBS
 
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 46aa178..05b6ef3 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,7 +568,13 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/
+INPUT                  = ../src/lib/cc ../src/lib/config \
+    ../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
+    ../src/bin/auth ../src/bin/resolver ../src/lib/bench \
+    ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
+    ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
+    ../src/bin/sockcreator/ ../src/lib/util/
+    ../src/lib/resolve
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -1159,7 +1165,7 @@ XML_DTD                =
 # and cross-referencing information) to the XML output. Note that
 # enabling this will significantly increase the size of the XML output.
 
-XML_PROGRAMLISTING     = YES
+XML_PROGRAMLISTING     = NO
 
 #---------------------------------------------------------------------------
 # configuration options for the AutoGen Definitions output
diff --git a/doc/guide/bind10-guide.html b/doc/guide/bind10-guide.html
index a631a9c..069f508 100644
--- a/doc/guide/bind10-guide.html
+++ b/doc/guide/bind10-guide.html
@@ -1,19 +1,19 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Guide</title><link rel="stylesheet" href="./bind10-guide.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><meta name="description" content="BIND 10 is a Domain Name System (DNS) suite managed by Internet Systems Consortium (ISC). It includes DNS libraries and modular components for controlling authoritative and recursive DNS servers. This is the reference guide for BIND 10 version 20110322. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Guide"><div class="titlepage"><div><div><h1 class="title"><a name="id1168230298903"></a>BIND 10 Guide</h1></div><div><h2 class="subtitle">Administrator Reference for BIND 10</h2></div><div><p class="releaseinfo">This is the referenc
 e guide for BIND 10 version
-        20110322.</p></div><div><p class="copyright">Copyright © 2010 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>BIND 10 is a Domain Name System (DNS) suite managed by
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Guide</title><link rel="stylesheet" href="./bind10-guide.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><meta name="description" content="BIND 10 is a Domain Name System (DNS) suite managed by Internet Systems Consortium (ISC). It includes DNS libraries and modular components for controlling authoritative and recursive DNS servers. This is the reference guide for BIND 10 version 20110519. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Guide"><div class="titlepage"><div><div><h1 class="title"><a name="id1168230298903"></a>BIND 10 Guide</h1></div><div><h2 class="subtitle">Administrator Reference for BIND 10</h2></div><div><p class="releaseinfo">This is the referenc
 e guide for BIND 10 version
+        20110519.</p></div><div><p class="copyright">Copyright © 2010 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>BIND 10 is a Domain Name System (DNS) suite managed by
 	Internet Systems Consortium (ISC). It includes DNS libraries
 	and modular components for controlling authoritative and
 	recursive DNS servers.
       </p><p>
-        This is the reference guide for BIND 10 version 20110322.
+        This is the reference guide for BIND 10 version 20110519.
 	The most up-to-date version of this document, along with
-	other documents for BIND 10, can be found at <a class="ulink" href="http://bind10.isc.org/docs" target="_top">http://bind10.isc.org/docs</a>.  </p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#intro">1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230299038">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299065">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installation">2. Installation</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230284842">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">In
 stallation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285021">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230285041">Retrieve from Git</a></span></dt><dt><span class="section"><a href="#id1168230285101">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230285198">Build</a></span></dt><dt><span class="section"><a href="#id1168230285214">Install</a></span></dt><dt><span class="section"><a href="#id1168230285238">Install Hierarchy</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#bind10">3. Starting BIND10 with <span class="command"><strong>bind10</strong></span></a></span></dt><dd><dl><dt><span class="section"><a href="#start">Starting BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#msgq">4. Command channel</a></span></dt><dt><span class="chapter"><a href="#cfgmgr">5. Configuration manager</a></span></dt><dt><span class="chapter"><a hr
 ef="#cmdctl">6. Remote control daemon</a></span></dt><dd><dl><dt><span class="section"><a href="#cmdctl.spec">Configuration specification for b10-cmdctl</a></span></dt></dl></dd><dt><span class="chapter"><a href="#bindctl">7. Control and configure user interface</a></span></dt><dt><span class="chapter"><a href="#authserver">8. Authoritative Server</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285812">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285877">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285908">Loading Master Zones Files</a></span></dt></dl></dd><dt><span class="chapter"><a href="#xfrin">9. Incoming Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#xfrout">10. Outbound Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#zonemgr">11. Secondary Manager</a></span></dt><dt><span class="chapter"><a href="#resolverserver">12. Recursive Name Server<
 /a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230286296">Forwarding</a></span></dt></dl></dd><dt><span class="chapter"><a href="#statistics">13. Statistics</a></span></dt></dl></div><div class="chapter" title="Chapter 1. Introduction"><div class="titlepage"><div><div><h2 class="title"><a name="intro"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230299038">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299065">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></div><p>
+	other documents for BIND 10, can be found at <a class="ulink" href="http://bind10.isc.org/docs" target="_top">http://bind10.isc.org/docs</a>.  </p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#intro">1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230299038">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299065">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installation">2. Installation</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230284846">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">In
 stallation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285026">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230285045">Retrieve from Git</a></span></dt><dt><span class="section"><a href="#id1168230285106">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230285203">Build</a></span></dt><dt><span class="section"><a href="#id1168230285219">Install</a></span></dt><dt><span class="section"><a href="#id1168230285242">Install Hierarchy</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#bind10">3. Starting BIND10 with <span class="command"><strong>bind10</strong></span></a></span></dt><dd><dl><dt><span class="section"><a href="#start">Starting BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#msgq">4. Command channel</a></span></dt><dt><span class="chapter"><a href="#cfgmgr">5. Configuration manager</a></span></dt><dt><span class="chapter"><a hr
 ef="#cmdctl">6. Remote control daemon</a></span></dt><dd><dl><dt><span class="section"><a href="#cmdctl.spec">Configuration specification for b10-cmdctl</a></span></dt></dl></dd><dt><span class="chapter"><a href="#bindctl">7. Control and configure user interface</a></span></dt><dt><span class="chapter"><a href="#authserver">8. Authoritative Server</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285816">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285881">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285912">Loading Master Zones Files</a></span></dt></dl></dd><dt><span class="chapter"><a href="#xfrin">9. Incoming Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#xfrout">10. Outbound Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#zonemgr">11. Secondary Manager</a></span></dt><dt><span class="chapter"><a href="#resolverserver">12. Recursive Name Server<
 /a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230286300">Forwarding</a></span></dt></dl></dd><dt><span class="chapter"><a href="#statistics">13. Statistics</a></span></dt></dl></div><div class="chapter" title="Chapter 1. Introduction"><div class="titlepage"><div><div><h2 class="title"><a name="intro"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230299038">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299065">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></div><p>
       BIND is the popular implementation of a DNS server, developer
       interfaces, and DNS tools.
       BIND 10 is a rewrite of BIND 9.  BIND 10 is written in C++ and Python
       and provides a modular environment for serving and maintaining DNS.
     </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
         This guide covers the experimental prototype of
-        BIND 10 version 20110322.
+        BIND 10 version 20110519.
       </p></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
         BIND 10 provides a EDNS0- and DNSSEC-capable
         authoritative DNS server and a caching recursive name server
@@ -31,12 +31,16 @@
       </p></div><div class="section" title="Required Software"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230299065"></a>Required Software</h2></div></div></div><p>
         BIND 10 requires Python 3.1.  Later versions may work, but Python
         3.1 is the minimum version which will work.
-      </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+      </p><p>
+	BIND 10 uses the Botan crypto library for C++. It requires
+	at least Botan version 1.8. To build BIND 10, install the
+	Botan libraries and development include headers.
+      </p><p>
 	The authoritative server requires SQLite 3.3.9 or newer.
 	The <span class="command"><strong>b10-xfrin</strong></span>, <span class="command"><strong>b10-xfrout</strong></span>,
 	and <span class="command"><strong>b10-zonemgr</strong></span> modules require the
 	libpython3 library and the Python _sqlite3.so module.
-      </p></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+      </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
           Some operating systems do not provide these dependencies
           in their default installation nor standard packages
           collections.
@@ -132,7 +136,7 @@
       and, of course, DNS. These include detailed developer
       documentation and code examples.
 
-    </p></div><div class="chapter" title="Chapter 2. Installation"><div class="titlepage"><div><div><h2 class="title"><a name="installation"></a>Chapter 2. Installation</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230284842">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285021">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230285041">Retrieve from Git</a></span></dt><dt><span class="section"><a href="#id1168230285101">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230285198">Build</a></span></dt><dt><span class="section"><a href="#id1168230285214">Install</a></span></dt><dt><span class="section"><a href="#id1168230285238">Install Hierarchy<
 /a></span></dt></dl></dd></dl></div><div class="section" title="Building Requirements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230284842"></a>Building Requirements</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+    </p></div><div class="chapter" title="Chapter 2. Installation"><div class="titlepage"><div><div><h2 class="title"><a name="installation"></a>Chapter 2. Installation</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230284846">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285026">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230285045">Retrieve from Git</a></span></dt><dt><span class="section"><a href="#id1168230285106">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230285203">Build</a></span></dt><dt><span class="section"><a href="#id1168230285219">Install</a></span></dt><dt><span class="section"><a href="#id1168230285242">Install Hierarchy<
 /a></span></dt></dl></dd></dl></div><div class="section" title="Building Requirements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230284846"></a>Building Requirements</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
             Some operating systems have split their distribution packages into
             a run-time and a development package.  You will need to install
             the development package versions, which include header files and
@@ -188,14 +192,14 @@
         the Git code revision control system or as a downloadable
         tar file. It may also be available in pre-compiled ready-to-use
         packages from operating system vendors.
-      </p><div class="section" title="Download Tar File"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285021"></a>Download Tar File</h3></div></div></div><p>
+      </p><div class="section" title="Download Tar File"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285026"></a>Download Tar File</h3></div></div></div><p>
           Downloading a release tar file is the recommended method to
           obtain the source code.
         </p><p>
           The BIND 10 releases are available as tar file downloads from
           <a class="ulink" href="ftp://ftp.isc.org/isc/bind10/" target="_top">ftp://ftp.isc.org/isc/bind10/</a>.
           Periodic development snapshots may also be available.
-        </p></div><div class="section" title="Retrieve from Git"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285041"></a>Retrieve from Git</h3></div></div></div><p>
+        </p></div><div class="section" title="Retrieve from Git"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285045"></a>Retrieve from Git</h3></div></div></div><p>
           Downloading this "bleeding edge" code is recommended only for
           developers or advanced users.  Using development code in a production
           environment is not recommended.
@@ -229,7 +233,7 @@
           <span class="command"><strong>autoheader</strong></span>,
           <span class="command"><strong>automake</strong></span>,
           and related commands.
-        </p></div><div class="section" title="Configure before the build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285101"></a>Configure before the build</h3></div></div></div><p>
+        </p></div><div class="section" title="Configure before the build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285106"></a>Configure before the build</h3></div></div></div><p>
           BIND 10 uses the GNU Build System to discover build environment
           details.
           To generate the makefiles using the defaults, simply run:
@@ -260,16 +264,16 @@
         </p><p>
           If the configure fails, it may be due to missing or old
           dependencies.
-        </p></div><div class="section" title="Build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285198"></a>Build</h3></div></div></div><p>
+        </p></div><div class="section" title="Build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285203"></a>Build</h3></div></div></div><p>
     After the configure step is complete, to build the executables
     from the C++ code and prepare the Python scripts, run:
 
           </p><pre class="screen">$ <strong class="userinput"><code>make</code></strong></pre><p>
-        </p></div><div class="section" title="Install"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285214"></a>Install</h3></div></div></div><p>
+        </p></div><div class="section" title="Install"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285219"></a>Install</h3></div></div></div><p>
           To install the BIND 10 executables, support files,
           and documentation, run:
           </p><pre class="screen">$ <strong class="userinput"><code>make install</code></strong></pre><p>
-        </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The install step may require superuser privileges.</p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285238"></a>Install Hierarchy</h3></div></div></div><p>
+        </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The install step may require superuser privileges.</p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230285242"></a>Install Hierarchy</h3></div></div></div><p>
           The following is the layout of the complete BIND 10 installation:
           </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
                 <code class="filename">bin/</code> —
@@ -486,12 +490,12 @@ shutdown
       the details and relays (over a <span class="command"><strong>b10-msgq</strong></span> command
       channel) the configuration on to the specified module.
     </p><p>
-    </p></div><div class="chapter" title="Chapter 8. Authoritative Server"><div class="titlepage"><div><div><h2 class="title"><a name="authserver"></a>Chapter 8. Authoritative Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230285812">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285877">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285908">Loading Master Zones Files</a></span></dt></dl></div><p>
+    </p></div><div class="chapter" title="Chapter 8. Authoritative Server"><div class="titlepage"><div><div><h2 class="title"><a name="authserver"></a>Chapter 8. Authoritative Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230285816">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285881">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285912">Loading Master Zones Files</a></span></dt></dl></div><p>
       The <span class="command"><strong>b10-auth</strong></span> is the authoritative DNS server.
       It supports EDNS0 and DNSSEC. It supports IPv6.
       Normally it is started by the <span class="command"><strong>bind10</strong></span> master
       process.
-    </p><div class="section" title="Server Configurations"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285812"></a>Server Configurations</h2></div></div></div><p>
+    </p><div class="section" title="Server Configurations"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285816"></a>Server Configurations</h2></div></div></div><p>
         <span class="command"><strong>b10-auth</strong></span> is configured via the
         <span class="command"><strong>b10-cfgmgr</strong></span> configuration manager.
         The module name is <span class="quote">“<span class="quote">Auth</span>”</span>.
@@ -511,7 +515,7 @@ This may be a temporary setting until then.
         </p><div class="variablelist"><dl><dt><span class="term">shutdown</span></dt><dd>Stop the authoritative DNS server.
               </dd></dl></div><p>
 
-      </p></div><div class="section" title="Data Source Backends"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285877"></a>Data Source Backends</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+      </p></div><div class="section" title="Data Source Backends"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285881"></a>Data Source Backends</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
         For the development prototype release, <span class="command"><strong>b10-auth</strong></span>
         supports a SQLite3 data source backend and in-memory data source
         backend.
@@ -525,7 +529,7 @@ This may be a temporary setting until then.
         The default is <code class="filename">/usr/local/var/</code>.)
   This data file location may be changed by defining the
   <span class="quote">“<span class="quote">database_file</span>”</span> configuration.
-      </p></div><div class="section" title="Loading Master Zones Files"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285908"></a>Loading Master Zones Files</h2></div></div></div><p>
+      </p></div><div class="section" title="Loading Master Zones Files"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285912"></a>Loading Master Zones Files</h2></div></div></div><p>
         RFC 1035 style DNS master zone files may imported
         into a BIND 10 data source by using the
         <span class="command"><strong>b10-loadzone</strong></span> utility.
@@ -603,7 +607,7 @@ This may be a temporary setting until then.
     </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
      Access control (such as allowing notifies) is not yet provided.
      The primary/secondary service is not yet complete.
-    </p></div></div><div class="chapter" title="Chapter 12. Recursive Name Server"><div class="titlepage"><div><div><h2 class="title"><a name="resolverserver"></a>Chapter 12. Recursive Name Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230286296">Forwarding</a></span></dt></dl></div><p>
+    </p></div></div><div class="chapter" title="Chapter 12. Recursive Name Server"><div class="titlepage"><div><div><h2 class="title"><a name="resolverserver"></a>Chapter 12. Recursive Name Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230286300">Forwarding</a></span></dt></dl></div><p>
       The <span class="command"><strong>b10-resolver</strong></span> process is started by
       <span class="command"><strong>bind10</strong></span>.
 
@@ -632,7 +636,7 @@ This may be a temporary setting until then.
 > <strong class="userinput"><code>config set Resolver/listen_on [{ "address": "127.0.0.1", "port": 53 }]</code></strong>
 > <strong class="userinput"><code>config commit</code></strong>
 </pre><p>
-    </p><div class="section" title="Forwarding"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230286296"></a>Forwarding</h2></div></div></div><p>
+    </p><div class="section" title="Forwarding"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230286300"></a>Forwarding</h2></div></div></div><p>
 
         To enable forwarding, the upstream address and port must be
         configured to forward queries to, such as:
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index c020f11..5eb4dc7 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -79,12 +79,24 @@
         3.1 is the minimum version which will work.
       </para>
 
-      <note><para>
+      <para>
+	BIND 10 uses the Botan crypto library for C++. It requires
+	at least Botan version 1.8. To build BIND 10, install the
+	Botan libraries and development include headers.
+      </para>
+
+<!--
+TODO
+Debian and Ubuntu:
+ libgmp3-dev and libbz2-dev required for botan too
+-->
+
+      <para>
 	The authoritative server requires SQLite 3.3.9 or newer.
 	The <command>b10-xfrin</command>, <command>b10-xfrout</command>,
 	and <command>b10-zonemgr</command> modules require the
 	libpython3 library and the Python _sqlite3.so module.
-      </para></note>
+      </para>
 <!-- TODO: this will change ... -->
 
 <!-- TODO: list where to get these from -->
diff --git a/ext/asio/README b/ext/asio/README
index c581e8e..da12a9d 100644
--- a/ext/asio/README
+++ b/ext/asio/README
@@ -1,5 +1,10 @@
 ASIO library header files
-Version 1.4.5 (2010-05-12)
+Version 1.4.8 (2011-04-19)
 Downloaded from http://sourceforge.net/projects/asio/files
 Project page: http://think-async.com/Asio
-No local modifications.
+
+Local modifications:
+Added ASIO_DECL to a number of function definitions
+git commit c32718be9f5409b6f72d98ddcd0b1ccd4c5c2293
+See also the bug report at:
+http://sourceforge.net/tracker/?func=detail&aid=3291113&group_id=122478&atid=694037
diff --git a/ext/asio/asio.hpp b/ext/asio/asio.hpp
index d8acd58..b0ebc96 100644
--- a/ext/asio/asio.hpp
+++ b/ext/asio/asio.hpp
@@ -2,7 +2,7 @@
 // asio.hpp
 // ~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/basic_datagram_socket.hpp b/ext/asio/asio/basic_datagram_socket.hpp
index cb149f9..2cbb354 100644
--- a/ext/asio/asio/basic_datagram_socket.hpp
+++ b/ext/asio/asio/basic_datagram_socket.hpp
@@ -2,7 +2,7 @@
 // basic_datagram_socket.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_socket.hpp"
 #include "asio/datagram_socket_service.hpp"
-#include "asio/error.hpp"
 #include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_deadline_timer.hpp b/ext/asio/asio/basic_deadline_timer.hpp
index 0d183f7..27781e7 100644
--- a/ext/asio/asio/basic_deadline_timer.hpp
+++ b/ext/asio/asio/basic_deadline_timer.hpp
@@ -2,7 +2,7 @@
 // basic_deadline_timer.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_io_object.hpp"
 #include "asio/deadline_timer_service.hpp"
-#include "asio/error.hpp"
 #include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_io_object.hpp b/ext/asio/asio/basic_io_object.hpp
index 092170d..da35462 100644
--- a/ext/asio/asio/basic_io_object.hpp
+++ b/ext/asio/asio/basic_io_object.hpp
@@ -2,7 +2,7 @@
 // basic_io_object.hpp
 // ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_raw_socket.hpp b/ext/asio/asio/basic_raw_socket.hpp
index 9d93b97..7a55c4a 100644
--- a/ext/asio/asio/basic_raw_socket.hpp
+++ b/ext/asio/asio/basic_raw_socket.hpp
@@ -2,7 +2,7 @@
 // basic_raw_socket.hpp
 // ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_socket.hpp"
-#include "asio/raw_socket_service.hpp"
-#include "asio/error.hpp"
 #include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/raw_socket_service.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_serial_port.hpp b/ext/asio/asio/basic_serial_port.hpp
index edb7bb0..38fe5e9 100644
--- a/ext/asio/asio/basic_serial_port.hpp
+++ b/ext/asio/asio/basic_serial_port.hpp
@@ -2,7 +2,7 @@
 // basic_serial_port.hpp
 // ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,21 +16,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <string>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_SERIAL_PORT) \
+  || defined(GENERATING_DOCUMENTATION)
 
+#include <string>
 #include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/serial_port_base.hpp"
 #include "asio/serial_port_service.hpp"
-#include "asio/detail/throw_error.hpp"
 
-#if defined(ASIO_HAS_SERIAL_PORT) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
@@ -614,9 +612,9 @@ public:
 
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_SERIAL_PORT)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BASIC_SERIAL_PORT_HPP
diff --git a/ext/asio/asio/basic_socket.hpp b/ext/asio/asio/basic_socket.hpp
index 8b3f1d7..5c66b4a 100644
--- a/ext/asio/asio/basic_socket.hpp
+++ b/ext/asio/asio/basic_socket.hpp
@@ -2,7 +2,7 @@
 // basic_socket.hpp
 // ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/socket_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_socket_acceptor.hpp b/ext/asio/asio/basic_socket_acceptor.hpp
index 97fa56b..15f9220 100644
--- a/ext/asio/asio/basic_socket_acceptor.hpp
+++ b/ext/asio/asio/basic_socket_acceptor.hpp
@@ -2,7 +2,7 @@
 // basic_socket_acceptor.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_io_object.hpp"
 #include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/socket_acceptor_service.hpp"
 #include "asio/socket_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_socket_iostream.hpp b/ext/asio/asio/basic_socket_iostream.hpp
index 361ecb8..efcd51e 100644
--- a/ext/asio/asio/basic_socket_iostream.hpp
+++ b/ext/asio/asio/basic_socket_iostream.hpp
@@ -2,7 +2,7 @@
 // basic_socket_iostream.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/push_options.hpp"
 #include <boost/preprocessor/arithmetic/inc.hpp>
 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
 #include <boost/preprocessor/repetition/enum_params.hpp>
 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
 #include <boost/utility/base_from_member.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_socket_streambuf.hpp"
 #include "asio/stream_socket_service.hpp"
 
@@ -79,6 +72,8 @@
   } \
   /**/
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Iostream interface for a socket.
@@ -146,11 +141,11 @@ public:
 
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #undef ASIO_PRIVATE_CTR_DEF
 #undef ASIO_PRIVATE_CONNECT_DEF
 
 #endif // defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP
diff --git a/ext/asio/asio/basic_socket_streambuf.hpp b/ext/asio/asio/basic_socket_streambuf.hpp
index ae0264e..05fc865 100644
--- a/ext/asio/asio/basic_socket_streambuf.hpp
+++ b/ext/asio/asio/basic_socket_streambuf.hpp
@@ -2,7 +2,7 @@
 // basic_socket_streambuf.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/push_options.hpp"
 #include <streambuf>
 #include <boost/array.hpp>
 #include <boost/preprocessor/arithmetic/inc.hpp>
@@ -31,12 +26,10 @@
 #include <boost/preprocessor/repetition/enum_params.hpp>
 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
 #include <boost/utility/base_from_member.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/stream_socket_service.hpp"
-#include "asio/detail/throw_error.hpp"
 
 #if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
 #define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
@@ -74,6 +67,8 @@
   } \
   /**/
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Iostream streambuf for a socket.
@@ -286,10 +281,10 @@ private:
 
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #undef ASIO_PRIVATE_CONNECT_DEF
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
diff --git a/ext/asio/asio/basic_stream_socket.hpp b/ext/asio/asio/basic_stream_socket.hpp
index b7b4f06..41543fc 100644
--- a/ext/asio/asio/basic_stream_socket.hpp
+++ b/ext/asio/asio/basic_stream_socket.hpp
@@ -2,7 +2,7 @@
 // basic_stream_socket.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/stream_socket_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/basic_streambuf.hpp b/ext/asio/asio/basic_streambuf.hpp
index b34b3fe..17157da 100644
--- a/ext/asio/asio/basic_streambuf.hpp
+++ b/ext/asio/asio/basic_streambuf.hpp
@@ -2,7 +2,7 @@
 // basic_streambuf.hpp
 // ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,23 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/push_options.hpp"
 #include <algorithm>
 #include <cstring>
-#include <memory>
 #include <stdexcept>
 #include <streambuf>
 #include <vector>
 #include <boost/limits.hpp>
 #include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/basic_streambuf_fwd.hpp"
 #include "asio/buffer.hpp"
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Automatically resizable buffer class based on std::streambuf.
@@ -107,7 +102,11 @@ namespace asio {
  * is >> s;
  * @endcode
  */
+#if defined(GENERATING_DOCUMENTATION)
 template <typename Allocator = std::allocator<char> >
+#else
+template <typename Allocator>
+#endif
 class basic_streambuf
   : public std::streambuf,
     private noncopyable
@@ -337,8 +336,27 @@ protected:
 private:
   std::size_t max_size_;
   std::vector<char_type, Allocator> buffer_;
+
+  // Helper function to get the preferred size for reading data.
+  friend std::size_t read_size_helper(
+      basic_streambuf& sb, std::size_t max_size)
+  {
+    return std::min<std::size_t>(
+        std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
+        std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
+  }
 };
 
+// Helper function to get the preferred size for reading data. Used for any
+// user-provided specialisations of basic_streambuf.
+template <typename Allocator>
+inline std::size_t read_size_helper(
+    basic_streambuf<Allocator>& sb, std::size_t max_size)
+{
+  return std::min<std::size_t>(512,
+      std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
+}
+
 } // namespace asio
 
 #include "asio/detail/pop_options.hpp"
diff --git a/ext/asio/asio/basic_streambuf_fwd.hpp b/ext/asio/asio/basic_streambuf_fwd.hpp
new file mode 100644
index 0000000..e1d81ac
--- /dev/null
+++ b/ext/asio/asio/basic_streambuf_fwd.hpp
@@ -0,0 +1,33 @@
+//
+// basic_streambuf_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_STREAMBUF_FWD_HPP
+#define ASIO_BASIC_STREAMBUF_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include <memory>
+
+namespace asio {
+
+template <typename Allocator = std::allocator<char> >
+class basic_streambuf;
+
+} // namespace asio
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_STREAMBUF_FWD_HPP
diff --git a/ext/asio/asio/buffer.hpp b/ext/asio/asio/buffer.hpp
index 43b475c..6810fca 100644
--- a/ext/asio/asio/buffer.hpp
+++ b/ext/asio/asio/buffer.hpp
@@ -2,7 +2,7 @@
 // buffer.hpp
 // ~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include <boost/array.hpp>
-#include <boost/type_traits/is_const.hpp>
 #include <string>
 #include <vector>
-#include "asio/detail/pop_options.hpp"
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/array_fwd.hpp"
 
 #if defined(BOOST_MSVC)
 # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
@@ -43,11 +39,17 @@
 #endif // defined(__GNUC__)
 
 #if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-# include "asio/detail/push_options.hpp"
 # include <boost/function.hpp>
-# include "asio/detail/pop_options.hpp"
 #endif // ASIO_ENABLE_BUFFER_DEBUGGING
 
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
+  || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+# include <boost/type_traits/is_const.hpp>
+#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+       // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 class mutable_buffer;
diff --git a/ext/asio/asio/buffered_read_stream.hpp b/ext/asio/asio/buffered_read_stream.hpp
index afd22ce..d9dc311 100644
--- a/ext/asio/asio/buffered_read_stream.hpp
+++ b/ext/asio/asio/buffered_read_stream.hpp
@@ -2,7 +2,7 @@
 // buffered_read_stream.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <cstring>
-#include <boost/config.hpp>
 #include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffered_read_stream_fwd.hpp"
 #include "asio/buffer.hpp"
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
 #include "asio/detail/bind_handler.hpp"
 #include "asio/detail/buffer_resize_guard.hpp"
 #include "asio/detail/buffered_stream_storage.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/buffered_read_stream_fwd.hpp b/ext/asio/asio/buffered_read_stream_fwd.hpp
index 5078775..0e8495a 100644
--- a/ext/asio/asio/buffered_read_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_read_stream_fwd.hpp
@@ -2,7 +2,7 @@
 // buffered_read_stream_fwd.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 
 template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_read_stream;
 
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffered_stream.hpp b/ext/asio/asio/buffered_stream.hpp
index 23dc9c3..11b99f6 100644
--- a/ext/asio/asio/buffered_stream.hpp
+++ b/ext/asio/asio/buffered_stream.hpp
@@ -2,7 +2,7 @@
 // buffered_stream.hpp
 // ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffered_read_stream.hpp"
 #include "asio/buffered_write_stream.hpp"
 #include "asio/buffered_stream_fwd.hpp"
+#include "asio/detail/noncopyable.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/buffered_stream_fwd.hpp b/ext/asio/asio/buffered_stream_fwd.hpp
index f26cd43..a8e958e 100644
--- a/ext/asio/asio/buffered_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_stream_fwd.hpp
@@ -2,7 +2,7 @@
 // buffered_stream_fwd.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 
 template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_stream;
 
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BUFFERED_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffered_write_stream.hpp b/ext/asio/asio/buffered_write_stream.hpp
index 30a92ce..ee0ec77 100644
--- a/ext/asio/asio/buffered_write_stream.hpp
+++ b/ext/asio/asio/buffered_write_stream.hpp
@@ -2,7 +2,7 @@
 // buffered_write_stream.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,21 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <cstring>
-#include <boost/config.hpp>
 #include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffered_write_stream_fwd.hpp"
 #include "asio/buffer.hpp"
 #include "asio/completion_condition.hpp"
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/write.hpp"
 #include "asio/detail/bind_handler.hpp"
 #include "asio/detail/buffered_stream_storage.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/buffered_write_stream_fwd.hpp b/ext/asio/asio/buffered_write_stream_fwd.hpp
index dc0e014..cb09fe8 100644
--- a/ext/asio/asio/buffered_write_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_write_stream_fwd.hpp
@@ -2,7 +2,7 @@
 // buffered_write_stream_fwd.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 
 template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_write_stream;
 
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffers_iterator.hpp b/ext/asio/asio/buffers_iterator.hpp
index 7da55f2..dcca2d3 100644
--- a/ext/asio/asio/buffers_iterator.hpp
+++ b/ext/asio/asio/buffers_iterator.hpp
@@ -2,7 +2,7 @@
 // buffers_iterator.hpp
 // ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <boost/assert.hpp>
-#include <boost/config.hpp>
 #include <boost/detail/workaround.hpp>
 #include <boost/iterator.hpp>
 #include <boost/type_traits/is_convertible.hpp>
 #include <boost/type_traits/add_const.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffer.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 namespace detail
@@ -210,6 +207,15 @@ public:
     return tmp;
   }
 
+  /// Addition operator.
+  friend buffers_iterator operator+(std::ptrdiff_t difference,
+      const buffers_iterator& iter)
+  {
+    buffers_iterator tmp(iter);
+    tmp.advance(difference);
+    return tmp;
+  }
+
   /// Subtraction operator.
   friend buffers_iterator operator-(const buffers_iterator& iter,
       std::ptrdiff_t difference)
diff --git a/ext/asio/asio/completion_condition.hpp b/ext/asio/asio/completion_condition.hpp
index d4e631d..dd1fb27 100644
--- a/ext/asio/asio/completion_condition.hpp
+++ b/ext/asio/asio/completion_condition.hpp
@@ -2,7 +2,7 @@
 // completion_condition.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <cstddef>
 
 #include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/datagram_socket_service.hpp b/ext/asio/asio/datagram_socket_service.hpp
index 7d135ee..87821c3 100644
--- a/ext/asio/asio/datagram_socket_service.hpp
+++ b/ext/asio/asio/datagram_socket_service.hpp
@@ -2,7 +2,7 @@
 // datagram_socket_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 # include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
 # include "asio/detail/reactive_socket_service.hpp"
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Default service implementation for a datagram socket.
diff --git a/ext/asio/asio/deadline_timer.hpp b/ext/asio/asio/deadline_timer.hpp
index e0905f2..fd0d5dc 100644
--- a/ext/asio/asio/deadline_timer.hpp
+++ b/ext/asio/asio/deadline_timer.hpp
@@ -2,7 +2,7 @@
 // deadline_timer.hpp
 // ~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/socket_types.hpp" // Must come before posix_time.
+#include "asio/basic_deadline_timer.hpp"
 
 #include "asio/detail/push_options.hpp"
 #include <boost/date_time/posix_time/posix_time_types.hpp>
 #include "asio/detail/pop_options.hpp"
 
-#include "asio/basic_deadline_timer.hpp"
-
 namespace asio {
 
 /// Typedef for the typical usage of timer. Uses a UTC clock.
@@ -32,6 +30,4 @@ typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
 
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DEADLINE_TIMER_HPP
diff --git a/ext/asio/asio/deadline_timer_service.hpp b/ext/asio/asio/deadline_timer_service.hpp
index 284a690..60d898b 100644
--- a/ext/asio/asio/deadline_timer_service.hpp
+++ b/ext/asio/asio/deadline_timer_service.hpp
@@ -2,7 +2,7 @@
 // deadline_timer_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/deadline_timer_service.hpp"
 #include "asio/io_service.hpp"
 #include "asio/time_traits.hpp"
-#include "asio/detail/deadline_timer_service.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/detail/array_fwd.hpp b/ext/asio/asio/detail/array_fwd.hpp
new file mode 100644
index 0000000..12c295c
--- /dev/null
+++ b/ext/asio/asio/detail/array_fwd.hpp
@@ -0,0 +1,25 @@
+//
+// detail/array_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_ARRAY_FWD_HPP
+#define ASIO_DETAIL_ARRAY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+namespace boost {
+
+template<class T, std::size_t N>
+class array;
+
+} // namespace boost
+
+#endif // ASIO_DETAIL_ARRAY_FWD_HPP
diff --git a/ext/asio/asio/detail/base_from_completion_cond.hpp b/ext/asio/asio/detail/base_from_completion_cond.hpp
index 90a11f9..93cc8c4 100644
--- a/ext/asio/asio/detail/base_from_completion_cond.hpp
+++ b/ext/asio/asio/detail/base_from_completion_cond.hpp
@@ -1,8 +1,8 @@
 //
-// base_from_completion_cond.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/base_from_completion_cond.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/completion_condition.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -31,7 +32,8 @@ protected:
   {
   }
 
-  std::size_t check(const asio::error_code& ec,
+  std::size_t check_for_completion(
+      const asio::error_code& ec,
       std::size_t total_transferred)
   {
     return detail::adapt_completion_condition_result(
@@ -50,7 +52,8 @@ protected:
   {
   }
 
-  static std::size_t check(const asio::error_code& ec,
+  static std::size_t check_for_completion(
+      const asio::error_code& ec,
       std::size_t total_transferred)
   {
     return transfer_all_t()(ec, total_transferred);
diff --git a/ext/asio/asio/detail/bind_handler.hpp b/ext/asio/asio/detail/bind_handler.hpp
index 5d9eb00..f663a5b 100644
--- a/ext/asio/asio/detail/bind_handler.hpp
+++ b/ext/asio/asio/detail/bind_handler.hpp
@@ -1,8 +1,8 @@
 //
-// bind_handler.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/bind_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/handler_alloc_helpers.hpp"
 #include "asio/detail/handler_invoke_helpers.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -35,7 +36,7 @@ public:
 
   void operator()()
   {
-    handler_(arg1_);
+    handler_(static_cast<const Arg1&>(arg1_));
   }
 
   void operator()() const
@@ -92,7 +93,8 @@ public:
 
   void operator()()
   {
-    handler_(arg1_, arg2_);
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_));
   }
 
   void operator()() const
@@ -152,7 +154,9 @@ public:
 
   void operator()()
   {
-    handler_(arg1_, arg2_, arg3_);
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_),
+        static_cast<const Arg3&>(arg3_));
   }
 
   void operator()() const
@@ -216,7 +220,10 @@ public:
 
   void operator()()
   {
-    handler_(arg1_, arg2_, arg3_, arg4_);
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_),
+        static_cast<const Arg3&>(arg3_),
+        static_cast<const Arg4&>(arg4_));
   }
 
   void operator()() const
@@ -287,7 +294,11 @@ public:
 
   void operator()()
   {
-    handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_),
+        static_cast<const Arg3&>(arg3_),
+        static_cast<const Arg4&>(arg4_),
+        static_cast<const Arg5&>(arg5_));
   }
 
   void operator()() const
diff --git a/ext/asio/asio/detail/buffer_resize_guard.hpp b/ext/asio/asio/detail/buffer_resize_guard.hpp
index 368de32..4bf6a8e 100644
--- a/ext/asio/asio/detail/buffer_resize_guard.hpp
+++ b/ext/asio/asio/detail/buffer_resize_guard.hpp
@@ -1,8 +1,8 @@
 //
-// buffer_resize_guard.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <boost/limits.hpp>
 
 #include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
diff --git a/ext/asio/asio/detail/buffer_sequence_adapter.hpp b/ext/asio/asio/detail/buffer_sequence_adapter.hpp
index 6269d6a..17044b7 100644
--- a/ext/asio/asio/detail/buffer_sequence_adapter.hpp
+++ b/ext/asio/asio/detail/buffer_sequence_adapter.hpp
@@ -1,8 +1,8 @@
 //
-// buffer_sequence_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffer_sequence_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,9 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/buffer.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -32,14 +34,14 @@ protected:
       const asio::mutable_buffer& buffer)
   {
     buf.buf = asio::buffer_cast<char*>(buffer);
-    buf.len = asio::buffer_size(buffer);
+    buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
   }
 
   static void init_native_buffer(WSABUF& buf,
       const asio::const_buffer& buffer)
   {
     buf.buf = const_cast<char*>(asio::buffer_cast<const char*>(buffer));
-    buf.len = asio::buffer_size(buffer);
+    buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
   }
 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
   typedef iovec native_buffer_type;
@@ -158,7 +160,7 @@ public:
   explicit buffer_sequence_adapter(
       const asio::mutable_buffers_1& buffers)
   {
-    init_native_buffer(buffer_, buffers);
+    init_native_buffer(buffer_, Buffer(buffers));
     total_buffer_size_ = asio::buffer_size(buffers);
   }
 
@@ -205,7 +207,7 @@ public:
   explicit buffer_sequence_adapter(
       const asio::const_buffers_1& buffers)
   {
-    init_native_buffer(buffer_, buffers);
+    init_native_buffer(buffer_, Buffer(buffers));
     total_buffer_size_ = asio::buffer_size(buffers);
   }
 
diff --git a/ext/asio/asio/detail/buffered_stream_storage.hpp b/ext/asio/asio/detail/buffered_stream_storage.hpp
index 51f6556..7e1b746 100644
--- a/ext/asio/asio/detail/buffered_stream_storage.hpp
+++ b/ext/asio/asio/detail/buffered_stream_storage.hpp
@@ -1,8 +1,8 @@
 //
-// buffered_stream_storage.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <cassert>
 #include <cstddef>
 #include <cstring>
 #include <vector>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
diff --git a/ext/asio/asio/detail/call_stack.hpp b/ext/asio/asio/detail/call_stack.hpp
index 0e9ddaf..7ad5dc5 100644
--- a/ext/asio/asio/detail/call_stack.hpp
+++ b/ext/asio/asio/detail/call_stack.hpp
@@ -1,8 +1,8 @@
 //
-// call_stack.hpp
-// ~~~~~~~~~~~~~~
+// detail/call_stack.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/tss_ptr.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/completion_handler.hpp b/ext/asio/asio/detail/completion_handler.hpp
index 16167df..0224d7e 100644
--- a/ext/asio/asio/detail/completion_handler.hpp
+++ b/ext/asio/asio/detail/completion_handler.hpp
@@ -1,8 +1,8 @@
 //
-// completion_handler.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/completion_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/fenced_block.hpp"
 #include "asio/detail/handler_alloc_helpers.hpp"
 #include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/operation.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -29,6 +30,8 @@ template <typename Handler>
 class completion_handler : public operation
 {
 public:
+  ASIO_DEFINE_HANDLER_PTR(completion_handler);
+
   completion_handler(Handler h)
     : operation(&completion_handler::do_complete),
       handler_(h)
@@ -40,20 +43,21 @@ public:
   {
     // Take ownership of the handler object.
     completion_handler* h(static_cast<completion_handler*>(base));
-    typedef handler_alloc_traits<Handler, completion_handler> alloc_traits;
-    handler_ptr<alloc_traits> ptr(h->handler_, h);
+    ptr p = { boost::addressof(h->handler_), h, h };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    Handler handler(h->handler_);
+    p.h = boost::addressof(handler);
+    p.reset();
 
     // Make the upcall if required.
     if (owner)
     {
-      // Make a copy of the handler so that the memory can be deallocated
-      // before the upcall is made. Even if we're not about to make an
-      // upcall, a sub-object of the handler may be the true owner of the
-      // memory associated with the handler. Consequently, a local copy of
-      // the handler is required to ensure that any owning sub-object remains
-      // valid until after we have deallocated the memory here.
-      Handler handler(h->handler_);
-      ptr.reset();
       asio::detail::fenced_block b;
       asio_handler_invoke_helpers::invoke(handler, handler);
     }
diff --git a/ext/asio/asio/detail/config.hpp b/ext/asio/asio/detail/config.hpp
new file mode 100644
index 0000000..8328d76
--- /dev/null
+++ b/ext/asio/asio/detail/config.hpp
@@ -0,0 +1,205 @@
+//
+// detail/config.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_CONFIG_HPP
+#define ASIO_DETAIL_CONFIG_HPP
+
+#include <boost/config.hpp>
+
+// Default to a header-only implementation. The user must specifically request
+// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
+// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
+#if !defined(ASIO_HEADER_ONLY)
+# if !defined(ASIO_SEPARATE_COMPILATION)
+#  if !defined(ASIO_DYN_LINK)
+#   define ASIO_HEADER_ONLY
+#  endif // !defined(ASIO_DYN_LINK)
+# endif // !defined(ASIO_SEPARATE_COMPILATION)
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#if defined(ASIO_HEADER_ONLY)
+# define ASIO_DECL inline
+#else // defined(ASIO_HEADER_ONLY)
+# if defined(BOOST_HAS_DECLSPEC)
+// We need to import/export our code only if the user has specifically asked
+// for it by defining ASIO_DYN_LINK.
+#  if defined(ASIO_DYN_LINK)
+// Export if this is our own source, otherwise import.
+#   if defined(ASIO_SOURCE)
+#    define ASIO_DECL __declspec(dllexport)
+#   else // defined(ASIO_SOURCE)
+#    define ASIO_DECL __declspec(dllimport)
+#   endif // defined(ASIO_SOURCE)
+#  endif // defined(ASIO_DYN_LINK)
+# endif // defined(BOOST_HAS_DECLSPEC)
+#endif // defined(ASIO_HEADER_ONLY)
+
+// If ASIO_DECL isn't defined yet define it now.
+#if !defined(ASIO_DECL)
+# define ASIO_DECL
+#endif // !defined(ASIO_DECL)
+
+// Windows: target OS version.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+#  if defined(_MSC_VER) || defined(__BORLANDC__)
+#   pragma message( \
+  "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
+  "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
+  "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
+  "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
+#  else // defined(_MSC_VER) || defined(__BORLANDC__)
+#   warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
+#   warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
+#   warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
+#  endif // defined(_MSC_VER) || defined(__BORLANDC__)
+#  define _WIN32_WINNT 0x0501
+# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER)
+#  if defined(_WIN32) && !defined(WIN32)
+#   if !defined(_WINSOCK2API_)
+#    define WIN32 // Needed for correct types in winsock2.h
+#   else // !defined(_WINSOCK2API_)
+#    error Please define the macro WIN32 in your compiler options
+#   endif // !defined(_WINSOCK2API_)
+#  endif // defined(_WIN32) && !defined(WIN32)
+# endif // defined(_MSC_VER)
+# if defined(__BORLANDC__)
+#  if defined(__WIN32__) && !defined(WIN32)
+#   if !defined(_WINSOCK2API_)
+#    define WIN32 // Needed for correct types in winsock2.h
+#   else // !defined(_WINSOCK2API_)
+#    error Please define the macro WIN32 in your compiler options
+#   endif // !defined(_WINSOCK2API_)
+#  endif // defined(__WIN32__) && !defined(WIN32)
+# endif // defined(__BORLANDC__)
+# if defined(__CYGWIN__)
+#  if !defined(__USE_W32_SOCKETS)
+#   error You must add -D__USE_W32_SOCKETS to your compiler options.
+#  endif // !defined(__USE_W32_SOCKETS)
+# endif // defined(__CYGWIN__)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: minimise header inclusion.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#  if !defined(WIN32_LEAN_AND_MEAN)
+#   define WIN32_LEAN_AND_MEAN
+#  endif // !defined(WIN32_LEAN_AND_MEAN)
+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: suppress definition of "min" and "max" macros.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_NOMINMAX)
+#  if !defined(NOMINMAX)
+#   define NOMINMAX 1
+#  endif // !defined(NOMINMAX)
+# endif // !defined(ASIO_NO_NOMINMAX)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: IO Completion Ports.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#  if !defined(UNDER_CE)
+#   if !defined(ASIO_DISABLE_IOCP)
+#    define ASIO_HAS_IOCP 1
+#   endif // !defined(ASIO_DISABLE_IOCP)
+#  endif // !defined(UNDER_CE)
+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Linux: epoll, eventfd and timerfd.
+#if defined(__linux__)
+# include <linux/version.h>
+# if !defined(ASIO_DISABLE_EPOLL)
+#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+#   define ASIO_HAS_EPOLL 1
+#  endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+# endif // !defined(ASIO_DISABLE_EVENTFD)
+# if !defined(ASIO_DISABLE_EVENTFD)
+#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#   define ASIO_HAS_EVENTFD 1
+#  endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# endif // !defined(ASIO_DISABLE_EVENTFD)
+# if defined(ASIO_HAS_EPOLL)
+#  if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+#   define ASIO_HAS_TIMERFD 1
+#  endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# endif // defined(ASIO_HAS_EPOLL)
+#endif // defined(__linux__)
+
+// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue.
+#if (defined(__MACH__) && defined(__APPLE__)) \
+  || defined(__FreeBSD__) \
+  || defined(__NetBSD__) \
+  || defined(__OpenBSD__)
+# if !defined(ASIO_DISABLE_KQUEUE)
+#  define ASIO_HAS_KQUEUE 1
+# endif // !defined(ASIO_DISABLE_KQUEUE)
+#endif // (defined(__MACH__) && defined(__APPLE__))
+       //   || defined(__FreeBSD__)
+       //   || defined(__NetBSD__)
+       //   || defined(__OpenBSD__)
+
+// Solaris: /dev/poll.
+#if defined(__sun)
+# if !defined(ASIO_DISABLE_DEV_POLL)
+#  define ASIO_HAS_DEV_POLL 1
+# endif // !defined(ASIO_DISABLE_DEV_POLL)
+#endif // defined(__sun)
+
+// Serial ports.
+#if defined(ASIO_HAS_IOCP) \
+   || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# if !defined(__SYMBIAN32__)
+#  if !defined(ASIO_DISABLE_SERIAL_PORT)
+#   define ASIO_HAS_SERIAL_PORT 1
+#  endif // !defined(ASIO_DISABLE_SERIAL_PORT)
+# endif // !defined(__SYMBIAN32__)
+#endif // defined(ASIO_HAS_IOCP)
+       //   || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+// Windows: stream handles.
+#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+#  define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+
+// Windows: random access handles.
+#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+#  define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+
+// Windows: OVERLAPPED wrapper.
+#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+# if defined(ASIO_HAS_IOCP)
+#  define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+
+// POSIX: stream-oriented file descriptors.
+#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#  define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
+# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+
+// UNIX domain sockets.
+#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#  define ASIO_HAS_LOCAL_SOCKETS 1
+# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+
+#endif // ASIO_DETAIL_CONFIG_HPP
diff --git a/ext/asio/asio/detail/consuming_buffers.hpp b/ext/asio/asio/detail/consuming_buffers.hpp
index 80b6a8e..8969ae4 100644
--- a/ext/asio/asio/detail/consuming_buffers.hpp
+++ b/ext/asio/asio/detail/consuming_buffers.hpp
@@ -1,8 +1,8 @@
 //
-// consuming_buffers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <algorithm>
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <boost/iterator.hpp>
 #include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffer.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -156,12 +152,14 @@ public:
   consuming_buffers(const Buffers& buffers)
     : buffers_(buffers),
       at_end_(buffers_.begin() == buffers_.end()),
-      first_(*buffers_.begin()),
       begin_remainder_(buffers_.begin()),
       max_size_((std::numeric_limits<std::size_t>::max)())
   {
     if (!at_end_)
+    {
+      first_ = *buffers_.begin();
       ++begin_remainder_;
+    }
   }
 
   // Copy constructor.
diff --git a/ext/asio/asio/detail/deadline_timer_service.hpp b/ext/asio/asio/detail/deadline_timer_service.hpp
index 6daf7ac..782f5c3 100644
--- a/ext/asio/asio/detail/deadline_timer_service.hpp
+++ b/ext/asio/asio/detail/deadline_timer_service.hpp
@@ -1,8 +1,8 @@
 //
-// deadline_timer_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,8 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/detail/bind_handler.hpp"
@@ -33,6 +27,13 @@
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue.hpp"
 #include "asio/detail/timer_scheduler.hpp"
+#include "asio/detail/wait_handler.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -54,6 +55,7 @@ public:
   {
     time_type expiry;
     bool might_have_pending_waits;
+    typename timer_queue<Time_Traits>::per_timer_data timer_data;
   };
 
   // Constructor.
@@ -97,7 +99,7 @@ public:
       ec = asio::error_code();
       return 0;
     }
-    std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
+    std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
     impl.might_have_pending_waits = false;
     ec = asio::error_code();
     return count;
@@ -151,59 +153,21 @@ public:
     ec = asio::error_code();
   }
 
-  template <typename Handler>
-  class wait_handler : public timer_op
-  {
-  public:
-    wait_handler(Handler handler)
-      : timer_op(&wait_handler::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      wait_handler* h(static_cast<wait_handler*>(base));
-      typedef handler_alloc_traits<Handler, wait_handler> alloc_traits;
-      handler_ptr<alloc_traits> ptr(h->handler_, h);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder1<Handler, asio::error_code>
-          handler(h->handler_, h->ec_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous wait on the timer.
   template <typename Handler>
   void async_wait(implementation_type& impl, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef wait_handler<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef wait_handler<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
 
     impl.might_have_pending_waits = true;
 
-    scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl);
-    ptr.release();
+    scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
+    p.v = p.p = 0;
   }
 
 private:
diff --git a/ext/asio/asio/detail/descriptor_ops.hpp b/ext/asio/asio/detail/descriptor_ops.hpp
index ea3731e..5cac91d 100644
--- a/ext/asio/asio/detail/descriptor_ops.hpp
+++ b/ext/asio/asio/detail/descriptor_ops.hpp
@@ -1,8 +1,8 @@
 //
-// descriptor_ops.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,34 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <cerrno>
-#include "asio/detail/pop_options.hpp"
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
-#include "asio/error.hpp"
+#include <cstddef>
+#include "asio/error_code.hpp"
 #include "asio/detail/socket_types.hpp"
 
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 namespace descriptor_ops {
 
-inline void clear_error(asio::error_code& ec)
+// Descriptor state bits.
+enum
 {
-  errno = 0;
-  ec = asio::error_code();
-}
+  // The user wants a non-blocking descriptor.
+  user_set_non_blocking = 1,
+
+  // The descriptor has been set non-blocking.
+  internal_non_blocking = 2,
+
+  // Helper "state" used to determine whether the descriptor is non-blocking.
+  non_blocking = user_set_non_blocking | internal_non_blocking
+};
+
+typedef unsigned char state_type;
 
 template <typename ReturnType>
 inline ReturnType error_wrapper(ReturnType return_value,
@@ -46,131 +53,53 @@ inline ReturnType error_wrapper(ReturnType return_value,
   return return_value;
 }
 
-inline int open(const char* path, int flags, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::open(path, flags), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int open(const char* path, int flags,
+    asio::error_code& ec);
 
-inline int close(int d, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::close(d), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int close(int d, state_type& state,
+    asio::error_code& ec);
 
-inline void init_buf_iov_base(void*& base, void* addr)
-{
-  base = addr;
-}
-
-template <typename T>
-inline void init_buf_iov_base(T& base, void* addr)
-{
-  base = static_cast<T>(addr);
-}
+ASIO_DECL bool set_internal_non_blocking(int d,
+    state_type& state, asio::error_code& ec);
 
 typedef iovec buf;
 
-inline void init_buf(buf& b, void* data, size_t size)
-{
-  init_buf_iov_base(b.iov_base, data);
-  b.iov_len = size;
-}
+ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec);
 
-inline void init_buf(buf& b, const void* data, size_t size)
-{
-  init_buf_iov_base(b.iov_base, const_cast<void*>(data));
-  b.iov_len = size;
-}
+ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred);
 
-inline int scatter_read(int d, buf* bufs, size_t count,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL std::size_t sync_write(int d, state_type state,
+    const buf* bufs, std::size_t count, bool all_empty,
+    asio::error_code& ec);
 
-inline int gather_write(int d, const buf* bufs, size_t count,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL bool non_blocking_write(int d,
+    const buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred);
 
-inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::ioctl(d, cmd, arg), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int ioctl(int d, state_type& state, long cmd,
+    ioctl_arg_type* arg, asio::error_code& ec);
 
-inline int fcntl(int d, long cmd, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::fcntl(d, cmd), ec);
-  if (result != -1)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int fcntl(int d, long cmd, asio::error_code& ec);
 
-inline int fcntl(int d, long cmd, long arg, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::fcntl(d, cmd, arg), ec);
-  if (result != -1)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int fcntl(int d, long cmd,
+    long arg, asio::error_code& ec);
 
-inline int poll_read(int d, asio::error_code& ec)
-{
-  clear_error(ec);
-  pollfd fds;
-  fds.fd = d;
-  fds.events = POLLIN;
-  fds.revents = 0;
-  clear_error(ec);
-  int result = error_wrapper(::poll(&fds, 1, -1), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int poll_read(int d, asio::error_code& ec);
 
-inline int poll_write(int d, asio::error_code& ec)
-{
-  clear_error(ec);
-  pollfd fds;
-  fds.fd = d;
-  fds.events = POLLOUT;
-  fds.revents = 0;
-  clear_error(ec);
-  int result = error_wrapper(::poll(&fds, 1, -1), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int poll_write(int d, asio::error_code& ec);
 
 } // namespace descriptor_ops
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/descriptor_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP
diff --git a/ext/asio/asio/detail/descriptor_read_op.hpp b/ext/asio/asio/detail/descriptor_read_op.hpp
new file mode 100644
index 0000000..0d45167
--- /dev/null
+++ b/ext/asio/asio/detail/descriptor_read_op.hpp
@@ -0,0 +1,114 @@
+//
+// detail/descriptor_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class descriptor_read_op_base : public reactor_op
+{
+public:
+  descriptor_read_op_base(int descriptor,
+      const MutableBufferSequence& buffers, func_type complete_func)
+    : reactor_op(&descriptor_read_op_base::do_perform, complete_func),
+      descriptor_(descriptor),
+      buffers_(buffers)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(o->buffers_);
+
+    return descriptor_ops::non_blocking_read(o->descriptor_,
+        bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+  }
+
+private:
+  int descriptor_;
+  MutableBufferSequence buffers_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class descriptor_read_op
+  : public descriptor_read_op_base<MutableBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
+
+  descriptor_read_op(int descriptor,
+      const MutableBufferSequence& buffers, Handler handler)
+    : descriptor_read_op_base<MutableBufferSequence>(
+        descriptor, buffers, &descriptor_read_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
diff --git a/ext/asio/asio/detail/descriptor_write_op.hpp b/ext/asio/asio/detail/descriptor_write_op.hpp
new file mode 100644
index 0000000..9caa283
--- /dev/null
+++ b/ext/asio/asio/detail/descriptor_write_op.hpp
@@ -0,0 +1,114 @@
+//
+// detail/descriptor_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class descriptor_write_op_base : public reactor_op
+{
+public:
+  descriptor_write_op_base(int descriptor,
+      const ConstBufferSequence& buffers, func_type complete_func)
+    : reactor_op(&descriptor_write_op_base::do_perform, complete_func),
+      descriptor_(descriptor),
+      buffers_(buffers)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(o->buffers_);
+
+    return descriptor_ops::non_blocking_write(o->descriptor_,
+        bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+  }
+
+private:
+  int descriptor_;
+  ConstBufferSequence buffers_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class descriptor_write_op
+  : public descriptor_write_op_base<ConstBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
+
+  descriptor_write_op(int descriptor,
+      const ConstBufferSequence& buffers, Handler handler)
+    : descriptor_write_op_base<ConstBufferSequence>(
+        descriptor, buffers, &descriptor_write_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
diff --git a/ext/asio/asio/detail/dev_poll_reactor.hpp b/ext/asio/asio/detail/dev_poll_reactor.hpp
index 1367b71..6bbf1b2 100644
--- a/ext/asio/asio/detail/dev_poll_reactor.hpp
+++ b/ext/asio/asio/detail/dev_poll_reactor.hpp
@@ -1,8 +1,8 @@
 //
-// dev_poll_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,36 +15,28 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_DEV_POLL)
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
 #include <vector>
-#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/throw_exception.hpp>
 #include <sys/devpoll.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
+#include "asio/detail/dev_poll_reactor_fwd.hpp"
 #include "asio/detail/hash_map.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/reactor_op_queue.hpp"
 #include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 #include "asio/detail/timer_queue_fwd.hpp"
 #include "asio/detail/timer_queue_set.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -62,358 +54,93 @@ public:
   };
 
   // Constructor.
-  dev_poll_reactor(asio::io_service& io_service)
-    : asio::detail::service_base<dev_poll_reactor>(io_service),
-      io_service_(use_service<io_service_impl>(io_service)),
-      mutex_(),
-      dev_poll_fd_(do_dev_poll_create()),
-      interrupter_(),
-      shutdown_(false)
-  {
-    // Add the interrupter's descriptor to /dev/poll.
-    ::pollfd ev = { 0 };
-    ev.fd = interrupter_.read_descriptor();
-    ev.events = POLLIN | POLLERR;
-    ev.revents = 0;
-    ::write(dev_poll_fd_, &ev, sizeof(ev));
-  }
+  ASIO_DECL dev_poll_reactor(asio::io_service& io_service);
 
   // Destructor.
-  ~dev_poll_reactor()
-  {
-    shutdown_service();
-    ::close(dev_poll_fd_);
-  }
+  ASIO_DECL ~dev_poll_reactor();
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    shutdown_ = true;
-    lock.unlock();
-
-    op_queue<operation> ops;
-
-    for (int i = 0; i < max_ops; ++i)
-      op_queue_[i].get_all_operations(ops);
-
-    timer_queues_.get_all_timers(ops);
-  } 
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task.
-  void init_task()
-  {
-    io_service_.init_task();
-  }
+  ASIO_DECL void init_task();
 
   // Register a socket with the reactor. Returns 0 on success, system error
   // code on failure.
-  int register_descriptor(socket_type, per_descriptor_data&)
+  ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op)
   {
-    return 0;
+    io_service_.post_immediate_completion(op);
   }
 
   // Start a new operation. The reactor operation will be performed when the
   // given descriptor is flagged as ready, or an error has occurred.
-  void start_op(int op_type, socket_type descriptor,
-      per_descriptor_data&, reactor_op* op, bool allow_speculative)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    if (shutdown_)
-      return;
-
-    if (allow_speculative)
-    {
-      if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
-      {
-        if (!op_queue_[op_type].has_operation(descriptor))
-        {
-          if (op->perform())
-          {
-            lock.unlock();
-            io_service_.post_immediate_completion(op);
-            return;
-          }
-        }
-      }
-    }
-
-    bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
-    io_service_.work_started();
-    if (first)
-    {
-      ::pollfd& ev = add_pending_event_change(descriptor);
-      ev.events = POLLERR | POLLHUP;
-      if (op_type == read_op
-          || op_queue_[read_op].has_operation(descriptor))
-        ev.events |= POLLIN;
-      if (op_type == write_op
-          || op_queue_[write_op].has_operation(descriptor))
-        ev.events |= POLLOUT;
-      if (op_type == except_op
-          || op_queue_[except_op].has_operation(descriptor))
-        ev.events |= POLLPRI;
-      interrupter_.interrupt();
-    }
-  }
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data&, reactor_op* op, bool allow_speculative);
 
   // Cancel all operations associated with the given descriptor. The
   // handlers associated with the descriptor will be invoked with the
   // operation_aborted error.
-  void cancel_ops(socket_type descriptor, per_descriptor_data&)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
-  }
+  ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
 
   // Cancel any operations that are running against the descriptor and remove
   // its registration from the reactor.
-  void close_descriptor(socket_type descriptor, per_descriptor_data&)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    // Remove the descriptor from /dev/poll.
-    ::pollfd& ev = add_pending_event_change(descriptor);
-    ev.events = POLLREMOVE;
-    interrupter_.interrupt();
-
-    // Cancel any outstanding operations associated with the descriptor.
-    cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
-  }
+  ASIO_DECL void close_descriptor(
+      socket_type descriptor, per_descriptor_data&);
 
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
-  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    timer_queues_.insert(&timer_queue);
-  }
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Remove a timer queue from the reactor.
   template <typename Time_Traits>
-  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    timer_queues_.erase(&timer_queue);
-  }
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Schedule a new operation in the given timer queue to expire at the
   // specified absolute time.
   template <typename Time_Traits>
-  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
-      const typename Time_Traits::time_type& time, timer_op* op, void* token)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (!shutdown_)
-    {
-      bool earliest = timer_queue.enqueue_timer(time, op, token);
-      io_service_.work_started();
-      if (earliest)
-        interrupter_.interrupt();
-    }
-  }
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
 
   // Cancel the timer operations associated with the given token. Returns the
   // number of operations that have been posted or dispatched.
   template <typename Time_Traits>
-  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    op_queue<operation> ops;
-    std::size_t n = timer_queue.cancel_timer(token, ops);
-    lock.unlock();
-    io_service_.post_deferred_completions(ops);
-    return n;
-  }
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer);
 
   // Run /dev/poll once until interrupted or events are ready to be dispatched.
-  void run(bool block, op_queue<operation>& ops)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    // We can return immediately if there's no work to do and the reactor is
-    // not supposed to block.
-    if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
-        && op_queue_[except_op].empty() && timer_queues_.all_empty())
-      return;
-
-    // Write the pending event registration changes to the /dev/poll descriptor.
-    std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
-    if (events_size > 0)
-    {
-      errno = 0;
-      int result = ::write(dev_poll_fd_,
-          &pending_event_changes_[0], events_size);
-      if (result != static_cast<int>(events_size))
-      {
-        asio::error_code ec = asio::error_code(
-            errno, asio::error::get_system_category());
-        for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
-        {
-          int descriptor = pending_event_changes_[i].fd;
-          for (int j = 0; j < max_ops; ++j)
-            op_queue_[j].cancel_operations(descriptor, ops, ec);
-        }
-      }
-      pending_event_changes_.clear();
-      pending_event_change_index_.clear();
-    }
-
-    int timeout = block ? get_timeout() : 0;
-    lock.unlock();
-
-    // Block on the /dev/poll descriptor.
-    ::pollfd events[128] = { { 0 } };
-    ::dvpoll dp = { 0 };
-    dp.dp_fds = events;
-    dp.dp_nfds = 128;
-    dp.dp_timeout = timeout;
-    int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
-
-    lock.lock();
-
-    // Dispatch the waiting events.
-    for (int i = 0; i < num_events; ++i)
-    {
-      int descriptor = events[i].fd;
-      if (descriptor == interrupter_.read_descriptor())
-      {
-        interrupter_.reset();
-      }
-      else
-      {
-        bool more_reads = false;
-        bool more_writes = false;
-        bool more_except = false;
-
-        // Exception operations must be processed first to ensure that any
-        // out-of-band data is read before normal data.
-        if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
-          more_except =
-            op_queue_[except_op].perform_operations(descriptor, ops);
-        else
-          more_except = op_queue_[except_op].has_operation(descriptor);
-
-        if (events[i].events & (POLLIN | POLLERR | POLLHUP))
-          more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
-        else
-          more_reads = op_queue_[read_op].has_operation(descriptor);
-
-        if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
-          more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
-        else
-          more_writes = op_queue_[write_op].has_operation(descriptor);
-
-        if ((events[i].events & (POLLERR | POLLHUP)) != 0
-              && !more_except && !more_reads && !more_writes)
-        {
-          // If we have an event and no operations associated with the
-          // descriptor then we need to delete the descriptor from /dev/poll.
-          // The poll operation can produce POLLHUP or POLLERR events when there
-          // is no operation pending, so if we do not remove the descriptor we
-          // can end up in a tight polling loop.
-          ::pollfd ev = { 0 };
-          ev.fd = descriptor;
-          ev.events = POLLREMOVE;
-          ev.revents = 0;
-          ::write(dev_poll_fd_, &ev, sizeof(ev));
-        }
-        else
-        {
-          ::pollfd ev = { 0 };
-          ev.fd = descriptor;
-          ev.events = POLLERR | POLLHUP;
-          if (more_reads)
-            ev.events |= POLLIN;
-          if (more_writes)
-            ev.events |= POLLOUT;
-          if (more_except)
-            ev.events |= POLLPRI;
-          ev.revents = 0;
-          int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
-          if (result != sizeof(ev))
-          {
-            asio::error_code ec(errno,
-                asio::error::get_system_category());
-            for (int j = 0; j < max_ops; ++j)
-              op_queue_[j].cancel_operations(descriptor, ops, ec);
-          }
-        }
-      }
-    }
-    timer_queues_.get_ready_timers(ops);
-  }
+  ASIO_DECL void run(bool block, op_queue<operation>& ops);
 
   // Interrupt the select loop.
-  void interrupt()
-  {
-    interrupter_.interrupt();
-  }
+  ASIO_DECL void interrupt();
 
 private:
   // Create the /dev/poll file descriptor. Throws an exception if the descriptor
   // cannot be created.
-  static int do_dev_poll_create()
-  {
-    int fd = ::open("/dev/poll", O_RDWR);
-    if (fd == -1)
-    {
-      boost::throw_exception(
-          asio::system_error(
-            asio::error_code(errno,
-              asio::error::get_system_category()),
-            "/dev/poll"));
-    }
-    return fd;
-  }
+  ASIO_DECL static int do_dev_poll_create();
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
 
   // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
   // value is returned as a number of milliseconds. A return value of -1
   // indicates that the poll should block indefinitely.
-  int get_timeout()
-  {
-    // By default we will wait no longer than 5 minutes. This will ensure that
-    // any changes to the system clock are detected after no longer than this.
-    return timer_queues_.wait_duration_msec(5 * 60 * 1000);
-  }
+  ASIO_DECL int get_timeout();
 
   // Cancel all operations associated with the given descriptor. The do_cancel
   // function of the handler objects will be invoked. This function does not
   // acquire the dev_poll_reactor's mutex.
-  void cancel_ops_unlocked(socket_type descriptor,
-      const asio::error_code& ec)
-  {
-    bool need_interrupt = false;
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-      need_interrupt = op_queue_[i].cancel_operations(
-          descriptor, ops, ec) || need_interrupt;
-    io_service_.post_deferred_completions(ops);
-    if (need_interrupt)
-      interrupter_.interrupt();
-  }
+  ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+      const asio::error_code& ec);
 
   // Add a pending event entry for the given descriptor.
-  ::pollfd& add_pending_event_change(int descriptor)
-  {
-    hash_map<int, std::size_t>::iterator iter
-      = pending_event_change_index_.find(descriptor);
-    if (iter == pending_event_change_index_.end())
-    {
-      std::size_t index = pending_event_changes_.size();
-      pending_event_changes_.reserve(pending_event_changes_.size() + 1);
-      pending_event_change_index_.insert(std::make_pair(descriptor, index));
-      pending_event_changes_.push_back(::pollfd());
-      pending_event_changes_[index].fd = descriptor;
-      pending_event_changes_[index].revents = 0;
-      return pending_event_changes_[index];
-    }
-    else
-    {
-      return pending_event_changes_[iter->second];
-    }
-  }
+  ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
 
   // The io_service implementation used to post completions.
   io_service_impl& io_service_;
@@ -446,8 +173,13 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_DEV_POLL)
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/dev_poll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/dev_poll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
 #endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
index f7f1aeb..c54f5e1 100644
--- a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// dev_poll_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/dev_poll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,9 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if !defined(ASIO_DISABLE_DEV_POLL)
-#if defined(__sun) // This service is only supported on Solaris.
-
-// Define this to indicate that /dev/poll is supported on the target platform.
-#define ASIO_HAS_DEV_POLL 1
+#if defined(ASIO_HAS_DEV_POLL)
 
 namespace asio {
 namespace detail {
@@ -31,9 +27,6 @@ class dev_poll_reactor;
 } // namespace detail
 } // namespace asio
 
-#endif // defined(__sun)
-#endif // !defined(ASIO_DISABLE_DEV_POLL)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_DEV_POLL)
 
 #endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/epoll_reactor.hpp b/ext/asio/asio/detail/epoll_reactor.hpp
index 0a1eac0..a085766 100644
--- a/ext/asio/asio/detail/epoll_reactor.hpp
+++ b/ext/asio/asio/detail/epoll_reactor.hpp
@@ -1,8 +1,8 @@
 //
-// epoll_reactor.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,43 +15,24 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/epoll_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_EPOLL)
 
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <sys/epoll.h>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/hash_map.hpp"
+#include "asio/detail/epoll_reactor_fwd.hpp"
 #include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 #include "asio/detail/timer_queue_fwd.hpp"
 #include "asio/detail/timer_queue_set.hpp"
 
-#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-# define ASIO_HAS_TIMERFD 1
-#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-
-#if defined(ASIO_HAS_TIMERFD)
-# include "asio/detail/push_options.hpp"
-# include <sys/timerfd.h>
-# include "asio/detail/pop_options.hpp"
-#endif // defined(ASIO_HAS_TIMERFD)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -64,357 +45,86 @@ public:
     connect_op = 1, except_op = 2, max_ops = 3 };
 
   // Per-descriptor queues.
-  struct descriptor_state
+  class descriptor_state
   {
-    descriptor_state() {}
-    descriptor_state(const descriptor_state&) {}
-    void operator=(const descriptor_state&) {}
-
+    friend class epoll_reactor;
+    friend class object_pool_access;
     mutex mutex_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
+    descriptor_state* next_;
+    descriptor_state* prev_;
   };
 
   // Per-descriptor data.
   typedef descriptor_state* per_descriptor_data;
 
   // Constructor.
-  epoll_reactor(asio::io_service& io_service)
-    : asio::detail::service_base<epoll_reactor>(io_service),
-      io_service_(use_service<io_service_impl>(io_service)),
-      mutex_(),
-      epoll_fd_(do_epoll_create()),
-#if defined(ASIO_HAS_TIMERFD)
-      timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
-#else // defined(ASIO_HAS_TIMERFD)
-      timer_fd_(-1),
-#endif // defined(ASIO_HAS_TIMERFD)
-      interrupter_(),
-      shutdown_(false)
-  {
-    // Add the interrupter's descriptor to epoll.
-    epoll_event ev = { 0, { 0 } };
-    ev.events = EPOLLIN | EPOLLERR | EPOLLET;
-    ev.data.ptr = &interrupter_;
-    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
-    interrupter_.interrupt();
-
-    // Add the timer descriptor to epoll.
-    if (timer_fd_ != -1)
-    {
-      ev.events = EPOLLIN | EPOLLERR;
-      ev.data.ptr = &timer_fd_;
-      epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
-    }
-  }
+  ASIO_DECL epoll_reactor(asio::io_service& io_service);
 
   // Destructor.
-  ~epoll_reactor()
-  {
-    close(epoll_fd_);
-    if (timer_fd_ != -1)
-      close(timer_fd_);
-  }
+  ASIO_DECL ~epoll_reactor();
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    mutex::scoped_lock lock(mutex_);
-    shutdown_ = true;
-    lock.unlock();
-
-    op_queue<operation> ops;
-
-    descriptor_map::iterator iter = registered_descriptors_.begin();
-    descriptor_map::iterator end = registered_descriptors_.end();
-    while (iter != end)
-    {
-      for (int i = 0; i < max_ops; ++i)
-        ops.push(iter->second.op_queue_[i]);
-      iter->second.shutdown_ = true;
-      ++iter;
-    }
-
-    timer_queues_.get_all_timers(ops);
-  }
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task.
-  void init_task()
-  {
-    io_service_.init_task();
-  }
+  ASIO_DECL void init_task();
 
   // Register a socket with the reactor. Returns 0 on success, system error
   // code on failure.
-  int register_descriptor(socket_type descriptor,
-      per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock lock(registered_descriptors_mutex_);
-
-    descriptor_map::iterator new_entry = registered_descriptors_.insert(
-          std::make_pair(descriptor, descriptor_state())).first;
-    descriptor_data = &new_entry->second;
-
-    epoll_event ev = { 0, { 0 } };
-    ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
-    ev.data.ptr = descriptor_data;
-    int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
-    if (result != 0)
-      return errno;
-
-    descriptor_data->shutdown_ = false;
+  ASIO_DECL int register_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
-    return 0;
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op)
+  {
+    io_service_.post_immediate_completion(op);
   }
 
   // Start a new operation. The reactor operation will be performed when the
   // given descriptor is flagged as ready, or an error has occurred.
-  void start_op(int op_type, socket_type descriptor,
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
       per_descriptor_data& descriptor_data,
-      reactor_op* op, bool allow_speculative)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-    if (descriptor_data->shutdown_)
-      return;
-
-    if (descriptor_data->op_queue_[op_type].empty())
-    {
-      if (allow_speculative
-          && (op_type != read_op
-            || descriptor_data->op_queue_[except_op].empty()))
-      {
-        if (op->perform())
-        {
-          descriptor_lock.unlock();
-          io_service_.post_immediate_completion(op);
-          return;
-        }
-      }
-      else
-      {
-        epoll_event ev = { 0, { 0 } };
-        ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
-          | EPOLLOUT | EPOLLPRI | EPOLLET;
-        ev.data.ptr = descriptor_data;
-        epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
-      }
-    }
-
-    descriptor_data->op_queue_[op_type].push(op);
-    io_service_.work_started();
-  }
+      reactor_op* op, bool allow_speculative);
 
   // Cancel all operations associated with the given descriptor. The
   // handlers associated with the descriptor will be invoked with the
   // operation_aborted error.
-  void cancel_ops(socket_type, per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-    {
-      while (reactor_op* op = descriptor_data->op_queue_[i].front())
-      {
-        op->ec_ = asio::error::operation_aborted;
-        descriptor_data->op_queue_[i].pop();
-        ops.push(op);
-      }
-    }
-
-    descriptor_lock.unlock();
-
-    io_service_.post_deferred_completions(ops);
-  }
+  ASIO_DECL void cancel_ops(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
   // Cancel any operations that are running against the descriptor and remove
   // its registration from the reactor.
-  void close_descriptor(socket_type descriptor,
-      per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-    mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
-
-    // Remove the descriptor from the set of known descriptors. The descriptor
-    // will be automatically removed from the epoll set when it is closed.
-    descriptor_data->shutdown_ = true;
-
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-    {
-      while (reactor_op* op = descriptor_data->op_queue_[i].front())
-      {
-        op->ec_ = asio::error::operation_aborted;
-        descriptor_data->op_queue_[i].pop();
-        ops.push(op);
-      }
-    }
-
-    descriptor_lock.unlock();
-
-    registered_descriptors_.erase(descriptor);
-
-    descriptors_lock.unlock();
-
-    io_service_.post_deferred_completions(ops);
-  }
+  ASIO_DECL void close_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
-  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    mutex::scoped_lock lock(mutex_);
-    timer_queues_.insert(&timer_queue);
-  }
+  void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
 
   // Remove a timer queue from the reactor.
   template <typename Time_Traits>
-  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    mutex::scoped_lock lock(mutex_);
-    timer_queues_.erase(&timer_queue);
-  }
+  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
 
   // Schedule a new operation in the given timer queue to expire at the
   // specified absolute time.
   template <typename Time_Traits>
-  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
-      const typename Time_Traits::time_type& time, timer_op* op, void* token)
-  {
-    mutex::scoped_lock lock(mutex_);
-    if (!shutdown_)
-    {
-      bool earliest = timer_queue.enqueue_timer(time, op, token);
-      io_service_.work_started();
-      if (earliest)
-      {
-#if defined(ASIO_HAS_TIMERFD)
-        if (timer_fd_ != -1)
-        {
-          itimerspec new_timeout;
-          itimerspec old_timeout;
-          int flags = get_timeout(new_timeout);
-          timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
-          return;
-        }
-#endif // defined(ASIO_HAS_TIMERFD)
-        interrupter_.interrupt();
-      }
-    }
-  }
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
 
   // Cancel the timer operations associated with the given token. Returns the
   // number of operations that have been posted or dispatched.
   template <typename Time_Traits>
-  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
-  {
-    mutex::scoped_lock lock(mutex_);
-    op_queue<operation> ops;
-    std::size_t n = timer_queue.cancel_timer(token, ops);
-    lock.unlock();
-    io_service_.post_deferred_completions(ops);
-    return n;
-  }
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer);
 
   // Run epoll once until interrupted or events are ready to be dispatched.
-  void run(bool block, op_queue<operation>& ops)
-  {
-    // Calculate a timeout only if timerfd is not used.
-    int timeout;
-    if (timer_fd_ != -1)
-      timeout = block ? -1 : 0;
-    else
-    {
-      mutex::scoped_lock lock(mutex_);
-      timeout = block ? get_timeout() : 0;
-    }
-
-    // Block on the epoll descriptor.
-    epoll_event events[128];
-    int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
-
-#if defined(ASIO_HAS_TIMERFD)
-    bool check_timers = (timer_fd_ == -1);
-#else // defined(ASIO_HAS_TIMERFD)
-    bool check_timers = true;
-#endif // defined(ASIO_HAS_TIMERFD)
-
-    // Dispatch the waiting events.
-    for (int i = 0; i < num_events; ++i)
-    {
-      void* ptr = events[i].data.ptr;
-      if (ptr == &interrupter_)
-      {
-        // No need to reset the interrupter since we're leaving the descriptor
-        // in a ready-to-read state and relying on edge-triggered notifications
-        // to make it so that we only get woken up when the descriptor's epoll
-        // registration is updated.
-
-#if defined(ASIO_HAS_TIMERFD)
-        if (timer_fd_ == -1)
-          check_timers = true;
-#else // defined(ASIO_HAS_TIMERFD)
-        check_timers = true;
-#endif // defined(ASIO_HAS_TIMERFD)
-      }
-#if defined(ASIO_HAS_TIMERFD)
-      else if (ptr == &timer_fd_)
-      {
-        check_timers = true;
-      }
-#endif // defined(ASIO_HAS_TIMERFD)
-      else
-      {
-        descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
-        mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
-        // Exception operations must be processed first to ensure that any
-        // out-of-band data is read before normal data.
-        static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
-        for (int j = max_ops - 1; j >= 0; --j)
-        {
-          if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
-          {
-            while (reactor_op* op = descriptor_data->op_queue_[j].front())
-            {
-              if (op->perform())
-              {
-                descriptor_data->op_queue_[j].pop();
-                ops.push(op);
-              }
-              else
-                break;
-            }
-          }
-        }
-      }
-    }
-
-    if (check_timers)
-    {
-      mutex::scoped_lock common_lock(mutex_);
-      timer_queues_.get_ready_timers(ops);
-
-#if defined(ASIO_HAS_TIMERFD)
-      if (timer_fd_ != -1)
-      {
-        itimerspec new_timeout;
-        itimerspec old_timeout;
-        int flags = get_timeout(new_timeout);
-        timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
-      }
-#endif // defined(ASIO_HAS_TIMERFD)
-    }
-  }
+  ASIO_DECL void run(bool block, op_queue<operation>& ops);
 
   // Interrupt the select loop.
-  void interrupt()
-  {
-    epoll_event ev = { 0, { 0 } };
-    ev.events = EPOLLIN | EPOLLERR | EPOLLET;
-    ev.data.ptr = &interrupter_;
-    epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
-  }
+  ASIO_DECL void interrupt();
 
 private:
   // The hint to pass to epoll_create to size its data structures.
@@ -422,44 +132,26 @@ private:
 
   // Create the epoll file descriptor. Throws an exception if the descriptor
   // cannot be created.
-  static int do_epoll_create()
-  {
-    int fd = epoll_create(epoll_size);
-    if (fd == -1)
-    {
-      boost::throw_exception(
-          asio::system_error(
-            asio::error_code(errno,
-              asio::error::get_system_category()),
-            "epoll"));
-    }
-    return fd;
-  }
+  ASIO_DECL static int do_epoll_create();
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Called to recalculate and update the timeout.
+  ASIO_DECL void update_timeout();
 
   // Get the timeout value for the epoll_wait call. The timeout value is
   // returned as a number of milliseconds. A return value of -1 indicates
   // that epoll_wait should block indefinitely.
-  int get_timeout()
-  {
-    // By default we will wait no longer than 5 minutes. This will ensure that
-    // any changes to the system clock are detected after no longer than this.
-    return timer_queues_.wait_duration_msec(5 * 60 * 1000);
-  }
+  ASIO_DECL int get_timeout();
 
 #if defined(ASIO_HAS_TIMERFD)
   // Get the timeout value for the timer descriptor. The return value is the
   // flag argument to be used when calling timerfd_settime.
-  int get_timeout(itimerspec& ts)
-  {
-    ts.it_interval.tv_sec = 0;
-    ts.it_interval.tv_nsec = 0;
-
-    long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
-    ts.it_value.tv_sec = usec / 1000000;
-    ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
-
-    return usec ? 0 : TFD_TIMER_ABSTIME;
-  }
+  ASIO_DECL int get_timeout(itimerspec& ts);
 #endif // defined(ASIO_HAS_TIMERFD)
 
   // The io_service implementation used to post completions.
@@ -486,22 +178,20 @@ private:
   // Mutex to protect access to the registered descriptors.
   mutex registered_descriptors_mutex_;
 
-  // Keep track of all registered descriptors. This code relies on the fact that
-  // the hash_map implementation pools deleted nodes, meaning that we can assume
-  // our descriptor_state pointer remains valid even after the entry is removed.
-  // Technically this is not true for C++98, as that standard says that spliced
-  // elements in a list are invalidated. However, C++0x fixes this shortcoming
-  // so we'll just assume that C++98 std::list implementations will do the right
-  // thing anyway.
-  typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
-  descriptor_map registered_descriptors_;
+  // Keep track of all registered descriptors.
+  object_pool<descriptor_state> registered_descriptors_;
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_EPOLL)
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/epoll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/epoll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EPOLL)
+
 #endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/epoll_reactor_fwd.hpp b/ext/asio/asio/detail/epoll_reactor_fwd.hpp
index 266bccd..49df6ed 100644
--- a/ext/asio/asio/detail/epoll_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/epoll_reactor_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// epoll_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/epoll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,9 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if !defined(ASIO_DISABLE_EPOLL)
-#if defined(__linux__) // This service is only supported on Linux.
-
-#include "asio/detail/push_options.hpp"
-#include <linux/version.h>
-#include "asio/detail/pop_options.hpp"
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
-
-// Define this to indicate that epoll is supported on the target platform.
-#define ASIO_HAS_EPOLL 1
+#if defined(ASIO_HAS_EPOLL)
 
 namespace asio {
 namespace detail {
@@ -37,10 +27,6 @@ class epoll_reactor;
 } // namespace detail
 } // namespace asio
 
-#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
-#endif // defined(__linux__)
-#endif // !defined(ASIO_DISABLE_EPOLL)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_EPOLL)
 
 #endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/event.hpp b/ext/asio/asio/detail/event.hpp
index 65aa4cb..46ee8a6 100644
--- a/ext/asio/asio/detail/event.hpp
+++ b/ext/asio/asio/detail/event.hpp
@@ -1,8 +1,8 @@
 //
-// event.hpp
-// ~~~~~~~~~
+// detail/event.hpp
+// ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 # include "asio/detail/null_event.hpp"
@@ -45,6 +41,4 @@ typedef posix_event event;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_EVENT_HPP
diff --git a/ext/asio/asio/detail/eventfd_select_interrupter.hpp b/ext/asio/asio/detail/eventfd_select_interrupter.hpp
index 63b7ac4..0d3b958 100644
--- a/ext/asio/asio/detail/eventfd_select_interrupter.hpp
+++ b/ext/asio/asio/detail/eventfd_select_interrupter.hpp
@@ -1,8 +1,8 @@
 //
-// eventfd_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/eventfd_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,36 +16,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if defined(__linux__)
-# if !defined(ASIO_DISABLE_EVENTFD)
-#  include <linux/version.h>
-#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-#   define ASIO_HAS_EVENTFD
-#  endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-# endif // !defined(ASIO_DISABLE_EVENTFD)
-#endif // defined(__linux__)
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_EVENTFD)
 
 #include "asio/detail/push_options.hpp"
-#include <fcntl.h>
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-# include <asm/unistd.h>
-#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-# include <sys/eventfd.h>
-#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_types.hpp"
 
 namespace asio {
 namespace detail {
@@ -54,87 +29,16 @@ class eventfd_select_interrupter
 {
 public:
   // Constructor.
-  eventfd_select_interrupter()
-  {
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-    write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
-#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-    write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
-#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-    if (read_descriptor_ != -1)
-    {
-      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
-    }
-    else
-    {
-      int pipe_fds[2];
-      if (pipe(pipe_fds) == 0)
-      {
-        read_descriptor_ = pipe_fds[0];
-        ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
-        write_descriptor_ = pipe_fds[1];
-        ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
-      }
-      else
-      {
-        asio::error_code ec(errno,
-            asio::error::get_system_category());
-        asio::system_error e(ec, "eventfd_select_interrupter");
-        boost::throw_exception(e);
-      }
-    }
-  }
+  ASIO_DECL eventfd_select_interrupter();
 
   // Destructor.
-  ~eventfd_select_interrupter()
-  {
-    if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
-      ::close(write_descriptor_);
-    if (read_descriptor_ != -1)
-      ::close(read_descriptor_);
-  }
+  ASIO_DECL ~eventfd_select_interrupter();
 
   // Interrupt the select call.
-  void interrupt()
-  {
-    uint64_t counter(1UL);
-    int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
-    (void)result;
-  }
+  ASIO_DECL void interrupt();
 
   // Reset the select interrupt. Returns true if the call was interrupted.
-  bool reset()
-  {
-    if (write_descriptor_ == read_descriptor_)
-    {
-      for (;;)
-      {
-        // Only perform one read. The kernel maintains an atomic counter.
-        uint64_t counter(0);
-        errno = 0;
-        int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
-        if (bytes_read < 0 && errno == EINTR)
-          continue;
-        bool was_interrupted = (bytes_read > 0);
-        return was_interrupted;
-      }
-    }
-    else
-    {
-      for (;;)
-      {
-        // Clear all data from the pipe.
-        char data[1024];
-        int bytes_read = ::read(read_descriptor_, data, sizeof(data));
-        if (bytes_read < 0 && errno == EINTR)
-          continue;
-        bool was_interrupted = (bytes_read > 0);
-        while (bytes_read == sizeof(data))
-          bytes_read = ::read(read_descriptor_, data, sizeof(data));
-        return was_interrupted;
-      }
-    }
-  }
+  ASIO_DECL bool reset();
 
   // Get the read descriptor to be passed to select.
   int read_descriptor() const
@@ -159,8 +63,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_EVENTFD)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
 #endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/fd_set_adapter.hpp b/ext/asio/asio/detail/fd_set_adapter.hpp
index a575491..953cad1 100644
--- a/ext/asio/asio/detail/fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/fd_set_adapter.hpp
@@ -1,8 +1,8 @@
 //
-// fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/posix_fd_set_adapter.hpp"
 #include "asio/detail/win_fd_set_adapter.hpp"
 
@@ -36,6 +31,4 @@ typedef posix_fd_set_adapter fd_set_adapter;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/fenced_block.hpp b/ext/asio/asio/detail/fenced_block.hpp
index 60198bc..70c47e1 100644
--- a/ext/asio/asio/detail/fenced_block.hpp
+++ b/ext/asio/asio/detail/fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// fenced_block.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,25 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+  || defined(ASIO_DISABLE_THREADS) \
+  || defined(ASIO_DISABLE_FENCED_BLOCK)
 # include "asio/detail/null_fenced_block.hpp"
 #elif defined(__MACH__) && defined(__APPLE__)
 # include "asio/detail/macos_fenced_block.hpp"
 #elif defined(__sun)
 # include "asio/detail/solaris_fenced_block.hpp"
+#elif defined(__GNUC__) && defined(__arm__)
+# include "asio/detail/gcc_arm_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+# include "asio/detail/gcc_hppa_fenced_block.hpp"
 #elif defined(__GNUC__) \
   && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
   && !defined(__INTEL_COMPILER) && !defined(__ICL) \
   && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
-# include "asio/detail/gcc_fenced_block.hpp"
+# include "asio/detail/gcc_sync_fenced_block.hpp"
 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 # include "asio/detail/gcc_x86_fenced_block.hpp"
 #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -43,17 +45,23 @@
 namespace asio {
 namespace detail {
 
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+  || defined(ASIO_DISABLE_THREADS) \
+  || defined(ASIO_DISABLE_FENCED_BLOCK)
 typedef null_fenced_block fenced_block;
 #elif defined(__MACH__) && defined(__APPLE__)
 typedef macos_fenced_block fenced_block;
 #elif defined(__sun)
 typedef solaris_fenced_block fenced_block;
+#elif defined(__GNUC__) && defined(__arm__)
+typedef gcc_arm_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+typedef gcc_hppa_fenced_block fenced_block;
 #elif defined(__GNUC__) \
   && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
   && !defined(__INTEL_COMPILER) && !defined(__ICL) \
   && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
-typedef gcc_fenced_block fenced_block;
+typedef gcc_sync_fenced_block fenced_block;
 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 typedef gcc_x86_fenced_block fenced_block;
 #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -65,6 +73,4 @@ typedef null_fenced_block fenced_block;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_arm_fenced_block.hpp b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp
new file mode 100644
index 0000000..76c4d99
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp
@@ -0,0 +1,76 @@
+//
+// detail/gcc_arm_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && defined(__arm__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_arm_fenced_block
+  : private noncopyable
+{
+public:
+  // Constructor.
+  gcc_arm_fenced_block()
+  {
+    barrier();
+  }
+
+  // Destructor.
+  ~gcc_arm_fenced_block()
+  {
+    barrier();
+  }
+
+private:
+  static void barrier()
+  {
+#if defined(__ARM_ARCH_4__) \
+    || defined(__ARM_ARCH_4T__) \
+    || defined(__ARM_ARCH_5__) \
+    || defined(__ARM_ARCH_5E__) \
+    || defined(__ARM_ARCH_5T__) \
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__) \
+    || defined(__ARM_ARCH_6__) \
+    || defined(__ARM_ARCH_6J__) \
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6T2__)
+    int a = 0, b = 0;
+    __asm__ __volatile__ ("swp %0, %1, [%2]"
+        : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");
+#else
+    // ARMv7 and later.
+    __asm__ __volatile__ ("dmb" : : : "memory");
+#endif
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && defined(__arm__)
+
+#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
new file mode 100644
index 0000000..215086a
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
@@ -0,0 +1,58 @@
+//
+// detail/gcc_hppa_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_hppa_fenced_block
+  : private noncopyable
+{
+public:
+  // Constructor.
+  gcc_hppa_fenced_block()
+  {
+    barrier();
+  }
+
+  // Destructor.
+  ~gcc_hppa_fenced_block()
+  {
+    barrier();
+  }
+
+private:
+  static void barrier()
+  {
+    // This is just a placeholder and almost certainly not sufficient.
+    __asm__ __volatile__ ("" : : : "memory");
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_sync_fenced_block.hpp b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp
new file mode 100644
index 0000000..569b559
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp
@@ -0,0 +1,61 @@
+//
+// detail/gcc_sync_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) \
+  && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+  && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+  && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_sync_fenced_block
+  : private noncopyable
+{
+public:
+  // Constructor.
+  gcc_sync_fenced_block()
+    : value_(0)
+  {
+    __sync_lock_test_and_set(&value_, 1);
+  }
+
+  // Destructor.
+  ~gcc_sync_fenced_block()
+  {
+    __sync_lock_release(&value_);
+  }
+
+private:
+  int value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__)
+       // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
+       // && !defined(__INTEL_COMPILER) && !defined(__ICL)
+       // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
index 48119f4..3e2e5bc 100644
--- a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
+++ b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// gcc_x86_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/gcc_x86_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -54,8 +52,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
 #endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/handler_alloc_helpers.hpp b/ext/asio/asio/detail/handler_alloc_helpers.hpp
index 0ac42a7..9ae80de 100644
--- a/ext/asio/asio/detail/handler_alloc_helpers.hpp
+++ b/ext/asio/asio/detail/handler_alloc_helpers.hpp
@@ -1,8 +1,8 @@
 //
-// handler_alloc_helpers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/detail/workaround.hpp>
 #include <boost/utility/addressof.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/handler_alloc_hook.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/handler_alloc_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 // Calls to asio_handler_allocate and asio_handler_deallocate must be made from
 // a namespace that does not contain any overloads of these functions. The
@@ -56,203 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
 
 } // namespace asio_handler_alloc_helpers
 
-namespace asio {
-namespace detail {
-
-// Traits for handler allocation.
-template <typename Handler, typename Object>
-struct handler_alloc_traits
-{
-  typedef Handler handler_type;
-  typedef Object value_type;
-  typedef Object* pointer_type;
-  BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
-};
-
-template <typename Alloc_Traits>
-class handler_ptr;
-
-// Helper class to provide RAII on uninitialised handler memory.
-template <typename Alloc_Traits>
-class raw_handler_ptr
-  : private noncopyable
-{
-public:
-  typedef typename Alloc_Traits::handler_type handler_type;
-  typedef typename Alloc_Traits::value_type value_type;
-  typedef typename Alloc_Traits::pointer_type pointer_type;
-  BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
-
-  // Constructor allocates the memory.
-  raw_handler_ptr(handler_type& handler)
-    : handler_(handler),
-      pointer_(static_cast<pointer_type>(
-            asio_handler_alloc_helpers::allocate(value_size, handler_)))
-  {
-  }
-
-  // Destructor automatically deallocates memory, unless it has been stolen by
-  // a handler_ptr object.
-  ~raw_handler_ptr()
-  {
-    if (pointer_)
-      asio_handler_alloc_helpers::deallocate(
-          pointer_, value_size, handler_);
-  }
-
-private:
-  friend class handler_ptr<Alloc_Traits>;
-  handler_type& handler_;
-  pointer_type pointer_;
-};
-
-// Helper class to provide RAII on uninitialised handler memory.
-template <typename Alloc_Traits>
-class handler_ptr
-  : private noncopyable
-{
-public:
-  typedef typename Alloc_Traits::handler_type handler_type;
-  typedef typename Alloc_Traits::value_type value_type;
-  typedef typename Alloc_Traits::pointer_type pointer_type;
-  BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
-  typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
-
-  // Take ownership of existing memory.
-  handler_ptr(handler_type& handler, pointer_type pointer)
-    : handler_(handler),
-      pointer_(pointer)
-  {
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  handler_ptr(raw_ptr_type& raw_ptr)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type)
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
-      typename Arg5>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
-      Arg5& a5)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
-      typename Arg5, typename Arg6>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
-      Arg5& a5, Arg6& a6)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
-      typename Arg5, typename Arg6, typename Arg7>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
-      Arg5& a5, Arg6& a6, Arg7& a7)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Construct object in raw memory and take ownership if construction succeeds.
-  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
-      typename Arg5, typename Arg6, typename Arg7, typename Arg8>
-  handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
-      Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
-    : handler_(raw_ptr.handler_),
-      pointer_(new (raw_ptr.pointer_) value_type(
-            a1, a2, a3, a4, a5, a6, a7, a8))
-  {
-    raw_ptr.pointer_ = 0;
-  }
-
-  // Destructor automatically deallocates memory, unless it has been released.
-  ~handler_ptr()
-  {
-    reset();
-  }
-
-  // Get the memory.
-  pointer_type get() const
-  {
-    return pointer_;
-  }
-
-  // Release ownership of the memory.
-  pointer_type release()
-  {
-    pointer_type tmp = pointer_;
-    pointer_ = 0;
-    return tmp;
-  }
-
-  // Explicitly destroy and deallocate the memory.
-  void reset()
-  {
-    if (pointer_)
-    {
-      pointer_->value_type::~value_type();
-      asio_handler_alloc_helpers::deallocate(
-          pointer_, value_size, handler_);
-      pointer_ = 0;
-    }
-  }
-
-private:
-  handler_type& handler_;
-  pointer_type pointer_;
-};
-
-} // namespace detail
-} // namespace asio
+#define ASIO_DEFINE_HANDLER_PTR(op) \
+  struct ptr \
+  { \
+    Handler* h; \
+    void* v; \
+    op* p; \
+    ~ptr() \
+    { \
+      reset(); \
+    } \
+    void reset() \
+    { \
+      if (p) \
+      { \
+        p->~op(); \
+        p = 0; \
+      } \
+      if (v) \
+      { \
+        asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \
+        v = 0; \
+      } \
+    } \
+  } \
+  /**/
 
 #include "asio/detail/pop_options.hpp"
 
diff --git a/ext/asio/asio/detail/handler_invoke_helpers.hpp b/ext/asio/asio/detail/handler_invoke_helpers.hpp
index 8332567..5b122d9 100644
--- a/ext/asio/asio/detail/handler_invoke_helpers.hpp
+++ b/ext/asio/asio/detail/handler_invoke_helpers.hpp
@@ -1,8 +1,8 @@
 //
-// handler_invoke_helpers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/detail/workaround.hpp>
 #include <boost/utility/addressof.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/handler_invoke_hook.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 // Calls to asio_handler_invoke must be made from a namespace that does not
 // contain overloads of this function. The asio_handler_invoke_helpers
 // namespace is defined here for that purpose.
diff --git a/ext/asio/asio/detail/hash_map.hpp b/ext/asio/asio/detail/hash_map.hpp
index b2a1517..a3957df 100644
--- a/ext/asio/asio/detail/hash_map.hpp
+++ b/ext/asio/asio/detail/hash_map.hpp
@@ -1,8 +1,8 @@
 //
-// hash_map.hpp
-// ~~~~~~~~~~~~
+// detail/hash_map.hpp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,33 +15,38 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cassert>
 #include <list>
 #include <utility>
-#include <boost/functional/hash.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 
-template <typename T>
-inline std::size_t calculate_hash_value(const T& t)
+inline std::size_t calculate_hash_value(int i)
+{
+  return static_cast<std::size_t>(i);
+}
+
+inline std::size_t calculate_hash_value(void* p)
 {
-  return boost::hash_value(t);
+  return reinterpret_cast<std::size_t>(p)
+    + (reinterpret_cast<std::size_t>(p) >> 3);
 }
 
-#if defined(_WIN64)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 inline std::size_t calculate_hash_value(SOCKET s)
 {
   return static_cast<std::size_t>(s);
 }
-#endif // defined(_WIN64)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
 // Note: assumes K and V are POD types.
 template <typename K, typename V>
diff --git a/ext/asio/asio/detail/impl/descriptor_ops.ipp b/ext/asio/asio/detail/impl/descriptor_ops.ipp
new file mode 100644
index 0000000..8e0c27d
--- /dev/null
+++ b/ext/asio/asio/detail/impl/descriptor_ops.ipp
@@ -0,0 +1,382 @@
+//
+// detail/impl/descriptor_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cerrno>
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/error.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+ASIO_DECL
+int open(const char* path, int flags, asio::error_code& ec)
+{
+  errno = 0;
+  int result = error_wrapper(::open(path, flags), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int close(int d, state_type& state, asio::error_code& ec)
+{
+  int result = 0;
+  if (d != -1)
+  {
+    if (state & internal_non_blocking)
+    {
+#if defined(__SYMBIAN32__)
+      int flags = ::fcntl(d, F_GETFL, 0);
+      if (flags >= 0)
+        ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__)
+      ioctl_arg_type arg = 0;
+      ::ioctl(d, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__)
+      state &= ~internal_non_blocking;
+    }
+
+    errno = 0;
+    result = error_wrapper(::close(d), ec);
+  }
+
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+bool set_internal_non_blocking(int d,
+    state_type& state, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+  errno = 0;
+#if defined(__SYMBIAN32__)
+  int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
+  if (result >= 0)
+  {
+    errno = 0;
+    result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec);
+  }
+#else // defined(__SYMBIAN32__)
+  ioctl_arg_type arg = 1;
+  int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
+#endif // defined(__SYMBIAN32__)
+
+  if (result >= 0)
+  {
+    ec = asio::error_code();
+    state |= internal_non_blocking;
+    return true;
+  }
+
+  return false;
+}
+
+ASIO_DECL
+std::size_t sync_read(int d, state_type state, buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (all_empty)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    errno = 0;
+    int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Check for EOF.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_read(d, ec) < 0)
+      return 0;
+  }
+}
+
+ASIO_DECL
+bool non_blocking_read(int d, buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    errno = 0;
+    int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+
+    // Check for end of stream.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes > 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+ASIO_DECL
+std::size_t sync_write(int d, state_type state, const buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes on a stream is a no-op.
+  if (all_empty)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    errno = 0;
+    int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_write(d, ec) < 0)
+      return 0;
+  }
+}
+
+ASIO_DECL
+bool non_blocking_write(int d, const buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    errno = 0;
+    int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes >= 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+ASIO_DECL
+int ioctl(int d, state_type& state, long cmd,
+    ioctl_arg_type* arg, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  errno = 0;
+  int result = error_wrapper(::ioctl(d, cmd, arg), ec);
+
+  if (result >= 0)
+  {
+    ec = asio::error_code();
+
+    // When updating the non-blocking mode we always perform the ioctl syscall,
+    // even if the flags would otherwise indicate that the descriptor is
+    // already in the correct state. This ensures that the underlying
+    // descriptor is put into the state that has been requested by the user. If
+    // the ioctl syscall was successful then we need to update the flags to
+    // match.
+    if (cmd == static_cast<long>(FIONBIO))
+    {
+      if (*arg)
+      {
+        state |= user_set_non_blocking;
+      }
+      else
+      {
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        state &= ~(user_set_non_blocking | internal_non_blocking);
+      }
+    }
+  }
+
+  return result;
+}
+
+ASIO_DECL
+int fcntl(int d, long cmd, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  errno = 0;
+  int result = error_wrapper(::fcntl(d, cmd), ec);
+  if (result != -1)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int fcntl(int d, long cmd, long arg, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  errno = 0;
+  int result = error_wrapper(::fcntl(d, cmd, arg), ec);
+  if (result != -1)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int poll_read(int d, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  pollfd fds;
+  fds.fd = d;
+  fds.events = POLLIN;
+  fds.revents = 0;
+  errno = 0;
+  int result = error_wrapper(::poll(&fds, 1, -1), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int poll_write(int d, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  pollfd fds;
+  fds.fd = d;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  errno = 0;
+  int result = error_wrapper(::poll(&fds, 1, -1), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.hpp b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp
new file mode 100644
index 0000000..7fbef82
--- /dev/null
+++ b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp
@@ -0,0 +1,77 @@
+//
+// detail/impl/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    io_service_.post_immediate_completion(op);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  io_service_.work_started();
+  if (earliest)
+    interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops);
+  lock.unlock();
+  io_service_.post_deferred_completions(ops);
+  return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.ipp b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp
new file mode 100644
index 0000000..0d1456f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp
@@ -0,0 +1,338 @@
+//
+// detail/impl/dev_poll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/dev_poll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+dev_poll_reactor::dev_poll_reactor(asio::io_service& io_service)
+  : asio::detail::service_base<dev_poll_reactor>(io_service),
+    io_service_(use_service<io_service_impl>(io_service)),
+    mutex_(),
+    dev_poll_fd_(do_dev_poll_create()),
+    interrupter_(),
+    shutdown_(false)
+{
+  // Add the interrupter's descriptor to /dev/poll.
+  ::pollfd ev = { 0 };
+  ev.fd = interrupter_.read_descriptor();
+  ev.events = POLLIN | POLLERR;
+  ev.revents = 0;
+  ::write(dev_poll_fd_, &ev, sizeof(ev));
+}
+
+dev_poll_reactor::~dev_poll_reactor()
+{
+  shutdown_service();
+  ::close(dev_poll_fd_);
+}
+
+void dev_poll_reactor::shutdown_service()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].get_all_operations(ops);
+
+  timer_queues_.get_all_timers(ops);
+} 
+
+void dev_poll_reactor::init_task()
+{
+  io_service_.init_task();
+}
+
+int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
+{
+  return 0;
+}
+
+void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&,
+    reactor_op* op, bool allow_speculative)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    post_immediate_completion(op);
+    return;
+  }
+
+  if (allow_speculative)
+  {
+    if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
+    {
+      if (!op_queue_[op_type].has_operation(descriptor))
+      {
+        if (op->perform())
+        {
+          lock.unlock();
+          io_service_.post_immediate_completion(op);
+          return;
+        }
+      }
+    }
+  }
+
+  bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+  io_service_.work_started();
+  if (first)
+  {
+    ::pollfd& ev = add_pending_event_change(descriptor);
+    ev.events = POLLERR | POLLHUP;
+    if (op_type == read_op
+        || op_queue_[read_op].has_operation(descriptor))
+      ev.events |= POLLIN;
+    if (op_type == write_op
+        || op_queue_[write_op].has_operation(descriptor))
+      ev.events |= POLLOUT;
+    if (op_type == except_op
+        || op_queue_[except_op].has_operation(descriptor))
+      ev.events |= POLLPRI;
+    interrupter_.interrupt();
+  }
+}
+
+void dev_poll_reactor::cancel_ops(socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::close_descriptor(socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Remove the descriptor from /dev/poll.
+  ::pollfd& ev = add_pending_event_change(descriptor);
+  ev.events = POLLREMOVE;
+  interrupter_.interrupt();
+
+  // Cancel any outstanding operations associated with the descriptor.
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // We can return immediately if there's no work to do and the reactor is
+  // not supposed to block.
+  if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+      && op_queue_[except_op].empty() && timer_queues_.all_empty())
+    return;
+
+  // Write the pending event registration changes to the /dev/poll descriptor.
+  std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+  if (events_size > 0)
+  {
+    errno = 0;
+    int result = ::write(dev_poll_fd_,
+        &pending_event_changes_[0], events_size);
+    if (result != static_cast<int>(events_size))
+    {
+      asio::error_code ec = asio::error_code(
+          errno, asio::error::get_system_category());
+      for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+      {
+        int descriptor = pending_event_changes_[i].fd;
+        for (int j = 0; j < max_ops; ++j)
+          op_queue_[j].cancel_operations(descriptor, ops, ec);
+      }
+    }
+    pending_event_changes_.clear();
+    pending_event_change_index_.clear();
+  }
+
+  int timeout = block ? get_timeout() : 0;
+  lock.unlock();
+
+  // Block on the /dev/poll descriptor.
+  ::pollfd events[128] = { { 0 } };
+  ::dvpoll dp = { 0 };
+  dp.dp_fds = events;
+  dp.dp_nfds = 128;
+  dp.dp_timeout = timeout;
+  int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
+
+  lock.lock();
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    int descriptor = events[i].fd;
+    if (descriptor == interrupter_.read_descriptor())
+    {
+      interrupter_.reset();
+    }
+    else
+    {
+      bool more_reads = false;
+      bool more_writes = false;
+      bool more_except = false;
+
+      // Exception operations must be processed first to ensure that any
+      // out-of-band data is read before normal data.
+      if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
+        more_except =
+          op_queue_[except_op].perform_operations(descriptor, ops);
+      else
+        more_except = op_queue_[except_op].has_operation(descriptor);
+
+      if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+        more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
+      else
+        more_reads = op_queue_[read_op].has_operation(descriptor);
+
+      if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+        more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
+      else
+        more_writes = op_queue_[write_op].has_operation(descriptor);
+
+      if ((events[i].events & (POLLERR | POLLHUP)) != 0
+            && !more_except && !more_reads && !more_writes)
+      {
+        // If we have an event and no operations associated with the
+        // descriptor then we need to delete the descriptor from /dev/poll.
+        // The poll operation can produce POLLHUP or POLLERR events when there
+        // is no operation pending, so if we do not remove the descriptor we
+        // can end up in a tight polling loop.
+        ::pollfd ev = { 0 };
+        ev.fd = descriptor;
+        ev.events = POLLREMOVE;
+        ev.revents = 0;
+        ::write(dev_poll_fd_, &ev, sizeof(ev));
+      }
+      else
+      {
+        ::pollfd ev = { 0 };
+        ev.fd = descriptor;
+        ev.events = POLLERR | POLLHUP;
+        if (more_reads)
+          ev.events |= POLLIN;
+        if (more_writes)
+          ev.events |= POLLOUT;
+        if (more_except)
+          ev.events |= POLLPRI;
+        ev.revents = 0;
+        int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
+        if (result != sizeof(ev))
+        {
+          asio::error_code ec(errno,
+              asio::error::get_system_category());
+          for (int j = 0; j < max_ops; ++j)
+            op_queue_[j].cancel_operations(descriptor, ops, ec);
+        }
+      }
+    }
+  }
+  timer_queues_.get_ready_timers(ops);
+}
+
+void dev_poll_reactor::interrupt()
+{
+  interrupter_.interrupt();
+}
+
+int dev_poll_reactor::do_dev_poll_create()
+{
+  int fd = ::open("/dev/poll", O_RDWR);
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "/dev/poll");
+  }
+  return fd;
+}
+
+void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+int dev_poll_reactor::get_timeout()
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+}
+
+void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
+    const asio::error_code& ec)
+{
+  bool need_interrupt = false;
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+    need_interrupt = op_queue_[i].cancel_operations(
+        descriptor, ops, ec) || need_interrupt;
+  io_service_.post_deferred_completions(ops);
+  if (need_interrupt)
+    interrupter_.interrupt();
+}
+
+::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)
+{
+  hash_map<int, std::size_t>::iterator iter
+    = pending_event_change_index_.find(descriptor);
+  if (iter == pending_event_change_index_.end())
+  {
+    std::size_t index = pending_event_changes_.size();
+    pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+    pending_event_change_index_.insert(std::make_pair(descriptor, index));
+    pending_event_changes_.push_back(::pollfd());
+    pending_event_changes_[index].fd = descriptor;
+    pending_event_changes_[index].revents = 0;
+    return pending_event_changes_[index];
+  }
+  else
+  {
+    return pending_event_changes_[iter->second];
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/epoll_reactor.hpp b/ext/asio/asio/detail/impl/epoll_reactor.hpp
new file mode 100644
index 0000000..9f50a23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/epoll_reactor.hpp
@@ -0,0 +1,75 @@
+//
+// detail/impl/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    io_service_.post_immediate_completion(op);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  io_service_.work_started();
+  if (earliest)
+    update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops);
+  lock.unlock();
+  io_service_.post_deferred_completions(ops);
+  return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/epoll_reactor.ipp b/ext/asio/asio/detail/impl/epoll_reactor.ipp
new file mode 100644
index 0000000..a95b8f2
--- /dev/null
+++ b/ext/asio/asio/detail/impl/epoll_reactor.ipp
@@ -0,0 +1,390 @@
+//
+// detail/impl/epoll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include <cstddef>
+#include <sys/epoll.h>
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+epoll_reactor::epoll_reactor(asio::io_service& io_service)
+  : asio::detail::service_base<epoll_reactor>(io_service),
+    io_service_(use_service<io_service_impl>(io_service)),
+    mutex_(),
+    epoll_fd_(do_epoll_create()),
+#if defined(ASIO_HAS_TIMERFD)
+    timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
+#else // defined(ASIO_HAS_TIMERFD)
+    timer_fd_(-1),
+#endif // defined(ASIO_HAS_TIMERFD)
+    interrupter_(),
+    shutdown_(false)
+{
+  // Add the interrupter's descriptor to epoll.
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+  ev.data.ptr = &interrupter_;
+  epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+  interrupter_.interrupt();
+
+  // Add the timer descriptor to epoll.
+  if (timer_fd_ != -1)
+  {
+    ev.events = EPOLLIN | EPOLLERR;
+    ev.data.ptr = &timer_fd_;
+    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+  }
+}
+
+epoll_reactor::~epoll_reactor()
+{
+  close(epoll_fd_);
+  if (timer_fd_ != -1)
+    close(timer_fd_);
+}
+
+void epoll_reactor::shutdown_service()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  while (descriptor_state* state = registered_descriptors_.first())
+  {
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(state->op_queue_[i]);
+    state->shutdown_ = true;
+    registered_descriptors_.free(state);
+  }
+
+  timer_queues_.get_all_timers(ops);
+}
+
+void epoll_reactor::init_task()
+{
+  io_service_.init_task();
+}
+
+int epoll_reactor::register_descriptor(socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  mutex::scoped_lock lock(registered_descriptors_mutex_);
+
+  descriptor_data = registered_descriptors_.alloc();
+  descriptor_data->shutdown_ = false;
+
+  lock.unlock();
+
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
+  ev.data.ptr = descriptor_data;
+  int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+  if (result != 0)
+    return errno;
+
+  return 0;
+}
+
+void epoll_reactor::start_op(int op_type, socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data,
+    reactor_op* op, bool allow_speculative)
+{
+  if (!descriptor_data)
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    post_immediate_completion(op);
+    return;
+  }
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (descriptor_data->shutdown_)
+  {
+    post_immediate_completion(op);
+    return;
+  }
+
+  if (descriptor_data->op_queue_[op_type].empty())
+  {
+    if (allow_speculative
+        && (op_type != read_op
+          || descriptor_data->op_queue_[except_op].empty()))
+    {
+      if (op->perform())
+      {
+        descriptor_lock.unlock();
+        io_service_.post_immediate_completion(op);
+        return;
+      }
+    }
+    else
+    {
+      epoll_event ev = { 0, { 0 } };
+      ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
+        | EPOLLOUT | EPOLLPRI | EPOLLET;
+      ev.data.ptr = descriptor_data;
+      epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+    }
+  }
+
+  descriptor_data->op_queue_[op_type].push(op);
+  io_service_.work_started();
+}
+
+void epoll_reactor::cancel_ops(socket_type,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+  {
+    while (reactor_op* op = descriptor_data->op_queue_[i].front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      descriptor_data->op_queue_[i].pop();
+      ops.push(op);
+    }
+  }
+
+  descriptor_lock.unlock();
+
+  io_service_.post_deferred_completions(ops);
+}
+
+void epoll_reactor::close_descriptor(socket_type,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    // Remove the descriptor from the set of known descriptors. The descriptor
+    // will be automatically removed from the epoll set when it is closed.
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+    {
+      while (reactor_op* op = descriptor_data->op_queue_[i].front())
+      {
+        op->ec_ = asio::error::operation_aborted;
+        descriptor_data->op_queue_[i].pop();
+        ops.push(op);
+      }
+    }
+
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    registered_descriptors_.free(descriptor_data);
+    descriptor_data = 0;
+
+    descriptors_lock.unlock();
+
+    io_service_.post_deferred_completions(ops);
+  }
+}
+
+void epoll_reactor::run(bool block, op_queue<operation>& ops)
+{
+  // Calculate a timeout only if timerfd is not used.
+  int timeout;
+  if (timer_fd_ != -1)
+    timeout = block ? -1 : 0;
+  else
+  {
+    mutex::scoped_lock lock(mutex_);
+    timeout = block ? get_timeout() : 0;
+  }
+
+  // Block on the epoll descriptor.
+  epoll_event events[128];
+  int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
+
+#if defined(ASIO_HAS_TIMERFD)
+  bool check_timers = (timer_fd_ == -1);
+#else // defined(ASIO_HAS_TIMERFD)
+  bool check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    void* ptr = events[i].data.ptr;
+    if (ptr == &interrupter_)
+    {
+      // No need to reset the interrupter since we're leaving the descriptor
+      // in a ready-to-read state and relying on edge-triggered notifications
+      // to make it so that we only get woken up when the descriptor's epoll
+      // registration is updated.
+
+#if defined(ASIO_HAS_TIMERFD)
+      if (timer_fd_ == -1)
+        check_timers = true;
+#else // defined(ASIO_HAS_TIMERFD)
+      check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+    }
+#if defined(ASIO_HAS_TIMERFD)
+    else if (ptr == &timer_fd_)
+    {
+      check_timers = true;
+    }
+#endif // defined(ASIO_HAS_TIMERFD)
+    else
+    {
+      descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+      mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+      // Exception operations must be processed first to ensure that any
+      // out-of-band data is read before normal data.
+      static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+      for (int j = max_ops - 1; j >= 0; --j)
+      {
+        if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
+        {
+          while (reactor_op* op = descriptor_data->op_queue_[j].front())
+          {
+            if (op->perform())
+            {
+              descriptor_data->op_queue_[j].pop();
+              ops.push(op);
+            }
+            else
+              break;
+          }
+        }
+      }
+    }
+  }
+
+  if (check_timers)
+  {
+    mutex::scoped_lock common_lock(mutex_);
+    timer_queues_.get_ready_timers(ops);
+
+#if defined(ASIO_HAS_TIMERFD)
+    if (timer_fd_ != -1)
+    {
+      itimerspec new_timeout;
+      itimerspec old_timeout;
+      int flags = get_timeout(new_timeout);
+      timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+    }
+#endif // defined(ASIO_HAS_TIMERFD)
+  }
+}
+
+void epoll_reactor::interrupt()
+{
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+  ev.data.ptr = &interrupter_;
+  epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
+}
+
+int epoll_reactor::do_epoll_create()
+{
+  int fd = epoll_create(epoll_size);
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "epoll");
+  }
+  return fd;
+}
+
+void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+void epoll_reactor::update_timeout()
+{
+#if defined(ASIO_HAS_TIMERFD)
+  if (timer_fd_ != -1)
+  {
+    itimerspec new_timeout;
+    itimerspec old_timeout;
+    int flags = get_timeout(new_timeout);
+    timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+    return;
+  }
+#endif // defined(ASIO_HAS_TIMERFD)
+  interrupt();
+}
+
+int epoll_reactor::get_timeout()
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+}
+
+#if defined(ASIO_HAS_TIMERFD)
+int epoll_reactor::get_timeout(itimerspec& ts)
+{
+  ts.it_interval.tv_sec = 0;
+  ts.it_interval.tv_nsec = 0;
+
+  long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+  ts.it_value.tv_sec = usec / 1000000;
+  ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
+
+  return usec ? 0 : TFD_TIMER_ABSTIME;
+}
+#endif // defined(ASIO_HAS_TIMERFD)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
new file mode 100644
index 0000000..959d356
--- /dev/null
+++ b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
@@ -0,0 +1,125 @@
+//
+// detail/impl/eventfd_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <asm/unistd.h>
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <sys/eventfd.h>
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+#include "asio/detail/eventfd_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+eventfd_select_interrupter::eventfd_select_interrupter()
+{
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+  write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+  write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+  if (read_descriptor_ != -1)
+  {
+    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+  }
+  else
+  {
+    int pipe_fds[2];
+    if (pipe(pipe_fds) == 0)
+    {
+      read_descriptor_ = pipe_fds[0];
+      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+      write_descriptor_ = pipe_fds[1];
+      ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+    }
+    else
+    {
+      asio::error_code ec(errno,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "eventfd_select_interrupter");
+    }
+  }
+}
+
+eventfd_select_interrupter::~eventfd_select_interrupter()
+{
+  if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
+    ::close(write_descriptor_);
+  if (read_descriptor_ != -1)
+    ::close(read_descriptor_);
+}
+
+void eventfd_select_interrupter::interrupt()
+{
+  uint64_t counter(1UL);
+  int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
+  (void)result;
+}
+
+bool eventfd_select_interrupter::reset()
+{
+  if (write_descriptor_ == read_descriptor_)
+  {
+    for (;;)
+    {
+      // Only perform one read. The kernel maintains an atomic counter.
+      uint64_t counter(0);
+      errno = 0;
+      int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
+      if (bytes_read < 0 && errno == EINTR)
+        continue;
+      bool was_interrupted = (bytes_read > 0);
+      return was_interrupted;
+    }
+  }
+  else
+  {
+    for (;;)
+    {
+      // Clear all data from the pipe.
+      char data[1024];
+      int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+      if (bytes_read < 0 && errno == EINTR)
+        continue;
+      bool was_interrupted = (bytes_read > 0);
+      while (bytes_read == sizeof(data))
+        bytes_read = ::read(read_descriptor_, data, sizeof(data));
+      return was_interrupted;
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.hpp b/ext/asio/asio/detail/impl/kqueue_reactor.hpp
new file mode 100644
index 0000000..7950c3b
--- /dev/null
+++ b/ext/asio/asio/detail/impl/kqueue_reactor.hpp
@@ -0,0 +1,79 @@
+//
+// detail/impl/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    io_service_.post_immediate_completion(op);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  io_service_.work_started();
+  if (earliest)
+    interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops);
+  lock.unlock();
+  io_service_.post_deferred_completions(ops);
+  return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.ipp b/ext/asio/asio/detail/impl/kqueue_reactor.ipp
new file mode 100644
index 0000000..8db77cb
--- /dev/null
+++ b/ext/asio/asio/detail/impl/kqueue_reactor.ipp
@@ -0,0 +1,385 @@
+//
+// detail/impl/kqueue_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(__NetBSD__)
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+    EV_SET(ev, ident, filt, flags, fflags, \
+      data, reinterpret_cast<intptr_t>(udata))
+#else
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+    EV_SET(ev, ident, filt, flags, fflags, data, udata)
+#endif
+
+namespace asio {
+namespace detail {
+
+kqueue_reactor::kqueue_reactor(asio::io_service& io_service)
+  : asio::detail::service_base<kqueue_reactor>(io_service),
+    io_service_(use_service<io_service_impl>(io_service)),
+    mutex_(),
+    kqueue_fd_(do_kqueue_create()),
+    interrupter_(),
+    shutdown_(false)
+{
+  // The interrupter is put into a permanently readable state. Whenever we
+  // want to interrupt the blocked kevent call we register a one-shot read
+  // operation against the descriptor.
+  interrupter_.interrupt();
+}
+
+kqueue_reactor::~kqueue_reactor()
+{
+  close(kqueue_fd_);
+}
+
+void kqueue_reactor::shutdown_service()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  while (descriptor_state* state = registered_descriptors_.first())
+  {
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(state->op_queue_[i]);
+    state->shutdown_ = true;
+    registered_descriptors_.free(state);
+  }
+
+  timer_queues_.get_all_timers(ops);
+}
+
+void kqueue_reactor::init_task()
+{
+  io_service_.init_task();
+}
+
+int kqueue_reactor::register_descriptor(socket_type,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  mutex::scoped_lock lock(registered_descriptors_mutex_);
+
+  descriptor_data = registered_descriptors_.alloc();
+  descriptor_data->shutdown_ = false;
+
+  return 0;
+}
+
+void kqueue_reactor::start_op(int op_type, socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data,
+    reactor_op* op, bool allow_speculative)
+{
+  if (!descriptor_data)
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    post_immediate_completion(op);
+    return;
+  }
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (descriptor_data->shutdown_)
+  {
+    post_immediate_completion(op);
+    return;
+  }
+
+  bool first = descriptor_data->op_queue_[op_type].empty();
+  if (first)
+  {
+    if (allow_speculative)
+    {
+      if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
+      {
+        if (op->perform())
+        {
+          descriptor_lock.unlock();
+          io_service_.post_immediate_completion(op);
+          return;
+        }
+      }
+    }
+  }
+
+  descriptor_data->op_queue_[op_type].push(op);
+  io_service_.work_started();
+
+  if (first)
+  {
+    struct kevent event;
+    switch (op_type)
+    {
+    case read_op:
+      ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+          EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+      break;
+    case write_op:
+      ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
+          EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+      break;
+    case except_op:
+      if (!descriptor_data->op_queue_[read_op].empty())
+        return; // Already registered for read events.
+      ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+          EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+      break;
+    }
+
+    if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+    {
+      op->ec_ = asio::error_code(errno,
+          asio::error::get_system_category());
+      descriptor_data->op_queue_[op_type].pop();
+      io_service_.post_deferred_completion(op);
+    }
+  }
+}
+
+void kqueue_reactor::cancel_ops(socket_type,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+  {
+    while (reactor_op* op = descriptor_data->op_queue_[i].front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      descriptor_data->op_queue_[i].pop();
+      ops.push(op);
+    }
+  }
+
+  descriptor_lock.unlock();
+
+  io_service_.post_deferred_completions(ops);
+}
+
+void kqueue_reactor::close_descriptor(socket_type,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    // Remove the descriptor from the set of known descriptors. The descriptor
+    // will be automatically removed from the kqueue set when it is closed.
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+    {
+      while (reactor_op* op = descriptor_data->op_queue_[i].front())
+      {
+        op->ec_ = asio::error::operation_aborted;
+        descriptor_data->op_queue_[i].pop();
+        ops.push(op);
+      }
+    }
+
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    registered_descriptors_.free(descriptor_data);
+    descriptor_data = 0;
+
+    descriptors_lock.unlock();
+
+    io_service_.post_deferred_completions(ops);
+  }
+}
+
+void kqueue_reactor::run(bool block, op_queue<operation>& ops)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  // Determine how long to block while waiting for events.
+  timespec timeout_buf = { 0, 0 };
+  timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
+
+  lock.unlock();
+
+  // Block on the kqueue descriptor.
+  struct kevent events[128];
+  int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    int descriptor = events[i].ident;
+    void* ptr = reinterpret_cast<void*>(events[i].udata);
+    if (ptr == &interrupter_)
+    {
+      // No need to reset the interrupter since we're leaving the descriptor
+      // in a ready-to-read state and relying on one-shot notifications.
+    }
+    else
+    {
+      descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+      mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+      // Exception operations must be processed first to ensure that any
+      // out-of-band data is read before normal data.
+#if defined(__NetBSD__)
+      static const unsigned int filter[max_ops] =
+#else
+      static const int filter[max_ops] =
+#endif
+        { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
+      for (int j = max_ops - 1; j >= 0; --j)
+      {
+        if (events[i].filter == filter[j])
+        {
+          if (j != except_op || events[i].flags & EV_OOBAND)
+          {
+            while (reactor_op* op = descriptor_data->op_queue_[j].front())
+            {
+              if (events[i].flags & EV_ERROR)
+              {
+                op->ec_ = asio::error_code(events[i].data,
+                    asio::error::get_system_category());
+                descriptor_data->op_queue_[j].pop();
+                ops.push(op);
+              }
+              if (op->perform())
+              {
+                descriptor_data->op_queue_[j].pop();
+                ops.push(op);
+              }
+              else
+                break;
+            }
+          }
+        }
+      }
+
+      // Renew registration for event notifications.
+      struct kevent event;
+      switch (events[i].filter)
+      {
+      case EVFILT_READ:
+        if (!descriptor_data->op_queue_[read_op].empty())
+          ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+              EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+        else if (!descriptor_data->op_queue_[except_op].empty())
+          ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+              EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+        else
+          continue;
+      case EVFILT_WRITE:
+        if (!descriptor_data->op_queue_[write_op].empty())
+          ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
+              EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+        else
+          continue;
+      default:
+        break;
+      }
+      if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+      {
+        asio::error_code error(errno,
+            asio::error::get_system_category());
+        for (int j = 0; j < max_ops; ++j)
+        {
+          while (reactor_op* op = descriptor_data->op_queue_[j].front())
+          {
+            op->ec_ = error;
+            descriptor_data->op_queue_[j].pop();
+            ops.push(op);
+          }
+        }
+      }
+    }
+  }
+
+  lock.lock();
+  timer_queues_.get_ready_timers(ops);
+}
+
+void kqueue_reactor::interrupt()
+{
+  struct kevent event;
+  ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(),
+      EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
+  ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
+}
+
+int kqueue_reactor::do_kqueue_create()
+{
+  int fd = ::kqueue();
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "kqueue");
+  }
+  return fd;
+}
+
+void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+timespec* kqueue_reactor::get_timeout(timespec& ts)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+  ts.tv_sec = usec / 1000000;
+  ts.tv_nsec = (usec % 1000000) * 1000;
+  return &ts;
+}
+
+} // namespace detail
+} // namespace asio
+
+#undef ASIO_KQUEUE_EV_SET
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
new file mode 100644
index 0000000..aac20d4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
@@ -0,0 +1,96 @@
+//
+// detail/impl/pipe_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "asio/detail/pipe_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+pipe_select_interrupter::pipe_select_interrupter()
+{
+  int pipe_fds[2];
+  if (pipe(pipe_fds) == 0)
+  {
+    read_descriptor_ = pipe_fds[0];
+    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+    write_descriptor_ = pipe_fds[1];
+    ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+  }
+  else
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "pipe_select_interrupter");
+  }
+}
+
+pipe_select_interrupter::~pipe_select_interrupter()
+{
+  if (read_descriptor_ != -1)
+    ::close(read_descriptor_);
+  if (write_descriptor_ != -1)
+    ::close(write_descriptor_);
+}
+
+void pipe_select_interrupter::interrupt()
+{
+  char byte = 0;
+  int result = ::write(write_descriptor_, &byte, 1);
+  (void)result;
+}
+
+bool pipe_select_interrupter::reset()
+{
+  for (;;)
+  {
+    char data[1024];
+    int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+    if (bytes_read < 0 && errno == EINTR)
+      continue;
+    bool was_interrupted = (bytes_read > 0);
+    while (bytes_read == sizeof(data))
+      bytes_read = ::read(read_descriptor_, data, sizeof(data));
+    return was_interrupted;
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/posix_event.ipp b/ext/asio/asio/detail/impl/posix_event.ipp
new file mode 100644
index 0000000..3206418
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_event.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_event.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_event::posix_event()
+  : signalled_(false)
+{
+  int error = ::pthread_cond_init(&cond_, 0);
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "event");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
diff --git a/ext/asio/asio/detail/impl/posix_mutex.ipp b/ext/asio/asio/detail/impl/posix_mutex.ipp
new file mode 100644
index 0000000..12b6659
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_mutex.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_mutex.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_mutex::posix_mutex()
+{
+  int error = ::pthread_mutex_init(&mutex_, 0);
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "mutex");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
diff --git a/ext/asio/asio/detail/impl/posix_thread.ipp b/ext/asio/asio/detail/impl/posix_thread.ipp
new file mode 100644
index 0000000..ce91c57
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_thread.ipp
@@ -0,0 +1,74 @@
+//
+// detail/impl/posix_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_thread.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_thread::~posix_thread()
+{
+  if (!joined_)
+    ::pthread_detach(thread_);
+}
+
+void posix_thread::join()
+{
+  if (!joined_)
+  {
+    ::pthread_join(thread_, 0);
+    joined_ = true;
+  }
+}
+
+void posix_thread::start_thread(func_base* arg)
+{
+  int error = ::pthread_create(&thread_, 0,
+        asio_detail_posix_thread_function, arg);
+  if (error != 0)
+  {
+    delete arg;
+    asio::error_code ec(error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread");
+  }
+}
+
+void* asio_detail_posix_thread_function(void* arg)
+{
+  posix_thread::auto_func_base_ptr func = {
+      static_cast<posix_thread::func_base*>(arg) };
+  func.ptr->run();
+  return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
diff --git a/ext/asio/asio/detail/impl/posix_tss_ptr.ipp b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp
new file mode 100644
index 0000000..89b40f7
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_tss_ptr.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void posix_tss_ptr_create(pthread_key_t& key)
+{
+  int error = ::pthread_key_create(&key, 0);
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "tss");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
new file mode 100644
index 0000000..706d60f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
@@ -0,0 +1,136 @@
+//
+// detail/impl/reactive_descriptor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/error.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_descriptor_service::reactive_descriptor_service(
+    asio::io_service& io_service)
+  : reactor_(asio::use_service<reactor>(io_service))
+{
+  reactor_.init_task();
+}
+
+void reactive_descriptor_service::shutdown_service()
+{
+}
+
+void reactive_descriptor_service::construct(
+    reactive_descriptor_service::implementation_type& impl)
+{
+  impl.descriptor_ = -1;
+  impl.state_ = 0;
+}
+
+void reactive_descriptor_service::destroy(
+    reactive_descriptor_service::implementation_type& impl)
+{
+  if (is_open(impl))
+    reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+  asio::error_code ignored_ec;
+  descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
+}
+
+asio::error_code reactive_descriptor_service::assign(
+    reactive_descriptor_service::implementation_type& impl,
+    const native_type& native_descriptor, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (int err = reactor_.register_descriptor(
+        native_descriptor, impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.descriptor_ = native_descriptor;
+  impl.state_ = 0;
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_descriptor_service::close(
+    reactive_descriptor_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+    reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+  if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0)
+    construct(impl);
+
+  return ec;
+}
+
+asio::error_code reactive_descriptor_service::cancel(
+    reactive_descriptor_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
+  ec = asio::error_code();
+  return ec;
+}
+
+void reactive_descriptor_service::start_op(
+    reactive_descriptor_service::implementation_type& impl,
+    int op_type, reactor_op* op, bool non_blocking, bool noop)
+{
+  if (!noop)
+  {
+    if ((impl.state_ & descriptor_ops::non_blocking) ||
+        descriptor_ops::set_internal_non_blocking(
+          impl.descriptor_, impl.state_, op->ec_))
+    {
+      reactor_.start_op(op_type, impl.descriptor_,
+          impl.reactor_data_, op, non_blocking);
+      return;
+    }
+  }
+
+  reactor_.post_immediate_completion(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
new file mode 100644
index 0000000..c4df793
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
@@ -0,0 +1,151 @@
+//
+// detail/impl/reactive_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <cstring>
+#include "asio/detail/reactive_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_serial_port_service::reactive_serial_port_service(
+    asio::io_service& io_service)
+  : descriptor_service_(io_service)
+{
+}
+
+void reactive_serial_port_service::shutdown_service()
+{
+  descriptor_service_.shutdown_service();
+}
+
+asio::error_code reactive_serial_port_service::open(
+    reactive_serial_port_service::implementation_type& impl,
+    const std::string& device, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  descriptor_ops::state_type state = 0;
+  int fd = descriptor_ops::open(device.c_str(),
+      O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
+  if (fd < 0)
+    return ec;
+
+  int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
+  if (s >= 0)
+    s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
+  if (s < 0)
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+    return ec;
+  }
+
+  // Set up default serial port options.
+  termios ios;
+  errno = 0;
+  s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
+  if (s >= 0)
+  {
+#if defined(_BSD_SOURCE)
+    ::cfmakeraw(&ios);
+#else
+    ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
+        | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+    ios.c_oflag &= ~OPOST;
+    ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+    ios.c_cflag &= ~(CSIZE | PARENB);
+    ios.c_cflag |= CS8;
+#endif
+    ios.c_iflag |= IGNPAR;
+    ios.c_cflag |= CREAD | CLOCAL;
+    errno = 0;
+    s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
+  }
+  if (s < 0)
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+    return ec;
+  }
+
+  // We're done. Take ownership of the serial port descriptor.
+  if (descriptor_service_.assign(impl, fd, ec))
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+  }
+
+  return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_set_option(
+    reactive_serial_port_service::implementation_type& impl,
+    reactive_serial_port_service::store_function_type store,
+    const void* option, asio::error_code& ec)
+{
+  termios ios;
+  errno = 0;
+  descriptor_ops::error_wrapper(::tcgetattr(
+        descriptor_service_.native(impl), &ios), ec);
+  if (ec)
+    return ec;
+
+  if (store(option, ios, ec))
+    return ec;
+
+  errno = 0;
+  descriptor_ops::error_wrapper(::tcsetattr(
+        descriptor_service_.native(impl), TCSANOW, &ios), ec);
+  return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_get_option(
+    const reactive_serial_port_service::implementation_type& impl,
+    reactive_serial_port_service::load_function_type load,
+    void* option, asio::error_code& ec) const
+{
+  termios ios;
+  errno = 0;
+  descriptor_ops::error_wrapper(::tcgetattr(
+        descriptor_service_.native(impl), &ios), ec);
+  if (ec)
+    return ec;
+
+  return load(option, ios, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
new file mode 100644
index 0000000..54e7944
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
@@ -0,0 +1,212 @@
+//
+// detail/reactive_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/reactive_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base::reactive_socket_service_base(
+    asio::io_service& io_service)
+  : reactor_(use_service<reactor>(io_service))
+{
+  reactor_.init_task();
+}
+
+void reactive_socket_service_base::shutdown_service()
+{
+}
+
+void reactive_socket_service_base::construct(
+    reactive_socket_service_base::base_implementation_type& impl)
+{
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+}
+
+void reactive_socket_service_base::destroy(
+    reactive_socket_service_base::base_implementation_type& impl)
+{
+  if (impl.socket_ != invalid_socket)
+  {
+    reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+    asio::error_code ignored_ec;
+    socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+  }
+}
+
+asio::error_code reactive_socket_service_base::close(
+    reactive_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+    reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+  if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0)
+    construct(impl);
+
+  return ec;
+}
+
+asio::error_code reactive_socket_service_base::cancel(
+    reactive_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_open(
+    reactive_socket_service_base::base_implementation_type& impl,
+    int af, int type, int protocol, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+  if (sock.get() == invalid_socket)
+    return ec;
+
+  if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.socket_ = sock.release();
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_assign(
+    reactive_socket_service_base::base_implementation_type& impl, int type,
+    const reactive_socket_service_base::native_type& native_socket,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (int err = reactor_.register_descriptor(
+        native_socket, impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.socket_ = native_socket;
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  ec = asio::error_code();
+  return ec;
+}
+
+void reactive_socket_service_base::start_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    int op_type, reactor_op* op, bool non_blocking, bool noop)
+{
+  if (!noop)
+  {
+    if ((impl.state_ & socket_ops::non_blocking)
+        || socket_ops::set_internal_non_blocking(
+          impl.socket_, impl.state_, op->ec_))
+    {
+      reactor_.start_op(op_type, impl.socket_,
+          impl.reactor_data_, op, non_blocking);
+      return;
+    }
+  }
+
+  reactor_.post_immediate_completion(op);
+}
+
+void reactive_socket_service_base::start_accept_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactor_op* op, bool peer_is_open)
+{
+  if (!peer_is_open)
+    start_op(impl, reactor::read_op, op, true, false);
+  else
+  {
+    op->ec_ = asio::error::already_open;
+    reactor_.post_immediate_completion(op);
+  }
+}
+
+void reactive_socket_service_base::start_connect_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactor_op* op, const socket_addr_type* addr, size_t addrlen)
+{
+  if ((impl.state_ & socket_ops::non_blocking)
+      || socket_ops::set_internal_non_blocking(
+        impl.socket_, impl.state_, op->ec_))
+  {
+    if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+    {
+      if (op->ec_ == asio::error::in_progress
+          || op->ec_ == asio::error::would_block)
+      {
+        op->ec_ = asio::error_code();
+        reactor_.start_op(reactor::connect_op,
+            impl.socket_, impl.reactor_data_, op, false);
+        return;
+      }
+    }
+  }
+
+  reactor_.post_immediate_completion(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/resolver_service_base.ipp b/ext/asio/asio/detail/impl/resolver_service_base.ipp
new file mode 100644
index 0000000..a844a23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/resolver_service_base.ipp
@@ -0,0 +1,106 @@
+//
+// detail/impl/resolver_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base::work_io_service_runner
+{
+public:
+  work_io_service_runner(asio::io_service& io_service)
+    : io_service_(io_service) {}
+  void operator()() { io_service_.run(); }
+private:
+  asio::io_service& io_service_;
+};
+
+resolver_service_base::resolver_service_base(
+    asio::io_service& io_service)
+  : io_service_impl_(asio::use_service<io_service_impl>(io_service)),
+    work_io_service_(new asio::io_service),
+    work_io_service_impl_(asio::use_service<
+        io_service_impl>(*work_io_service_)),
+    work_(new asio::io_service::work(*work_io_service_)),
+    work_thread_(0)
+{
+}
+
+resolver_service_base::~resolver_service_base()
+{
+  shutdown_service();
+}
+
+void resolver_service_base::shutdown_service()
+{
+  work_.reset();
+  if (work_io_service_)
+  {
+    work_io_service_->stop();
+    if (work_thread_)
+    {
+      work_thread_->join();
+      work_thread_.reset();
+    }
+    work_io_service_.reset();
+  }
+}
+
+void resolver_service_base::construct(
+    resolver_service_base::implementation_type& impl)
+{
+  impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::destroy(
+    resolver_service_base::implementation_type&)
+{
+}
+
+void resolver_service_base::cancel(
+    resolver_service_base::implementation_type& impl)
+{
+  impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::start_resolve_op(operation* op)
+{
+  start_work_thread();
+  io_service_impl_.work_started();
+  work_io_service_impl_.post_immediate_completion(op);
+}
+
+void resolver_service_base::start_work_thread()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (!work_thread_)
+  {
+    work_thread_.reset(new asio::detail::thread(
+          work_io_service_runner(*work_io_service_)));
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/select_reactor.hpp b/ext/asio/asio/detail/impl/select_reactor.hpp
new file mode 100644
index 0000000..50d3ad4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/select_reactor.hpp
@@ -0,0 +1,84 @@
+//
+// detail/impl/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    io_service_.post_immediate_completion(op);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  io_service_.work_started();
+  if (earliest)
+    interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops);
+  lock.unlock();
+  io_service_.post_deferred_completions(ops);
+  return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/select_reactor.ipp b/ext/asio/asio/detail/impl/select_reactor.ipp
new file mode 100644
index 0000000..1a59be3
--- /dev/null
+++ b/ext/asio/asio/detail/impl/select_reactor.ipp
@@ -0,0 +1,273 @@
+//
+// detail/impl/select_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE))
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+select_reactor::select_reactor(asio::io_service& io_service)
+  : asio::detail::service_base<select_reactor>(io_service),
+    io_service_(use_service<io_service_impl>(io_service)),
+    mutex_(),
+    interrupter_(),
+#if defined(ASIO_HAS_IOCP)
+    stop_thread_(false),
+    thread_(0),
+#endif // defined(ASIO_HAS_IOCP)
+    shutdown_(false)
+{
+#if defined(ASIO_HAS_IOCP)
+  asio::detail::signal_blocker sb;
+  thread_ = new asio::detail::thread(
+      bind_handler(&select_reactor::call_run_thread, this));
+#endif // defined(ASIO_HAS_IOCP)
+}
+
+select_reactor::~select_reactor()
+{
+  shutdown_service();
+}
+
+void select_reactor::shutdown_service()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+#if defined(ASIO_HAS_IOCP)
+  stop_thread_ = true;
+#endif // defined(ASIO_HAS_IOCP)
+  lock.unlock();
+
+#if defined(ASIO_HAS_IOCP)
+  if (thread_)
+  {
+    interrupter_.interrupt();
+    thread_->join();
+    delete thread_;
+    thread_ = 0;
+  }
+#endif // defined(ASIO_HAS_IOCP)
+
+  op_queue<operation> ops;
+
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].get_all_operations(ops);
+
+  timer_queues_.get_all_timers(ops);
+}
+
+void select_reactor::init_task()
+{
+  io_service_.init_task();
+}
+
+int select_reactor::register_descriptor(socket_type,
+    select_reactor::per_descriptor_data&)
+{
+  return 0;
+}
+
+void select_reactor::start_op(int op_type, socket_type descriptor,
+    select_reactor::per_descriptor_data&, reactor_op* op, bool)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    post_immediate_completion(op);
+    return;
+  }
+
+  bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+  io_service_.work_started();
+  if (first)
+    interrupter_.interrupt();
+}
+
+void select_reactor::cancel_ops(socket_type descriptor,
+    select_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::close_descriptor(socket_type descriptor,
+    select_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::run(bool block, op_queue<operation>& ops)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_IOCP)
+  // Check if the thread is supposed to stop.
+  if (stop_thread_)
+    return;
+#endif // defined(ASIO_HAS_IOCP)
+
+  // Set up the descriptor sets.
+  fd_set_adapter fds[max_select_ops];
+  fds[read_op].set(interrupter_.read_descriptor());
+  socket_type max_fd = 0;
+  bool have_work_to_do = !timer_queues_.all_empty();
+  for (int i = 0; i < max_select_ops; ++i)
+  {
+    have_work_to_do = have_work_to_do || !op_queue_[i].empty();
+    op_queue_[i].get_descriptors(fds[i], ops);
+    if (fds[i].max_descriptor() > max_fd)
+      max_fd = fds[i].max_descriptor();
+  }
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  // Connection operations on Windows use both except and write fd_sets.
+  have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
+  op_queue_[connect_op].get_descriptors(fds[write_op], ops);
+  if (fds[write_op].max_descriptor() > max_fd)
+    max_fd = fds[write_op].max_descriptor();
+  op_queue_[connect_op].get_descriptors(fds[except_op], ops);
+  if (fds[except_op].max_descriptor() > max_fd)
+    max_fd = fds[except_op].max_descriptor();
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+  // We can return immediately if there's no work to do and the reactor is
+  // not supposed to block.
+  if (!block && !have_work_to_do)
+    return;
+
+  // Determine how long to block while waiting for events.
+  timeval tv_buf = { 0, 0 };
+  timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
+
+  lock.unlock();
+
+  // Block on the select call until descriptors become ready.
+  asio::error_code ec;
+  int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+      fds[read_op], fds[write_op], fds[except_op], tv, ec);
+
+  // Reset the interrupter.
+  if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
+    interrupter_.reset();
+
+  lock.lock();
+
+  // Dispatch all ready operations.
+  if (retval > 0)
+  {
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    // Connection operations on Windows use both except and write fd_sets.
+    op_queue_[connect_op].perform_operations_for_descriptors(
+        fds[except_op], ops);
+    op_queue_[connect_op].perform_operations_for_descriptors(
+        fds[write_op], ops);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+    // Exception operations must be processed first to ensure that any
+    // out-of-band data is read before normal data.
+    for (int i = max_select_ops - 1; i >= 0; --i)
+      op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
+  }
+  timer_queues_.get_ready_timers(ops);
+}
+
+void select_reactor::interrupt()
+{
+  interrupter_.interrupt();
+}
+
+#if defined(ASIO_HAS_IOCP)
+void select_reactor::run_thread()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  while (!stop_thread_)
+  {
+    lock.unlock();
+    op_queue<operation> ops;
+    run(true, ops);
+    io_service_.post_deferred_completions(ops);
+    lock.lock();
+  }
+}
+
+void select_reactor::call_run_thread(select_reactor* reactor)
+{
+  reactor->run_thread();
+}
+#endif // defined(ASIO_HAS_IOCP)
+
+void select_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+timeval* select_reactor::get_timeout(timeval& tv)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+  tv.tv_sec = usec / 1000000;
+  tv.tv_usec = usec % 1000000;
+  return &tv;
+}
+
+void select_reactor::cancel_ops_unlocked(socket_type descriptor,
+    const asio::error_code& ec)
+{
+  bool need_interrupt = false;
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+    need_interrupt = op_queue_[i].cancel_operations(
+        descriptor, ops, ec) || need_interrupt;
+  io_service_.post_deferred_completions(ops);
+  if (need_interrupt)
+    interrupter_.interrupt();
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/service_registry.hpp b/ext/asio/asio/detail/impl/service_registry.hpp
new file mode 100644
index 0000000..c2aa9ec
--- /dev/null
+++ b/ext/asio/asio/detail/impl/service_registry.hpp
@@ -0,0 +1,70 @@
+//
+// detail/impl/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Service>
+Service& service_registry::use_service()
+{
+  asio::io_service::service::key key;
+  init_key(key, Service::id);
+  factory_type factory = &service_registry::create<Service>;
+  return *static_cast<Service*>(do_use_service(key, factory));
+}
+
+template <typename Service>
+void service_registry::add_service(Service* new_service)
+{
+  asio::io_service::service::key key;
+  init_key(key, Service::id);
+  return do_add_service(key, new_service);
+}
+
+template <typename Service>
+bool service_registry::has_service() const
+{
+  asio::io_service::service::key key;
+  init_key(key, Service::id);
+  return do_has_service(key);
+}
+
+#if !defined(ASIO_NO_TYPEID)
+template <typename Service>
+void service_registry::init_key(asio::io_service::service::key& key,
+    const asio::detail::service_id<Service>& /*id*/)
+{
+  key.type_info_ = &typeid(typeid_wrapper<Service>);
+  key.id_ = 0;
+}
+#endif // !defined(ASIO_NO_TYPEID)
+
+template <typename Service>
+asio::io_service::service* service_registry::create(
+    asio::io_service& owner)
+{
+  return new Service(owner);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
diff --git a/ext/asio/asio/detail/impl/service_registry.ipp b/ext/asio/asio/detail/impl/service_registry.ipp
new file mode 100644
index 0000000..57c57b8
--- /dev/null
+++ b/ext/asio/asio/detail/impl/service_registry.ipp
@@ -0,0 +1,164 @@
+//
+// detail/impl/service_registry.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+service_registry::service_registry(asio::io_service& o)
+  : owner_(o),
+    first_service_(0)
+{
+}
+
+service_registry::~service_registry()
+{
+  // Shutdown all services. This must be done in a separate loop before the
+  // services are destroyed since the destructors of user-defined handler
+  // objects may try to access other service objects.
+  asio::io_service::service* service = first_service_;
+  while (service)
+  {
+    service->shutdown_service();
+    service = service->next_;
+  }
+
+  // Destroy all services.
+  while (first_service_)
+  {
+    asio::io_service::service* next_service = first_service_->next_;
+    destroy(first_service_);
+    first_service_ = next_service;
+  }
+}
+
+void service_registry::init_key(asio::io_service::service::key& key,
+    const asio::io_service::id& id)
+{
+  key.type_info_ = 0;
+  key.id_ = &id;
+}
+
+bool service_registry::keys_match(
+    const asio::io_service::service::key& key1,
+    const asio::io_service::service::key& key2)
+{
+  if (key1.id_ && key2.id_)
+    if (key1.id_ == key2.id_)
+      return true;
+  if (key1.type_info_ && key2.type_info_)
+    if (*key1.type_info_ == *key2.type_info_)
+      return true;
+  return false;
+}
+
+void service_registry::destroy(asio::io_service::service* service)
+{
+  delete service;
+}
+
+asio::io_service::service* service_registry::do_use_service(
+    const asio::io_service::service::key& key,
+    factory_type factory)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // First see if there is an existing service object with the given key.
+  asio::io_service::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return service;
+    service = service->next_;
+  }
+
+  // Create a new service object. The service registry's mutex is not locked
+  // at this time to allow for nested calls into this function from the new
+  // service's constructor.
+  lock.unlock();
+  auto_service_ptr new_service = { factory(owner_) };
+  new_service.ptr_->key_ = key;
+  lock.lock();
+
+  // Check that nobody else created another service object of the same type
+  // while the lock was released.
+  service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return service;
+    service = service->next_;
+  }
+
+  // Service was successfully initialised, pass ownership to registry.
+  new_service.ptr_->next_ = first_service_;
+  first_service_ = new_service.ptr_;
+  new_service.ptr_ = 0;
+  return first_service_;
+}
+
+void service_registry::do_add_service(
+    const asio::io_service::service::key& key,
+    asio::io_service::service* new_service)
+{
+  if (&owner_ != &new_service->io_service())
+    boost::throw_exception(invalid_service_owner());
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Check if there is an existing service object with the given key.
+  asio::io_service::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      boost::throw_exception(service_already_exists());
+    service = service->next_;
+  }
+
+  // Take ownership of the service object.
+  new_service->key_ = key;
+  new_service->next_ = first_service_;
+  first_service_ = new_service;
+}
+
+bool service_registry::do_has_service(
+    const asio::io_service::service::key& key) const
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  asio::io_service::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return true;
+    service = service->next_;
+  }
+
+  return false;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
diff --git a/ext/asio/asio/detail/impl/socket_ops.ipp b/ext/asio/asio/detail/impl/socket_ops.ipp
new file mode 100644
index 0000000..66006ea
--- /dev/null
+++ b/ext/asio/asio/detail/impl/socket_ops.ipp
@@ -0,0 +1,2917 @@
+//
+// detail/impl/socket_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_OPS_IPP
+#define ASIO_DETAIL_SOCKET_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/assert.hpp>
+#include <boost/detail/workaround.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <new>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux)
+// HP-UX doesn't declare these functions extern "C", so they are declared again
+// here to avoid linker errors about undefined symbols.
+extern "C" char* if_indextoname(unsigned int, char*);
+extern "C" unsigned int if_nametoindex(const char*);
+#endif // defined(__hpux)
+
+inline void clear_last_error()
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  WSASetLastError(0);
+#else
+  errno = 0;
+#endif
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+    asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  ec = asio::error_code(WSAGetLastError(),
+      asio::error::get_system_category());
+#else
+  ec = asio::error_code(errno,
+      asio::error::get_system_category());
+#endif
+  return return_value;
+}
+
+template <typename SockLenType>
+inline socket_type call_accept(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+  socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
+  if (addrlen)
+    *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+ASIO_DECL
+socket_type accept(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return invalid_socket;
+  }
+
+  clear_last_error();
+
+  socket_type new_s = error_wrapper(call_accept(
+        &msghdr::msg_namelen, s, addr, addrlen), ec);
+  if (new_s == invalid_socket)
+    return new_s;
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+  int optval = 1;
+  int result = error_wrapper(::setsockopt(new_s,
+        SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+  if (result != 0)
+  {
+    ::close(new_s);
+    return invalid_socket;
+  }
+#endif
+
+  ec = asio::error_code();
+  return new_s;
+}
+
+ASIO_DECL
+socket_type sync_accept(socket_type s, state_type state,
+    socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec)
+{
+  // Accept a socket.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (new_socket != invalid_socket)
+      return new_socket;
+
+    // Operation failed.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+    {
+      if (state & user_set_non_blocking)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+    else if (ec == asio::error::connection_aborted)
+    {
+      if (state & enable_connection_aborted)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+#if defined(EPROTO)
+    else if (ec.value() == EPROTO)
+    {
+      if (state & enable_connection_aborted)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+#endif // defined(EPROTO)
+    else
+      return invalid_socket;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, ec) < 0)
+      return invalid_socket;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_accept(socket_type s,
+    void* output_buffer, DWORD address_length,
+    socket_addr_type* addr, std::size_t* addrlen,
+    socket_type new_socket, asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_aborted;
+
+  if (!ec)
+  {
+    // Get the address of the peer.
+    if (addr && addrlen)
+    {
+      LPSOCKADDR local_addr = 0;
+      int local_addr_length = 0;
+      LPSOCKADDR remote_addr = 0;
+      int remote_addr_length = 0;
+      GetAcceptExSockaddrs(output_buffer, 0, address_length,
+          address_length, &local_addr, &local_addr_length,
+          &remote_addr, &remote_addr_length);
+      if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
+      {
+        ec = asio::error::invalid_argument;
+      }
+      else
+      {
+        using namespace std; // For memcpy.
+        memcpy(addr, remote_addr, remote_addr_length);
+        *addrlen = static_cast<std::size_t>(remote_addr_length);
+      }
+    }
+
+    // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+    // and getpeername will work on the accepted socket.
+    SOCKET update_ctx_param = s;
+    socket_ops::state_type state = 0;
+    socket_ops::setsockopt(new_socket, state,
+          SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+          &update_ctx_param, sizeof(SOCKET), ec);
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_accept(socket_type s,
+    state_type state, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, socket_type& new_socket)
+{
+  for (;;)
+  {
+    // Accept the waiting connection.
+    new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (new_socket != invalid_socket)
+      return true;
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Operation failed.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+    {
+      if (state & user_set_non_blocking)
+        return true;
+      // Fall through to retry operation.
+    }
+    else if (ec == asio::error::connection_aborted)
+    {
+      if (state & enable_connection_aborted)
+        return true;
+      // Fall through to retry operation.
+    }
+#if defined(EPROTO)
+    else if (ec.value() == EPROTO)
+    {
+      if (state & enable_connection_aborted)
+        return true;
+      // Fall through to retry operation.
+    }
+#endif // defined(EPROTO)
+    else
+      return true;
+
+    return false;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+template <typename SockLenType>
+inline int call_bind(SockLenType msghdr::*,
+    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+  return ::bind(s, addr, (SockLenType)addrlen);
+}
+
+ASIO_DECL
+int bind(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+  int result = error_wrapper(call_bind(
+        &msghdr::msg_namelen, s, addr, addrlen), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int close(socket_type s, state_type& state,
+    bool destruction, asio::error_code& ec)
+{
+  int result = 0;
+  if (s != invalid_socket)
+  {
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    if ((state & non_blocking) && (state & user_set_linger))
+    {
+      ioctl_arg_type arg = 0;
+      ::ioctlsocket(s, FIONBIO, &arg);
+      state &= ~non_blocking;
+    }
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    if (state & non_blocking)
+    {
+#if defined(__SYMBIAN32__)
+      int flags = ::fcntl(s, F_GETFL, 0);
+      if (flags >= 0)
+        ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__)
+      ioctl_arg_type arg = 0;
+      ::ioctl(s, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__)
+      state &= ~non_blocking;
+    }
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+    if (destruction && (state & user_set_linger))
+    {
+      ::linger opt;
+      opt.l_onoff = 0;
+      opt.l_linger = 0;
+      asio::error_code ignored_ec;
+      socket_ops::setsockopt(s, state, SOL_SOCKET,
+          SO_LINGER, &opt, sizeof(opt), ignored_ec);
+    }
+
+    clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    result = error_wrapper(::closesocket(s), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    result = error_wrapper(::close(s), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  }
+
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+bool set_internal_non_blocking(socket_type s,
+    state_type& state, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  ioctl_arg_type arg = 1;
+  int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
+#elif defined(__SYMBIAN32__)
+  int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
+  if (result >= 0)
+  {
+    clear_last_error();
+    result = error_wrapper(::fcntl(s, F_SETFL, result | O_NONBLOCK), ec);
+  }
+#else
+  ioctl_arg_type arg = 1;
+  int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
+#endif
+
+  if (result >= 0)
+  {
+    ec = asio::error_code();
+    state |= internal_non_blocking;
+    return true;
+  }
+
+  return false;
+}
+
+ASIO_DECL
+int shutdown(socket_type s, int what, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+  int result = error_wrapper(::shutdown(s, what), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+template <typename SockLenType>
+inline int call_connect(SockLenType msghdr::*,
+    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+  return ::connect(s, addr, (SockLenType)addrlen);
+}
+
+ASIO_DECL
+int connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+  int result = error_wrapper(call_connect(
+        &msghdr::msg_namelen, s, addr, addrlen), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+void sync_connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  // Perform the connect operation.
+  socket_ops::connect(s, addr, addrlen, ec);
+  if (ec != asio::error::in_progress
+      && ec != asio::error::would_block)
+  {
+    // The connect operation finished immediately.
+    return;
+  }
+
+  // Wait for socket to become ready.
+  if (socket_ops::poll_connect(s, ec) < 0)
+    return;
+
+  // Get the error code from the connect operation.
+  int connect_error = 0;
+  size_t connect_error_len = sizeof(connect_error);
+  if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+        &connect_error, &connect_error_len, ec) == socket_error_retval)
+    return;
+
+  // Return the result of the connect operation.
+  ec = asio::error_code(connect_error,
+      asio::error::get_system_category());
+}
+
+ASIO_DECL
+bool non_blocking_connect(socket_type s, asio::error_code& ec)
+{
+  // Get the error code from the connect operation.
+  int connect_error = 0;
+  size_t connect_error_len = sizeof(connect_error);
+  if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+        &connect_error, &connect_error_len, ec) == 0)
+  {
+    if (connect_error)
+    {
+      ec = asio::error_code(connect_error,
+          asio::error::get_system_category());
+    }
+    else
+      ec = asio::error_code();
+  }
+
+  return true;
+}
+
+ASIO_DECL
+int socketpair(int af, int type, int protocol,
+    socket_type sv[2], asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  (void)(af);
+  (void)(type);
+  (void)(protocol);
+  (void)(sv);
+  ec = asio::error::operation_not_supported;
+  return socket_error_retval;
+#else
+  clear_last_error();
+  int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+#endif
+}
+
+ASIO_DECL
+bool sockatmark(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+#if defined(SIOCATMARK)
+  ioctl_arg_type value = 0;
+# if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec);
+# else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec);
+# endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  if (result == 0)
+    ec = asio::error_code();
+# if defined(ENOTTY)
+  if (ec.value() == ENOTTY)
+    ec = asio::error::not_socket;
+# endif // defined(ENOTTY)
+#else // defined(SIOCATMARK)
+  int value = error_wrapper(::sockatmark(s), ec);
+  if (value != -1)
+    ec = asio::error_code();
+#endif // defined(SIOCATMARK)
+
+  return ec ? false : value != 0;
+}
+
+ASIO_DECL
+size_t available(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  ioctl_arg_type value = 0;
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  if (result == 0)
+    ec = asio::error_code();
+#if defined(ENOTTY)
+  if (ec.value() == ENOTTY)
+    ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+
+  return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
+}
+
+ASIO_DECL
+int listen(socket_type s, int backlog, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+  int result = error_wrapper(::listen(s, backlog), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+inline void init_buf_iov_base(void*& base, void* addr)
+{
+  base = addr;
+}
+
+template <typename T>
+inline void init_buf_iov_base(T& base, void* addr)
+{
+  base = static_cast<T>(addr);
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ASIO_DECL
+void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  b.buf = static_cast<char*>(data);
+  b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  init_buf_iov_base(b.iov_base, data);
+  b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  b.buf = static_cast<char*>(const_cast<void*>(data));
+  b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+  b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
+{
+  name = addr;
+}
+
+inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
+{
+  name = const_cast<socket_addr_type*>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
+{
+  name = reinterpret_cast<T>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
+{
+  name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
+}
+
+ASIO_DECL
+int recv(socket_type s, buf* bufs, size_t count, int flags,
+    asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  DWORD recv_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int result = error_wrapper(::WSARecv(s, bufs,
+        recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec = asio::error_code();
+  return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  msg.msg_iov = bufs;
+  msg.msg_iovlen = count;
+  int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_recv(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (all_empty && (state & stream_oriented))
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    int bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Check for EOF.
+    if ((state & stream_oriented) && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_recv(state_type state,
+    const weak_cancel_token_type& cancel_token, bool all_empty,
+    asio::error_code& ec, size_t bytes_transferred)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+
+  // Check for connection closed.
+  else if (!ec && bytes_transferred == 0
+      && (state & stream_oriented) != 0
+      && !all_empty)
+  {
+    ec = asio::error::eof;
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_recv(socket_type s,
+    buf* bufs, size_t count, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    int bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+    // Check for end of stream.
+    if (is_stream && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes >= 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  DWORD recv_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int tmp_addrlen = (int)*addrlen;
+  int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
+        &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
+  *addrlen = (std::size_t)tmp_addrlen;
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec = asio::error_code();
+  return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  init_msghdr_msg_name(msg.msg_name, addr);
+  msg.msg_namelen = *addrlen;
+  msg.msg_iov = bufs;
+  msg.msg_iovlen = count;
+  int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+  *addrlen = msg.msg_namelen;
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_recvfrom(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_recvfrom(socket_type s,
+    buf* bufs, size_t count, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes >= 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int send(socket_type s, const buf* bufs, size_t count, int flags,
+    asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  DWORD send_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD send_flags = flags;
+  int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
+        send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec = asio::error_code();
+  return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  msg.msg_iov = const_cast<buf*>(bufs);
+  msg.msg_iovlen = count;
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_send(socket_type s, state_type state, const buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes to a stream is a no-op.
+  if (all_empty && (state & stream_oriented))
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    int bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_send(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_send(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    int bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes >= 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  DWORD send_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
+        send_buf_count, &bytes_transferred, flags, addr,
+        static_cast<int>(addrlen), 0, 0), ec);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec = asio::error_code();
+  return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  init_msghdr_msg_name(msg.msg_name, addr);
+  msg.msg_namelen = addrlen;
+  msg.msg_iov = const_cast<buf*>(bufs);
+  msg.msg_iovlen = count;
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
+    size_t count, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, ec) < 0)
+      return 0;
+  }
+}
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_sendto(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation is complete.
+    if (bytes >= 0)
+    {
+      ec = asio::error_code();
+      bytes_transferred = bytes;
+    }
+    else
+      bytes_transferred = 0;
+
+    return true;
+  }
+}
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+socket_type socket(int af, int type, int protocol,
+    asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
+        WSA_FLAG_OVERLAPPED), ec);
+  if (s == invalid_socket)
+    return s;
+
+  if (af == AF_INET6)
+  {
+    // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
+    // false. This will only succeed on Windows Vista and later versions of
+    // Windows, where a dual-stack IPv4/v6 implementation is available.
+    DWORD optval = 0;
+    ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+        reinterpret_cast<const char*>(&optval), sizeof(optval));
+  }
+
+  ec = asio::error_code();
+
+  return s;
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+  socket_type s = error_wrapper(::socket(af, type, protocol), ec);
+  if (s == invalid_socket)
+    return s;
+
+  int optval = 1;
+  int result = error_wrapper(::setsockopt(s,
+        SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+  if (result != 0)
+  {
+    ::close(s);
+    return invalid_socket;
+  }
+
+  return s;
+#else
+  int s = error_wrapper(::socket(af, type, protocol), ec);
+  if (s >= 0)
+    ec = asio::error_code();
+  return s;
+#endif
+}
+
+template <typename SockLenType>
+inline int call_setsockopt(SockLenType msghdr::*,
+    socket_type s, int level, int optname,
+    const void* optval, std::size_t optlen)
+{
+  return ::setsockopt(s, level, optname,
+      (const char*)optval, (SockLenType)optlen);
+}
+
+ASIO_DECL
+int setsockopt(socket_type s, state_type& state, int level, int optname,
+    const void* optval, std::size_t optlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level && optname == always_fail_option)
+  {
+    ec = asio::error::invalid_argument;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level
+      && optname == enable_connection_aborted_option)
+  {
+    if (optlen != sizeof(int))
+    {
+      ec = asio::error::invalid_argument;
+      return socket_error_retval;
+    }
+
+    if (*static_cast<const int*>(optval))
+      state |= enable_connection_aborted;
+    else
+      state &= ~enable_connection_aborted;
+    ec = asio::error_code();
+    return 0;
+  }
+
+  if (level == SOL_SOCKET && optname == SO_LINGER)
+    state |= user_set_linger;
+
+#if defined(__BORLANDC__)
+  // Mysteriously, using the getsockopt and setsockopt functions directly with
+  // Borland C++ results in incorrect values being set and read. The bug can be
+  // worked around by using function addresses resolved with GetProcAddress.
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+    if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+    {
+      clear_last_error();
+      return error_wrapper(sso(s, level, optname,
+            reinterpret_cast<const char*>(optval),
+            static_cast<int>(optlen)), ec);
+    }
+  }
+  ec = asio::error::fault;
+  return socket_error_retval;
+#else // defined(__BORLANDC__)
+  clear_last_error();
+  int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen), ec);
+  if (result == 0)
+  {
+    ec = asio::error_code();
+
+#if defined(__MACH__) && defined(__APPLE__) \
+  || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+    // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+    // need to also set SO_REUSEPORT on BSD-based platforms.
+    if ((state & datagram_oriented)
+        && level == SOL_SOCKET && optname == SO_REUSEADDR)
+    {
+      call_setsockopt(&msghdr::msg_namelen, s,
+          SOL_SOCKET, SO_REUSEPORT, optval, optlen);
+    }
+#endif
+  }
+
+  return result;
+#endif // defined(__BORLANDC__)
+}
+
+template <typename SockLenType>
+inline int call_getsockopt(SockLenType msghdr::*,
+    socket_type s, int level, int optname,
+    void* optval, std::size_t* optlen)
+{
+  SockLenType tmp_optlen = (SockLenType)*optlen;
+  int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
+  *optlen = (std::size_t)tmp_optlen;
+  return result;
+}
+
+ASIO_DECL
+int getsockopt(socket_type s, state_type state, int level, int optname,
+    void* optval, size_t* optlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level && optname == always_fail_option)
+  {
+    ec = asio::error::invalid_argument;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level
+      && optname == enable_connection_aborted_option)
+  {
+    if (*optlen != sizeof(int))
+    {
+      ec = asio::error::invalid_argument;
+      return socket_error_retval;
+    }
+
+    *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
+    ec = asio::error_code();
+    return 0;
+  }
+
+#if defined(__BORLANDC__)
+  // Mysteriously, using the getsockopt and setsockopt functions directly with
+  // Borland C++ results in incorrect values being set and read. The bug can be
+  // worked around by using function addresses resolved with GetProcAddress.
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+    if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+    {
+      clear_last_error();
+      int tmp_optlen = static_cast<int>(*optlen);
+      int result = error_wrapper(gso(s, level, optname,
+            reinterpret_cast<char*>(optval), &tmp_optlen), ec);
+      *optlen = static_cast<size_t>(tmp_optlen);
+      if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+          && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+      {
+        // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+        // only supported on Windows Vista and later. To simplify program logic
+        // we will fake success of getting this option and specify that the
+        // value is non-zero (i.e. true). This corresponds to the behavior of
+        // IPv6 sockets on Windows platforms pre-Vista.
+        *static_cast<DWORD*>(optval) = 1;
+        ec = asio::error_code();
+      }
+      return result;
+    }
+  }
+  ec = asio::error::fault;
+  return socket_error_retval;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  clear_last_error();
+  int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen), ec);
+  if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+      && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+  {
+    // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
+    // supported on Windows Vista and later. To simplify program logic we will
+    // fake success of getting this option and specify that the value is
+    // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
+    // on Windows platforms pre-Vista.
+    *static_cast<DWORD*>(optval) = 1;
+    ec = asio::error_code();
+  }
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  clear_last_error();
+  int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen), ec);
+#if defined(__linux__)
+  if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
+      && (optname == SO_SNDBUF || optname == SO_RCVBUF))
+  {
+    // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
+    // to set the buffer size to N*2. Linux puts additional stuff into the
+    // buffers so that only about half is actually available to the application.
+    // The retrieved value is divided by 2 here to make it appear as though the
+    // correct value has been set.
+    *static_cast<int*>(optval) /= 2;
+  }
+#endif // defined(__linux__)
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline int call_getpeername(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = (SockLenType)*addrlen;
+  int result = ::getpeername(s, addr, &tmp_addrlen);
+  *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+ASIO_DECL
+int getpeername(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, bool cached, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  if (cached)
+  {
+    // Check if socket is still connected.
+    DWORD connect_time = 0;
+    size_t connect_time_len = sizeof(connect_time);
+    if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
+          &connect_time, &connect_time_len, ec) == socket_error_retval)
+    {
+      return socket_error_retval;
+    }
+    if (connect_time == 0xFFFFFFFF)
+    {
+      ec = asio::error::not_connected;
+      return socket_error_retval;
+    }
+
+    // The cached value is still valid.
+    ec = asio::error_code();
+    return 0;
+  }
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  (void)cached;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+  clear_last_error();
+  int result = error_wrapper(call_getpeername(
+        &msghdr::msg_namelen, s, addr, addrlen), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+template <typename SockLenType>
+inline int call_getsockname(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = (SockLenType)*addrlen;
+  int result = ::getsockname(s, addr, &tmp_addrlen);
+  *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+ASIO_DECL
+int getsockname(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+  int result = error_wrapper(call_getsockname(
+        &msghdr::msg_namelen, s, addr, addrlen), ec);
+  if (result == 0)
+    ec = asio::error_code();
+  return result;
+}
+
+ASIO_DECL
+int ioctl(socket_type s, state_type& state, int cmd,
+    ioctl_arg_type* arg, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
+#elif defined(__MACH__) && defined(__APPLE__) \
+  || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+  int result = error_wrapper(::ioctl(s,
+        static_cast<unsigned int>(cmd), arg), ec);
+#else
+  int result = error_wrapper(::ioctl(s, cmd, arg), ec);
+#endif
+  if (result >= 0)
+  {
+    ec = asio::error_code();
+
+    // When updating the non-blocking mode we always perform the ioctl syscall,
+    // even if the flags would otherwise indicate that the socket is already in
+    // the correct state. This ensures that the underlying socket is put into
+    // the state that has been requested by the user. If the ioctl syscall was
+    // successful then we need to update the flags to match.
+    if (cmd == static_cast<int>(FIONBIO))
+    {
+      if (*arg)
+      {
+        state |= user_set_non_blocking;
+      }
+      else
+      {
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        state &= ~(user_set_non_blocking | internal_non_blocking);
+      }
+    }
+  }
+
+  return result;
+}
+
+ASIO_DECL
+int select(int nfds, fd_set* readfds, fd_set* writefds,
+    fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  if (!readfds && !writefds && !exceptfds && timeout)
+  {
+    DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+    if (milliseconds == 0)
+      milliseconds = 1; // Force context switch.
+    ::Sleep(milliseconds);
+    ec = asio::error_code();
+    return 0;
+  }
+
+  // The select() call allows timeout values measured in microseconds, but the
+  // system clock (as wrapped by boost::posix_time::microsec_clock) typically
+  // has a resolution of 10 milliseconds. This can lead to a spinning select
+  // reactor, meaning increased CPU usage, when waiting for the earliest
+  // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
+  // spin we'll use a minimum timeout of 1 millisecond.
+  if (timeout && timeout->tv_sec == 0
+      && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
+    timeout->tv_usec = 1000;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__SELECT)
+  timespec ts;
+  ts.tv_sec = timeout ? timeout->tv_sec : 0;
+  ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
+  return error_wrapper(::pselect(nfds, readfds,
+        writefds, exceptfds, timeout ? &ts : 0, 0), ec);
+#else
+  int result = error_wrapper(::select(nfds, readfds,
+        writefds, exceptfds, timeout), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif
+}
+
+ASIO_DECL
+int poll_read(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  clear_last_error();
+  int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#else // defined(BOOST_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLIN;
+  fds.revents = 0;
+  clear_last_error();
+  int result = error_wrapper(::poll(&fds, 1, -1), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+int poll_write(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  clear_last_error();
+  int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#else // defined(BOOST_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  clear_last_error();
+  int result = error_wrapper(::poll(&fds, 1, -1), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+int poll_connect(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set write_fds;
+  FD_ZERO(&write_fds);
+  FD_SET(s, &write_fds);
+  fd_set except_fds;
+  FD_ZERO(&except_fds);
+  FD_SET(s, &except_fds);
+  clear_last_error();
+  int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#else // defined(BOOST_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  clear_last_error();
+  int result = error_wrapper(::poll(&fds, 1, -1), ec);
+  if (result >= 0)
+    ec = asio::error_code();
+  return result;
+#endif // defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+    unsigned long scope_id, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  using namespace std; // For memcpy.
+
+  if (af != AF_INET && af != AF_INET6)
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+
+  union
+  {
+    socket_addr_type base;
+    sockaddr_storage_type storage;
+    sockaddr_in4_type v4;
+    sockaddr_in6_type v6;
+  } address;
+  DWORD address_length;
+  if (af == AF_INET)
+  {
+    address_length = sizeof(sockaddr_in4_type);
+    address.v4.sin_family = AF_INET;
+    address.v4.sin_port = 0;
+    memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
+  }
+  else // AF_INET6
+  {
+    address_length = sizeof(sockaddr_in6_type);
+    address.v6.sin6_family = AF_INET6;
+    address.v6.sin6_port = 0;
+    address.v6.sin6_flowinfo = 0;
+    address.v6.sin6_scope_id = scope_id;
+    memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
+  }
+
+  DWORD string_length = static_cast<DWORD>(length);
+#if defined(BOOST_NO_ANSI_APIS)
+  LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
+  int result = error_wrapper(::WSAAddressToStringW(&address.base,
+        address_length, 0, string_buffer, &string_length), ec);
+  ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
+#else
+  int result = error_wrapper(::WSAAddressToStringA(
+        &address.base, address_length, 0, dest, &string_length), ec);
+#endif
+
+  // Windows may set error code on success.
+  if (result != socket_error_retval)
+    ec = asio::error_code();
+
+  // Windows may not set an error code on failure.
+  else if (result == socket_error_retval && !ec)
+    ec = asio::error::invalid_argument;
+
+  return result == socket_error_retval ? 0 : dest;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
+  if (result == 0 && !ec)
+    ec = asio::error::invalid_argument;
+  if (result != 0 && af == AF_INET6 && scope_id != 0)
+  {
+    using namespace std; // For strcat and sprintf.
+    char if_name[IF_NAMESIZE + 1] = "%";
+    const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
+    bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+    if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
+      sprintf(if_name + 1, "%lu", scope_id);
+    strcat(dest, if_name);
+  }
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+int inet_pton(int af, const char* src, void* dest,
+    unsigned long* scope_id, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  using namespace std; // For memcpy and strcmp.
+
+  if (af != AF_INET && af != AF_INET6)
+  {
+    ec = asio::error::address_family_not_supported;
+    return -1;
+  }
+
+  union
+  {
+    socket_addr_type base;
+    sockaddr_storage_type storage;
+    sockaddr_in4_type v4;
+    sockaddr_in6_type v6;
+  } address;
+  int address_length = sizeof(sockaddr_storage_type);
+#if defined(BOOST_NO_ANSI_APIS)
+  int num_wide_chars = strlen(src) + 1;
+  LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
+  ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
+  int result = error_wrapper(::WSAStringToAddressW(
+        wide_buffer, af, 0, &address.base, &address_length), ec);
+#else
+  int result = error_wrapper(::WSAStringToAddressA(
+        const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
+#endif
+
+  if (af == AF_INET)
+  {
+    if (result != socket_error_retval)
+    {
+      memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+      ec = asio::error_code();
+    }
+    else if (strcmp(src, "255.255.255.255") == 0)
+    {
+      static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+      ec = asio::error_code();
+    }
+  }
+  else // AF_INET6
+  {
+    if (result != socket_error_retval)
+    {
+      memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
+      if (scope_id)
+        *scope_id = address.v6.sin6_scope_id;
+      ec = asio::error_code();
+    }
+  }
+
+  // Windows may not set an error code on failure.
+  if (result == socket_error_retval && !ec)
+    ec = asio::error::invalid_argument;
+
+  if (result != socket_error_retval)
+    ec = asio::error_code();
+
+  return result == socket_error_retval ? -1 : 1;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  int result = error_wrapper(::inet_pton(af, src, dest), ec);
+  if (result <= 0 && !ec)
+    ec = asio::error::invalid_argument;
+  if (result > 0 && af == AF_INET6 && scope_id)
+  {
+    using namespace std; // For strchr and atoi.
+    *scope_id = 0;
+    if (const char* if_name = strchr(src, '%'))
+    {
+      in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+      bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+      if (is_link_local)
+        *scope_id = if_nametoindex(if_name + 1);
+      if (*scope_id == 0)
+        *scope_id = atoi(if_name + 1);
+    }
+  }
+  return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+int gethostname(char* name, int namelen, asio::error_code& ec)
+{
+  clear_last_error();
+  int result = error_wrapper(::gethostname(name, namelen), ec);
+#if defined(BOOST_WINDOWS)
+  if (result == 0)
+    ec = asio::error_code();
+#endif
+  return result;
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
+  || defined(__MACH__) && defined(__APPLE__)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline asio::error_code translate_netdb_error(int error)
+{
+  switch (error)
+  {
+  case 0:
+    return asio::error_code();
+  case HOST_NOT_FOUND:
+    return asio::error::host_not_found;
+  case TRY_AGAIN:
+    return asio::error::host_not_found_try_again;
+  case NO_RECOVERY:
+    return asio::error::no_recovery;
+  case NO_DATA:
+    return asio::error::no_data;
+  default:
+    BOOST_ASSERT(false);
+    return asio::error::invalid_argument;
+  }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+    hostent* result, char* buffer, int buflength, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  (void)(buffer);
+  (void)(buflength);
+  hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
+  if (!retval)
+    return 0;
+  ec = asio::error_code();
+  *result = *retval;
+  return retval;
+#elif defined(__sun) || defined(__QNX__)
+  int error = 0;
+  hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
+        buffer, buflength, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+  (void)(buffer);
+  (void)(buflength);
+  int error = 0;
+  hostent* retval = error_wrapper(::getipnodebyaddr(
+        addr, length, af, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return retval;
+#else
+  hostent* retval = 0;
+  int error = 0;
+  error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
+        buflength, &retval, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#endif
+}
+
+inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
+    char* buffer, int buflength, int ai_flags, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+  (void)(buffer);
+  (void)(buflength);
+  (void)(ai_flags);
+  if (af != AF_INET)
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  hostent* retval = error_wrapper(::gethostbyname(name), ec);
+  if (!retval)
+    return 0;
+  ec = asio::error_code();
+  *result = *retval;
+  return result;
+#elif defined(__sun) || defined(__QNX__)
+  (void)(ai_flags);
+  if (af != AF_INET)
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  int error = 0;
+  hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
+        buflength, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+  (void)(buffer);
+  (void)(buflength);
+  int error = 0;
+  hostent* retval = error_wrapper(::getipnodebyname(
+        name, af, ai_flags, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return retval;
+#else
+  (void)(ai_flags);
+  if (af != AF_INET)
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  hostent* retval = 0;
+  int error = 0;
+  error_wrapper(::gethostbyname_r(name, result,
+        buffer, buflength, &retval, &error), ec);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#endif
+}
+
+inline void freehostent(hostent* h)
+{
+#if defined(__MACH__) && defined(__APPLE__)
+  if (h)
+    ::freehostent(h);
+#else
+  (void)(h);
+#endif
+}
+
+// Emulation of getaddrinfo based on implementation in:
+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
+
+struct gai_search
+{
+  const char* host;
+  int family;
+};
+
+inline int gai_nsearch(const char* host,
+    const addrinfo_type* hints, gai_search (&search)[2])
+{
+  int search_count = 0;
+  if (host == 0 || host[0] == '\0')
+  {
+    if (hints->ai_flags & AI_PASSIVE)
+    {
+      // No host and AI_PASSIVE implies wildcard bind.
+      switch (hints->ai_family)
+      {
+      case AF_INET:
+        search[search_count].host = "0.0.0.0";
+        search[search_count].family = AF_INET;
+        ++search_count;
+        break;
+      case AF_INET6:
+        search[search_count].host = "0::0";
+        search[search_count].family = AF_INET6;
+        ++search_count;
+        break;
+      case AF_UNSPEC:
+        search[search_count].host = "0::0";
+        search[search_count].family = AF_INET6;
+        ++search_count;
+        search[search_count].host = "0.0.0.0";
+        search[search_count].family = AF_INET;
+        ++search_count;
+        break;
+      default:
+        break;
+      }
+    }
+    else
+    {
+      // No host and not AI_PASSIVE means connect to local host.
+      switch (hints->ai_family)
+      {
+      case AF_INET:
+        search[search_count].host = "localhost";
+        search[search_count].family = AF_INET;
+        ++search_count;
+        break;
+      case AF_INET6:
+        search[search_count].host = "localhost";
+        search[search_count].family = AF_INET6;
+        ++search_count;
+        break;
+      case AF_UNSPEC:
+        search[search_count].host = "localhost";
+        search[search_count].family = AF_INET6;
+        ++search_count;
+        search[search_count].host = "localhost";
+        search[search_count].family = AF_INET;
+        ++search_count;
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  else
+  {
+    // Host is specified.
+    switch (hints->ai_family)
+    {
+    case AF_INET:
+      search[search_count].host = host;
+      search[search_count].family = AF_INET;
+      ++search_count;
+      break;
+    case AF_INET6:
+      search[search_count].host = host;
+      search[search_count].family = AF_INET6;
+      ++search_count;
+      break;
+    case AF_UNSPEC:
+      search[search_count].host = host;
+      search[search_count].family = AF_INET6;
+      ++search_count;
+      search[search_count].host = host;
+      search[search_count].family = AF_INET;
+      ++search_count;
+      break;
+    default:
+      break;
+    }
+  }
+  return search_count;
+}
+
+template <typename T>
+inline T* gai_alloc(std::size_t size = sizeof(T))
+{
+  using namespace std;
+  T* p = static_cast<T*>(::operator new(size, std::nothrow));
+  if (p)
+    memset(p, 0, size);
+  return p;
+}
+
+inline void gai_free(void* p)
+{
+  ::operator delete(p);
+}
+
+inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
+{
+  using namespace std;
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+  strcpy_s(target, max_size, source);
+#else
+  *target = 0;
+  strncat(target, source, max_size);
+#endif
+}
+
+enum { gai_clone_flag = 1 << 30 };
+
+inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
+    const void* addr, int family)
+{
+  using namespace std;
+
+  addrinfo_type* ai = gai_alloc<addrinfo_type>();
+  if (ai == 0)
+    return EAI_MEMORY;
+
+  ai->ai_next = 0;
+  **next = ai;
+  *next = &ai->ai_next;
+
+  ai->ai_canonname = 0;
+  ai->ai_socktype = hints->ai_socktype;
+  if (ai->ai_socktype == 0)
+    ai->ai_flags |= gai_clone_flag;
+  ai->ai_protocol = hints->ai_protocol;
+  ai->ai_family = family;
+
+  switch (ai->ai_family)
+  {
+  case AF_INET:
+    {
+      sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+      if (sinptr == 0)
+        return EAI_MEMORY;
+      sinptr->sin_family = AF_INET;
+      memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
+      ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
+      ai->ai_addrlen = sizeof(sockaddr_in4_type);
+      break;
+    }
+  case AF_INET6:
+    {
+      sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+      if (sin6ptr == 0)
+        return EAI_MEMORY;
+      sin6ptr->sin6_family = AF_INET6;
+      memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
+      ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
+      ai->ai_addrlen = sizeof(sockaddr_in6_type);
+      break;
+    }
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+inline addrinfo_type* gai_clone(addrinfo_type* ai)
+{
+  using namespace std;
+
+  addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
+  if (new_ai == 0)
+    return new_ai;
+
+  new_ai->ai_next = ai->ai_next;
+  ai->ai_next = new_ai;
+
+  new_ai->ai_flags = 0;
+  new_ai->ai_family = ai->ai_family;
+  new_ai->ai_socktype = ai->ai_socktype;
+  new_ai->ai_protocol = ai->ai_protocol;
+  new_ai->ai_canonname = 0;
+  new_ai->ai_addrlen = ai->ai_addrlen;
+  new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
+  memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+  return new_ai;
+}
+
+inline int gai_port(addrinfo_type* aihead, int port, int socktype)
+{
+  int num_found = 0;
+
+  for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
+  {
+    if (ai->ai_flags & gai_clone_flag)
+    {
+      if (ai->ai_socktype != 0)
+      {
+        ai = gai_clone(ai);
+        if (ai == 0)
+          return -1;
+        // ai now points to newly cloned entry.
+      }
+    }
+    else if (ai->ai_socktype != socktype)
+    {
+      // Ignore if mismatch on socket type.
+      continue;
+    }
+
+    ai->ai_socktype = socktype;
+
+    switch (ai->ai_family)
+    {
+    case AF_INET:
+      {
+        sockaddr_in4_type* sinptr =
+          reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+        sinptr->sin_port = port;
+        ++num_found;
+        break;
+      }
+    case AF_INET6:
+      {
+        sockaddr_in6_type* sin6ptr =
+          reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+        sin6ptr->sin6_port = port;
+        ++num_found;
+        break;
+      }
+    default:
+      break;
+    }
+  }
+
+  return num_found;
+}
+
+inline int gai_serv(addrinfo_type* aihead,
+    const addrinfo_type* hints, const char* serv)
+{
+  using namespace std;
+
+  int num_found = 0;
+
+  if (
+#if defined(AI_NUMERICSERV)
+      (hints->ai_flags & AI_NUMERICSERV) ||
+#endif
+      isdigit(static_cast<unsigned char>(serv[0])))
+  {
+    int port = htons(atoi(serv));
+    if (hints->ai_socktype)
+    {
+      // Caller specifies socket type.
+      int rc = gai_port(aihead, port, hints->ai_socktype);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+    }
+    else
+    {
+      // Caller does not specify socket type.
+      int rc = gai_port(aihead, port, SOCK_STREAM);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+      rc = gai_port(aihead, port, SOCK_DGRAM);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+    }
+  }
+  else
+  {
+    // Try service name with TCP first, then UDP.
+    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
+    {
+      servent* sptr = getservbyname(serv, "tcp");
+      if (sptr != 0)
+      {
+        int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
+        if (rc < 0)
+          return EAI_MEMORY;
+        num_found += rc;
+      }
+    }
+    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
+    {
+      servent* sptr = getservbyname(serv, "udp");
+      if (sptr != 0)
+      {
+        int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
+        if (rc < 0)
+          return EAI_MEMORY;
+        num_found += rc;
+      }
+    }
+  }
+
+  if (num_found == 0)
+  {
+    if (hints->ai_socktype == 0)
+    {
+      // All calls to getservbyname() failed.
+      return EAI_NONAME;
+    }
+    else
+    {
+      // Service not supported for socket type.
+      return EAI_SERVICE;
+    }
+  }
+
+  return 0;
+}
+
+inline int gai_echeck(const char* host, const char* service,
+    int flags, int family, int socktype, int protocol)
+{
+  (void)(flags);
+  (void)(protocol);
+
+  // Host or service must be specified.
+  if (host == 0 || host[0] == '\0')
+    if (service == 0 || service[0] == '\0')
+      return EAI_NONAME;
+
+  // Check combination of family and socket type.
+  switch (family)
+  {
+  case AF_UNSPEC:
+    break;
+  case AF_INET:
+  case AF_INET6:
+    if (service != 0 && service[0] != '\0')
+      if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+        return EAI_SOCKTYPE;
+    break;
+  default:
+    return EAI_FAMILY;
+  }
+
+  return 0;
+}
+
+inline void freeaddrinfo_emulation(addrinfo_type* aihead)
+{
+  addrinfo_type* ai = aihead;
+  while (ai)
+  {
+    gai_free(ai->ai_addr);
+    gai_free(ai->ai_canonname);
+    addrinfo_type* ainext = ai->ai_next;
+    gai_free(ai);
+    ai = ainext;
+  }
+}
+
+inline int getaddrinfo_emulation(const char* host, const char* service,
+    const addrinfo_type* hintsp, addrinfo_type** result)
+{
+  // Set up linked list of addrinfo structures.
+  addrinfo_type* aihead = 0;
+  addrinfo_type** ainext = &aihead;
+  char* canon = 0;
+
+  // Supply default hints if not specified by caller.
+  addrinfo_type hints = addrinfo_type();
+  hints.ai_family = AF_UNSPEC;
+  if (hintsp)
+    hints = *hintsp;
+
+  // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
+  // and AI_ALL flags.
+#if defined(AI_V4MAPPED)
+  if (hints.ai_family != AF_INET6)
+    hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+  if (hints.ai_family != AF_INET6)
+    hints.ai_flags &= ~AI_ALL;
+#endif
+
+  // Basic error checking.
+  int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
+      hints.ai_socktype, hints.ai_protocol);
+  if (rc != 0)
+  {
+    freeaddrinfo_emulation(aihead);
+    return rc;
+  }
+
+  gai_search search[2];
+  int search_count = gai_nsearch(host, &hints, search);
+  for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
+  {
+    // Check for IPv4 dotted decimal string.
+    in4_addr_type inaddr;
+    asio::error_code ec;
+    if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
+    {
+      if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        return EAI_FAMILY;
+      }
+      if (sptr->family == AF_INET)
+      {
+        rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
+        if (rc != 0)
+        {
+          freeaddrinfo_emulation(aihead);
+          gai_free(canon);
+          return rc;
+        }
+      }
+      continue;
+    }
+
+    // Check for IPv6 hex string.
+    in6_addr_type in6addr;
+    if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
+    {
+      if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        return EAI_FAMILY;
+      }
+      if (sptr->family == AF_INET6)
+      {
+        rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
+        if (rc != 0)
+        {
+          freeaddrinfo_emulation(aihead);
+          gai_free(canon);
+          return rc;
+        }
+      }
+      continue;
+    }
+
+    // Look up hostname.
+    hostent hent;
+    char hbuf[8192] = "";
+    hostent* hptr = socket_ops::gethostbyname(sptr->host,
+        sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
+    if (hptr == 0)
+    {
+      if (search_count == 2)
+      {
+        // Failure is OK if there are multiple searches.
+        continue;
+      }
+      freeaddrinfo_emulation(aihead);
+      gai_free(canon);
+      if (ec == asio::error::host_not_found)
+        return EAI_NONAME;
+      if (ec == asio::error::host_not_found_try_again)
+        return EAI_AGAIN;
+      if (ec == asio::error::no_recovery)
+        return EAI_FAIL;
+      if (ec == asio::error::no_data)
+        return EAI_NONAME;
+      return EAI_NONAME;
+    }
+
+    // Check for address family mismatch if one was specified.
+    if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
+    {
+      freeaddrinfo_emulation(aihead);
+      gai_free(canon);
+      socket_ops::freehostent(hptr);
+      return EAI_FAMILY;
+    }
+
+    // Save canonical name first time.
+    if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
+        && (hints.ai_flags & AI_CANONNAME) && canon == 0)
+    {
+      std::size_t canon_len = strlen(hptr->h_name) + 1;
+      canon = gai_alloc<char>(canon_len);
+      if (canon == 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        socket_ops::freehostent(hptr);
+        return EAI_MEMORY;
+      }
+      gai_strcpy(canon, hptr->h_name, canon_len);
+    }
+
+    // Create an addrinfo structure for each returned address.
+    for (char** ap = hptr->h_addr_list; *ap; ++ap)
+    {
+      rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
+      if (rc != 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        socket_ops::freehostent(hptr);
+        return EAI_FAMILY;
+      }
+    }
+
+    socket_ops::freehostent(hptr);
+  }
+
+  // Check if we found anything.
+  if (aihead == 0)
+  {
+    gai_free(canon);
+    return EAI_NONAME;
+  }
+
+  // Return canonical name in first entry.
+  if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
+  {
+    if (canon)
+    {
+      aihead->ai_canonname = canon;
+      canon = 0;
+    }
+    else
+    {
+      std::size_t canonname_len = strlen(search[0].host) + 1;
+      aihead->ai_canonname = gai_alloc<char>(canonname_len);
+      if (aihead->ai_canonname == 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        return EAI_MEMORY;
+      }
+      gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
+    }
+  }
+  gai_free(canon);
+
+  // Process the service name.
+  if (service != 0 && service[0] != '\0')
+  {
+    rc = gai_serv(aihead, &hints, service);
+    if (rc != 0)
+    {
+      freeaddrinfo_emulation(aihead);
+      return rc;
+    }
+  }
+
+  // Return result to caller.
+  *result = aihead;
+  return 0;
+}
+
+inline asio::error_code getnameinfo_emulation(
+    const socket_addr_type* sa, std::size_t salen, char* host,
+    std::size_t hostlen, char* serv, std::size_t servlen, int flags,
+    asio::error_code& ec)
+{
+  using namespace std;
+
+  const char* addr;
+  size_t addr_len;
+  unsigned short port;
+  switch (sa->sa_family)
+  {
+  case AF_INET:
+    if (salen != sizeof(sockaddr_in4_type))
+    {
+      return ec = asio::error::invalid_argument;
+    }
+    addr = reinterpret_cast<const char*>(
+        &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
+    addr_len = sizeof(in4_addr_type);
+    port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
+    break;
+  case AF_INET6:
+    if (salen != sizeof(sockaddr_in6_type))
+    {
+      return ec = asio::error::invalid_argument;
+    }
+    addr = reinterpret_cast<const char*>(
+        &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
+    addr_len = sizeof(in6_addr_type);
+    port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
+    break;
+  default:
+    return ec = asio::error::address_family_not_supported;
+  }
+
+  if (host && hostlen > 0)
+  {
+    if (flags & NI_NUMERICHOST)
+    {
+      if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
+      {
+        return ec;
+      }
+    }
+    else
+    {
+      hostent hent;
+      char hbuf[8192] = "";
+      hostent* hptr = socket_ops::gethostbyaddr(addr,
+          static_cast<int>(addr_len), sa->sa_family,
+          &hent, hbuf, sizeof(hbuf), ec);
+      if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
+      {
+        if (flags & NI_NOFQDN)
+        {
+          char* dot = strchr(hptr->h_name, '.');
+          if (dot)
+          {
+            *dot = 0;
+          }
+        }
+        gai_strcpy(host, hptr->h_name, hostlen);
+        socket_ops::freehostent(hptr);
+      }
+      else
+      {
+        socket_ops::freehostent(hptr);
+        if (flags & NI_NAMEREQD)
+        {
+          return ec = asio::error::host_not_found;
+        }
+        if (socket_ops::inet_ntop(sa->sa_family,
+              addr, host, hostlen, 0, ec) == 0)
+        {
+          return ec;
+        }
+      }
+    }
+  }
+
+  if (serv && servlen > 0)
+  {
+    if (flags & NI_NUMERICSERV)
+    {
+      if (servlen < 6)
+      {
+        return ec = asio::error::no_buffer_space;
+      }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+      sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+      sprintf(serv, "%u", ntohs(port));
+#endif
+    }
+    else
+    {
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \
+      && !defined(ASIO_DISABLE_THREADS)
+      static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+      ::pthread_mutex_lock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+       //   && !defined(ASIO_DISABLE_THREADS)
+      servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
+      if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
+      {
+        gai_strcpy(serv, sptr->s_name, servlen);
+      }
+      else
+      {
+        if (servlen < 6)
+        {
+          return ec = asio::error::no_buffer_space;
+        }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+        sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+        sprintf(serv, "%u", ntohs(port));
+#endif
+      }
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \
+      && !defined(ASIO_DISABLE_THREADS)
+      ::pthread_mutex_unlock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+       //   && !defined(ASIO_DISABLE_THREADS)
+    }
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+       //   || defined(__MACH__) && defined(__APPLE__)
+
+inline asio::error_code translate_addrinfo_error(int error)
+{
+  switch (error)
+  {
+  case 0:
+    return asio::error_code();
+  case EAI_AGAIN:
+    return asio::error::host_not_found_try_again;
+  case EAI_BADFLAGS:
+    return asio::error::invalid_argument;
+  case EAI_FAIL:
+    return asio::error::no_recovery;
+  case EAI_FAMILY:
+    return asio::error::address_family_not_supported;
+  case EAI_MEMORY:
+    return asio::error::no_memory;
+  case EAI_NONAME:
+#if defined(EAI_ADDRFAMILY)
+  case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+  case EAI_NODATA:
+#endif
+    return asio::error::host_not_found;
+  case EAI_SERVICE:
+    return asio::error::service_not_found;
+  case EAI_SOCKTYPE:
+    return asio::error::socket_type_not_supported;
+  default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    return asio::error_code(
+        WSAGetLastError(), asio::error::get_system_category());
+#else
+    return asio::error_code(
+        errno, asio::error::get_system_category());
+#endif
+  }
+}
+
+ASIO_DECL
+asio::error_code getaddrinfo(const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec)
+{
+  host = (host && *host) ? host : 0;
+  service = (service && *service) ? service : 0;
+  clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+  // Building for Windows XP, Windows Server 2003, or later.
+  int error = ::getaddrinfo(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *gai_t)(const char*,
+      const char*, const addrinfo_type*, addrinfo_type**);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
+    {
+      int error = gai(host, service, &hints, result);
+      return ec = translate_addrinfo_error(error);
+    }
+  }
+  int error = getaddrinfo_emulation(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+  int error = getaddrinfo_emulation(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+#else
+  int error = ::getaddrinfo(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+#endif
+}
+
+ASIO_DECL
+asio::error_code background_getaddrinfo(
+    const weak_cancel_token_type& cancel_token, const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec)
+{
+  if (cancel_token.expired())
+    ec = asio::error::operation_aborted;
+  else
+    socket_ops::getaddrinfo(host, service, hints, result, ec);
+  return ec;
+}
+
+ASIO_DECL
+void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+  // Building for Windows XP, Windows Server 2003, or later.
+  ::freeaddrinfo(ai);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *fai_t)(addrinfo_type*);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
+    {
+      fai(ai);
+      return;
+    }
+  }
+  freeaddrinfo_emulation(ai);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+  freeaddrinfo_emulation(ai);
+#else
+  ::freeaddrinfo(ai);
+#endif
+}
+
+ASIO_DECL
+asio::error_code getnameinfo(const socket_addr_type* addr,
+    std::size_t addrlen, char* host, std::size_t hostlen,
+    char* serv, std::size_t servlen, int flags, asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+  // Building for Windows XP, Windows Server 2003, or later.
+  clear_last_error();
+  int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
+      host, static_cast<DWORD>(hostlen),
+      serv, static_cast<DWORD>(servlen), flags);
+  return ec = translate_addrinfo_error(error);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *gni_t)(const socket_addr_type*,
+      int, char*, DWORD, char*, DWORD, int);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
+    {
+      clear_last_error();
+      int error = gni(addr, static_cast<int>(addrlen),
+          host, static_cast<DWORD>(hostlen),
+          serv, static_cast<DWORD>(servlen), flags);
+      return ec = translate_addrinfo_error(error);
+    }
+  }
+  clear_last_error();
+  return getnameinfo_emulation(addr, addrlen,
+      host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+  using namespace std; // For memcpy.
+  sockaddr_storage_type tmp_addr;
+  memcpy(&tmp_addr, addr, addrlen);
+  tmp_addr.ss_len = addrlen;
+  addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+  clear_last_error();
+  return getnameinfo_emulation(addr, addrlen,
+      host, hostlen, serv, servlen, flags, ec);
+#else
+  clear_last_error();
+  int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+  return ec = translate_addrinfo_error(error);
+#endif
+}
+
+ASIO_DECL
+asio::error_code sync_getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+  // First try resolving with the service name. If that fails try resolving
+  // but allow the service to be returned as a number.
+  int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+  socket_ops::getnameinfo(addr, addrlen, host,
+      hostlen, serv, servlen, flags, ec);
+  if (ec)
+  {
+    socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+        serv, servlen, flags | NI_NUMERICSERV, ec);
+  }
+
+  return ec;
+}
+
+ASIO_DECL
+asio::error_code background_getnameinfo(
+    const weak_cancel_token_type& cancel_token,
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+  if (cancel_token.expired())
+  {
+    ec = asio::error::operation_aborted;
+  }
+  else
+  {
+    // First try resolving with the service name. If that fails try resolving
+    // but allow the service to be returned as a number.
+    int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+    socket_ops::getnameinfo(addr, addrlen, host,
+        hostlen, serv, servlen, flags, ec);
+    if (ec)
+    {
+      socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+          serv, servlen, flags | NI_NUMERICSERV, ec);
+    }
+  }
+
+  return ec;
+}
+
+ASIO_DECL
+u_long_type network_to_host_long(u_long_type value)
+{
+  return ntohl(value);
+}
+
+ASIO_DECL
+u_long_type host_to_network_long(u_long_type value)
+{
+  return htonl(value);
+}
+
+ASIO_DECL
+u_short_type network_to_host_short(u_short_type value)
+{
+  return ntohs(value);
+}
+
+ASIO_DECL
+u_short_type host_to_network_short(u_short_type value)
+{
+  return htons(value);
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPS_IPP
diff --git a/ext/asio/asio/detail/impl/socket_select_interrupter.ipp b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp
new file mode 100644
index 0000000..181c543
--- /dev/null
+++ b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp
@@ -0,0 +1,151 @@
+//
+// detail/impl/socket_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+
+#include <cstdlib>
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+socket_select_interrupter::socket_select_interrupter()
+{
+  asio::error_code ec;
+  socket_holder acceptor(socket_ops::socket(
+        AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+  if (acceptor.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  int opt = 1;
+  socket_ops::state_type acceptor_state = 0;
+  socket_ops::setsockopt(acceptor.get(), acceptor_state,
+      SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+
+  using namespace std; // For memset.
+  sockaddr_in4_type addr;
+  std::size_t addr_len = sizeof(addr);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+  addr.sin_port = 0;
+  if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+        addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+        &addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  // Some broken firewalls on Windows will intermittently cause getsockname to
+  // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
+  // explicitly specify the target address here to work around this problem.
+  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+  if (socket_ops::listen(acceptor.get(),
+        SOMAXCONN, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  socket_holder client(socket_ops::socket(
+        AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+  if (client.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+        addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+  if (server.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+  
+  ioctl_arg_type non_blocking = 1;
+  socket_ops::state_type client_state = 0;
+  if (socket_ops::ioctl(client.get(), client_state,
+        FIONBIO, &non_blocking, ec))
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  opt = 1;
+  socket_ops::setsockopt(client.get(), client_state,
+      IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+  non_blocking = 1;
+  socket_ops::state_type server_state = 0;
+  if (socket_ops::ioctl(server.get(), server_state,
+        FIONBIO, &non_blocking, ec))
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  opt = 1;
+  socket_ops::setsockopt(server.get(), server_state,
+      IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+  read_descriptor_ = server.release();
+  write_descriptor_ = client.release();
+}
+
+socket_select_interrupter::~socket_select_interrupter()
+{
+  asio::error_code ec;
+  socket_ops::state_type state = socket_ops::internal_non_blocking;
+  if (read_descriptor_ != invalid_socket)
+    socket_ops::close(read_descriptor_, state, true, ec);
+  if (write_descriptor_ != invalid_socket)
+    socket_ops::close(write_descriptor_, state, true, ec);
+}
+
+void socket_select_interrupter::interrupt()
+{
+  char byte = 0;
+  socket_ops::buf b;
+  socket_ops::init_buf(b, &byte, 1);
+  asio::error_code ec;
+  socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+}
+
+bool socket_select_interrupter::reset()
+{
+  char data[1024];
+  socket_ops::buf b;
+  socket_ops::init_buf(b, data, sizeof(data));
+  asio::error_code ec;
+  int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+  bool was_interrupted = (bytes_read > 0);
+  while (bytes_read == sizeof(data))
+    bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+  return was_interrupted;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
+#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/strand_service.hpp b/ext/asio/asio/detail/impl/strand_service.hpp
new file mode 100644
index 0000000..81f438a
--- /dev/null
+++ b/ext/asio/asio/detail/impl/strand_service.hpp
@@ -0,0 +1,140 @@
+//
+// detail/impl/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline strand_service::strand_impl::strand_impl()
+  : operation(&strand_service::do_complete),
+    count_(0)
+{
+}
+
+struct strand_service::on_dispatch_exit
+{
+  io_service_impl* io_service_;
+  strand_impl* impl_;
+
+  ~on_dispatch_exit()
+  {
+    impl_->mutex_.lock();
+    bool more_handlers = (--impl_->count_ > 0);
+    impl_->mutex_.unlock();
+
+    if (more_handlers)
+      io_service_->post_immediate_completion(impl_);
+  }
+};
+
+inline void strand_service::destroy(strand_service::implementation_type& impl)
+{
+  impl = 0;
+}
+
+template <typename Handler>
+void strand_service::dispatch(strand_service::implementation_type& impl,
+    Handler handler)
+{
+  // If we are already in the strand then the handler can run immediately.
+  if (call_stack<strand_impl>::contains(impl))
+  {
+    asio::detail::fenced_block b;
+    asio_handler_invoke_helpers::invoke(handler, handler);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler> op;
+  typename op::ptr p = { boost::addressof(handler),
+    asio_handler_alloc_helpers::allocate(
+      sizeof(op), handler), 0 };
+  p.p = new (p.v) op(handler);
+
+  // If we are running inside the io_service, and no other handler is queued
+  // or running, then the handler can run immediately.
+  bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
+  impl->mutex_.lock();
+  bool first = (++impl->count_ == 1);
+  if (can_dispatch && first)
+  {
+    // Immediate invocation is allowed.
+    impl->mutex_.unlock();
+
+    // Memory must be releaesed before any upcall is made.
+    p.reset();
+
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl);
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_dispatch_exit on_exit = { &io_service_, impl };
+    (void)on_exit;
+
+    asio::detail::fenced_block b;
+    asio_handler_invoke_helpers::invoke(handler, handler);
+    return;
+  }
+
+  // Immediate invocation is not allowed, so enqueue for later.
+  impl->queue_.push(p.p);
+  impl->mutex_.unlock();
+  p.v = p.p = 0;
+
+  // The first handler to be enqueued is responsible for scheduling the
+  // strand.
+  if (first)
+    io_service_.post_immediate_completion(impl);
+}
+
+// Request the io_service to invoke the given handler and return immediately.
+template <typename Handler>
+void strand_service::post(strand_service::implementation_type& impl,
+    Handler handler)
+{
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler> op;
+  typename op::ptr p = { boost::addressof(handler),
+    asio_handler_alloc_helpers::allocate(
+      sizeof(op), handler), 0 };
+  p.p = new (p.v) op(handler);
+
+  // Add the handler to the queue.
+  impl->mutex_.lock();
+  bool first = (++impl->count_ == 1);
+  impl->queue_.push(p.p);
+  impl->mutex_.unlock();
+  p.v = p.p = 0;
+
+  // The first handler to be enqueue is responsible for scheduling the strand.
+  if (first)
+    io_service_.post_immediate_completion(impl);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/strand_service.ipp b/ext/asio/asio/detail/impl/strand_service.ipp
new file mode 100644
index 0000000..84b806a
--- /dev/null
+++ b/ext/asio/asio/detail/impl/strand_service.ipp
@@ -0,0 +1,106 @@
+//
+// detail/impl/strand_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/strand_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct strand_service::on_do_complete_exit
+{
+  io_service_impl* owner_;
+  strand_impl* impl_;
+
+  ~on_do_complete_exit()
+  {
+    impl_->mutex_.lock();
+    bool more_handlers = (--impl_->count_ > 0);
+    impl_->mutex_.unlock();
+
+    if (more_handlers)
+      owner_->post_immediate_completion(impl_);
+  }
+};
+
+strand_service::strand_service(asio::io_service& io_service)
+  : asio::detail::service_base<strand_service>(io_service),
+    io_service_(asio::use_service<io_service_impl>(io_service)),
+    mutex_(),
+    salt_(0)
+{
+}
+
+void strand_service::shutdown_service()
+{
+  op_queue<operation> ops;
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  for (std::size_t i = 0; i < num_implementations; ++i)
+    if (strand_impl* impl = implementations_[i].get())
+      ops.push(impl->queue_);
+}
+
+void strand_service::construct(strand_service::implementation_type& impl)
+{
+  std::size_t salt = salt_++;
+  std::size_t index = reinterpret_cast<std::size_t>(&impl);
+  index += (reinterpret_cast<std::size_t>(&impl) >> 3);
+  index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
+  index = index % num_implementations;
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (!implementations_[index])
+    implementations_[index].reset(new strand_impl);
+  impl = implementations_[index].get();
+}
+
+void strand_service::do_complete(io_service_impl* owner, operation* base,
+    asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+{
+  if (owner)
+  {
+    strand_impl* impl = static_cast<strand_impl*>(base);
+
+    // Get the next handler to be executed.
+    impl->mutex_.lock();
+    operation* o = impl->queue_.front();
+    impl->queue_.pop();
+    impl->mutex_.unlock();
+
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl);
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_do_complete_exit on_exit = { owner, impl };
+    (void)on_exit;
+
+    o->complete(*owner);
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/task_io_service.hpp b/ext/asio/asio/detail/impl/task_io_service.hpp
new file mode 100644
index 0000000..20ffd61
--- /dev/null
+++ b/ext/asio/asio/detail/impl/task_io_service.hpp
@@ -0,0 +1,60 @@
+//
+// detail/impl/task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+void task_io_service::dispatch(Handler handler)
+{
+  if (call_stack<task_io_service>::contains(this))
+  {
+    asio::detail::fenced_block b;
+    asio_handler_invoke_helpers::invoke(handler, handler);
+  }
+  else
+    post(handler);
+}
+
+template <typename Handler>
+void task_io_service::post(Handler handler)
+{
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler> op;
+  typename op::ptr p = { boost::addressof(handler),
+    asio_handler_alloc_helpers::allocate(
+      sizeof(op), handler), 0 };
+  p.p = new (p.v) op(handler);
+
+  post_immediate_completion(p.p);
+  p.v = p.p = 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/task_io_service.ipp b/ext/asio/asio/detail/impl/task_io_service.ipp
new file mode 100644
index 0000000..12a22be
--- /dev/null
+++ b/ext/asio/asio/detail/impl/task_io_service.ipp
@@ -0,0 +1,354 @@
+//
+// detail/impl/task_io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include <boost/limits.hpp>
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/task_io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct task_io_service::task_cleanup
+{
+  ~task_cleanup()
+  {
+    // Enqueue the completed operations and reinsert the task at the end of
+    // the operation queue.
+    lock_->lock();
+    task_io_service_->task_interrupted_ = true;
+    task_io_service_->op_queue_.push(*ops_);
+    task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
+  }
+
+  task_io_service* task_io_service_;
+  mutex::scoped_lock* lock_;
+  op_queue<operation>* ops_;
+};
+
+struct task_io_service::work_finished_on_block_exit
+{
+  ~work_finished_on_block_exit()
+  {
+    task_io_service_->work_finished();
+  }
+
+  task_io_service* task_io_service_;
+};
+
+struct task_io_service::idle_thread_info
+{
+  event wakeup_event;
+  idle_thread_info* next;
+};
+
+task_io_service::task_io_service(asio::io_service& io_service)
+  : asio::detail::service_base<task_io_service>(io_service),
+    mutex_(),
+    task_(0),
+    task_interrupted_(true),
+    outstanding_work_(0),
+    stopped_(false),
+    shutdown_(false),
+    first_idle_thread_(0)
+{
+}
+
+void task_io_service::init(std::size_t /*concurrency_hint*/)
+{
+}
+
+void task_io_service::shutdown_service()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  // Destroy handler objects.
+  while (!op_queue_.empty())
+  {
+    operation* o = op_queue_.front();
+    op_queue_.pop();
+    if (o != &task_operation_)
+      o->destroy();
+  }
+
+  // Reset to initial state.
+  task_ = 0;
+}
+
+void task_io_service::init_task()
+{
+  mutex::scoped_lock lock(mutex_);
+  if (!shutdown_ && !task_)
+  {
+    task_ = &use_service<reactor>(this->get_io_service());
+    op_queue_.push(&task_operation_);
+    wake_one_thread_and_unlock(lock);
+  }
+}
+
+std::size_t task_io_service::run(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  call_stack<task_io_service>::context ctx(this);
+
+  idle_thread_info this_idle_thread;
+  this_idle_thread.next = 0;
+
+  mutex::scoped_lock lock(mutex_);
+
+  std::size_t n = 0;
+  for (; do_one(lock, &this_idle_thread); lock.lock())
+    if (n != (std::numeric_limits<std::size_t>::max)())
+      ++n;
+  return n;
+}
+
+std::size_t task_io_service::run_one(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  call_stack<task_io_service>::context ctx(this);
+
+  idle_thread_info this_idle_thread;
+  this_idle_thread.next = 0;
+
+  mutex::scoped_lock lock(mutex_);
+
+  return do_one(lock, &this_idle_thread);
+}
+
+std::size_t task_io_service::poll(asio::error_code& ec)
+{
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  call_stack<task_io_service>::context ctx(this);
+
+  mutex::scoped_lock lock(mutex_);
+
+  std::size_t n = 0;
+  for (; do_one(lock, 0); lock.lock())
+    if (n != (std::numeric_limits<std::size_t>::max)())
+      ++n;
+  return n;
+}
+
+std::size_t task_io_service::poll_one(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  call_stack<task_io_service>::context ctx(this);
+
+  mutex::scoped_lock lock(mutex_);
+
+  return do_one(lock, 0);
+}
+
+void task_io_service::stop()
+{
+  mutex::scoped_lock lock(mutex_);
+  stop_all_threads(lock);
+}
+
+void task_io_service::reset()
+{
+  mutex::scoped_lock lock(mutex_);
+  stopped_ = false;
+}
+
+void task_io_service::post_immediate_completion(task_io_service::operation* op)
+{
+  work_started();
+  post_deferred_completion(op);
+}
+
+void task_io_service::post_deferred_completion(task_io_service::operation* op)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue_.push(op);
+  wake_one_thread_and_unlock(lock);
+}
+
+void task_io_service::post_deferred_completions(
+    op_queue<task_io_service::operation>& ops)
+{
+  if (!ops.empty())
+  {
+    mutex::scoped_lock lock(mutex_);
+    op_queue_.push(ops);
+    wake_one_thread_and_unlock(lock);
+  }
+}
+
+std::size_t task_io_service::do_one(mutex::scoped_lock& lock,
+    task_io_service::idle_thread_info* this_idle_thread)
+{
+  bool polling = !this_idle_thread;
+  bool task_has_run = false;
+  while (!stopped_)
+  {
+    if (!op_queue_.empty())
+    {
+      // Prepare to execute first handler from queue.
+      operation* o = op_queue_.front();
+      op_queue_.pop();
+      bool more_handlers = (!op_queue_.empty());
+
+      if (o == &task_operation_)
+      {
+        task_interrupted_ = more_handlers || polling;
+
+        // If the task has already run and we're polling then we're done.
+        if (task_has_run && polling)
+        {
+          task_interrupted_ = true;
+          op_queue_.push(&task_operation_);
+          return 0;
+        }
+        task_has_run = true;
+
+        if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
+          lock.unlock();
+
+        op_queue<operation> completed_ops;
+        task_cleanup c = { this, &lock, &completed_ops };
+        (void)c;
+
+        // Run the task. May throw an exception. Only block if the operation
+        // queue is empty and we're not polling, otherwise we want to return
+        // as soon as possible.
+        task_->run(!more_handlers && !polling, completed_ops);
+      }
+      else
+      {
+        if (more_handlers)
+          wake_one_thread_and_unlock(lock);
+        else
+          lock.unlock();
+
+        // Ensure the count of outstanding work is decremented on block exit.
+        work_finished_on_block_exit on_exit = { this };
+        (void)on_exit;
+
+        // Complete the operation. May throw an exception.
+        o->complete(*this); // deletes the operation object
+
+        return 1;
+      }
+    }
+    else if (this_idle_thread)
+    {
+      // Nothing to run right now, so just wait for work to do.
+      this_idle_thread->next = first_idle_thread_;
+      first_idle_thread_ = this_idle_thread;
+      this_idle_thread->wakeup_event.clear(lock);
+      this_idle_thread->wakeup_event.wait(lock);
+    }
+    else
+    {
+      return 0;
+    }
+  }
+
+  return 0;
+}
+
+void task_io_service::stop_all_threads(
+    mutex::scoped_lock& lock)
+{
+  stopped_ = true;
+
+  while (first_idle_thread_)
+  {
+    idle_thread_info* idle_thread = first_idle_thread_;
+    first_idle_thread_ = idle_thread->next;
+    idle_thread->next = 0;
+    idle_thread->wakeup_event.signal(lock);
+  }
+
+  if (!task_interrupted_ && task_)
+  {
+    task_interrupted_ = true;
+    task_->interrupt();
+  }
+}
+
+bool task_io_service::wake_one_idle_thread_and_unlock(
+    mutex::scoped_lock& lock)
+{
+  if (first_idle_thread_)
+  {
+    idle_thread_info* idle_thread = first_idle_thread_;
+    first_idle_thread_ = idle_thread->next;
+    idle_thread->next = 0;
+    idle_thread->wakeup_event.signal_and_unlock(lock);
+    return true;
+  }
+  return false;
+}
+
+void task_io_service::wake_one_thread_and_unlock(
+    mutex::scoped_lock& lock)
+{
+  if (!wake_one_idle_thread_and_unlock(lock))
+  {
+    if (!task_interrupted_ && task_)
+    {
+      task_interrupted_ = true;
+      task_->interrupt();
+    }
+    lock.unlock();
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/throw_error.ipp b/ext/asio/asio/detail/impl/throw_error.ipp
new file mode 100644
index 0000000..a04fbf4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/throw_error.ipp
@@ -0,0 +1,47 @@
+//
+// detail/impl/throw_error.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/throw_error.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL
+void do_throw_error(const asio::error_code& err)
+{
+  asio::system_error e(err);
+  boost::throw_exception(e);
+}
+
+ASIO_DECL
+void do_throw_error(const asio::error_code& err, const char* location)
+{
+  asio::system_error e(err, location);
+  boost::throw_exception(e);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP
diff --git a/ext/asio/asio/detail/impl/timer_queue.ipp b/ext/asio/asio/detail/impl/timer_queue.ipp
new file mode 100644
index 0000000..63fbd7e
--- /dev/null
+++ b/ext/asio/asio/detail/impl/timer_queue.ipp
@@ -0,0 +1,85 @@
+//
+// detail/impl/timer_queue.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HEADER_ONLY)
+
+#include "asio/detail/timer_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()
+{
+}
+
+timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()
+{
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(
+    const time_type& time, per_timer_data& timer, timer_op* op)
+{
+  return impl_.enqueue_timer(time, timer, op);
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const
+{
+  return impl_.empty();
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(
+    long max_duration) const
+{
+  return impl_.wait_duration_msec(max_duration);
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(
+    long max_duration) const
+{
+  return impl_.wait_duration_usec(max_duration);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(
+    op_queue<operation>& ops)
+{
+  impl_.get_ready_timers(ops);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(
+    op_queue<operation>& ops)
+{
+  impl_.get_all_timers(ops);
+}
+
+std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
+    per_timer_data& timer, op_queue<operation>& ops)
+{
+  return impl_.cancel_timer(timer, ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
diff --git a/ext/asio/asio/detail/impl/timer_queue_set.ipp b/ext/asio/asio/detail/impl/timer_queue_set.ipp
new file mode 100644
index 0000000..81ab5a9
--- /dev/null
+++ b/ext/asio/asio/detail/impl/timer_queue_set.ipp
@@ -0,0 +1,101 @@
+//
+// detail/impl/timer_queue_set.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue_set::timer_queue_set()
+  : first_(0)
+{
+}
+
+void timer_queue_set::insert(timer_queue_base* q)
+{
+  q->next_ = first_;
+  first_ = q;
+}
+
+void timer_queue_set::erase(timer_queue_base* q)
+{
+  if (first_)
+  {
+    if (q == first_)
+    {
+      first_ = q->next_;
+      q->next_ = 0;
+      return;
+    }
+
+    for (timer_queue_base* p = first_; p->next_; p = p->next_)
+    {
+      if (p->next_ == q)
+      {
+        p->next_ = q->next_;
+        q->next_ = 0;
+        return;
+      }
+    }
+  }
+}
+
+bool timer_queue_set::all_empty() const
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    if (!p->empty())
+      return false;
+  return true;
+}
+
+long timer_queue_set::wait_duration_msec(long max_duration) const
+{
+  long min_duration = max_duration;
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    min_duration = p->wait_duration_msec(min_duration);
+  return min_duration;
+}
+
+long timer_queue_set::wait_duration_usec(long max_duration) const
+{
+  long min_duration = max_duration;
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    min_duration = p->wait_duration_usec(min_duration);
+  return min_duration;
+}
+
+void timer_queue_set::get_ready_timers(op_queue<operation>& ops)
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    p->get_ready_timers(ops);
+}
+
+void timer_queue_set::get_all_timers(op_queue<operation>& ops)
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    p->get_all_timers(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
diff --git a/ext/asio/asio/detail/impl/win_event.ipp b/ext/asio/asio/detail/impl/win_event.ipp
new file mode 100644
index 0000000..2b72f6e
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_event.ipp
@@ -0,0 +1,50 @@
+//
+// detail/win_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_event.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_event::win_event()
+  : event_(::CreateEvent(0, true, false, 0))
+{
+  if (!event_)
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "event");
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
new file mode 100644
index 0000000..3b30b1d
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
@@ -0,0 +1,452 @@
+//
+// detail/impl/win_iocp_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service::overlapped_wrapper
+  : public OVERLAPPED
+{
+public:
+  explicit overlapped_wrapper(asio::error_code& ec)
+  {
+    Internal = 0;
+    InternalHigh = 0;
+    Offset = 0;
+    OffsetHigh = 0;
+
+    // Create a non-signalled manual-reset event, for GetOverlappedResult.
+    hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
+    if (hEvent)
+    {
+      // As documented in GetQueuedCompletionStatus, setting the low order
+      // bit of this event prevents our synchronous writes from being treated
+      // as completion port events.
+      *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
+    }
+    else
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+  }
+
+  ~overlapped_wrapper()
+  {
+    if (hEvent)
+    {
+      ::CloseHandle(hEvent);
+    }
+  }
+};
+
+win_iocp_handle_service::win_iocp_handle_service(
+    asio::io_service& io_service)
+  : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
+    mutex_(),
+    impl_list_(0)
+{
+}
+
+void win_iocp_handle_service::shutdown_service()
+{
+  // Close all implementations, causing all operations to complete.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  implementation_type* impl = impl_list_;
+  while (impl)
+  {
+    close_for_destruction(*impl);
+    impl = impl->next_;
+  }
+}
+
+void win_iocp_handle_service::construct(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  impl.handle_ = INVALID_HANDLE_VALUE;
+  impl.safe_cancellation_thread_id_ = 0;
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::destroy(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  close_for_destruction(impl);
+  
+  // Remove implementation from linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_handle_service::assign(
+    win_iocp_handle_service::implementation_type& impl,
+    const native_type& native_handle, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (iocp_service_.register_handle(native_handle, ec))
+    return ec;
+
+  impl.handle_ = native_handle;
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_handle_service::close(
+    win_iocp_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    if (!::CloseHandle(impl.handle_))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+      return ec;
+    }
+
+    impl.handle_ = INVALID_HANDLE_VALUE;
+    impl.safe_cancellation_thread_id_ = 0;
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_handle_service::cancel(
+    win_iocp_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+  }
+  else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+  {
+    // The version of Windows supports cancellation from any thread.
+    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+    cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+    if (!cancel_io_ex(impl.handle_, 0))
+    {
+      DWORD last_error = ::GetLastError();
+      if (last_error == ERROR_NOT_FOUND)
+      {
+        // ERROR_NOT_FOUND means that there were no operations to be
+        // cancelled. We swallow this error to match the behaviour on other
+        // platforms.
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else if (impl.safe_cancellation_thread_id_ == 0)
+  {
+    // No operations have been started, so there's nothing to cancel.
+    ec = asio::error_code();
+  }
+  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+  {
+    // Asynchronous operations have been started from the current thread only,
+    // so it is safe to try to cancel them using CancelIo.
+    if (!::CancelIo(impl.handle_))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else
+  {
+    // Asynchronous operations have been started from more than one thread,
+    // so cancellation is not safe.
+    ec = asio::error::operation_not_supported;
+  }
+
+  return ec;
+}
+
+size_t win_iocp_handle_service::do_write(
+    win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+    const asio::const_buffer& buffer, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes on a handle is a no-op.
+  if (asio::buffer_size(buffer) == 0)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  overlapped_wrapper overlapped(ec);
+  if (ec)
+  {
+    return 0;
+  }
+
+  // Write the data. 
+  overlapped.Offset = offset & 0xFFFFFFFF;
+  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+  BOOL ok = ::WriteFile(impl.handle_,
+      asio::buffer_cast<LPCVOID>(buffer),
+      static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
+  if (!ok) 
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error != ERROR_IO_PENDING)
+    {
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+      return 0;
+    }
+  }
+
+  // Wait for the operation to complete.
+  DWORD bytes_transferred = 0;
+  ok = ::GetOverlappedResult(impl.handle_,
+      &overlapped, &bytes_transferred, TRUE);
+  if (!ok)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return 0;
+  }
+
+  ec = asio::error_code();
+  return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_write_op(
+    win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+    const asio::const_buffer& buffer, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+  {
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  }
+  else if (asio::buffer_size(buffer) == 0)
+  {
+    // A request to write 0 bytes on a handle is a no-op.
+    iocp_service_.on_completion(op);
+  }
+  else
+  {
+    DWORD bytes_transferred = 0;
+    op->Offset = offset & 0xFFFFFFFF;
+    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+    BOOL ok = ::WriteFile(impl.handle_,
+        asio::buffer_cast<LPCVOID>(buffer),
+        static_cast<DWORD>(asio::buffer_size(buffer)),
+        &bytes_transferred, op);
+    DWORD last_error = ::GetLastError();
+    if (!ok && last_error != ERROR_IO_PENDING
+        && last_error != ERROR_MORE_DATA)
+    {
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    }
+    else
+    {
+      iocp_service_.on_pending(op);
+    }
+  }
+}
+
+size_t win_iocp_handle_service::do_read(
+    win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+    const asio::mutable_buffer& buffer, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+  
+  // A request to read 0 bytes on a stream handle is a no-op.
+  if (asio::buffer_size(buffer) == 0)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  overlapped_wrapper overlapped(ec);
+  if (ec)
+  {
+    return 0;
+  }
+
+  // Read some data.
+  overlapped.Offset = offset & 0xFFFFFFFF;
+  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+  BOOL ok = ::ReadFile(impl.handle_,
+      asio::buffer_cast<LPVOID>(buffer),
+      static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
+  if (!ok) 
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
+    {
+      if (last_error == ERROR_HANDLE_EOF)
+      {
+        ec = asio::error::eof;
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+      return 0;
+    }
+  }
+
+  // Wait for the operation to complete.
+  DWORD bytes_transferred = 0;
+  ok = ::GetOverlappedResult(impl.handle_,
+      &overlapped, &bytes_transferred, TRUE);
+  if (!ok)
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error == ERROR_HANDLE_EOF)
+    {
+      ec = asio::error::eof;
+    }
+    else
+    {
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    return 0;
+  }
+
+  ec = asio::error_code();
+  return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_read_op(
+    win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+    const asio::mutable_buffer& buffer, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+  {
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  }
+  else if (asio::buffer_size(buffer) == 0)
+  {
+    // A request to read 0 bytes on a handle is a no-op.
+    iocp_service_.on_completion(op);
+  }
+  else
+  {
+    DWORD bytes_transferred = 0;
+    op->Offset = offset & 0xFFFFFFFF;
+    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+    BOOL ok = ::ReadFile(impl.handle_,
+        asio::buffer_cast<LPVOID>(buffer),
+        static_cast<DWORD>(asio::buffer_size(buffer)),
+        &bytes_transferred, op);
+    DWORD last_error = ::GetLastError();
+    if (!ok && last_error != ERROR_IO_PENDING
+        && last_error != ERROR_MORE_DATA)
+    {
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    }
+    else
+    {
+      iocp_service_.on_pending(op);
+    }
+  }
+}
+
+void win_iocp_handle_service::update_cancellation_thread_id(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  if (impl.safe_cancellation_thread_id_ == 0)
+    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+    impl.safe_cancellation_thread_id_ = ~DWORD(0);
+}
+
+void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
+{
+  if (is_open(impl))
+  {
+    ::CloseHandle(impl.handle_);
+    impl.handle_ = INVALID_HANDLE_VALUE;
+    impl.safe_cancellation_thread_id_ = 0;
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.hpp b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp
new file mode 100644
index 0000000..ab23547
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp
@@ -0,0 +1,115 @@
+//
+// detail/impl/win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+void win_iocp_io_service::dispatch(Handler handler)
+{
+  if (call_stack<win_iocp_io_service>::contains(this))
+  {
+    asio::detail::fenced_block b;
+    asio_handler_invoke_helpers::invoke(handler, handler);
+  }
+  else
+    post(handler);
+}
+
+template <typename Handler>
+void win_iocp_io_service::post(Handler handler)
+{
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler> op;
+  typename op::ptr p = { boost::addressof(handler),
+    asio_handler_alloc_helpers::allocate(
+      sizeof(op), handler), 0 };
+  p.p = new (p.v) op(handler);
+
+  post_immediate_completion(p.p);
+  p.v = p.p = 0;
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::add_timer_queue(
+    timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::remove_timer_queue(
+    timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+  // If the service has been shut down we silently discard the timer.
+  if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+  {
+    post_immediate_completion(op);
+    return;
+  }
+
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  work_started();
+  if (earliest)
+    update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+  // If the service has been shut down we silently ignore the cancellation.
+  if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+    return 0;
+
+  mutex::scoped_lock lock(dispatch_mutex_);
+  op_queue<win_iocp_operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops);
+  post_deferred_completions(ops);
+  return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.ipp b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp
new file mode 100644
index 0000000..890e32f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp
@@ -0,0 +1,496 @@
+//
+// detail/impl/win_iocp_io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/limits.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_io_service::work_finished_on_block_exit
+{
+  ~work_finished_on_block_exit()
+  {
+    io_service_->work_finished();
+  }
+
+  win_iocp_io_service* io_service_;
+};
+
+struct win_iocp_io_service::timer_thread_function
+{
+  void operator()()
+  {
+    while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0)
+    {
+      if (::WaitForSingleObject(io_service_->waitable_timer_.handle,
+            INFINITE) == WAIT_OBJECT_0)
+      {
+        ::InterlockedExchange(&io_service_->dispatch_required_, 1);
+        ::PostQueuedCompletionStatus(io_service_->iocp_.handle,
+            0, wake_for_dispatch, 0);
+      }
+    }
+  }
+
+  win_iocp_io_service* io_service_;
+};
+
+win_iocp_io_service::win_iocp_io_service(asio::io_service& io_service)
+  : asio::detail::service_base<win_iocp_io_service>(io_service),
+    iocp_(),
+    outstanding_work_(0),
+    stopped_(0),
+    shutdown_(0),
+    dispatch_required_(0)
+{
+}
+
+void win_iocp_io_service::init(size_t concurrency_hint)
+{
+  iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+      static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
+  if (!iocp_.handle)
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "iocp");
+  }
+}
+
+void win_iocp_io_service::shutdown_service()
+{
+  ::InterlockedExchange(&shutdown_, 1);
+
+  if (timer_thread_)
+  {
+    LARGE_INTEGER timeout;
+    timeout.QuadPart = 1;
+    ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
+  }
+
+  while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
+  {
+    op_queue<win_iocp_operation> ops;
+    timer_queues_.get_all_timers(ops);
+    ops.push(completed_ops_);
+    if (!ops.empty())
+    {
+      while (win_iocp_operation* op = ops.front())
+      {
+        ops.pop();
+        ::InterlockedDecrement(&outstanding_work_);
+        op->destroy();
+      }
+    }
+    else
+    {
+      DWORD bytes_transferred = 0;
+      dword_ptr_t completion_key = 0;
+      LPOVERLAPPED overlapped = 0;
+      ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+          &completion_key, &overlapped, gqcs_timeout);
+      if (overlapped)
+      {
+        ::InterlockedDecrement(&outstanding_work_);
+        static_cast<win_iocp_operation*>(overlapped)->destroy();
+      }
+    }
+  }
+
+  if (timer_thread_)
+    timer_thread_->join();
+}
+
+asio::error_code win_iocp_io_service::register_handle(
+    HANDLE handle, asio::error_code& ec)
+{
+  if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+  return ec;
+}
+
+size_t win_iocp_io_service::run(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  call_stack<win_iocp_io_service>::context ctx(this);
+
+  size_t n = 0;
+  while (do_one(true, ec))
+    if (n != (std::numeric_limits<size_t>::max)())
+      ++n;
+  return n;
+}
+
+size_t win_iocp_io_service::run_one(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  call_stack<win_iocp_io_service>::context ctx(this);
+
+  return do_one(true, ec);
+}
+
+size_t win_iocp_io_service::poll(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  call_stack<win_iocp_io_service>::context ctx(this);
+
+  size_t n = 0;
+  while (do_one(false, ec))
+    if (n != (std::numeric_limits<size_t>::max)())
+      ++n;
+  return n;
+}
+
+size_t win_iocp_io_service::poll_one(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  call_stack<win_iocp_io_service>::context ctx(this);
+
+  return do_one(false, ec);
+}
+
+void win_iocp_io_service::stop()
+{
+  if (::InterlockedExchange(&stopped_, 1) == 0)
+  {
+    if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+    {
+      DWORD last_error = ::GetLastError();
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "pqcs");
+    }
+  }
+}
+
+void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op)
+{
+  // Flag the operation as ready.
+  op->ready_ = 1;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle,
+        0, overlapped_contains_result, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+void win_iocp_io_service::post_deferred_completions(
+    op_queue<win_iocp_operation>& ops)
+{
+  while (win_iocp_operation* op = ops.front())
+  {
+    ops.pop();
+
+    // Flag the operation as ready.
+    op->ready_ = 1;
+
+    // Enqueue the operation on the I/O completion port.
+    if (!::PostQueuedCompletionStatus(iocp_.handle,
+          0, overlapped_contains_result, op))
+    {
+      // Out of resources. Put on completed queue instead.
+      mutex::scoped_lock lock(dispatch_mutex_);
+      completed_ops_.push(op);
+      completed_ops_.push(ops);
+      ::InterlockedExchange(&dispatch_required_, 1);
+    }
+  }
+}
+
+void win_iocp_io_service::on_pending(win_iocp_operation* op)
+{
+  if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+  {
+    // Enqueue the operation on the I/O completion port.
+    if (!::PostQueuedCompletionStatus(iocp_.handle,
+          0, overlapped_contains_result, op))
+    {
+      // Out of resources. Put on completed queue instead.
+      mutex::scoped_lock lock(dispatch_mutex_);
+      completed_ops_.push(op);
+      ::InterlockedExchange(&dispatch_required_, 1);
+    }
+  }
+}
+
+void win_iocp_io_service::on_completion(win_iocp_operation* op,
+    DWORD last_error, DWORD bytes_transferred)
+{
+  // Flag that the operation is ready for invocation.
+  op->ready_ = 1;
+
+  // Store results in the OVERLAPPED structure.
+  op->Internal = asio::error::get_system_category();
+  op->Offset = last_error;
+  op->OffsetHigh = bytes_transferred;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle,
+        0, overlapped_contains_result, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+void win_iocp_io_service::on_completion(win_iocp_operation* op,
+    const asio::error_code& ec, DWORD bytes_transferred)
+{
+  // Flag that the operation is ready for invocation.
+  op->ready_ = 1;
+
+  // Store results in the OVERLAPPED structure.
+  op->Internal = ec.category();
+  op->Offset = ec.value();
+  op->OffsetHigh = bytes_transferred;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle,
+        0, overlapped_contains_result, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+size_t win_iocp_io_service::do_one(bool block, asio::error_code& ec)
+{
+  for (;;)
+  {
+    // Try to acquire responsibility for dispatching timers and completed ops.
+    if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)
+    {
+      mutex::scoped_lock lock(dispatch_mutex_);
+
+      // Dispatch pending timers and operations.
+      op_queue<win_iocp_operation> ops;
+      ops.push(completed_ops_);
+      timer_queues_.get_ready_timers(ops);
+      post_deferred_completions(ops);
+      update_timeout();
+    }
+
+    // Get the next operation from the queue.
+    DWORD bytes_transferred = 0;
+    dword_ptr_t completion_key = 0;
+    LPOVERLAPPED overlapped = 0;
+    ::SetLastError(0);
+    BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+        &completion_key, &overlapped, block ? gqcs_timeout : 0);
+    DWORD last_error = ::GetLastError();
+
+    if (overlapped)
+    {
+      win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
+      asio::error_code result_ec(last_error,
+          asio::error::get_system_category());
+
+      // We may have been passed the last_error and bytes_transferred in the
+      // OVERLAPPED structure itself.
+      if (completion_key == overlapped_contains_result)
+      {
+        result_ec = asio::error_code(static_cast<int>(op->Offset),
+            static_cast<asio::error_category>(op->Internal));
+        bytes_transferred = op->OffsetHigh;
+      }
+
+      // Otherwise ensure any result has been saved into the OVERLAPPED
+      // structure.
+      else
+      {
+        op->Internal = result_ec.category();
+        op->Offset = result_ec.value();
+        op->OffsetHigh = bytes_transferred;
+      }
+
+      // Dispatch the operation only if ready. The operation may not be ready
+      // if the initiating function (e.g. a call to WSARecv) has not yet
+      // returned. This is because the initiating function still wants access
+      // to the operation's OVERLAPPED structure.
+      if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+      {
+        // Ensure the count of outstanding work is decremented on block exit.
+        work_finished_on_block_exit on_exit = { this };
+        (void)on_exit;
+
+        op->complete(*this, result_ec, bytes_transferred);
+        ec = asio::error_code();
+        return 1;
+      }
+    }
+    else if (!ok)
+    {
+      if (last_error != WAIT_TIMEOUT)
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+        return 0;
+      }
+
+      // If we're not polling we need to keep going until we get a real handler.
+      if (block)
+        continue;
+
+      ec = asio::error_code();
+      return 0;
+    }
+    else if (completion_key == wake_for_dispatch)
+    {
+      // We have been woken up to try to acquire responsibility for dispatching
+      // timers and completed operations.
+    }
+    else
+    {
+      // The stopped_ flag is always checked to ensure that any leftover
+      // interrupts from a previous run invocation are ignored.
+      if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+      {
+        // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+        if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+        {
+          last_error = ::GetLastError();
+          ec = asio::error_code(last_error,
+              asio::error::get_system_category());
+          return 0;
+        }
+
+        ec = asio::error_code();
+        return 0;
+      }
+    }
+  }
+}
+
+void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  timer_queues_.insert(&queue);
+
+  if (!waitable_timer_.handle)
+  {
+    waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);
+    if (waitable_timer_.handle == 0)
+    {
+      DWORD last_error = ::GetLastError();
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "timer");
+    }
+
+    LARGE_INTEGER timeout;
+    timeout.QuadPart = -max_timeout_usec;
+    timeout.QuadPart *= 10;
+    ::SetWaitableTimer(waitable_timer_.handle,
+        &timeout, max_timeout_msec, 0, 0, FALSE);
+  }
+
+  if (!timer_thread_)
+  {
+    timer_thread_function thread_function = { this };
+    timer_thread_.reset(new thread(thread_function, 65536));
+  }
+}
+
+void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  timer_queues_.erase(&queue);
+}
+
+void win_iocp_io_service::update_timeout()
+{
+  if (timer_thread_)
+  {
+    // There's no point updating the waitable timer if the new timeout period
+    // exceeds the maximum timeout. In that case, we might as well wait for the
+    // existing period of the timer to expire.
+    long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);
+    if (timeout_usec < max_timeout_usec)
+    {
+      LARGE_INTEGER timeout;
+      timeout.QuadPart = -timeout_usec;
+      timeout.QuadPart *= 10;
+      ::SetWaitableTimer(waitable_timer_.handle,
+          &timeout, max_timeout_msec, 0, 0, FALSE);
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
new file mode 100644
index 0000000..7631514
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
@@ -0,0 +1,180 @@
+//
+// detail/impl/win_iocp_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <cstring>
+#include "asio/detail/win_iocp_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_serial_port_service::win_iocp_serial_port_service(
+    asio::io_service& io_service)
+  : handle_service_(io_service)
+{
+}
+
+void win_iocp_serial_port_service::shutdown_service()
+{
+}
+
+asio::error_code win_iocp_serial_port_service::open(
+    win_iocp_serial_port_service::implementation_type& impl,
+    const std::string& device, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  // For convenience, add a leading \\.\ sequence if not already present.
+  std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
+
+  // Open a handle to the serial port.
+  ::HANDLE handle = ::CreateFileA(name.c_str(),
+      GENERIC_READ | GENERIC_WRITE, 0, 0,
+      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+  if (handle == INVALID_HANDLE_VALUE)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Determine the initial serial port parameters.
+  using namespace std; // For memset.
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle, &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Set some default serial port parameters. This implementation does not
+  // support changing these, so they might as well be in a known state.
+  dcb.fBinary = TRUE; // Win32 only supports binary mode.
+  dcb.fDsrSensitivity = FALSE;
+  dcb.fNull = FALSE; // Do not ignore NULL characters.
+  dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
+  if (!::SetCommState(handle, &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Set up timeouts so that the serial port will behave similarly to a
+  // network socket. Reads wait for at least one byte, then return with
+  // whatever they have. Writes return once everything is out the door.
+  ::COMMTIMEOUTS timeouts;
+  timeouts.ReadIntervalTimeout = 1;
+  timeouts.ReadTotalTimeoutMultiplier = 0;
+  timeouts.ReadTotalTimeoutConstant = 0;
+  timeouts.WriteTotalTimeoutMultiplier = 0;
+  timeouts.WriteTotalTimeoutConstant = 0;
+  if (!::SetCommTimeouts(handle, &timeouts))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // We're done. Take ownership of the serial port handle.
+  if (handle_service_.assign(impl, handle, ec))
+    ::CloseHandle(handle);
+  return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_set_option(
+    win_iocp_serial_port_service::implementation_type& impl,
+    win_iocp_serial_port_service::store_function_type store,
+    const void* option, asio::error_code& ec)
+{
+  using namespace std; // For memcpy.
+
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle_service_.native(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  if (store(option, dcb, ec))
+    return ec;
+
+  if (!::SetCommState(handle_service_.native(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_get_option(
+    const win_iocp_serial_port_service::implementation_type& impl,
+    win_iocp_serial_port_service::load_function_type load,
+    void* option, asio::error_code& ec) const
+{
+  using namespace std; // For memset.
+
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle_service_.native(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  return load(option, dcb, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
new file mode 100644
index 0000000..37c6f63
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
@@ -0,0 +1,575 @@
+//
+// detail/impl/win_iocp_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_socket_service_base::win_iocp_socket_service_base(
+    asio::io_service& io_service)
+  : io_service_(io_service),
+    iocp_service_(use_service<win_iocp_io_service>(io_service)),
+    reactor_(0),
+    mutex_(),
+    impl_list_(0)
+{
+}
+
+void win_iocp_socket_service_base::shutdown_service()
+{
+  // Close all implementations, causing all operations to complete.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  base_implementation_type* impl = impl_list_;
+  while (impl)
+  {
+    asio::error_code ignored_ec;
+    close_for_destruction(*impl);
+    impl = impl->next_;
+  }
+}
+
+void win_iocp_socket_service_base::construct(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+  impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::destroy(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  close_for_destruction(impl);
+
+  // Remove implementation from linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_socket_service_base::close(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    // Check if the reactor was created, in which case we need to close the
+    // socket on the reactor as well to cancel any operations that might be
+    // running there.
+    reactor* r = static_cast<reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->close_descriptor(impl.socket_, impl.reactor_data_);
+  }
+
+  if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0)
+  {
+    impl.socket_ = invalid_socket;
+    impl.state_ = 0;
+    impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+    impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+  }
+
+  return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::cancel(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+  else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+  {
+    // The version of Windows supports cancellation from any thread.
+    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+    cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+    socket_type sock = impl.socket_;
+    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+    if (!cancel_io_ex(sock_as_handle, 0))
+    {
+      DWORD last_error = ::GetLastError();
+      if (last_error == ERROR_NOT_FOUND)
+      {
+        // ERROR_NOT_FOUND means that there were no operations to be
+        // cancelled. We swallow this error to match the behaviour on other
+        // platforms.
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+#if defined(ASIO_ENABLE_CANCELIO)
+  else if (impl.safe_cancellation_thread_id_ == 0)
+  {
+    // No operations have been started, so there's nothing to cancel.
+    ec = asio::error_code();
+  }
+  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+  {
+    // Asynchronous operations have been started from the current thread only,
+    // so it is safe to try to cancel them using CancelIo.
+    socket_type sock = impl.socket_;
+    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+    if (!::CancelIo(sock_as_handle))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else
+  {
+    // Asynchronous operations have been started from more than one thread,
+    // so cancellation is not safe.
+    ec = asio::error::operation_not_supported;
+  }
+#else // defined(ASIO_ENABLE_CANCELIO)
+  else
+  {
+    // Cancellation is not supported as CancelIo may not be used.
+    ec = asio::error::operation_not_supported;
+  }
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  // Cancel any operations started via the reactor.
+  if (!ec)
+  {
+    reactor* r = static_cast<reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->cancel_ops(impl.socket_, impl.reactor_data_);
+  }
+
+  return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_open(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int family, int type, int protocol, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  socket_holder sock(socket_ops::socket(family, type, protocol, ec));
+  if (sock.get() == invalid_socket)
+    return ec;
+
+  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
+  if (iocp_service_.register_handle(sock_as_handle, ec))
+    return ec;
+
+  impl.socket_ = sock.release();
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_assign(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int type, socket_type native_socket, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
+  if (iocp_service_.register_handle(sock_as_handle, ec))
+    return ec;
+
+  impl.socket_ = native_socket;
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+  ec = asio::error_code();
+  return ec;
+}
+
+void win_iocp_socket_service_base::start_send_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    socket_base::message_flags flags, bool noop, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (noop)
+    iocp_service_.on_completion(op);
+  else if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    int result = ::WSASend(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_send_to_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    const socket_addr_type* addr, int addrlen,
+    socket_base::message_flags flags, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    int result = ::WSASendTo(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, flags, addr, addrlen, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_receive_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    socket_base::message_flags flags, bool noop, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (noop)
+    iocp_service_.on_completion(op);
+  else if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    DWORD recv_flags = flags;
+    int result = ::WSARecv(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, &recv_flags, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_NETNAME_DELETED)
+      last_error = WSAECONNRESET;
+    else if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_null_buffers_receive_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    socket_base::message_flags flags, reactor_op* op)
+{
+  if ((impl.state_ & socket_ops::stream_oriented) != 0)
+  {
+    // For stream sockets on Windows, we may issue a 0-byte overlapped
+    // WSARecv to wait until there is data available on the socket.
+    ::WSABUF buf = { 0, 0 };
+    start_receive_op(impl, &buf, 1, flags, false, op);
+  }
+  else
+  {
+    start_reactor_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        op);
+  }
+}
+
+void win_iocp_socket_service_base::start_receive_from_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+    socket_base::message_flags flags, int* addrlen, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    DWORD recv_flags = flags;
+    int result = ::WSARecvFrom(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_accept_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    bool peer_is_open, socket_holder& new_socket, int family, int type,
+    int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else if (peer_is_open)
+    iocp_service_.on_completion(op, asio::error::already_open);
+  else
+  {
+    asio::error_code ec;
+    new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+    if (new_socket.get() == invalid_socket)
+      iocp_service_.on_completion(op, ec);
+    else
+    {
+      DWORD bytes_read = 0;
+      BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
+          0, address_length, address_length, &bytes_read, op);
+      DWORD last_error = ::WSAGetLastError();
+      if (!result && last_error != WSA_IO_PENDING)
+        iocp_service_.on_completion(op, last_error);
+      else
+        iocp_service_.on_pending(op);
+    }
+  }
+}
+
+void win_iocp_socket_service_base::restart_accept_op(
+    socket_type s, socket_holder& new_socket, int family, int type,
+    int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+  new_socket.reset();
+  iocp_service_.work_started();
+
+  asio::error_code ec;
+  new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+  if (new_socket.get() == invalid_socket)
+    iocp_service_.on_completion(op, ec);
+  else
+  {
+    DWORD bytes_read = 0;
+    BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
+        0, address_length, address_length, &bytes_read, op);
+    DWORD last_error = ::WSAGetLastError();
+    if (!result && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_reactor_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int op_type, reactor_op* op)
+{
+  reactor& r = get_reactor();
+  update_cancellation_thread_id(impl);
+
+  if (is_open(impl))
+  {
+    r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
+    return;
+  }
+  else
+    op->ec_ = asio::error::bad_descriptor;
+
+  iocp_service_.post_immediate_completion(op);
+}
+
+void win_iocp_socket_service_base::start_connect_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    reactor_op* op, const socket_addr_type* addr, std::size_t addrlen)
+{
+  reactor& r = get_reactor();
+  update_cancellation_thread_id(impl);
+
+  if ((impl.state_ & socket_ops::non_blocking) != 0
+      || socket_ops::set_internal_non_blocking(
+        impl.socket_, impl.state_, op->ec_))
+  {
+    if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+    {
+      if (op->ec_ == asio::error::in_progress
+          || op->ec_ == asio::error::would_block)
+      {
+        op->ec_ = asio::error_code();
+        r.start_op(reactor::connect_op, impl.socket_,
+            impl.reactor_data_, op, false);
+        return;
+      }
+    }
+  }
+
+  r.post_immediate_completion(op);
+}
+
+void win_iocp_socket_service_base::close_for_destruction(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  if (is_open(impl))
+  {
+    // Check if the reactor was created, in which case we need to close the
+    // socket on the reactor as well to cancel any operations that might be
+    // running there.
+    reactor* r = static_cast<reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->close_descriptor(impl.socket_, impl.reactor_data_);
+  }
+
+  asio::error_code ignored_ec;
+  socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+  impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+void win_iocp_socket_service_base::update_cancellation_thread_id(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+#if defined(ASIO_ENABLE_CANCELIO)
+  if (impl.safe_cancellation_thread_id_ == 0)
+    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+    impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(ASIO_ENABLE_CANCELIO)
+  (void)impl;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+reactor& win_iocp_socket_service_base::get_reactor()
+{
+  reactor* r = static_cast<reactor*>(
+        interlocked_compare_exchange_pointer(
+          reinterpret_cast<void**>(&reactor_), 0, 0));
+  if (!r)
+  {
+    r = &(use_service<reactor>(io_service_));
+    interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
+  }
+  return *r;
+}
+
+void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
+    void** dest, void* exch, void* cmp)
+{
+#if defined(_M_IX86)
+  return reinterpret_cast<void*>(InterlockedCompareExchange(
+        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
+        reinterpret_cast<LONG>(cmp)));
+#else
+  return InterlockedCompareExchangePointer(dest, exch, cmp);
+#endif
+}
+
+void* win_iocp_socket_service_base::interlocked_exchange_pointer(
+    void** dest, void* val)
+{
+#if defined(_M_IX86)
+  return reinterpret_cast<void*>(InterlockedExchange(
+        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
+#else
+  return InterlockedExchangePointer(dest, val);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/win_mutex.ipp b/ext/asio/asio/detail/impl/win_mutex.ipp
new file mode 100644
index 0000000..910cc23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_mutex.ipp
@@ -0,0 +1,78 @@
+//
+// detail/impl/win_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_mutex::win_mutex()
+{
+  int error = do_init();
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "mutex");
+}
+
+int win_mutex::do_init()
+{
+#if defined(__MINGW32__)
+  // Not sure if MinGW supports structured exception handling, so for now
+  // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+  ::InitializeCriticalSection(&crit_section_);
+# else
+  if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+    return ::GetLastError();
+# endif
+  return 0;
+#else
+  __try
+  {
+# if defined(UNDER_CE)
+    ::InitializeCriticalSection(&crit_section_);
+# else
+    if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+      return ::GetLastError();
+# endif
+  }
+  __except(GetExceptionCode() == STATUS_NO_MEMORY
+      ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+  {
+    return ERROR_OUTOFMEMORY;
+  }
+
+  return 0;
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
diff --git a/ext/asio/asio/detail/impl/win_thread.ipp b/ext/asio/asio/detail/impl/win_thread.ipp
new file mode 100644
index 0000000..65844c8
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_thread.ipp
@@ -0,0 +1,138 @@
+//
+// detail/impl/win_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <process.h>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_thread.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_thread::~win_thread()
+{
+  ::CloseHandle(thread_);
+
+  // The exit_event_ handle is deliberately allowed to leak here since it
+  // is an error for the owner of an internal thread not to join() it.
+}
+
+void win_thread::join()
+{
+  HANDLE handles[2] = { exit_event_, thread_ };
+  ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+  ::CloseHandle(exit_event_);
+  if (terminate_threads())
+  {
+    ::TerminateThread(thread_, 0);
+  }
+  else
+  {
+    ::QueueUserAPC(apc_function, thread_, 0);
+    ::WaitForSingleObject(thread_, INFINITE);
+  }
+}
+
+void win_thread::start_thread(func_base* arg, unsigned int stack_size)
+{
+  ::HANDLE entry_event = 0;
+  arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
+  if (!entry_event)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread.entry_event");
+  }
+
+  arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
+  if (!exit_event_)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread.exit_event");
+  }
+
+  unsigned int thread_id = 0;
+  thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,
+        stack_size, win_thread_function, arg, 0, &thread_id));
+  if (!thread_)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    if (entry_event)
+      ::CloseHandle(entry_event);
+    if (exit_event_)
+      ::CloseHandle(exit_event_);
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread");
+  }
+
+  if (entry_event)
+  {
+    ::WaitForSingleObject(entry_event, INFINITE);
+    ::CloseHandle(entry_event);
+  }
+}
+
+unsigned int __stdcall win_thread_function(void* arg)
+{
+  std::auto_ptr<win_thread::func_base> func(
+      static_cast<win_thread::func_base*>(arg));
+
+  ::SetEvent(func->entry_event_);
+
+  func->run();
+
+  // Signal that the thread has finished its work, but rather than returning go
+  // to sleep to put the thread into a well known state. If the thread is being
+  // joined during global object destruction then it may be killed using
+  // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
+  // call will be interrupted using QueueUserAPC and the thread will shut down
+  // cleanly.
+  HANDLE exit_event = func->exit_event_;
+  func.reset();
+  ::SetEvent(exit_event);
+  ::SleepEx(INFINITE, TRUE);
+
+  return 0;
+}
+
+#if defined(WINVER) && (WINVER < 0x0500)
+void __stdcall apc_function(ULONG) {}
+#else
+void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP
diff --git a/ext/asio/asio/detail/impl/win_tss_ptr.ipp b/ext/asio/asio/detail/impl/win_tss_ptr.ipp
new file mode 100644
index 0000000..de3ea3c
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_tss_ptr.ipp
@@ -0,0 +1,57 @@
+//
+// detail/impl/win_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_tss_ptr.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD win_tss_ptr_create()
+{
+#if defined(UNDER_CE)
+  enum { out_of_indexes = 0xFFFFFFFF };
+#else
+  enum { out_of_indexes = TLS_OUT_OF_INDEXES };
+#endif
+
+  DWORD tss_key = ::TlsAlloc();
+  if (tss_key == out_of_indexes)
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "tss");
+  }
+  return tss_key;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
diff --git a/ext/asio/asio/detail/impl/winsock_init.ipp b/ext/asio/asio/detail/impl/winsock_init.ipp
new file mode 100644
index 0000000..3b20c98
--- /dev/null
+++ b/ext/asio/asio/detail/impl/winsock_init.ipp
@@ -0,0 +1,69 @@
+//
+// detail/impl/winsock_init.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void winsock_init_base::startup(data& d,
+    unsigned char major, unsigned char minor)
+{
+  if (::InterlockedIncrement(&d.init_count_) == 1)
+  {
+    WSADATA wsa_data;
+    long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data);
+    ::InterlockedExchange(&d.result_, result);
+  }
+}
+
+void winsock_init_base::cleanup(data& d)
+{
+  if (::InterlockedDecrement(&d.init_count_) == 0)
+  {
+    ::WSACleanup();
+  }
+}
+
+void winsock_init_base::throw_on_error(data& d)
+{
+  long result = ::InterlockedExchangeAdd(&d.result_, 0);
+  if (result != 0)
+  {
+    asio::error_code ec(result,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "winsock");
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
diff --git a/ext/asio/asio/detail/io_control.hpp b/ext/asio/asio/detail/io_control.hpp
index df7171c..b3ef844 100644
--- a/ext/asio/asio/detail/io_control.hpp
+++ b/ext/asio/asio/detail/io_control.hpp
@@ -1,8 +1,8 @@
 //
-// io_control.hpp
-// ~~~~~~~~~~~~~~
+// detail/io_control.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 namespace io_control {
diff --git a/ext/asio/asio/detail/kqueue_reactor.hpp b/ext/asio/asio/detail/kqueue_reactor.hpp
index bfa004d..07087dd 100644
--- a/ext/asio/asio/detail/kqueue_reactor.hpp
+++ b/ext/asio/asio/detail/kqueue_reactor.hpp
@@ -1,8 +1,8 @@
 //
-// kqueue_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,41 +16,35 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/kqueue_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_KQUEUE)
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/time.h>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/hash_map.hpp"
+#include "asio/detail/kqueue_reactor_fwd.hpp"
 #include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 #include "asio/detail/timer_queue_fwd.hpp"
 #include "asio/detail/timer_queue_set.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
 
 // Older versions of Mac OS X may not define EV_OOBAND.
 #if !defined(EV_OOBAND)
 # define EV_OOBAND EV_FLAG1
 #endif // !defined(EV_OOBAND)
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -64,384 +58,98 @@ public:
   // Per-descriptor queues.
   struct descriptor_state
   {
-    descriptor_state() {}
-    descriptor_state(const descriptor_state&) {}
-    void operator=(const descriptor_state&) {}
-
+    friend class kqueue_reactor;
+    friend class object_pool_access;
     mutex mutex_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
+    descriptor_state* next_;
+    descriptor_state* prev_;
   };
 
   // Per-descriptor data.
   typedef descriptor_state* per_descriptor_data;
 
   // Constructor.
-  kqueue_reactor(asio::io_service& io_service)
-    : asio::detail::service_base<kqueue_reactor>(io_service),
-      io_service_(use_service<io_service_impl>(io_service)),
-      mutex_(),
-      kqueue_fd_(do_kqueue_create()),
-      interrupter_(),
-      shutdown_(false)
-  {
-    // The interrupter is put into a permanently readable state. Whenever we
-    // want to interrupt the blocked kevent call we register a one-shot read
-    // operation against the descriptor.
-    interrupter_.interrupt();
-  }
+  ASIO_DECL kqueue_reactor(asio::io_service& io_service);
 
   // Destructor.
-  ~kqueue_reactor()
-  {
-    close(kqueue_fd_);
-  }
+  ASIO_DECL ~kqueue_reactor();
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    mutex::scoped_lock lock(mutex_);
-    shutdown_ = true;
-    lock.unlock();
-
-    op_queue<operation> ops;
-
-    descriptor_map::iterator iter = registered_descriptors_.begin();
-    descriptor_map::iterator end = registered_descriptors_.end();
-    while (iter != end)
-    {
-      for (int i = 0; i < max_ops; ++i)
-        ops.push(iter->second.op_queue_[i]);
-      iter->second.shutdown_ = true;
-      ++iter;
-    }
-
-    timer_queues_.get_all_timers(ops);
-  }
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task.
-  void init_task()
-  {
-    io_service_.init_task();
-  }
+  ASIO_DECL void init_task();
 
   // Register a socket with the reactor. Returns 0 on success, system error
   // code on failure.
-  int register_descriptor(socket_type descriptor,
-      per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock lock(registered_descriptors_mutex_);
-
-    descriptor_map::iterator new_entry = registered_descriptors_.insert(
-          std::make_pair(descriptor, descriptor_state())).first;
-    descriptor_data = &new_entry->second;
+  ASIO_DECL int register_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
-    descriptor_data->shutdown_ = false;
-
-    return 0;
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op)
+  {
+    io_service_.post_immediate_completion(op);
   }
 
   // Start a new operation. The reactor operation will be performed when the
   // given descriptor is flagged as ready, or an error has occurred.
-  void start_op(int op_type, socket_type descriptor,
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
       per_descriptor_data& descriptor_data,
-      reactor_op* op, bool allow_speculative)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-    if (descriptor_data->shutdown_)
-      return;
-
-    bool first = descriptor_data->op_queue_[op_type].empty();
-    if (first)
-    {
-      if (allow_speculative)
-      {
-        if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
-        {
-          if (op->perform())
-          {
-            descriptor_lock.unlock();
-            io_service_.post_immediate_completion(op);
-            return;
-          }
-        }
-      }
-    }
-
-    descriptor_data->op_queue_[op_type].push(op);
-    io_service_.work_started();
-
-    if (first)
-    {
-      struct kevent event;
-      switch (op_type)
-      {
-      case read_op:
-        EV_SET(&event, descriptor, EVFILT_READ,
-            EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
-        break;
-      case write_op:
-        EV_SET(&event, descriptor, EVFILT_WRITE,
-            EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
-        break;
-      case except_op:
-        if (!descriptor_data->op_queue_[read_op].empty())
-          return; // Already registered for read events.
-        EV_SET(&event, descriptor, EVFILT_READ,
-            EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
-        break;
-      }
-
-      if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
-      {
-        op->ec_ = asio::error_code(errno,
-            asio::error::get_system_category());
-        descriptor_data->op_queue_[op_type].pop();
-        io_service_.post_deferred_completion(op);
-      }
-    }
-  }
+      reactor_op* op, bool allow_speculative);
 
   // Cancel all operations associated with the given descriptor. The
   // handlers associated with the descriptor will be invoked with the
   // operation_aborted error.
-  void cancel_ops(socket_type , per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-    {
-      while (reactor_op* op = descriptor_data->op_queue_[i].front())
-      {
-        op->ec_ = asio::error::operation_aborted;
-        descriptor_data->op_queue_[i].pop();
-        ops.push(op);
-      }
-    }
-
-    descriptor_lock.unlock();
-
-    io_service_.post_deferred_completions(ops);
-  }
+  ASIO_DECL void cancel_ops(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
   // Cancel any operations that are running against the descriptor and remove
   // its registration from the reactor.
-  void close_descriptor(socket_type descriptor,
-      per_descriptor_data& descriptor_data)
-  {
-    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-    mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
-
-    // Remove the descriptor from the set of known descriptors. The descriptor
-    // will be automatically removed from the kqueue set when it is closed.
-    descriptor_data->shutdown_ = true;
-
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-    {
-      while (reactor_op* op = descriptor_data->op_queue_[i].front())
-      {
-        op->ec_ = asio::error::operation_aborted;
-        descriptor_data->op_queue_[i].pop();
-        ops.push(op);
-      }
-    }
-
-    descriptor_lock.unlock();
-
-    registered_descriptors_.erase(descriptor);
-
-    descriptors_lock.unlock();
-
-    io_service_.post_deferred_completions(ops);
-  }
+  ASIO_DECL void close_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
 
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
-  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    mutex::scoped_lock lock(mutex_);
-    timer_queues_.insert(&timer_queue);
-  }
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Remove a timer queue from the reactor.
   template <typename Time_Traits>
-  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    mutex::scoped_lock lock(mutex_);
-    timer_queues_.erase(&timer_queue);
-  }
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Schedule a new operation in the given timer queue to expire at the
   // specified absolute time.
   template <typename Time_Traits>
-  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
-      const typename Time_Traits::time_type& time, timer_op* op, void* token)
-  {
-    mutex::scoped_lock lock(mutex_);
-    if (!shutdown_)
-    {
-      bool earliest = timer_queue.enqueue_timer(time, op, token);
-      io_service_.work_started();
-      if (earliest)
-        interrupt();
-    }
-  }
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
 
   // Cancel the timer operations associated with the given token. Returns the
   // number of operations that have been posted or dispatched.
   template <typename Time_Traits>
-  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
-  {
-    mutex::scoped_lock lock(mutex_);
-    op_queue<operation> ops;
-    std::size_t n = timer_queue.cancel_timer(token, ops);
-    lock.unlock();
-    io_service_.post_deferred_completions(ops);
-    return n;
-  }
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer);
 
   // Run the kqueue loop.
-  void run(bool block, op_queue<operation>& ops)
-  {
-    mutex::scoped_lock lock(mutex_);
-
-    // Determine how long to block while waiting for events.
-    timespec timeout_buf = { 0, 0 };
-    timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
-
-    lock.unlock();
-
-    // Block on the kqueue descriptor.
-    struct kevent events[128];
-    int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
-
-    // Dispatch the waiting events.
-    for (int i = 0; i < num_events; ++i)
-    {
-      int descriptor = events[i].ident;
-      void* ptr = events[i].udata;
-      if (ptr == &interrupter_)
-      {
-        // No need to reset the interrupter since we're leaving the descriptor
-        // in a ready-to-read state and relying on one-shot notifications.
-      }
-      else
-      {
-        descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
-        mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
-        // Exception operations must be processed first to ensure that any
-        // out-of-band data is read before normal data.
-        static const int filter[max_ops] =
-          { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
-        for (int j = max_ops - 1; j >= 0; --j)
-        {
-          if (events[i].filter == filter[j])
-          {
-            if (j != except_op || events[i].flags & EV_OOBAND)
-            {
-              while (reactor_op* op = descriptor_data->op_queue_[j].front())
-              {
-                if (events[i].flags & EV_ERROR)
-                {
-                  op->ec_ = asio::error_code(events[i].data,
-                      asio::error::get_system_category());
-                  descriptor_data->op_queue_[j].pop();
-                  ops.push(op);
-                }
-                if (op->perform())
-                {
-                  descriptor_data->op_queue_[j].pop();
-                  ops.push(op);
-                }
-                else
-                  break;
-              }
-            }
-          }
-        }
-
-        // Renew registration for event notifications.
-        struct kevent event;
-        switch (events[i].filter)
-        {
-        case EVFILT_READ:
-          if (!descriptor_data->op_queue_[read_op].empty())
-            EV_SET(&event, descriptor, EVFILT_READ,
-                EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
-          else if (!descriptor_data->op_queue_[except_op].empty())
-            EV_SET(&event, descriptor, EVFILT_READ,
-                EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
-          else
-            continue;
-        case EVFILT_WRITE:
-          if (!descriptor_data->op_queue_[write_op].empty())
-            EV_SET(&event, descriptor, EVFILT_WRITE,
-                EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
-          else
-            continue;
-        default:
-          break;
-        }
-        if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
-        {
-          asio::error_code error(errno,
-              asio::error::get_system_category());
-          for (int j = 0; j < max_ops; ++j)
-          {
-            while (reactor_op* op = descriptor_data->op_queue_[j].front())
-            {
-              op->ec_ = error;
-              descriptor_data->op_queue_[j].pop();
-              ops.push(op);
-            }
-          }
-        }
-      }
-    }
-
-    lock.lock();
-    timer_queues_.get_ready_timers(ops);
-  }
+  ASIO_DECL void run(bool block, op_queue<operation>& ops);
 
   // Interrupt the kqueue loop.
-  void interrupt()
-  {
-    struct kevent event;
-    EV_SET(&event, interrupter_.read_descriptor(),
-        EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
-    ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
-  }
+  ASIO_DECL void interrupt();
 
 private:
   // Create the kqueue file descriptor. Throws an exception if the descriptor
   // cannot be created.
-  static int do_kqueue_create()
-  {
-    int fd = kqueue();
-    if (fd == -1)
-    {
-      boost::throw_exception(
-          asio::system_error(
-            asio::error_code(errno,
-              asio::error::get_system_category()),
-            "kqueue"));
-    }
-    return fd;
-  }
+  ASIO_DECL static int do_kqueue_create();
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
 
   // Get the timeout value for the kevent call.
-  timespec* get_timeout(timespec& ts)
-  {
-    // By default we will wait no longer than 5 minutes. This will ensure that
-    // any changes to the system clock are detected after no longer than this.
-    long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
-    ts.tv_sec = usec / 1000000;
-    ts.tv_nsec = (usec % 1000000) * 1000;
-    return &ts;
-  }
+  ASIO_DECL timespec* get_timeout(timespec& ts);
 
   // The io_service implementation used to post completions.
   io_service_impl& io_service_;
@@ -464,22 +172,20 @@ private:
   // Mutex to protect access to the registered descriptors.
   mutex registered_descriptors_mutex_;
 
-  // Keep track of all registered descriptors. This code relies on the fact that
-  // the hash_map implementation pools deleted nodes, meaning that we can assume
-  // our descriptor_state pointer remains valid even after the entry is removed.
-  // Technically this is not true for C++98, as that standard says that spliced
-  // elements in a list are invalidated. However, C++0x fixes this shortcoming
-  // so we'll just assume that C++98 std::list implementations will do the right
-  // thing anyway.
-  typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
-  descriptor_map registered_descriptors_;
+  // Keep track of all registered descriptors.
+  object_pool<descriptor_state> registered_descriptors_;
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_KQUEUE)
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/kqueue_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/kqueue_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
 #endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
index abbc0c7..fda59ce 100644
--- a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// kqueue_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/kqueue_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,15 +16,9 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if !defined(ASIO_DISABLE_KQUEUE)
-
-#if (defined(__MACH__) && defined(__APPLE__)) \
-  || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-// Define this to indicate that kqueue is supported on the target platform.
-#define ASIO_HAS_KQUEUE 1
+#if defined(ASIO_HAS_KQUEUE)
 
 namespace asio {
 namespace detail {
@@ -34,11 +28,6 @@ class kqueue_reactor;
 } // namespace detail
 } // namespace asio
 
-#endif // (defined(__MACH__) && defined(__APPLE__))
-       // || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-#endif // !defined(ASIO_DISABLE_KQUEUE)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_KQUEUE)
 
 #endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/local_free_on_block_exit.hpp b/ext/asio/asio/detail/local_free_on_block_exit.hpp
index 554943c..a55bd4b 100644
--- a/ext/asio/asio/detail/local_free_on_block_exit.hpp
+++ b/ext/asio/asio/detail/local_free_on_block_exit.hpp
@@ -1,8 +1,8 @@
 //
-// local_free_on_block_exit.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/local_free_on_block_exit.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -52,8 +50,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
diff --git a/ext/asio/asio/detail/macos_fenced_block.hpp b/ext/asio/asio/detail/macos_fenced_block.hpp
index 3c303d6..fcb8bfc 100644
--- a/ext/asio/asio/detail/macos_fenced_block.hpp
+++ b/ext/asio/asio/detail/macos_fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// macos_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/macos_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(__MACH__) && defined(__APPLE__)
 
-#include "asio/detail/push_options.hpp"
 #include <libkern/OSAtomic.h>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -50,8 +46,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(__MACH__) && defined(__APPLE__)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(__MACH__) && defined(__APPLE__)
+
 #endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/mutex.hpp b/ext/asio/asio/detail/mutex.hpp
index 024ec7f..dc478ff 100644
--- a/ext/asio/asio/detail/mutex.hpp
+++ b/ext/asio/asio/detail/mutex.hpp
@@ -1,8 +1,8 @@
 //
-// mutex.hpp
-// ~~~~~~~~~
+// detail/mutex.hpp
+// ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 # include "asio/detail/null_mutex.hpp"
@@ -45,6 +41,4 @@ typedef posix_mutex mutex;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_MUTEX_HPP
diff --git a/ext/asio/asio/detail/noncopyable.hpp b/ext/asio/asio/detail/noncopyable.hpp
index 8b73ff0..e7f6437 100644
--- a/ext/asio/asio/detail/noncopyable.hpp
+++ b/ext/asio/asio/detail/noncopyable.hpp
@@ -1,8 +1,8 @@
 //
-// noncopyable.hpp
-// ~~~~~~~~~~~~~~~
+// detail/noncopyable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/noncopyable.hpp>
 #include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
diff --git a/ext/asio/asio/detail/null_event.hpp b/ext/asio/asio/detail/null_event.hpp
index bcea31b..db7b747 100644
--- a/ext/asio/asio/detail/null_event.hpp
+++ b/ext/asio/asio/detail/null_event.hpp
@@ -1,8 +1,8 @@
 //
-// null_event.hpp
-// ~~~~~~~~~~~~~~
+// detail/null_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -70,8 +68,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/ext/asio/asio/detail/null_fenced_block.hpp b/ext/asio/asio/detail/null_fenced_block.hpp
index dd9a095..fbd025f 100644
--- a/ext/asio/asio/detail/null_fenced_block.hpp
+++ b/ext/asio/asio/detail/null_fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// null_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/null_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/detail/null_mutex.hpp b/ext/asio/asio/detail/null_mutex.hpp
index 6661ef8..bbceb7c 100644
--- a/ext/asio/asio/detail/null_mutex.hpp
+++ b/ext/asio/asio/detail/null_mutex.hpp
@@ -1,8 +1,8 @@
 //
-// null_mutex.hpp
-// ~~~~~~~~~~~~~~
+// detail/null_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/scoped_lock.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -59,8 +57,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/ext/asio/asio/detail/null_signal_blocker.hpp b/ext/asio/asio/detail/null_signal_blocker.hpp
index a5db315..e0d996f 100644
--- a/ext/asio/asio/detail/null_signal_blocker.hpp
+++ b/ext/asio/asio/detail/null_signal_blocker.hpp
@@ -1,8 +1,8 @@
 //
-// null_signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+  || defined(ASIO_DISABLE_THREADS) \
+  || defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
 
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -56,8 +58,12 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_HAS_THREADS)
+       // || defined(ASIO_DISABLE_THREADS)
+       // || defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
 #endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/null_thread.hpp b/ext/asio/asio/detail/null_thread.hpp
index ce3d470..bfe918e 100644
--- a/ext/asio/asio/detail/null_thread.hpp
+++ b/ext/asio/asio/detail/null_thread.hpp
@@ -1,8 +1,8 @@
 //
-// null_thread.hpp
-// ~~~~~~~~~~~~~~~
+// detail/null_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -40,11 +34,10 @@ class null_thread
 public:
   // Constructor.
   template <typename Function>
-  null_thread(Function )
+  null_thread(Function, unsigned int = 0)
   {
-    asio::system_error e(
+    asio::detail::throw_error(
         asio::error::operation_not_supported, "thread");
-    boost::throw_exception(e);
   }
 
   // Destructor.
@@ -61,8 +54,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/ext/asio/asio/detail/null_tss_ptr.hpp b/ext/asio/asio/detail/null_tss_ptr.hpp
index 112b476..d3456e6 100644
--- a/ext/asio/asio/detail/null_tss_ptr.hpp
+++ b/ext/asio/asio/detail/null_tss_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// null_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -63,8 +61,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/object_pool.hpp b/ext/asio/asio/detail/object_pool.hpp
new file mode 100644
index 0000000..dc50feb
--- /dev/null
+++ b/ext/asio/asio/detail/object_pool.hpp
@@ -0,0 +1,146 @@
+//
+// detail/object_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_OBJECT_POOL_HPP
+#define ASIO_DETAIL_OBJECT_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Object>
+class object_pool;
+
+class object_pool_access
+{
+public:
+  template <typename Object>
+  static Object* create()
+  {
+    return new Object;
+  }
+
+  template <typename Object>
+  static void destroy(Object* o)
+  {
+    delete o;
+  }
+
+  template <typename Object>
+  static Object*& next(Object* o)
+  {
+    return o->next_;
+  }
+
+  template <typename Object>
+  static Object*& prev(Object* o)
+  {
+    return o->prev_;
+  }
+};
+
+template <typename Object>
+class object_pool
+  : private noncopyable
+{
+public:
+  // Constructor.
+  object_pool()
+    : live_list_(0),
+      free_list_(0)
+  {
+  }
+
+  // Destructor destroys all objects.
+  ~object_pool()
+  {
+    destroy_list(live_list_);
+    destroy_list(free_list_);
+  }
+
+  // Get the object at the start of the live list.
+  Object* first()
+  {
+    return live_list_;
+  }
+
+  // Allocate a new object.
+  Object* alloc()
+  {
+    Object* o = free_list_;
+    if (o)
+      free_list_ = object_pool_access::next(free_list_);
+    else
+      o = object_pool_access::create<Object>();
+
+    object_pool_access::next(o) = live_list_;
+    object_pool_access::prev(o) = 0;
+    if (live_list_)
+      object_pool_access::prev(live_list_) = o;
+    live_list_ = o;
+
+    return o;
+  }
+
+  // Free an object. Moves it to the free list. No destructors are run.
+  void free(Object* o)
+  {
+    if (live_list_ == o)
+      live_list_ = object_pool_access::next(o);
+
+    if (object_pool_access::prev(o))
+    {
+      object_pool_access::next(object_pool_access::prev(o))
+        = object_pool_access::next(o);
+    }
+
+    if (object_pool_access::next(o))
+    {
+      object_pool_access::prev(object_pool_access::next(o))
+        = object_pool_access::prev(o);
+    }
+
+    object_pool_access::next(o) = free_list_;
+    object_pool_access::prev(o) = 0;
+    free_list_ = o;
+  }
+
+private:
+  // Helper function to destroy all elements in a list.
+  void destroy_list(Object* list)
+  {
+    while (list)
+    {
+      Object* o = list;
+      list = object_pool_access::next(o);
+      object_pool_access::destroy(o);
+    }
+  }
+
+  // The list of live objects.
+  Object* live_list_;
+
+  // The free list.
+  Object* free_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OBJECT_POOL_HPP
diff --git a/ext/asio/asio/detail/old_win_sdk_compat.hpp b/ext/asio/asio/detail/old_win_sdk_compat.hpp
index 70e5916..fb75579 100644
--- a/ext/asio/asio/detail/old_win_sdk_compat.hpp
+++ b/ext/asio/asio/detail/old_win_sdk_compat.hpp
@@ -1,8 +1,8 @@
 //
-// old_win_sdk_compat.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
@@ -36,6 +32,8 @@
 // a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support
 // in that case.
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -321,6 +319,8 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
 } // namespace detail
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_OLD_WIN_SDK)
 
 // Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
@@ -335,6 +335,4 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
 
 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/ext/asio/asio/detail/op_queue.hpp b/ext/asio/asio/detail/op_queue.hpp
index ccf8b9a..38278ea 100644
--- a/ext/asio/asio/detail/op_queue.hpp
+++ b/ext/asio/asio/detail/op_queue.hpp
@@ -1,8 +1,8 @@
 //
-// op_queue.hpp
-// ~~~~~~~~~~~~
+// detail/op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/operation.hpp b/ext/asio/asio/detail/operation.hpp
index 6aba361..3435c05 100644
--- a/ext/asio/asio/detail/operation.hpp
+++ b/ext/asio/asio/detail/operation.hpp
@@ -1,8 +1,8 @@
 //
-// operation.hpp
-// ~~~~~~~~~~~~~
+// detail/operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 # include "asio/detail/win_iocp_operation.hpp"
 #else
-# include "asio/detail/reactor_fwd.hpp"
 # include "asio/detail/task_io_service_operation.hpp"
 #endif
 
@@ -32,12 +29,10 @@ namespace detail {
 #if defined(ASIO_HAS_IOCP)
 typedef win_iocp_operation operation;
 #else
-typedef task_io_service_operation<reactor> operation;
+typedef task_io_service_operation operation;
 #endif
 
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_OPERATION_HPP
diff --git a/ext/asio/asio/detail/pipe_select_interrupter.hpp b/ext/asio/asio/detail/pipe_select_interrupter.hpp
index 7469599..bf39426 100644
--- a/ext/asio/asio/detail/pipe_select_interrupter.hpp
+++ b/ext/asio/asio/detail/pipe_select_interrupter.hpp
@@ -1,8 +1,8 @@
 //
-// pipe_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#if !defined(BOOST_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
 
 #include "asio/detail/push_options.hpp"
-#include <fcntl.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_types.hpp"
 
 namespace asio {
 namespace detail {
@@ -39,57 +31,16 @@ class pipe_select_interrupter
 {
 public:
   // Constructor.
-  pipe_select_interrupter()
-  {
-    int pipe_fds[2];
-    if (pipe(pipe_fds) == 0)
-    {
-      read_descriptor_ = pipe_fds[0];
-      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
-      write_descriptor_ = pipe_fds[1];
-      ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
-    }
-    else
-    {
-      asio::error_code ec(errno,
-          asio::error::get_system_category());
-      asio::system_error e(ec, "pipe_select_interrupter");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL pipe_select_interrupter();
 
   // Destructor.
-  ~pipe_select_interrupter()
-  {
-    if (read_descriptor_ != -1)
-      ::close(read_descriptor_);
-    if (write_descriptor_ != -1)
-      ::close(write_descriptor_);
-  }
+  ASIO_DECL ~pipe_select_interrupter();
 
   // Interrupt the select call.
-  void interrupt()
-  {
-    char byte = 0;
-    int result = ::write(write_descriptor_, &byte, 1);
-    (void)result;
-  }
+  ASIO_DECL void interrupt();
 
   // Reset the select interrupt. Returns true if the call was interrupted.
-  bool reset()
-  {
-    for (;;)
-    {
-      char data[1024];
-      int bytes_read = ::read(read_descriptor_, data, sizeof(data));
-      if (bytes_read < 0 && errno == EINTR)
-        continue;
-      bool was_interrupted = (bytes_read > 0);
-      while (bytes_read == sizeof(data))
-        bytes_read = ::read(read_descriptor_, data, sizeof(data));
-      return was_interrupted;
-    }
-  }
+  ASIO_DECL bool reset();
 
   // Get the read descriptor to be passed to select.
   int read_descriptor() const
@@ -113,8 +64,15 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/pipe_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(BOOST_WINDOWS)
+
 #endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/pop_options.hpp b/ext/asio/asio/detail/pop_options.hpp
index a26b203..4e19336 100644
--- a/ext/asio/asio/detail/pop_options.hpp
+++ b/ext/asio/asio/detail/pop_options.hpp
@@ -1,8 +1,8 @@
 //
-// pop_options.hpp
-// ~~~~~~~~~~~~~~~
+// detail/pop_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -31,6 +31,16 @@
 #  pragma pack (pop)
 # endif
 
+# if defined(__OBJC__)
+#  if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+#   if defined(ASIO_OBJC_WORKAROUND)
+#    undef Protocol
+#    undef id
+#    undef ASIO_OBJC_WORKAROUND
+#   endif
+#  endif
+# endif
+
 #elif defined(__KCC)
 
 // Kai C++
diff --git a/ext/asio/asio/detail/posix_event.hpp b/ext/asio/asio/detail/posix_event.hpp
index 49c15aa..d0ec8b0 100644
--- a/ext/asio/asio/detail/posix_event.hpp
+++ b/ext/asio/asio/detail/posix_event.hpp
@@ -1,8 +1,8 @@
 //
-// posix_event.hpp
-// ~~~~~~~~~~~~~~~
+// detail/posix_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
 #include <boost/assert.hpp>
-#include <boost/throw_exception.hpp>
 #include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -41,19 +33,7 @@ class posix_event
 {
 public:
   // Constructor.
-  posix_event()
-    : signalled_(false)
-  {
-    int error = ::pthread_cond_init(&cond_, 0);
-    if (error != 0)
-    {
-      asio::system_error e(
-          asio::error_code(error,
-            asio::error::get_system_category()),
-          "event");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL posix_event();
 
   // Destructor.
   ~posix_event()
@@ -107,8 +87,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_HAS_PTHREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/ext/asio/asio/detail/posix_fd_set_adapter.hpp b/ext/asio/asio/detail/posix_fd_set_adapter.hpp
index 17ef269..92d6bba 100644
--- a/ext/asio/asio/detail/posix_fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/posix_fd_set_adapter.hpp
@@ -1,8 +1,8 @@
 //
-// posix_fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include "asio/detail/pop_options.hpp"
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
+#include <cstring>
 #include "asio/detail/socket_types.hpp"
 
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -74,8 +73,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/posix_mutex.hpp b/ext/asio/asio/detail/posix_mutex.hpp
index 230b83a..bcdf6b2 100644
--- a/ext/asio/asio/detail/posix_mutex.hpp
+++ b/ext/asio/asio/detail/posix_mutex.hpp
@@ -1,8 +1,8 @@
 //
-// posix_mutex.hpp
-// ~~~~~~~~~~~~~~~
+// detail/posix_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
 #include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/scoped_lock.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -45,18 +37,7 @@ public:
   typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
 
   // Constructor.
-  posix_mutex()
-  {
-    int error = ::pthread_mutex_init(&mutex_, 0);
-    if (error != 0)
-    {
-      asio::system_error e(
-          asio::error_code(error,
-            asio::error::get_system_category()),
-          "mutex");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL posix_mutex();
 
   // Destructor.
   ~posix_mutex()
@@ -84,8 +65,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_HAS_PTHREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/ext/asio/asio/detail/posix_signal_blocker.hpp b/ext/asio/asio/detail/posix_signal_blocker.hpp
index 135ca41..d41f128 100644
--- a/ext/asio/asio/detail/posix_signal_blocker.hpp
+++ b/ext/asio/asio/detail/posix_signal_blocker.hpp
@@ -1,8 +1,8 @@
 //
-// posix_signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
 #include <csignal>
 #include <pthread.h>
 #include <signal.h>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -83,8 +78,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_HAS_PTHREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/posix_thread.hpp b/ext/asio/asio/detail/posix_thread.hpp
index e0fea75..743417c 100644
--- a/ext/asio/asio/detail/posix_thread.hpp
+++ b/ext/asio/asio/detail/posix_thread.hpp
@@ -1,8 +1,8 @@
 //
-// posix_thread.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/posix_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,22 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
-#include <memory>
-#include <boost/throw_exception.hpp>
 #include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
-extern "C" void* asio_detail_posix_thread_function(void* arg);
+extern "C"
+{
+  ASIO_DECL void* asio_detail_posix_thread_function(void* arg);
+}
 
 class posix_thread
   : private noncopyable
@@ -47,36 +41,14 @@ public:
   posix_thread(Function f)
     : joined_(false)
   {
-    std::auto_ptr<func_base> arg(new func<Function>(f));
-    int error = ::pthread_create(&thread_, 0,
-          asio_detail_posix_thread_function, arg.get());
-    if (error != 0)
-    {
-      asio::system_error e(
-          asio::error_code(error,
-            asio::error::get_system_category()),
-          "thread");
-      boost::throw_exception(e);
-    }
-    arg.release();
+    start_thread(new func<Function>(f));
   }
 
   // Destructor.
-  ~posix_thread()
-  {
-    if (!joined_)
-      ::pthread_detach(thread_);
-  }
+  ASIO_DECL ~posix_thread();
 
   // Wait for the thread to exit.
-  void join()
-  {
-    if (!joined_)
-    {
-      ::pthread_join(thread_, 0);
-      joined_ = true;
-    }
-  }
+  ASIO_DECL void join();
 
 private:
   friend void* asio_detail_posix_thread_function(void* arg);
@@ -88,6 +60,12 @@ private:
     virtual void run() = 0;
   };
 
+  struct auto_func_base_ptr
+  {
+    func_base* ptr;
+    ~auto_func_base_ptr() { delete ptr; }
+  };
+
   template <typename Function>
   class func
     : public func_base
@@ -107,23 +85,21 @@ private:
     Function f_;
   };
 
+  ASIO_DECL void start_thread(func_base* arg);
+
   ::pthread_t thread_;
   bool joined_;
 };
 
-inline void* asio_detail_posix_thread_function(void* arg)
-{
-  std::auto_ptr<posix_thread::func_base> f(
-      static_cast<posix_thread::func_base*>(arg));
-  f->run();
-  return 0;
-}
-
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_HAS_PTHREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/ext/asio/asio/detail/posix_tss_ptr.hpp b/ext/asio/asio/detail/posix_tss_ptr.hpp
index 3b4ba07..30d9705 100644
--- a/ext/asio/asio/detail/posix_tss_ptr.hpp
+++ b/ext/asio/asio/detail/posix_tss_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// posix_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,21 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
 
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
 #include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
+// Helper function to create thread-specific storage.
+ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key);
+
 template <typename T>
 class posix_tss_ptr
   : private noncopyable
@@ -43,15 +38,7 @@ public:
   // Constructor.
   posix_tss_ptr()
   {
-    int error = ::pthread_key_create(&tss_key_, 0);
-    if (error != 0)
-    {
-      asio::system_error e(
-          asio::error_code(error,
-            asio::error::get_system_category()),
-          "tss");
-      boost::throw_exception(e);
-    }
+    posix_tss_ptr_create(tss_key_);
   }
 
   // Destructor.
@@ -76,13 +63,18 @@ private:
   // Thread-specific storage to allow unlocked access to determine whether a
   // thread is a member of the pool.
   pthread_key_t tss_key_;
+
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_HAS_PTHREADS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
 #endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/push_options.hpp b/ext/asio/asio/detail/push_options.hpp
index cb0e902..ebb3276 100644
--- a/ext/asio/asio/detail/push_options.hpp
+++ b/ext/asio/asio/detail/push_options.hpp
@@ -1,8 +1,8 @@
 //
-// push_options.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/push_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -31,6 +31,18 @@
 #  pragma pack (push, 8)
 # endif
 
+# if defined(__OBJC__)
+#  if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+#   if !defined(ASIO_DISABLE_OBJC_WORKAROUND)
+#    if !defined(Protocol) && !defined(id)
+#     define Protocol cpp_Protocol
+#     define id cpp_id
+#     define ASIO_OBJC_WORKAROUND
+#    endif
+#   endif
+#  endif
+# endif
+
 #elif defined(__KCC)
 
 // Kai C++
diff --git a/ext/asio/asio/detail/reactive_descriptor_service.hpp b/ext/asio/asio/detail/reactive_descriptor_service.hpp
index 7ad368d..f7e8bf5 100644
--- a/ext/asio/asio/detail/reactive_descriptor_service.hpp
+++ b/ext/asio/asio/detail/reactive_descriptor_service.hpp
@@ -1,8 +1,8 @@
 //
-// reactive_descriptor_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,24 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
+#include <boost/utility/addressof.hpp>
 #include "asio/buffer.hpp"
-#include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/detail/bind_handler.hpp"
 #include "asio/detail/buffer_sequence_adapter.hpp"
 #include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/descriptor_read_op.hpp"
+#include "asio/detail/descriptor_write_op.hpp"
 #include "asio/detail/fenced_block.hpp"
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/null_buffers_op.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
 #include "asio/detail/reactor.hpp"
-#include "asio/detail/reactor_op.hpp"
 
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -48,7 +51,7 @@ public:
     // Default constructor.
     implementation_type()
       : descriptor_(-1),
-        flags_(0)
+        state_(0)
     {
     }
 
@@ -59,94 +62,29 @@ public:
     // The native descriptor representation.
     int descriptor_;
 
-    enum
-    {
-      // The user wants a non-blocking descriptor.
-      user_set_non_blocking = 1,
-
-      // The descriptor has been set non-blocking.
-      internal_non_blocking = 2,
-
-      // Helper "flag" used to determine whether the descriptor is non-blocking.
-      non_blocking = user_set_non_blocking | internal_non_blocking
-    };
-
-    // Flags indicating the current state of the descriptor.
-    unsigned char flags_;
+    // The current state of the descriptor.
+    descriptor_ops::state_type state_;
 
     // Per-descriptor data used by the reactor.
     reactor::per_descriptor_data reactor_data_;
   };
 
-  // The maximum number of buffers to support in a single operation.
-  enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
-
   // Constructor.
-  reactive_descriptor_service(asio::io_service& io_service)
-    : io_service_impl_(asio::use_service<io_service_impl>(io_service)),
-      reactor_(asio::use_service<reactor>(io_service))
-  {
-    reactor_.init_task();
-  }
+  ASIO_DECL reactive_descriptor_service(
+      asio::io_service& io_service);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-  }
+  ASIO_DECL void shutdown_service();
 
   // Construct a new descriptor implementation.
-  void construct(implementation_type& impl)
-  {
-    impl.descriptor_ = -1;
-    impl.flags_ = 0;
-  }
+  ASIO_DECL void construct(implementation_type& impl);
 
   // Destroy a descriptor implementation.
-  void destroy(implementation_type& impl)
-  {
-    if (impl.descriptor_ != -1)
-    {
-      reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
-
-      if (impl.flags_ & implementation_type::internal_non_blocking)
-      {
-        ioctl_arg_type non_blocking = 0;
-        asio::error_code ignored_ec;
-        descriptor_ops::ioctl(impl.descriptor_,
-            FIONBIO, &non_blocking, ignored_ec);
-        impl.flags_ &= ~implementation_type::internal_non_blocking;
-      }
-
-      asio::error_code ignored_ec;
-      descriptor_ops::close(impl.descriptor_, ignored_ec);
-
-      impl.descriptor_ = -1;
-    }
-  }
+  ASIO_DECL void destroy(implementation_type& impl);
 
   // Assign a native descriptor to a descriptor implementation.
-  asio::error_code assign(implementation_type& impl,
-      const native_type& native_descriptor, asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    if (int err = reactor_.register_descriptor(
-          native_descriptor, impl.reactor_data_))
-    {
-      ec = asio::error_code(err,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    impl.descriptor_ = native_descriptor;
-    impl.flags_ = 0;
-    ec = asio::error_code();
-    return ec;
-  }
+  ASIO_DECL asio::error_code assign(implementation_type& impl,
+      const native_type& native_descriptor, asio::error_code& ec);
 
   // Determine whether the descriptor is open.
   bool is_open(const implementation_type& impl) const
@@ -155,31 +93,8 @@ public:
   }
 
   // Destroy a descriptor implementation.
-  asio::error_code close(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
-
-      if (impl.flags_ & implementation_type::internal_non_blocking)
-      {
-        ioctl_arg_type non_blocking = 0;
-        asio::error_code ignored_ec;
-        descriptor_ops::ioctl(impl.descriptor_,
-            FIONBIO, &non_blocking, ignored_ec);
-        impl.flags_ &= ~implementation_type::internal_non_blocking;
-      }
-
-      if (descriptor_ops::close(impl.descriptor_, ec) == -1)
-        return ec;
-
-      impl.descriptor_ = -1;
-    }
-
-    ec = asio::error_code();
-    return ec;
-  }
+  ASIO_DECL asio::error_code close(implementation_type& impl,
+      asio::error_code& ec);
 
   // Get the native descriptor representation.
   native_type native(const implementation_type& impl) const
@@ -188,56 +103,16 @@ public:
   }
 
   // Cancel all operations associated with the descriptor.
-  asio::error_code cancel(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
-    ec = asio::error_code();
-    return ec;
-  }
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
 
   // Perform an IO control command on the descriptor.
   template <typename IO_Control_Command>
   asio::error_code io_control(implementation_type& impl,
       IO_Control_Command& command, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    descriptor_ops::ioctl(impl.descriptor_, command.name(),
-        static_cast<ioctl_arg_type*>(command.data()), ec);
-
-    // When updating the non-blocking mode we always perform the ioctl syscall,
-    // even if the flags would otherwise indicate that the descriptor is
-    // already in the correct state. This ensures that the underlying
-    // descriptor is put into the state that has been requested by the user. If
-    // the ioctl syscall was successful then we need to update the flags to
-    // match.
-    if (!ec && command.name() == static_cast<int>(FIONBIO))
-    {
-      if (*static_cast<ioctl_arg_type*>(command.data()))
-      {
-        impl.flags_ |= implementation_type::user_set_non_blocking;
-      }
-      else
-      {
-        // Clearing the non-blocking mode always overrides any internally-set
-        // non-blocking flag. Any subsequent asynchronous operations will need
-        // to re-enable non-blocking I/O.
-        impl.flags_ &= ~(implementation_type::user_set_non_blocking
-            | implementation_type::internal_non_blocking);
-      }
-    }
-
+    descriptor_ops::ioctl(impl.descriptor_, impl.state_,
+        command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
     return ec;
   }
 
@@ -246,148 +121,23 @@ public:
   size_t write_some(implementation_type& impl,
       const ConstBufferSequence& buffers, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::const_buffer,
         ConstBufferSequence> bufs(buffers);
 
-    // A request to read_some 0 bytes on a stream is a no-op.
-    if (bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Send the data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      int bytes_sent = descriptor_ops::gather_write(
-          impl.descriptor_, bufs.buffers(), bufs.count(), ec);
-
-      // Check if operation succeeded.
-      if (bytes_sent >= 0)
-        return bytes_sent;
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for descriptor to become ready.
-      if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
-        return 0;
-    }
+    return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
+        bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
   }
 
   // Wait until data can be written without blocking.
   size_t write_some(implementation_type& impl,
       const null_buffers&, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for descriptor to become ready.
     descriptor_ops::poll_write(impl.descriptor_, ec);
 
     return 0;
   }
 
-  template <typename ConstBufferSequence>
-  class write_op_base : public reactor_op
-  {
-  public:
-    write_op_base(int descriptor,
-        const ConstBufferSequence& buffers, func_type complete_func)
-      : reactor_op(&write_op_base::do_perform, complete_func),
-        descriptor_(descriptor),
-        buffers_(buffers)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      write_op_base* o(static_cast<write_op_base*>(base));
-
-      buffer_sequence_adapter<asio::const_buffer,
-          ConstBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Write the data.
-        asio::error_code ec;
-        int bytes = descriptor_ops::gather_write(
-            o->descriptor_, bufs.buffers(), bufs.count(), ec);
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    int descriptor_;
-    ConstBufferSequence buffers_;
-  };
-
-  template <typename ConstBufferSequence, typename Handler>
-  class write_op : public write_op_base<ConstBufferSequence>
-  {
-  public:
-    write_op(int descriptor,
-        const ConstBufferSequence& buffers, Handler handler)
-      : write_op_base<ConstBufferSequence>(
-          descriptor, buffers, &write_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      write_op* o(static_cast<write_op*>(base));
-      typedef handler_alloc_traits<Handler, write_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous write. The data being sent must be valid for the
   // lifetime of the asynchronous operation.
   template <typename ConstBufferSequence, typename Handler>
@@ -395,15 +145,16 @@ public:
       const ConstBufferSequence& buffers, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef write_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.descriptor_, buffers, handler);
+    typedef descriptor_write_op<ConstBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.descriptor_, buffers, handler);
 
-    start_op(impl, reactor::write_op, ptr.get(), true,
+    start_op(impl, reactor::write_op, p.p, true,
         buffer_sequence_adapter<asio::const_buffer,
           ConstBufferSequence>::all_empty(buffers));
-    ptr.release();
+    p.v = p.p = 0;
   }
 
   // Start an asynchronous wait until data can be written without blocking.
@@ -412,13 +163,14 @@ public:
       const null_buffers&, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
 
-    start_op(impl, reactor::write_op, ptr.get(), false, false);
-    ptr.release();
+    start_op(impl, reactor::write_op, p.p, false, false);
+    p.v = p.p = 0;
   }
 
   // Read some data from the stream. Returns the number of bytes read.
@@ -426,157 +178,23 @@ public:
   size_t read_some(implementation_type& impl,
       const MutableBufferSequence& buffers, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::mutable_buffer,
         MutableBufferSequence> bufs(buffers);
 
-    // A request to read_some 0 bytes on a stream is a no-op.
-    if (bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Read some data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      int bytes_read = descriptor_ops::scatter_read(
-          impl.descriptor_, bufs.buffers(), bufs.count(), ec);
-
-      // Check if operation succeeded.
-      if (bytes_read > 0)
-        return bytes_read;
-
-      // Check for EOF.
-      if (bytes_read == 0)
-      {
-        ec = asio::error::eof;
-        return 0;
-      }
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for descriptor to become ready.
-      if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
-        return 0;
-    }
+    return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
+        bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
   }
 
   // Wait until data can be read without blocking.
   size_t read_some(implementation_type& impl,
       const null_buffers&, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for descriptor to become ready.
     descriptor_ops::poll_read(impl.descriptor_, ec);
 
     return 0;
   }
 
-  template <typename MutableBufferSequence>
-  class read_op_base : public reactor_op
-  {
-  public:
-    read_op_base(int descriptor,
-        const MutableBufferSequence& buffers, func_type complete_func)
-      : reactor_op(&read_op_base::do_perform, complete_func),
-        descriptor_(descriptor),
-        buffers_(buffers)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      read_op_base* o(static_cast<read_op_base*>(base));
-
-      buffer_sequence_adapter<asio::mutable_buffer,
-          MutableBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Read some data.
-        asio::error_code ec;
-        int bytes = descriptor_ops::scatter_read(
-            o->descriptor_, bufs.buffers(), bufs.count(), ec);
-        if (bytes == 0)
-          ec = asio::error::eof;
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    int descriptor_;
-    MutableBufferSequence buffers_;
-  };
-
-  template <typename MutableBufferSequence, typename Handler>
-  class read_op : public read_op_base<MutableBufferSequence>
-  {
-  public:
-    read_op(int descriptor,
-        const MutableBufferSequence& buffers, Handler handler)
-      : read_op_base<MutableBufferSequence>(
-          descriptor, buffers, &read_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      read_op* o(static_cast<read_op*>(base));
-      typedef handler_alloc_traits<Handler, read_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous read. The buffer for the data being read must be
   // valid for the lifetime of the asynchronous operation.
   template <typename MutableBufferSequence, typename Handler>
@@ -584,16 +202,16 @@ public:
       const MutableBufferSequence& buffers, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef read_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl.descriptor_, buffers, handler);
+    typedef descriptor_read_op<MutableBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.descriptor_, buffers, handler);
 
-    start_op(impl, reactor::read_op, ptr.get(), true,
+    start_op(impl, reactor::read_op, p.p, true,
         buffer_sequence_adapter<asio::mutable_buffer,
           MutableBufferSequence>::all_empty(buffers));
-    ptr.release();
+    p.v = p.p = 0;
   }
 
   // Wait until data can be read without blocking.
@@ -602,57 +220,20 @@ public:
       const null_buffers&, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
 
-    start_op(impl, reactor::read_op, ptr.get(), false, false);
-    ptr.release();
+    start_op(impl, reactor::read_op, p.p, false, false);
+    p.v = p.p = 0;
   }
 
 private:
   // Start the asynchronous operation.
-  void start_op(implementation_type& impl, int op_type,
-      reactor_op* op, bool non_blocking, bool noop)
-  {
-    if (!noop)
-    {
-      if (is_open(impl))
-      {
-        if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
-        {
-          reactor_.start_op(op_type, impl.descriptor_,
-              impl.reactor_data_, op, non_blocking);
-          return;
-        }
-      }
-      else
-        op->ec_ = asio::error::bad_descriptor;
-    }
-
-    io_service_impl_.post_immediate_completion(op);
-  }
-
-  // Determine whether the descriptor has been set non-blocking.
-  bool is_non_blocking(implementation_type& impl) const
-  {
-    return (impl.flags_ & implementation_type::non_blocking);
-  }
-
-  // Set the internal non-blocking flag.
-  bool set_non_blocking(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    ioctl_arg_type non_blocking = 1;
-    if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
-      return false;
-    impl.flags_ |= implementation_type::internal_non_blocking;
-    return true;
-  }
-
-  // The io_service implementation used to post completions.
-  io_service_impl& io_service_impl_;
+  ASIO_DECL void start_op(implementation_type& impl, int op_type,
+      reactor_op* op, bool non_blocking, bool noop);
 
   // The selector that performs event demultiplexing for the service.
   reactor& reactor_;
@@ -661,8 +242,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_descriptor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_null_buffers_op.hpp b/ext/asio/asio/detail/reactive_null_buffers_op.hpp
new file mode 100644
index 0000000..0c83c61
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_null_buffers_op.hpp
@@ -0,0 +1,83 @@
+//
+// detail/reactive_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class reactive_null_buffers_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);
+
+  reactive_null_buffers_op(Handler handler)
+    : reactor_op(&reactive_null_buffers_op::do_perform,
+        &reactive_null_buffers_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static bool do_perform(reactor_op*)
+  {
+    return true;
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_serial_port_service.hpp b/ext/asio/asio/detail/reactive_serial_port_service.hpp
index 186460f..556ea06 100644
--- a/ext/asio/asio/detail/reactive_serial_port_service.hpp
+++ b/ext/asio/asio/detail/reactive_serial_port_service.hpp
@@ -1,8 +1,8 @@
 //
-// reactive_serial_port_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,23 +16,20 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <string>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/serial_port_base.hpp"
-
-#if defined(ASIO_HAS_SERIAL_PORT) \
-  && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
+#include <string>
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
+#include "asio/serial_port_base.hpp"
 #include "asio/detail/descriptor_ops.hpp"
 #include "asio/detail/reactive_descriptor_service.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -46,119 +43,55 @@ public:
   // The implementation type of the serial port.
   typedef reactive_descriptor_service::implementation_type implementation_type;
 
-  reactive_serial_port_service(asio::io_service& io_service)
-    : descriptor_service_(io_service)
-  {
-  }
+  ASIO_DECL reactive_serial_port_service(
+      asio::io_service& io_service);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    descriptor_service_.shutdown_service();
-  }
+  ASIO_DECL void shutdown_service();
 
-  // Construct a new handle implementation.
+  // Construct a new serial port implementation.
   void construct(implementation_type& impl)
   {
     descriptor_service_.construct(impl);
   }
 
-  // Destroy a handle implementation.
+  // Destroy a serial port implementation.
   void destroy(implementation_type& impl)
   {
     descriptor_service_.destroy(impl);
   }
 
   // Open the serial port using the specified device name.
-  asio::error_code open(implementation_type& impl,
-      const std::string& device, asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    int fd = descriptor_ops::open(device.c_str(),
-        O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
-    if (fd < 0)
-      return ec;
-
-    int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
-    if (s >= 0)
-      s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
-    if (s < 0)
-    {
-      asio::error_code ignored_ec;
-      descriptor_ops::close(fd, ignored_ec);
-      return ec;
-    }
-  
-    // Set up default serial port options.
-    termios ios;
-    descriptor_ops::clear_error(ec);
-    s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
-    if (s >= 0)
-    {
-#if defined(_BSD_SOURCE)
-      ::cfmakeraw(&ios);
-#else
-      ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
-          | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
-      ios.c_oflag &= ~OPOST;
-      ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-      ios.c_cflag &= ~(CSIZE | PARENB);
-      ios.c_cflag |= CS8;
-#endif
-      ios.c_iflag |= IGNPAR;
-      ios.c_cflag |= CREAD | CLOCAL;
-      descriptor_ops::clear_error(ec);
-      s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
-    }
-    if (s < 0)
-    {
-      asio::error_code ignored_ec;
-      descriptor_ops::close(fd, ignored_ec);
-      return ec;
-    }
-  
-    // We're done. Take ownership of the serial port descriptor.
-    if (descriptor_service_.assign(impl, fd, ec))
-    {
-      asio::error_code ignored_ec;
-      descriptor_ops::close(fd, ignored_ec);
-    }
-
-    return ec;
-  }
+  ASIO_DECL asio::error_code open(implementation_type& impl,
+      const std::string& device, asio::error_code& ec);
 
-  // Assign a native handle to a handle implementation.
+  // Assign a native descriptor to a serial port implementation.
   asio::error_code assign(implementation_type& impl,
       const native_type& native_descriptor, asio::error_code& ec)
   {
     return descriptor_service_.assign(impl, native_descriptor, ec);
   }
 
-  // Determine whether the handle is open.
+  // Determine whether the serial port is open.
   bool is_open(const implementation_type& impl) const
   {
     return descriptor_service_.is_open(impl);
   }
 
-  // Destroy a handle implementation.
+  // Destroy a serial port implementation.
   asio::error_code close(implementation_type& impl,
       asio::error_code& ec)
   {
     return descriptor_service_.close(impl, ec);
   }
 
-  // Get the native handle representation.
+  // Get the native serial port representation.
   native_type native(implementation_type& impl)
   {
     return descriptor_service_.native(impl);
   }
 
-  // Cancel all operations associated with the handle.
+  // Cancel all operations associated with the serial port.
   asio::error_code cancel(implementation_type& impl,
       asio::error_code& ec)
   {
@@ -170,20 +103,9 @@ public:
   asio::error_code set_option(implementation_type& impl,
       const SettableSerialPortOption& option, asio::error_code& ec)
   {
-    termios ios;
-    descriptor_ops::clear_error(ec);
-    descriptor_ops::error_wrapper(::tcgetattr(
-          descriptor_service_.native(impl), &ios), ec);
-    if (ec)
-      return ec;
-
-    if (option.store(ios, ec))
-      return ec;
-
-    descriptor_ops::clear_error(ec);
-    descriptor_ops::error_wrapper(::tcsetattr(
-          descriptor_service_.native(impl), TCSANOW, &ios), ec);
-    return ec;
+    return do_set_option(impl,
+        &reactive_serial_port_service::store_option<SettableSerialPortOption>,
+        &option, ec);
   }
 
   // Get an option from the serial port.
@@ -191,21 +113,16 @@ public:
   asio::error_code get_option(const implementation_type& impl,
       GettableSerialPortOption& option, asio::error_code& ec) const
   {
-    termios ios;
-    descriptor_ops::clear_error(ec);
-    descriptor_ops::error_wrapper(::tcgetattr(
-          descriptor_service_.native(impl), &ios), ec);
-    if (ec)
-      return ec;
-
-    return option.load(ios, ec);
+    return do_get_option(impl,
+        &reactive_serial_port_service::load_option<GettableSerialPortOption>,
+        &option, ec);
   }
 
   // Send a break sequence to the serial port.
   asio::error_code send_break(implementation_type& impl,
       asio::error_code& ec)
   {
-    descriptor_ops::clear_error(ec);
+    errno = 0;
     descriptor_ops::error_wrapper(::tcsendbreak(
           descriptor_service_.native(impl), 0), ec);
     return ec;
@@ -246,6 +163,41 @@ public:
   }
 
 private:
+  // Function pointer type for storing a serial port option.
+  typedef asio::error_code (*store_function_type)(
+      const void*, termios&, asio::error_code&);
+
+  // Helper function template to store a serial port option.
+  template <typename SettableSerialPortOption>
+  static asio::error_code store_option(const void* option,
+      termios& storage, asio::error_code& ec)
+  {
+    return static_cast<const SettableSerialPortOption*>(option)->store(
+        storage, ec);
+  }
+
+  // Helper function to set a serial port option.
+  ASIO_DECL asio::error_code do_set_option(
+      implementation_type& impl, store_function_type store,
+      const void* option, asio::error_code& ec);
+
+  // Function pointer type for loading a serial port option.
+  typedef asio::error_code (*load_function_type)(
+      void*, const termios&, asio::error_code&);
+
+  // Helper function template to load a serial port option.
+  template <typename GettableSerialPortOption>
+  static asio::error_code load_option(void* option,
+      const termios& storage, asio::error_code& ec)
+  {
+    return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+  }
+
+  // Helper function to get a serial port option.
+  ASIO_DECL asio::error_code do_get_option(
+      const implementation_type& impl, load_function_type load,
+      void* option, asio::error_code& ec) const;
+
   // The implementation used for initiating asynchronous operations.
   reactive_descriptor_service descriptor_service_;
 };
@@ -253,9 +205,13 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_SERIAL_PORT)
-       //   && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
 #endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_accept_op.hpp b/ext/asio/asio/detail/reactive_socket_accept_op.hpp
new file mode 100644
index 0000000..76c6741
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_accept_op.hpp
@@ -0,0 +1,131 @@
+//
+// detail/reactive_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol>
+class reactive_socket_accept_op_base : public reactor_op
+{
+public:
+  reactive_socket_accept_op_base(socket_type socket,
+      socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+      typename Protocol::endpoint* peer_endpoint, func_type complete_func)
+    : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func),
+      socket_(socket),
+      state_(state),
+      peer_(peer),
+      protocol_(protocol),
+      peer_endpoint_(peer_endpoint)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_accept_op_base* o(
+        static_cast<reactive_socket_accept_op_base*>(base));
+
+    std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0;
+    socket_type new_socket = invalid_socket;
+    bool result = socket_ops::non_blocking_accept(o->socket_,
+          o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
+          o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket);
+
+    // On success, assign new connection to peer socket object.
+    if (new_socket >= 0)
+    {
+      socket_holder new_socket_holder(new_socket);
+      if (o->peer_endpoint_)
+        o->peer_endpoint_->resize(addrlen);
+      if (!o->peer_.assign(o->protocol_, new_socket, o->ec_))
+        new_socket_holder.release();
+    }
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  socket_ops::state_type state_;
+  Socket& peer_;
+  Protocol protocol_;
+  typename Protocol::endpoint* peer_endpoint_;
+};
+
+template <typename Socket, typename Protocol, typename Handler>
+class reactive_socket_accept_op :
+  public reactive_socket_accept_op_base<Socket, Protocol>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);
+
+  reactive_socket_accept_op(socket_type socket,
+      socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+      typename Protocol::endpoint* peer_endpoint, Handler handler)
+    : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer,
+        protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_connect_op.hpp b/ext/asio/asio/detail/reactive_socket_connect_op.hpp
new file mode 100644
index 0000000..8267091
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_connect_op.hpp
@@ -0,0 +1,101 @@
+//
+// detail/reactive_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_connect_op_base : public reactor_op
+{
+public:
+  reactive_socket_connect_op_base(socket_type socket, func_type complete_func)
+    : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func),
+      socket_(socket)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_connect_op_base* o(
+        static_cast<reactive_socket_connect_op_base*>(base));
+
+    return socket_ops::non_blocking_connect(o->socket_, o->ec_);
+  }
+
+private:
+  socket_type socket_;
+};
+
+template <typename Handler>
+class reactive_socket_connect_op : public reactive_socket_connect_op_base
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);
+
+  reactive_socket_connect_op(socket_type socket, Handler handler)
+    : reactive_socket_connect_op_base(socket,
+        &reactive_socket_connect_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_connect_op* o
+      (static_cast<reactive_socket_connect_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_recv_op.hpp b/ext/asio/asio/detail/reactive_socket_recv_op.hpp
new file mode 100644
index 0000000..91a30a8
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_recv_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/reactive_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base : public reactor_op
+{
+public:
+  reactive_socket_recv_op_base(socket_type socket,
+      socket_ops::state_type state, const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func),
+      socket_(socket),
+      state_(state),
+      buffers_(buffers),
+      flags_(flags)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_recv_op_base* o(
+        static_cast<reactive_socket_recv_op_base*>(base));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(o->buffers_);
+
+    return socket_ops::non_blocking_recv(o->socket_,
+        bufs.buffers(), bufs.count(), o->flags_,
+        (o->state_ & socket_ops::stream_oriented),
+        o->ec_, o->bytes_transferred_);
+  }
+
+private:
+  socket_type socket_;
+  socket_ops::state_type state_;
+  MutableBufferSequence buffers_;
+  socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recv_op :
+  public reactive_socket_recv_op_base<MutableBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
+
+  reactive_socket_recv_op(socket_type socket,
+      socket_ops::state_type state, const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+    : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state,
+        buffers, flags, &reactive_socket_recv_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..121d6ec
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
@@ -0,0 +1,128 @@
+//
+// detail/reactive_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base : public reactor_op
+{
+public:
+  reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type,
+      const MutableBufferSequence& buffers, Endpoint& endpoint,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func),
+      socket_(socket),
+      protocol_type_(protocol_type),
+      buffers_(buffers),
+      sender_endpoint_(endpoint),
+      flags_(flags)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_recvfrom_op_base* o(
+        static_cast<reactive_socket_recvfrom_op_base*>(base));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(o->buffers_);
+
+    std::size_t addr_len = o->sender_endpoint_.capacity();
+    bool result = socket_ops::non_blocking_recvfrom(o->socket_,
+        bufs.buffers(), bufs.count(), o->flags_,
+        o->sender_endpoint_.data(), &addr_len,
+        o->ec_, o->bytes_transferred_);
+
+    if (result && !o->ec_)
+      o->sender_endpoint_.resize(addr_len);
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  int protocol_type_;
+  MutableBufferSequence buffers_;
+  Endpoint& sender_endpoint_;
+  socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_recvfrom_op :
+  public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op);
+
+  reactive_socket_recvfrom_op(socket_type socket, int protocol_type,
+      const MutableBufferSequence& buffers, Endpoint& endpoint,
+      socket_base::message_flags flags, Handler handler)
+    : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(
+        socket, protocol_type, buffers, endpoint, flags,
+        &reactive_socket_recvfrom_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_recvfrom_op* o(
+        static_cast<reactive_socket_recvfrom_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_send_op.hpp b/ext/asio/asio/detail/reactive_socket_send_op.hpp
new file mode 100644
index 0000000..9a68dac
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_send_op.hpp
@@ -0,0 +1,115 @@
+//
+// detail/reactive_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class reactive_socket_send_op_base : public reactor_op
+{
+public:
+  reactive_socket_send_op_base(socket_type socket,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func),
+      socket_(socket),
+      buffers_(buffers),
+      flags_(flags)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_send_op_base* o(
+        static_cast<reactive_socket_send_op_base*>(base));
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(o->buffers_);
+
+    return socket_ops::non_blocking_send(o->socket_,
+          bufs.buffers(), bufs.count(), o->flags_,
+          o->ec_, o->bytes_transferred_);
+  }
+
+private:
+  socket_type socket_;
+  ConstBufferSequence buffers_;
+  socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class reactive_socket_send_op :
+  public reactive_socket_send_op_base<ConstBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
+
+  reactive_socket_send_op(socket_type socket,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+    : reactive_socket_send_op_base<ConstBufferSequence>(socket,
+        buffers, flags, &reactive_socket_send_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_sendto_op.hpp b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp
new file mode 100644
index 0000000..e466a25
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/reactive_socket_sendto_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Endpoint>
+class reactive_socket_sendto_op_base : public reactor_op
+{
+public:
+  reactive_socket_sendto_op_base(socket_type socket,
+      const ConstBufferSequence& buffers, const Endpoint& endpoint,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func),
+      socket_(socket),
+      buffers_(buffers),
+      destination_(endpoint),
+      flags_(flags)
+  {
+  }
+
+  static bool do_perform(reactor_op* base)
+  {
+    reactive_socket_sendto_op_base* o(
+        static_cast<reactive_socket_sendto_op_base*>(base));
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(o->buffers_);
+
+    return socket_ops::non_blocking_sendto(o->socket_,
+          bufs.buffers(), bufs.count(), o->flags_,
+          o->destination_.data(), o->destination_.size(),
+          o->ec_, o->bytes_transferred_);
+  }
+
+private:
+  socket_type socket_;
+  ConstBufferSequence buffers_;
+  Endpoint destination_;
+  socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_sendto_op :
+  public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op);
+
+  reactive_socket_sendto_op(socket_type socket,
+      const ConstBufferSequence& buffers, const Endpoint& endpoint,
+      socket_base::message_flags flags, Handler handler)
+    : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket,
+        buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_service.hpp b/ext/asio/asio/detail/reactive_socket_service.hpp
index 20bd512..daa9f60 100644
--- a/ext/asio/asio/detail/reactive_socket_service.hpp
+++ b/ext/asio/asio/detail/reactive_socket_service.hpp
@@ -1,8 +1,8 @@
 //
-// reactive_socket_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,37 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
 
+#include <boost/utility/addressof.hpp>
 #include "asio/buffer.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/socket_base.hpp"
-#include "asio/detail/bind_handler.hpp"
 #include "asio/detail/buffer_sequence_adapter.hpp"
-#include "asio/detail/fenced_block.hpp"
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/null_buffers_op.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_accept_op.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
+#include "asio/detail/reactive_socket_recvfrom_op.hpp"
+#include "asio/detail/reactive_socket_sendto_op.hpp"
+#include "asio/detail/reactive_socket_service_base.hpp"
 #include "asio/detail/reactor.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/socket_holder.hpp"
 #include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
 template <typename Protocol>
-class reactive_socket_service
+class reactive_socket_service :
+  public reactive_socket_service_base
 {
 public:
   // The protocol type.
@@ -49,132 +58,32 @@ public:
   typedef socket_type native_type;
 
   // The implementation type of the socket.
-  class implementation_type
-    : private asio::detail::noncopyable
+  struct implementation_type :
+    reactive_socket_service_base::base_implementation_type
   {
-  public:
     // Default constructor.
     implementation_type()
-      : socket_(invalid_socket),
-        flags_(0),
-        protocol_(endpoint_type().protocol())
+      : protocol_(endpoint_type().protocol())
     {
     }
 
-  private:
-    // Only this service will have access to the internal values.
-    friend class reactive_socket_service<Protocol>;
-
-    // The native socket representation.
-    socket_type socket_;
-
-    enum
-    {
-      // The user wants a non-blocking socket.
-      user_set_non_blocking = 1,
-
-      // The implementation wants a non-blocking socket (in order to be able to
-      // perform asynchronous read and write operations).
-      internal_non_blocking = 2,
-
-      // Helper "flag" used to determine whether the socket is non-blocking.
-      non_blocking = user_set_non_blocking | internal_non_blocking,
-
-      // User wants connection_aborted errors, which are disabled by default.
-      enable_connection_aborted = 4,
-
-      // The user set the linger option. Needs to be checked when closing.
-      user_set_linger = 8
-    };
-
-    // Flags indicating the current state of the socket.
-    unsigned char flags_;
-
     // The protocol associated with the socket.
     protocol_type protocol_;
-
-    // Per-descriptor data used by the reactor.
-    reactor::per_descriptor_data reactor_data_;
   };
 
   // Constructor.
   reactive_socket_service(asio::io_service& io_service)
-    : io_service_impl_(use_service<io_service_impl>(io_service)),
-      reactor_(use_service<reactor>(io_service))
-  {
-    reactor_.init_task();
-  }
-
-  // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-  }
-
-  // Construct a new socket implementation.
-  void construct(implementation_type& impl)
+    : reactive_socket_service_base(io_service)
   {
-    impl.socket_ = invalid_socket;
-    impl.flags_ = 0;
-  }
-
-  // Destroy a socket implementation.
-  void destroy(implementation_type& impl)
-  {
-    if (impl.socket_ != invalid_socket)
-    {
-      reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
-
-      if (impl.flags_ & implementation_type::non_blocking)
-      {
-        ioctl_arg_type non_blocking = 0;
-        asio::error_code ignored_ec;
-        socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
-        impl.flags_ &= ~implementation_type::non_blocking;
-      }
-
-      if (impl.flags_ & implementation_type::user_set_linger)
-      {
-        ::linger opt;
-        opt.l_onoff = 0;
-        opt.l_linger = 0;
-        asio::error_code ignored_ec;
-        socket_ops::setsockopt(impl.socket_,
-            SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
-      }
-
-      asio::error_code ignored_ec;
-      socket_ops::close(impl.socket_, ignored_ec);
-
-      impl.socket_ = invalid_socket;
-    }
   }
 
   // Open a new socket implementation.
   asio::error_code open(implementation_type& impl,
       const protocol_type& protocol, asio::error_code& ec)
   {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    socket_holder sock(socket_ops::socket(protocol.family(),
-          protocol.type(), protocol.protocol(), ec));
-    if (sock.get() == invalid_socket)
-      return ec;
-
-    if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
-    {
-      ec = asio::error_code(err,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    impl.socket_ = sock.release();
-    impl.flags_ = 0;
-    impl.protocol_ = protocol;
-    ec = asio::error_code();
+    if (!do_open(impl, protocol.family(),
+          protocol.type(), protocol.protocol(), ec))
+      impl.protocol_ = protocol;
     return ec;
   }
 
@@ -183,56 +92,8 @@ public:
       const protocol_type& protocol, const native_type& native_socket,
       asio::error_code& ec)
   {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    if (int err = reactor_.register_descriptor(
-          native_socket, impl.reactor_data_))
-    {
-      ec = asio::error_code(err,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    impl.socket_ = native_socket;
-    impl.flags_ = 0;
-    impl.protocol_ = protocol;
-    ec = asio::error_code();
-    return ec;
-  }
-
-  // Determine whether the socket is open.
-  bool is_open(const implementation_type& impl) const
-  {
-    return impl.socket_ != invalid_socket;
-  }
-
-  // Destroy a socket implementation.
-  asio::error_code close(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
-
-      if (impl.flags_ & implementation_type::non_blocking)
-      {
-        ioctl_arg_type non_blocking = 0;
-        asio::error_code ignored_ec;
-        socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
-        impl.flags_ &= ~implementation_type::non_blocking;
-      }
-
-      if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
-        return ec;
-
-      impl.socket_ = invalid_socket;
-    }
-
-    ec = asio::error_code();
+    if (!do_assign(impl, protocol.type(), native_socket, ec))
+      impl.protocol_ = protocol;
     return ec;
   }
 
@@ -242,153 +103,23 @@ public:
     return impl.socket_;
   }
 
-  // Cancel all operations associated with the socket.
-  asio::error_code cancel(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
-    ec = asio::error_code();
-    return ec;
-  }
-
-  // Determine whether the socket is at the out-of-band data mark.
-  bool at_mark(const implementation_type& impl,
-      asio::error_code& ec) const
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return false;
-    }
-
-#if defined(SIOCATMARK)
-    asio::detail::ioctl_arg_type value = 0;
-    socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
-# if defined(ENOTTY)
-    if (ec.value() == ENOTTY)
-      ec = asio::error::not_socket;
-# endif // defined(ENOTTY)
-#else // defined(SIOCATMARK)
-    int value = sockatmark(impl.socket_);
-    if (value == -1)
-      ec = asio::error_code(errno,
-          asio::error::get_system_category());
-    else
-      ec = asio::error_code();
-#endif // defined(SIOCATMARK)
-    return ec ? false : value != 0;
-  }
-
-  // Determine the number of bytes available for reading.
-  std::size_t available(const implementation_type& impl,
-      asio::error_code& ec) const
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    asio::detail::ioctl_arg_type value = 0;
-    socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
-#if defined(ENOTTY)
-    if (ec.value() == ENOTTY)
-      ec = asio::error::not_socket;
-#endif // defined(ENOTTY)
-    return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
-  }
-
   // Bind the socket to the specified local endpoint.
   asio::error_code bind(implementation_type& impl,
       const endpoint_type& endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
     socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
     return ec;
   }
 
-  // Place the socket into the state where it will listen for new connections.
-  asio::error_code listen(implementation_type& impl, int backlog,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::listen(impl.socket_, backlog, ec);
-    return ec;
-  }
-
   // Set a socket option.
   template <typename Option>
   asio::error_code set_option(implementation_type& impl,
       const Option& option, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    if (option.level(impl.protocol_) == custom_socket_option_level
-        && option.name(impl.protocol_) == enable_connection_aborted_option)
-    {
-      if (option.size(impl.protocol_) != sizeof(int))
-      {
-        ec = asio::error::invalid_argument;
-      }
-      else
-      {
-        if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
-          impl.flags_ |= implementation_type::enable_connection_aborted;
-        else
-          impl.flags_ &= ~implementation_type::enable_connection_aborted;
-        ec = asio::error_code();
-      }
-      return ec;
-    }
-    else
-    {
-      if (option.level(impl.protocol_) == SOL_SOCKET
-          && option.name(impl.protocol_) == SO_LINGER)
-      {
-        impl.flags_ |= implementation_type::user_set_linger;
-      }
-
-      socket_ops::setsockopt(impl.socket_,
-          option.level(impl.protocol_), option.name(impl.protocol_),
-          option.data(impl.protocol_), option.size(impl.protocol_), ec);
-
-#if defined(__MACH__) && defined(__APPLE__) \
-|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-      // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
-      // need to also set SO_REUSEPORT on BSD-based platforms.
-      if (!ec && impl.protocol_.type() == SOCK_DGRAM
-          && option.level(impl.protocol_) == SOL_SOCKET
-          && option.name(impl.protocol_) == SO_REUSEADDR)
-      {
-        asio::error_code ignored_ec;
-        socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
-            option.data(impl.protocol_), option.size(impl.protocol_),
-            ignored_ec);
-      }
-#endif
-
-      return ec;
-    }
+    socket_ops::setsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), option.size(impl.protocol_), ec);
+    return ec;
   }
 
   // Set a socket option.
@@ -396,78 +127,12 @@ public:
   asio::error_code get_option(const implementation_type& impl,
       Option& option, asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    if (option.level(impl.protocol_) == custom_socket_option_level
-        && option.name(impl.protocol_) == enable_connection_aborted_option)
-    {
-      if (option.size(impl.protocol_) != sizeof(int))
-      {
-        ec = asio::error::invalid_argument;
-      }
-      else
-      {
-        int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
-        if (impl.flags_ & implementation_type::enable_connection_aborted)
-          *target = 1;
-        else
-          *target = 0;
-        option.resize(impl.protocol_, sizeof(int));
-        ec = asio::error_code();
-      }
-      return ec;
-    }
-    else
-    {
-      size_t size = option.size(impl.protocol_);
-      socket_ops::getsockopt(impl.socket_,
-          option.level(impl.protocol_), option.name(impl.protocol_),
-          option.data(impl.protocol_), &size, ec);
-      if (!ec)
-        option.resize(impl.protocol_, size);
-      return ec;
-    }
-  }
-
-  // Perform an IO control command on the socket.
-  template <typename IO_Control_Command>
-  asio::error_code io_control(implementation_type& impl,
-      IO_Control_Command& command, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::ioctl(impl.socket_, command.name(),
-        static_cast<ioctl_arg_type*>(command.data()), ec);
-
-    // When updating the non-blocking mode we always perform the ioctl
-    // syscall, even if the flags would otherwise indicate that the socket is
-    // already in the correct state. This ensures that the underlying socket
-    // is put into the state that has been requested by the user. If the ioctl
-    // syscall was successful then we need to update the flags to match.
-    if (!ec && command.name() == static_cast<int>(FIONBIO))
-    {
-      if (*static_cast<ioctl_arg_type*>(command.data()))
-      {
-        impl.flags_ |= implementation_type::user_set_non_blocking;
-      }
-      else
-      {
-        // Clearing the non-blocking mode always overrides any internally-set
-        // non-blocking flag. Any subsequent asynchronous operations will need
-        // to re-enable non-blocking I/O.
-        impl.flags_ &= ~(implementation_type::user_set_non_blocking
-            | implementation_type::internal_non_blocking);
-      }
-    }
-
+    std::size_t size = option.size(impl.protocol_);
+    socket_ops::getsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), &size, ec);
+    if (!ec)
+      option.resize(impl.protocol_, size);
     return ec;
   }
 
@@ -475,12 +140,6 @@ public:
   endpoint_type local_endpoint(const implementation_type& impl,
       asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return endpoint_type();
-    }
-
     endpoint_type endpoint;
     std::size_t addr_len = endpoint.capacity();
     if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
@@ -493,218 +152,15 @@ public:
   endpoint_type remote_endpoint(const implementation_type& impl,
       asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return endpoint_type();
-    }
-
     endpoint_type endpoint;
     std::size_t addr_len = endpoint.capacity();
-    if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+    if (socket_ops::getpeername(impl.socket_,
+          endpoint.data(), &addr_len, false, ec))
       return endpoint_type();
     endpoint.resize(addr_len);
     return endpoint;
   }
 
-  /// Disable sends or receives on the socket.
-  asio::error_code shutdown(implementation_type& impl,
-      socket_base::shutdown_type what, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::shutdown(impl.socket_, what, ec);
-    return ec;
-  }
-
-  // Send the given data to the peer.
-  template <typename ConstBufferSequence>
-  size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
-      socket_base::message_flags flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    buffer_sequence_adapter<asio::const_buffer,
-        ConstBufferSequence> bufs(buffers);
-
-    // A request to receive 0 bytes on a stream socket is a no-op.
-    if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Send the data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      int bytes_sent = socket_ops::send(impl.socket_,
-          bufs.buffers(), bufs.count(), flags, ec);
-
-      // Check if operation succeeded.
-      if (bytes_sent >= 0)
-        return bytes_sent;
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for socket to become ready.
-      if (socket_ops::poll_write(impl.socket_, ec) < 0)
-        return 0;
-    }
-  }
-
-  // Wait until data can be sent without blocking.
-  size_t send(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    // Wait for socket to become ready.
-    socket_ops::poll_write(impl.socket_, ec);
-
-    return 0;
-  }
-
-  template <typename ConstBufferSequence>
-  class send_op_base : public reactor_op
-  {
-  public:
-    send_op_base(socket_type socket, const ConstBufferSequence& buffers,
-        socket_base::message_flags flags, func_type complete_func)
-      : reactor_op(&send_op_base::do_perform, complete_func),
-        socket_(socket),
-        buffers_(buffers),
-        flags_(flags)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      send_op_base* o(static_cast<send_op_base*>(base));
-
-      buffer_sequence_adapter<asio::const_buffer,
-          ConstBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Send the data.
-        asio::error_code ec;
-        int bytes = socket_ops::send(o->socket_,
-            bufs.buffers(), bufs.count(), o->flags_, ec);
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    socket_type socket_;
-    ConstBufferSequence buffers_;
-    socket_base::message_flags flags_;
-  };
-
-  template <typename ConstBufferSequence, typename Handler>
-  class send_op : public send_op_base<ConstBufferSequence>
-  {
-  public:
-    send_op(socket_type socket, const ConstBufferSequence& buffers,
-        socket_base::message_flags flags, Handler handler)
-      : send_op_base<ConstBufferSequence>(socket,
-          buffers, flags, &send_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      send_op* o(static_cast<send_op*>(base));
-      typedef handler_alloc_traits<Handler, send_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
-  // Start an asynchronous send. The data being sent must be valid for the
-  // lifetime of the asynchronous operation.
-  template <typename ConstBufferSequence, typename Handler>
-  void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
-      socket_base::message_flags flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef send_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl.socket_, buffers, flags, handler);
-
-    start_op(impl, reactor::write_op, ptr.get(), true,
-        (impl.protocol_.type() == SOCK_STREAM
-          && buffer_sequence_adapter<asio::const_buffer,
-            ConstBufferSequence>::all_empty(buffers)));
-    ptr.release();
-  }
-
-  // Start an asynchronous wait until data can be sent without blocking.
-  template <typename Handler>
-  void async_send(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    start_op(impl, reactor::write_op, ptr.get(), false, false);
-    ptr.release();
-  }
-
   // Send a datagram to the specified endpoint. Returns the number of bytes
   // sent.
   template <typename ConstBufferSequence>
@@ -712,148 +168,25 @@ public:
       const endpoint_type& destination, socket_base::message_flags flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::const_buffer,
         ConstBufferSequence> bufs(buffers);
 
-    // Send the data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(),
-          bufs.count(), flags, destination.data(), destination.size(), ec);
-
-      // Check if operation succeeded.
-      if (bytes_sent >= 0)
-        return bytes_sent;
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for socket to become ready.
-      if (socket_ops::poll_write(impl.socket_, ec) < 0)
-        return 0;
-    }
+    return socket_ops::sync_sendto(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags,
+        destination.data(), destination.size(), ec);
   }
 
   // Wait until data can be sent without blocking.
   size_t send_to(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, const endpoint_type&,
+      const endpoint_type&, socket_base::message_flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for socket to become ready.
     socket_ops::poll_write(impl.socket_, ec);
 
     return 0;
   }
 
-  template <typename ConstBufferSequence>
-  class send_to_op_base : public reactor_op
-  {
-  public:
-    send_to_op_base(socket_type socket, const ConstBufferSequence& buffers,
-        const endpoint_type& endpoint, socket_base::message_flags flags,
-        func_type complete_func)
-      : reactor_op(&send_to_op_base::do_perform, complete_func),
-        socket_(socket),
-        buffers_(buffers),
-        destination_(endpoint),
-        flags_(flags)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      send_to_op_base* o(static_cast<send_to_op_base*>(base));
-
-      buffer_sequence_adapter<asio::const_buffer,
-          ConstBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Send the data.
-        asio::error_code ec;
-        int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(),
-            o->flags_, o->destination_.data(), o->destination_.size(), ec);
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    socket_type socket_;
-    ConstBufferSequence buffers_;
-    endpoint_type destination_;
-    socket_base::message_flags flags_;
-  };
-
-  template <typename ConstBufferSequence, typename Handler>
-  class send_to_op : public send_to_op_base<ConstBufferSequence>
-  {
-  public:
-    send_to_op(socket_type socket, const ConstBufferSequence& buffers,
-        const endpoint_type& endpoint, socket_base::message_flags flags,
-        Handler handler)
-      : send_to_op_base<ConstBufferSequence>(socket,
-          buffers, endpoint, flags, &send_to_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      send_to_op* o(static_cast<send_to_op*>(base));
-      typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous send. The data being sent must be valid for the
   // lifetime of the asynchronous operation.
   template <typename ConstBufferSequence, typename Handler>
@@ -863,235 +196,31 @@ public:
       Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef send_to_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
-        buffers, destination, flags, handler);
+    typedef reactive_socket_sendto_op<ConstBufferSequence,
+        endpoint_type, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
 
-    start_op(impl, reactor::write_op, ptr.get(), true, false);
-    ptr.release();
+    start_op(impl, reactor::write_op, p.p, true, false);
+    p.v = p.p = 0;
   }
 
   // Start an asynchronous wait until data can be sent without blocking.
   template <typename Handler>
   void async_send_to(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, const endpoint_type&, Handler handler)
+      const endpoint_type&, socket_base::message_flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    start_op(impl, reactor::write_op, ptr.get(), false, false);
-    ptr.release();
-  }
-
-  // Receive some data from the peer. Returns the number of bytes received.
-  template <typename MutableBufferSequence>
-  size_t receive(implementation_type& impl,
-      const MutableBufferSequence& buffers,
-      socket_base::message_flags flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    buffer_sequence_adapter<asio::mutable_buffer,
-        MutableBufferSequence> bufs(buffers);
-
-    // A request to receive 0 bytes on a stream socket is a no-op.
-    if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Receive some data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      int bytes_recvd = socket_ops::recv(impl.socket_,
-          bufs.buffers(), bufs.count(), flags, ec);
-
-      // Check if operation succeeded.
-      if (bytes_recvd > 0)
-        return bytes_recvd;
-
-      // Check for EOF.
-      if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
-      {
-        ec = asio::error::eof;
-        return 0;
-      }
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for socket to become ready.
-      if (socket_ops::poll_read(impl.socket_, ec) < 0)
-        return 0;
-    }
-  }
-
-  // Wait until data can be received without blocking.
-  size_t receive(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    // Wait for socket to become ready.
-    socket_ops::poll_read(impl.socket_, ec);
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
 
-    return 0;
-  }
-
-  template <typename MutableBufferSequence>
-  class receive_op_base : public reactor_op
-  {
-  public:
-    receive_op_base(socket_type socket, int protocol_type,
-        const MutableBufferSequence& buffers,
-        socket_base::message_flags flags, func_type complete_func)
-      : reactor_op(&receive_op_base::do_perform, complete_func),
-        socket_(socket),
-        protocol_type_(protocol_type),
-        buffers_(buffers),
-        flags_(flags)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      receive_op_base* o(static_cast<receive_op_base*>(base));
-
-      buffer_sequence_adapter<asio::mutable_buffer,
-          MutableBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Receive some data.
-        asio::error_code ec;
-        int bytes = socket_ops::recv(o->socket_,
-            bufs.buffers(), bufs.count(), o->flags_, ec);
-        if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
-          ec = asio::error::eof;
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    socket_type socket_;
-    int protocol_type_;
-    MutableBufferSequence buffers_;
-    socket_base::message_flags flags_;
-  };
-
-  template <typename MutableBufferSequence, typename Handler>
-  class receive_op : public receive_op_base<MutableBufferSequence>
-  {
-  public:
-    receive_op(socket_type socket, int protocol_type,
-        const MutableBufferSequence& buffers,
-        socket_base::message_flags flags, Handler handler)
-      : receive_op_base<MutableBufferSequence>(socket,
-          protocol_type, buffers, flags, &receive_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      receive_op* o(static_cast<receive_op*>(base));
-      typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
-  // Start an asynchronous receive. The buffer for the data being received
-  // must be valid for the lifetime of the asynchronous operation.
-  template <typename MutableBufferSequence, typename Handler>
-  void async_receive(implementation_type& impl,
-      const MutableBufferSequence& buffers,
-      socket_base::message_flags flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef receive_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    int protocol_type = impl.protocol_.type();
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
-        protocol_type, buffers, flags, handler);
-
-    start_op(impl,
-        (flags & socket_base::message_out_of_band)
-          ? reactor::except_op : reactor::read_op,
-        ptr.get(), (flags & socket_base::message_out_of_band) == 0,
-        (impl.protocol_.type() == SOCK_STREAM
-          && buffer_sequence_adapter<asio::mutable_buffer,
-            MutableBufferSequence>::all_empty(buffers)));
-    ptr.release();
-  }
-
-  // Wait until data can be received without blocking.
-  template <typename Handler>
-  void async_receive(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    start_op(impl,
-        (flags & socket_base::message_out_of_band)
-          ? reactor::except_op : reactor::read_op,
-        ptr.get(), false, false);
-    ptr.release();
+    start_op(impl, reactor::write_op, p.p, false, false);
+    p.v = p.p = 0;
   }
 
   // Receive a datagram with the endpoint of the sender. Returns the number of
@@ -1102,47 +231,18 @@ public:
       endpoint_type& sender_endpoint, socket_base::message_flags flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::mutable_buffer,
         MutableBufferSequence> bufs(buffers);
 
-    // Receive some data.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      std::size_t addr_len = sender_endpoint.capacity();
-      int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(),
-          bufs.count(), flags, sender_endpoint.data(), &addr_len, ec);
+    std::size_t addr_len = sender_endpoint.capacity();
+    std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+        impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+        flags, sender_endpoint.data(), &addr_len, ec);
 
-      // Check if operation succeeded.
-      if (bytes_recvd > 0)
-      {
-        sender_endpoint.resize(addr_len);
-        return bytes_recvd;
-      }
+    if (!ec)
+      sender_endpoint.resize(addr_len);
 
-      // Check for EOF.
-      if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
-      {
-        ec = asio::error::eof;
-        return 0;
-      }
-
-      // Operation failed.
-      if ((impl.flags_ & implementation_type::user_set_non_blocking)
-          || (ec != asio::error::would_block
-            && ec != asio::error::try_again))
-        return 0;
-
-      // Wait for socket to become ready.
-      if (socket_ops::poll_read(impl.socket_, ec) < 0)
-        return 0;
-    }
+    return bytes_recvd;
   }
 
   // Wait until data can be received without blocking.
@@ -1150,12 +250,6 @@ public:
       endpoint_type& sender_endpoint, socket_base::message_flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for socket to become ready.
     socket_ops::poll_read(impl.socket_, ec);
 
@@ -1165,105 +259,6 @@ public:
     return 0;
   }
 
-  template <typename MutableBufferSequence>
-  class receive_from_op_base : public reactor_op
-  {
-  public:
-    receive_from_op_base(socket_type socket, int protocol_type,
-        const MutableBufferSequence& buffers, endpoint_type& endpoint,
-        socket_base::message_flags flags, func_type complete_func)
-      : reactor_op(&receive_from_op_base::do_perform, complete_func),
-        socket_(socket),
-        protocol_type_(protocol_type),
-        buffers_(buffers),
-        sender_endpoint_(endpoint),
-        flags_(flags)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      receive_from_op_base* o(static_cast<receive_from_op_base*>(base));
-
-      buffer_sequence_adapter<asio::mutable_buffer,
-          MutableBufferSequence> bufs(o->buffers_);
-
-      for (;;)
-      {
-        // Receive some data.
-        asio::error_code ec;
-        std::size_t addr_len = o->sender_endpoint_.capacity();
-        int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(),
-            bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec);
-        if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
-          ec = asio::error::eof;
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-
-        o->sender_endpoint_.resize(addr_len);
-        o->ec_ = ec;
-        o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
-        return true;
-      }
-    }
-
-  private:
-    socket_type socket_;
-    int protocol_type_;
-    MutableBufferSequence buffers_;
-    endpoint_type& sender_endpoint_;
-    socket_base::message_flags flags_;
-  };
-
-  template <typename MutableBufferSequence, typename Handler>
-  class receive_from_op : public receive_from_op_base<MutableBufferSequence>
-  {
-  public:
-    receive_from_op(socket_type socket, int protocol_type,
-        const MutableBufferSequence& buffers, endpoint_type& endpoint,
-        socket_base::message_flags flags, Handler handler)
-      : receive_from_op_base<MutableBufferSequence>(socket, protocol_type,
-          buffers, endpoint, flags, &receive_from_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      receive_from_op* o(static_cast<receive_from_op*>(base));
-      typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, o->ec_, o->bytes_transferred_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous receive. The buffer for the data being received and
   // the sender_endpoint object must both be valid for the lifetime of the
   // asynchronous operation.
@@ -1273,18 +268,20 @@ public:
       socket_base::message_flags flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef receive_from_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
+    typedef reactive_socket_recvfrom_op<MutableBufferSequence,
+        endpoint_type, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
     int protocol_type = impl.protocol_.type();
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
-        protocol_type, buffers, sender_endpoint, flags, handler);
+    p.p = new (p.v) op(impl.socket_, protocol_type,
+        buffers, sender_endpoint, flags, handler);
 
     start_op(impl,
         (flags & socket_base::message_out_of_band)
           ? reactor::except_op : reactor::read_op,
-        ptr.get(), true, false);
-    ptr.release();
+        p.p, true, false);
+    p.v = p.p = 0;
   }
 
   // Wait until data can be received without blocking.
@@ -1294,10 +291,11 @@ public:
       socket_base::message_flags flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
 
     // Reset endpoint since it can be given no sensible value at this time.
     sender_endpoint = endpoint_type();
@@ -1305,8 +303,8 @@ public:
     start_op(impl,
         (flags & socket_base::message_out_of_band)
           ? reactor::except_op : reactor::read_op,
-        ptr.get(), false, false);
-    ptr.release();
+        p.p, false, false);
+    p.v = p.p = 0;
   }
 
   // Accept a new connection.
@@ -1314,12 +312,6 @@ public:
   asio::error_code accept(implementation_type& impl,
       Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
     // We cannot accept a socket that is already open.
     if (peer.is_open())
     {
@@ -1327,181 +319,22 @@ public:
       return ec;
     }
 
-    // Accept a socket.
-    for (;;)
-    {
-      // Try to complete the operation without blocking.
-      socket_holder new_socket;
-      std::size_t addr_len = 0;
-      if (peer_endpoint)
-      {
-        addr_len = peer_endpoint->capacity();
-        new_socket.reset(socket_ops::accept(impl.socket_,
-              peer_endpoint->data(), &addr_len, ec));
-      }
-      else
-      {
-        new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
-      }
-
-      // Check if operation succeeded.
-      if (new_socket.get() >= 0)
-      {
-        if (peer_endpoint)
-          peer_endpoint->resize(addr_len);
-        peer.assign(impl.protocol_, new_socket.get(), ec);
-        if (!ec)
-          new_socket.release();
-        return ec;
-      }
+    std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+    socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+          impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+          peer_endpoint ? &addr_len : 0, ec));
 
-      // Operation failed.
-      if (ec == asio::error::would_block
-          || ec == asio::error::try_again)
-      {
-        if (impl.flags_ & implementation_type::user_set_non_blocking)
-          return ec;
-        // Fall through to retry operation.
-      }
-      else if (ec == asio::error::connection_aborted)
-      {
-        if (impl.flags_ & implementation_type::enable_connection_aborted)
-          return ec;
-        // Fall through to retry operation.
-      }
-#if defined(EPROTO)
-      else if (ec.value() == EPROTO)
-      {
-        if (impl.flags_ & implementation_type::enable_connection_aborted)
-          return ec;
-        // Fall through to retry operation.
-      }
-#endif // defined(EPROTO)
-      else
-        return ec;
-
-      // Wait for socket to become ready.
-      if (socket_ops::poll_read(impl.socket_, ec) < 0)
-        return ec;
-    }
-  }
-
-  template <typename Socket>
-  class accept_op_base : public reactor_op
-  {
-  public:
-    accept_op_base(socket_type socket, Socket& peer,
-        const protocol_type& protocol, endpoint_type* peer_endpoint,
-        bool enable_connection_aborted, func_type complete_func)
-      : reactor_op(&accept_op_base::do_perform, complete_func),
-        socket_(socket),
-        peer_(peer),
-        protocol_(protocol),
-        peer_endpoint_(peer_endpoint),
-        enable_connection_aborted_(enable_connection_aborted)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
+    // On success, assign new connection to peer socket object.
+    if (new_socket.get() != invalid_socket)
     {
-      accept_op_base* o(static_cast<accept_op_base*>(base));
-
-      for (;;)
-      {
-        // Accept the waiting connection.
-        asio::error_code ec;
-        socket_holder new_socket;
-        std::size_t addr_len = 0;
-        std::size_t* addr_len_p = 0;
-        socket_addr_type* addr = 0;
-        if (o->peer_endpoint_)
-        {
-          addr_len = o->peer_endpoint_->capacity();
-          addr_len_p = &addr_len;
-          addr = o->peer_endpoint_->data();
-        }
-        new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec));
-
-        // Retry operation if interrupted by signal.
-        if (ec == asio::error::interrupted)
-          continue;
-
-        // Check if we need to run the operation again.
-        if (ec == asio::error::would_block
-            || ec == asio::error::try_again)
-          return false;
-        if (ec == asio::error::connection_aborted
-            && !o->enable_connection_aborted_)
-          return false;
-#if defined(EPROTO)
-        if (ec.value() == EPROTO && !o->enable_connection_aborted_)
-          return false;
-#endif // defined(EPROTO)
-
-        // Transfer ownership of the new socket to the peer object.
-        if (!ec)
-        {
-          if (o->peer_endpoint_)
-            o->peer_endpoint_->resize(addr_len);
-          o->peer_.assign(o->protocol_, new_socket.get(), ec);
-          if (!ec)
-            new_socket.release();
-        }
-
-        o->ec_ = ec;
-        return true;
-      }
-    }
-
-  private:
-    socket_type socket_;
-    Socket& peer_;
-    protocol_type protocol_;
-    endpoint_type* peer_endpoint_;
-    bool enable_connection_aborted_;
-  };
-
-  template <typename Socket, typename Handler>
-  class accept_op : public accept_op_base<Socket>
-  {
-  public:
-    accept_op(socket_type socket, Socket& peer, const protocol_type& protocol,
-        endpoint_type* peer_endpoint, bool enable_connection_aborted,
-        Handler handler)
-      : accept_op_base<Socket>(socket, peer, protocol, peer_endpoint,
-          enable_connection_aborted, &accept_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      accept_op* o(static_cast<accept_op*>(base));
-      typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder1<Handler, asio::error_code>
-          handler(o->handler_, o->ec_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
+      if (peer_endpoint)
+        peer_endpoint->resize(addr_len);
+      if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+        new_socket.release();
     }
 
-  private:
-    Handler handler_;
-  };
+    return ec;
+  }
 
   // Start an asynchronous accept. The peer and peer_endpoint objects
   // must be valid until the accept's handler is invoked.
@@ -1510,230 +343,41 @@ public:
       endpoint_type* peer_endpoint, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef accept_op<Socket, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    bool enable_connection_aborted =
-      (impl.flags_ & implementation_type::enable_connection_aborted) != 0;
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, peer,
-        impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+    typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, impl.state_, peer,
+        impl.protocol_, peer_endpoint, handler);
 
-    start_accept_op(impl, ptr.get(), peer.is_open());
-    ptr.release();
+    start_accept_op(impl, p.p, peer.is_open());
+    p.v = p.p = 0;
   }
 
   // Connect the socket to the specified endpoint.
   asio::error_code connect(implementation_type& impl,
       const endpoint_type& peer_endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    // Perform the connect operation.
-    socket_ops::connect(impl.socket_,
+    socket_ops::sync_connect(impl.socket_,
         peer_endpoint.data(), peer_endpoint.size(), ec);
-    if (ec != asio::error::in_progress
-        && ec != asio::error::would_block)
-    {
-      // The connect operation finished immediately.
-      return ec;
-    }
-
-    // Wait for socket to become ready.
-    if (socket_ops::poll_connect(impl.socket_, ec) < 0)
-      return ec;
-
-    // Get the error code from the connect operation.
-    int connect_error = 0;
-    size_t connect_error_len = sizeof(connect_error);
-    if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR,
-          &connect_error, &connect_error_len, ec) == socket_error_retval)
-      return ec;
-
-    // Return the result of the connect operation.
-    ec = asio::error_code(connect_error,
-        asio::error::get_system_category());
     return ec;
   }
 
-  class connect_op_base : public reactor_op
-  {
-  public:
-    connect_op_base(socket_type socket, func_type complete_func)
-      : reactor_op(&connect_op_base::do_perform, complete_func),
-        socket_(socket)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      connect_op_base* o(static_cast<connect_op_base*>(base));
-
-      // Get the error code from the connect operation.
-      int connect_error = 0;
-      size_t connect_error_len = sizeof(connect_error);
-      if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
-            &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
-        return true;
-
-      // The connection failed so the handler will be posted with an error code.
-      if (connect_error)
-      {
-        o->ec_ = asio::error_code(connect_error,
-            asio::error::get_system_category());
-      }
-
-      return true;
-    }
-
-  private:
-    socket_type socket_;
-  };
-
-  template <typename Handler>
-  class connect_op : public connect_op_base
-  {
-  public:
-    connect_op(socket_type socket, Handler handler)
-      : connect_op_base(socket, &connect_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      connect_op* o(static_cast<connect_op*>(base));
-      typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder1<Handler, asio::error_code>
-          handler(o->handler_, o->ec_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous connect.
   template <typename Handler>
   void async_connect(implementation_type& impl,
       const endpoint_type& peer_endpoint, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef connect_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler);
-
-    start_connect_op(impl, ptr.get(), peer_endpoint);
-    ptr.release();
-  }
-
-private:
-  // Start the asynchronous read or write operation.
-  void start_op(implementation_type& impl, int op_type,
-      reactor_op* op, bool non_blocking, bool noop)
-  {
-    if (!noop)
-    {
-      if (is_open(impl))
-      {
-        if (!non_blocking || is_non_blocking(impl)
-            || set_non_blocking(impl, op->ec_))
-        {
-          reactor_.start_op(op_type, impl.socket_,
-              impl.reactor_data_, op, non_blocking);
-          return;
-        }
-      }
-      else
-        op->ec_ = asio::error::bad_descriptor;
-    }
+    typedef reactive_socket_connect_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, handler);
 
-    io_service_impl_.post_immediate_completion(op);
+    start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size());
+    p.v = p.p = 0;
   }
-
-  // Start the asynchronous accept operation.
-  void start_accept_op(implementation_type& impl,
-      reactor_op* op, bool peer_is_open)
-  {
-    if (!peer_is_open)
-      start_op(impl, reactor::read_op, op, true, false);
-    else
-    {
-      op->ec_ = asio::error::already_open;
-      io_service_impl_.post_immediate_completion(op);
-    }
-  }
-
-  // Start the asynchronous connect operation.
-  void start_connect_op(implementation_type& impl,
-      reactor_op* op, const endpoint_type& peer_endpoint)
-  {
-    if (is_open(impl))
-    {
-      if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
-      {
-        if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
-              peer_endpoint.size(), op->ec_) != 0)
-        {
-          if (op->ec_ == asio::error::in_progress
-              || op->ec_ == asio::error::would_block)
-          {
-            op->ec_ = asio::error_code();
-            reactor_.start_op(reactor::connect_op,
-                impl.socket_, impl.reactor_data_, op, false);
-            return;
-          }
-        }
-      }
-    }
-    else
-      op->ec_ = asio::error::bad_descriptor;
-
-    io_service_impl_.post_immediate_completion(op);
-  }
-
-  // Determine whether the socket has been set non-blocking.
-  bool is_non_blocking(implementation_type& impl) const
-  {
-    return (impl.flags_ & implementation_type::non_blocking);
-  }
-
-  // Set the internal non-blocking flag.
-  bool set_non_blocking(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    ioctl_arg_type non_blocking = 1;
-    if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
-      return false;
-    impl.flags_ |= implementation_type::internal_non_blocking;
-    return true;
-  }
-
-  // The io_service implementation used to post completions.
-  io_service_impl& io_service_impl_;
-
-  // The selector that performs event demultiplexing for the service.
-  reactor& reactor_;
 };
 
 } // namespace detail
@@ -1741,4 +385,6 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_service_base.hpp b/ext/asio/asio/detail/reactive_socket_service_base.hpp
new file mode 100644
index 0000000..b26d73e
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_service_base.hpp
@@ -0,0 +1,298 @@
+//
+// detail/reactive_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_recv_op.hpp"
+#include "asio/detail/reactive_socket_send_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base
+{
+public:
+  // The native type of a socket.
+  typedef socket_type native_type;
+
+  // The implementation type of the socket.
+  struct base_implementation_type
+  {
+    // The native socket representation.
+    socket_type socket_;
+
+    // The current state of the socket.
+    socket_ops::state_type state_;
+
+    // Per-descriptor data used by the reactor.
+    reactor::per_descriptor_data reactor_data_;
+  };
+
+  // Constructor.
+  ASIO_DECL reactive_socket_service_base(
+      asio::io_service& io_service);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown_service();
+
+  // Construct a new socket implementation.
+  ASIO_DECL void construct(base_implementation_type& impl);
+
+  // Destroy a socket implementation.
+  ASIO_DECL void destroy(base_implementation_type& impl);
+
+  // Determine whether the socket is open.
+  bool is_open(const base_implementation_type& impl) const
+  {
+    return impl.socket_ != invalid_socket;
+  }
+
+  // Destroy a socket implementation.
+  ASIO_DECL asio::error_code close(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Get the native socket representation.
+  native_type native(base_implementation_type& impl)
+  {
+    return impl.socket_;
+  }
+
+  // Cancel all operations associated with the socket.
+  ASIO_DECL asio::error_code cancel(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::sockatmark(impl.socket_, ec);
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::available(impl.socket_, ec);
+  }
+
+  // Place the socket into the state where it will listen for new connections.
+  asio::error_code listen(base_implementation_type& impl,
+      int backlog, asio::error_code& ec)
+  {
+    socket_ops::listen(impl.socket_, backlog, ec);
+    return ec;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(base_implementation_type& impl,
+      IO_Control_Command& command, asio::error_code& ec)
+  {
+    socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+    return ec;
+  }
+
+  /// Disable sends or receives on the socket.
+  asio::error_code shutdown(base_implementation_type& impl,
+      socket_base::shutdown_type what, asio::error_code& ec)
+  {
+    socket_ops::shutdown(impl.socket_, what, ec);
+    return ec;
+  }
+
+  // Send the given data to the peer.
+  template <typename ConstBufferSequence>
+  size_t send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_send(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler>
+  void async_send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
+
+    start_op(impl, reactor::write_op, p.p, true,
+        ((impl.state_ & socket_ops::stream_oriented)
+          && buffer_sequence_adapter<asio::const_buffer,
+            ConstBufferSequence>::all_empty(buffers)));
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler>
+  void async_send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
+
+    start_op(impl, reactor::write_op, p.p, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_recv(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence, typename Handler>
+  void async_receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, (flags & socket_base::message_out_of_band) == 0,
+        ((impl.state_ & socket_ops::stream_oriented)
+          && buffer_sequence_adapter<asio::mutable_buffer,
+            MutableBufferSequence>::all_empty(buffers)));
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler>
+  void async_receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, false, false);
+    p.v = p.p = 0;
+  }
+
+protected:
+  // Open a new socket implementation.
+  ASIO_DECL asio::error_code do_open(
+      base_implementation_type& impl, int af,
+      int type, int protocol, asio::error_code& ec);
+
+  // Assign a native socket to a socket implementation.
+  ASIO_DECL asio::error_code do_assign(
+      base_implementation_type& impl, int type,
+      const native_type& native_socket, asio::error_code& ec);
+
+  // Start the asynchronous read or write operation.
+  ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+      reactor_op* op, bool non_blocking, bool noop);
+
+  // Start the asynchronous accept operation.
+  ASIO_DECL void start_accept_op(base_implementation_type& impl,
+      reactor_op* op, bool peer_is_open);
+
+  // Start the asynchronous connect operation.
+  ASIO_DECL void start_connect_op(base_implementation_type& impl,
+      reactor_op* op, const socket_addr_type* addr, size_t addrlen);
+
+  // The selector that performs event demultiplexing for the service.
+  reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/reactor.hpp b/ext/asio/asio/detail/reactor.hpp
index 98ac360..0e938c9 100644
--- a/ext/asio/asio/detail/reactor.hpp
+++ b/ext/asio/asio/detail/reactor.hpp
@@ -1,8 +1,8 @@
 //
-// reactor.hpp
-// ~~~~~~~~~~~
+// detail/reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 #include "asio/detail/reactor_fwd.hpp"
 
 #if defined(ASIO_HAS_EPOLL)
@@ -29,6 +27,4 @@
 # include "asio/detail/select_reactor.hpp"
 #endif
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/reactor_fwd.hpp b/ext/asio/asio/detail/reactor_fwd.hpp
index 9c33be5..d45d768 100644
--- a/ext/asio/asio/detail/reactor_fwd.hpp
+++ b/ext/asio/asio/detail/reactor_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~
+// detail/reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,25 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
-#include "asio/detail/epoll_reactor_fwd.hpp"
-#include "asio/detail/kqueue_reactor_fwd.hpp"
-#include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/select_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor_fwd.hpp"
+#else
+# include "asio/detail/select_reactor_fwd.hpp"
+#endif
 
 namespace asio {
 namespace detail {
 
 #if defined(ASIO_HAS_IOCP)
-typedef select_reactor<true> reactor;
+typedef select_reactor reactor;
 #elif defined(ASIO_HAS_EPOLL)
 typedef epoll_reactor reactor;
 #elif defined(ASIO_HAS_KQUEUE)
@@ -35,12 +41,10 @@ typedef kqueue_reactor reactor;
 #elif defined(ASIO_HAS_DEV_POLL)
 typedef dev_poll_reactor reactor;
 #else
-typedef select_reactor<false> reactor;
+typedef select_reactor reactor;
 #endif
 
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/reactor_op.hpp b/ext/asio/asio/detail/reactor_op.hpp
index cd557fa..3009cf9 100644
--- a/ext/asio/asio/detail/reactor_op.hpp
+++ b/ext/asio/asio/detail/reactor_op.hpp
@@ -1,8 +1,8 @@
 //
-// reactor_op.hpp
-// ~~~~~~~~~~~~
+// detail/reactor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/operation.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/reactor_op_queue.hpp b/ext/asio/asio/detail/reactor_op_queue.hpp
index 233c0ae..6eed398 100644
--- a/ext/asio/asio/detail/reactor_op_queue.hpp
+++ b/ext/asio/asio/detail/reactor_op_queue.hpp
@@ -1,8 +1,8 @@
 //
-// reactor_op_queue.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
 #include "asio/detail/hash_map.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/reactor_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
diff --git a/ext/asio/asio/detail/regex_fwd.hpp b/ext/asio/asio/detail/regex_fwd.hpp
new file mode 100644
index 0000000..9da295b
--- /dev/null
+++ b/ext/asio/asio/detail/regex_fwd.hpp
@@ -0,0 +1,31 @@
+//
+// detail/regex_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REGEX_FWD_HPP
+#define ASIO_DETAIL_REGEX_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/regex_fwd.hpp>
+#include <boost/regex/v4/match_flags.hpp>
+
+namespace boost {
+
+template <class BidiIterator>
+struct sub_match;
+
+template <class BidiIterator, class Allocator>
+class match_results;
+
+} // namespace boost
+
+#endif // ASIO_DETAIL_REGEX_FWD_HPP
diff --git a/ext/asio/asio/detail/resolve_endpoint_op.hpp b/ext/asio/asio/detail/resolve_endpoint_op.hpp
new file mode 100644
index 0000000..0931fd0
--- /dev/null
+++ b/ext/asio/asio/detail/resolve_endpoint_op.hpp
@@ -0,0 +1,116 @@
+//
+// detail/resolve_endpoint_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_endpoint_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);
+
+  typedef typename Protocol::endpoint endpoint_type;
+  typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+
+  resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
+      const endpoint_type& endpoint, io_service_impl& ios, Handler handler)
+    : operation(&resolve_endpoint_op::do_complete),
+      cancel_token_(cancel_token),
+      endpoint_(endpoint),
+      io_service_impl_(ios),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the operation object.
+    resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    if (owner && owner != &o->io_service_impl_)
+    {
+      // The operation is being run on the worker io_service. Time to perform
+      // the resolver operation.
+    
+      // Perform the blocking endpoint resolution operation.
+      char host_name[NI_MAXHOST];
+      char service_name[NI_MAXSERV];
+      socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(),
+          o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+          o->endpoint_.protocol().type(), o->ec_);
+      o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name);
+
+      // Pass operation back to main io_service for completion.
+      o->io_service_impl_.post_deferred_completion(o);
+      p.v = p.p = 0;
+    }
+    else
+    {
+      // The operation has been returned to the main io_service. The completion
+      // handler is ready to be delivered.
+
+      // Make a copy of the handler so that the memory can be deallocated
+      // before the upcall is made. Even if we're not about to make an upcall,
+      // a sub-object of the handler may be the true owner of the memory
+      // associated with the handler. Consequently, a local copy of the handler
+      // is required to ensure that any owning sub-object remains valid until
+      // after we have deallocated the memory here.
+      detail::binder2<Handler, asio::error_code, iterator_type>
+        handler(o->handler_, o->ec_, o->iter_);
+      p.h = boost::addressof(handler.handler_);
+      p.reset();
+
+      if (owner)
+      {
+        asio::detail::fenced_block b;
+        asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+      }
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  endpoint_type endpoint_;
+  io_service_impl& io_service_impl_;
+  Handler handler_;
+  asio::error_code ec_;
+  iterator_type iter_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
diff --git a/ext/asio/asio/detail/resolve_op.hpp b/ext/asio/asio/detail/resolve_op.hpp
new file mode 100644
index 0000000..a04fbc3
--- /dev/null
+++ b/ext/asio/asio/detail/resolve_op.hpp
@@ -0,0 +1,126 @@
+//
+// detail/resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVE_OP_HPP
+#define ASIO_DETAIL_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(resolve_op);
+
+  typedef asio::ip::basic_resolver_query<Protocol> query_type;
+  typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+
+  resolve_op(socket_ops::weak_cancel_token_type cancel_token,
+      const query_type& query, io_service_impl& ios, Handler handler)
+    : operation(&resolve_op::do_complete),
+      cancel_token_(cancel_token),
+      query_(query),
+      io_service_impl_(ios),
+      handler_(handler),
+      addrinfo_(0)
+  {
+  }
+
+  ~resolve_op()
+  {
+    if (addrinfo_)
+      socket_ops::freeaddrinfo(addrinfo_);
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the operation object.
+    resolve_op* o(static_cast<resolve_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    if (owner && owner != &o->io_service_impl_)
+    {
+      // The operation is being run on the worker io_service. Time to perform
+      // the resolver operation.
+    
+      // Perform the blocking host resolution operation.
+      socket_ops::background_getaddrinfo(o->cancel_token_,
+          o->query_.host_name().c_str(), o->query_.service_name().c_str(),
+          o->query_.hints(), &o->addrinfo_, o->ec_);
+
+      // Pass operation back to main io_service for completion.
+      o->io_service_impl_.post_deferred_completion(o);
+      p.v = p.p = 0;
+    }
+    else
+    {
+      // The operation has been returned to the main io_service. The completion
+      // handler is ready to be delivered.
+
+      // Make a copy of the handler so that the memory can be deallocated
+      // before the upcall is made. Even if we're not about to make an upcall,
+      // a sub-object of the handler may be the true owner of the memory
+      // associated with the handler. Consequently, a local copy of the handler
+      // is required to ensure that any owning sub-object remains valid until
+      // after we have deallocated the memory here.
+      detail::binder2<Handler, asio::error_code, iterator_type>
+        handler(o->handler_, o->ec_, iterator_type());
+      p.h = boost::addressof(handler.handler_);
+      if (o->addrinfo_)
+      {
+        handler.arg2_ = iterator_type::create(o->addrinfo_,
+            o->query_.host_name(), o->query_.service_name());
+      }
+      p.reset();
+
+      if (owner)
+      {
+        asio::detail::fenced_block b;
+        asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+      }
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  query_type query_;
+  io_service_impl& io_service_impl_;
+  Handler handler_;
+  asio::error_code ec_;
+  asio::detail::addrinfo_type* addrinfo_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_OP_HPP
diff --git a/ext/asio/asio/detail/resolver_service.hpp b/ext/asio/asio/detail/resolver_service.hpp
index 562dc10..c2c3b0c 100644
--- a/ext/asio/asio/detail/resolver_service.hpp
+++ b/ext/asio/asio/detail/resolver_service.hpp
@@ -1,8 +1,8 @@
 //
-// resolver_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,68 +15,25 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/bind_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/mutex.hpp"
-#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/operation.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/thread.hpp"
+#include "asio/detail/resolve_endpoint_op.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 
 template <typename Protocol>
-class resolver_service
-  : public asio::detail::service_base<resolver_service<Protocol> >
+class resolver_service : public resolver_service_base
 {
-private:
-  // Helper class to perform exception-safe cleanup of addrinfo objects.
-  class auto_addrinfo
-    : private asio::detail::noncopyable
-  {
-  public:
-    explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
-      : ai_(ai)
-    {
-    }
-
-    ~auto_addrinfo()
-    {
-      if (ai_)
-        socket_ops::freeaddrinfo(ai_);
-    }
-
-    operator asio::detail::addrinfo_type*()
-    {
-      return ai_;
-    }
-
-  private:
-    asio::detail::addrinfo_type* ai_;
-  };
-
 public:
-  // The implementation type of the resolver. The shared pointer is used as a
-  // cancellation token to indicate to the background thread that the operation
-  // has been cancelled.
-  typedef boost::shared_ptr<void> implementation_type;
-  struct noop_deleter { void operator()(void*) {} };
+  // The implementation type of the resolver. A cancellation token is used to
+  // indicate to the background thread that the operation has been cancelled.
+  typedef socket_ops::shared_cancel_token_type implementation_type;
 
   // The endpoint type.
   typedef typename Protocol::endpoint endpoint_type;
@@ -89,55 +46,8 @@ public:
 
   // Constructor.
   resolver_service(asio::io_service& io_service)
-    : asio::detail::service_base<
-        resolver_service<Protocol> >(io_service),
-      mutex_(),
-      io_service_impl_(asio::use_service<io_service_impl>(io_service)),
-      work_io_service_(new asio::io_service),
-      work_io_service_impl_(asio::use_service<
-          io_service_impl>(*work_io_service_)),
-      work_(new asio::io_service::work(*work_io_service_)),
-      work_thread_(0)
-  {
-  }
-
-  // Destructor.
-  ~resolver_service()
+    : resolver_service_base(io_service)
   {
-    shutdown_service();
-  }
-
-  // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    work_.reset();
-    if (work_io_service_)
-    {
-      work_io_service_->stop();
-      if (work_thread_)
-      {
-        work_thread_->join();
-        work_thread_.reset();
-      }
-      work_io_service_.reset();
-    }
-  }
-
-  // Construct a new resolver implementation.
-  void construct(implementation_type& impl)
-  {
-    impl.reset(static_cast<void*>(0), noop_deleter());
-  }
-
-  // Destroy a resolver implementation.
-  void destroy(implementation_type&)
-  {
-  }
-
-  // Cancel pending asynchronous operations.
-  void cancel(implementation_type& impl)
-  {
-    impl.reset(static_cast<void*>(0), noop_deleter());
   }
 
   // Resolve a query to a list of entries.
@@ -145,293 +55,60 @@ public:
       asio::error_code& ec)
   {
     asio::detail::addrinfo_type* address_info = 0;
-    std::string host_name = query.host_name();
-    std::string service_name = query.service_name();
-    asio::detail::addrinfo_type hints = query.hints();
 
-    socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
-        service_name.c_str(), &hints, &address_info, ec);
+    socket_ops::getaddrinfo(query.host_name().c_str(),
+        query.service_name().c_str(), query.hints(), &address_info, ec);
     auto_addrinfo auto_address_info(address_info);
 
-    if (ec)
-      return iterator_type();
-
-    return iterator_type::create(address_info, host_name, service_name);
+    return ec ? iterator_type() : iterator_type::create(
+        address_info, query.host_name(), query.service_name());
   }
 
-  template <typename Handler>
-  class resolve_op
-    : public operation
-  {
-  public:
-    resolve_op(implementation_type impl, const query_type& query,
-        io_service_impl& io_service_impl, Handler handler)
-      : operation(&resolve_op::do_complete),
-        impl_(impl),
-        query_(query),
-        io_service_impl_(io_service_impl),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the operation object.
-      resolve_op* o(static_cast<resolve_op*>(base));
-      typedef handler_alloc_traits<Handler, resolve_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      if (owner)
-      {
-        if (owner != &o->io_service_impl_)
-        {
-          // The operation is being run on the worker io_service. Time to
-          // perform the resolver operation.
-        
-          if (o->impl_.expired())
-          {
-            // THe operation has been cancelled.
-            o->ec_ = asio::error::operation_aborted;
-          }
-          else
-          {
-            // Perform the blocking host resolution operation.
-            asio::detail::addrinfo_type* address_info = 0;
-            std::string host_name = o->query_.host_name();
-            std::string service_name = o->query_.service_name();
-            asio::detail::addrinfo_type hints = o->query_.hints();
-            socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
-                service_name.c_str(), &hints, &address_info, o->ec_);
-            auto_addrinfo auto_address_info(address_info);
-            o->iter_ = iterator_type::create(
-              address_info, host_name, service_name);
-          }
-
-          o->io_service_impl_.post_deferred_completion(o);
-          ptr.release();
-        }
-        else
-        {
-          // The operation has been returned to the main io_serice. The
-          // completion handler is ready to be delivered.
-
-          // Make a copy of the handler so that the memory can be deallocated
-          // before the upcall is made. Even if we're not about to make an
-          // upcall, a sub-object of the handler may be the true owner of the
-          // memory associated with the handler. Consequently, a local copy of
-          // the handler is required to ensure that any owning sub-object
-          // remains valid until after we have deallocated the memory here.
-          detail::binder2<Handler, asio::error_code, iterator_type>
-            handler(o->handler_, o->ec_, o->iter_);
-          ptr.reset();
-          asio::detail::fenced_block b;
-          asio_handler_invoke_helpers::invoke(handler, handler);
-        }
-      }
-    }
-
-  private:
-    boost::weak_ptr<void> impl_;
-    query_type query_;
-    io_service_impl& io_service_impl_;
-    Handler handler_;
-    asio::error_code ec_;
-    iterator_type iter_;
-  };
-
   // Asynchronously resolve a query to a list of entries.
   template <typename Handler>
   void async_resolve(implementation_type& impl, const query_type& query,
       Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef resolve_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl, query, io_service_impl_, handler);
-
-    if (work_io_service_)
-    {
-      start_work_thread();
-      io_service_impl_.work_started();
-      work_io_service_impl_.post_immediate_completion(ptr.get());
-      ptr.release();
-    }
+    typedef resolve_op<Protocol, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl, query, io_service_impl_, handler);
+
+    start_resolve_op(p.p);
+    p.v = p.p = 0;
   }
 
   // Resolve an endpoint to a list of entries.
   iterator_type resolve(implementation_type&,
       const endpoint_type& endpoint, asio::error_code& ec)
   {
-    // First try resolving with the service name. If that fails try resolving
-    // but allow the service to be returned as a number.
     char host_name[NI_MAXHOST];
     char service_name[NI_MAXSERV];
-    int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
-    socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
-        host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
-    if (ec)
-    {
-      flags |= NI_NUMERICSERV;
-      socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
-          host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
-    }
+    socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(),
+        host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+        endpoint.protocol().type(), ec);
 
-    if (ec)
-      return iterator_type();
-
-    return iterator_type::create(endpoint, host_name, service_name);
+    return ec ? iterator_type() : iterator_type::create(
+        endpoint, host_name, service_name);
   }
 
-  template <typename Handler>
-  class resolve_endpoint_op
-    : public operation
-  {
-  public:
-    resolve_endpoint_op(implementation_type impl, const endpoint_type& ep,
-        io_service_impl& io_service_impl, Handler handler)
-      : operation(&resolve_endpoint_op::do_complete),
-        impl_(impl),
-        ep_(ep),
-        io_service_impl_(io_service_impl),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the operation object.
-      resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
-      typedef handler_alloc_traits<Handler, resolve_endpoint_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      if (owner)
-      {
-        if (owner != &o->io_service_impl_)
-        {
-          // The operation is being run on the worker io_service. Time to
-          // perform the resolver operation.
-        
-          if (o->impl_.expired())
-          {
-            // THe operation has been cancelled.
-            o->ec_ = asio::error::operation_aborted;
-          }
-          else
-          {
-            // Perform the blocking endoint resolution operation.
-            char host_name[NI_MAXHOST];
-            char service_name[NI_MAXSERV];
-            int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
-            socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
-                host_name, NI_MAXHOST, service_name,
-                NI_MAXSERV, flags, o->ec_);
-            if (o->ec_)
-            {
-              flags |= NI_NUMERICSERV;
-              socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
-                  host_name, NI_MAXHOST, service_name,
-                  NI_MAXSERV, flags, o->ec_);
-            }
-            o->iter_ = iterator_type::create(o->ep_, host_name, service_name);
-          }
-
-          o->io_service_impl_.post_deferred_completion(o);
-          ptr.release();
-        }
-        else
-        {
-          // The operation has been returned to the main io_serice. The
-          // completion handler is ready to be delivered.
-
-          // Make a copy of the handler so that the memory can be deallocated
-          // before the upcall is made. Even if we're not about to make an
-          // upcall, a sub-object of the handler may be the true owner of the
-          // memory associated with the handler. Consequently, a local copy of
-          // the handler is required to ensure that any owning sub-object
-          // remains valid until after we have deallocated the memory here.
-          detail::binder2<Handler, asio::error_code, iterator_type>
-            handler(o->handler_, o->ec_, o->iter_);
-          ptr.reset();
-          asio::detail::fenced_block b;
-          asio_handler_invoke_helpers::invoke(handler, handler);
-        }
-      }
-    }
-
-  private:
-    boost::weak_ptr<void> impl_;
-    endpoint_type ep_;
-    io_service_impl& io_service_impl_;
-    Handler handler_;
-    asio::error_code ec_;
-    iterator_type iter_;
-  };
-
   // Asynchronously resolve an endpoint to a list of entries.
   template <typename Handler>
   void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
       Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef resolve_endpoint_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl, endpoint, io_service_impl_, handler);
-
-    if (work_io_service_)
-    {
-      start_work_thread();
-      io_service_impl_.work_started();
-      work_io_service_impl_.post_immediate_completion(ptr.get());
-      ptr.release();
-    }
-  }
-
-private:
-  // Helper class to run the work io_service in a thread.
-  class work_io_service_runner
-  {
-  public:
-    work_io_service_runner(asio::io_service& io_service)
-      : io_service_(io_service) {}
-    void operator()() { io_service_.run(); }
-  private:
-    asio::io_service& io_service_;
-  };
-
-  // Start the work thread if it's not already running.
-  void start_work_thread()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (!work_thread_)
-    {
-      work_thread_.reset(new asio::detail::thread(
-            work_io_service_runner(*work_io_service_)));
-    }
+    typedef resolve_endpoint_op<Protocol, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler);
+
+    start_resolve_op(p.p);
+    p.v = p.p = 0;
   }
-
-  // Mutex to protect access to internal data.
-  asio::detail::mutex mutex_;
-
-  // The io_service implementation used to post completions.
-  io_service_impl& io_service_impl_;
-
-  // Private io_service used for performing asynchronous host resolution.
-  boost::scoped_ptr<asio::io_service> work_io_service_;
-
-  // The work io_service implementation used to post completions.
-  io_service_impl& work_io_service_impl_;
-
-  // Work for the private io_service to perform.
-  boost::scoped_ptr<asio::io_service::work> work_;
-
-  // Thread used for running the work io_service's run loop.
-  boost::scoped_ptr<asio::detail::thread> work_thread_;
 };
 
 } // namespace detail
diff --git a/ext/asio/asio/detail/resolver_service_base.hpp b/ext/asio/asio/detail/resolver_service_base.hpp
new file mode 100644
index 0000000..d6f20bd
--- /dev/null
+++ b/ext/asio/asio/detail/resolver_service_base.hpp
@@ -0,0 +1,123 @@
+//
+// detail/resolver_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/scoped_ptr.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base
+{
+public:
+  // The implementation type of the resolver. A cancellation token is used to
+  // indicate to the background thread that the operation has been cancelled.
+  typedef socket_ops::shared_cancel_token_type implementation_type;
+
+  // Constructor.
+  ASIO_DECL resolver_service_base(asio::io_service& io_service);
+
+  // Destructor.
+  ASIO_DECL ~resolver_service_base();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown_service();
+
+  // Construct a new resolver implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Destroy a resolver implementation.
+  ASIO_DECL void destroy(implementation_type&);
+
+  // Cancel pending asynchronous operations.
+  ASIO_DECL void cancel(implementation_type& impl);
+
+protected:
+  // Helper function to start an asynchronous resolve operation.
+  ASIO_DECL void start_resolve_op(operation* op);
+
+  // Helper class to perform exception-safe cleanup of addrinfo objects.
+  class auto_addrinfo
+    : private asio::detail::noncopyable
+  {
+  public:
+    explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
+      : ai_(ai)
+    {
+    }
+
+    ~auto_addrinfo()
+    {
+      if (ai_)
+        socket_ops::freeaddrinfo(ai_);
+    }
+
+    operator asio::detail::addrinfo_type*()
+    {
+      return ai_;
+    }
+
+  private:
+    asio::detail::addrinfo_type* ai_;
+  };
+
+  // Helper class to run the work io_service in a thread.
+  class work_io_service_runner;
+
+  // Start the work thread if it's not already running.
+  ASIO_DECL void start_work_thread();
+
+  // The io_service implementation used to post completions.
+  io_service_impl& io_service_impl_;
+
+private:
+  // Mutex to protect access to internal data.
+  asio::detail::mutex mutex_;
+
+  // Private io_service used for performing asynchronous host resolution.
+  boost::scoped_ptr<asio::io_service> work_io_service_;
+
+  // The work io_service implementation used to post completions.
+  io_service_impl& work_io_service_impl_;
+
+  // Work for the private io_service to perform.
+  boost::scoped_ptr<asio::io_service::work> work_;
+
+  // Thread used for running the work io_service's run loop.
+  boost::scoped_ptr<asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/resolver_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/scoped_lock.hpp b/ext/asio/asio/detail/scoped_lock.hpp
index e6f6ba5..69b5725 100644
--- a/ext/asio/asio/detail/scoped_lock.hpp
+++ b/ext/asio/asio/detail/scoped_lock.hpp
@@ -1,8 +1,8 @@
 //
-// scoped_lock.hpp
-// ~~~~~~~~~~~~~~~
+// detail/scoped_lock.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 #include "asio/detail/noncopyable.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/select_interrupter.hpp b/ext/asio/asio/detail/select_interrupter.hpp
index ff5505b..e975ddc 100644
--- a/ext/asio/asio/detail/select_interrupter.hpp
+++ b/ext/asio/asio/detail/select_interrupter.hpp
@@ -1,8 +1,8 @@
 //
-// select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
 # include "asio/detail/socket_select_interrupter.hpp"
-#else
+#elif defined(ASIO_HAS_EVENTFD)
 # include "asio/detail/eventfd_select_interrupter.hpp"
+#else
 # include "asio/detail/pipe_select_interrupter.hpp"
 #endif
 
 namespace asio {
 namespace detail {
 
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
 typedef socket_select_interrupter select_interrupter;
 #elif defined(ASIO_HAS_EVENTFD)
 typedef eventfd_select_interrupter select_interrupter;
@@ -42,6 +39,4 @@ typedef pipe_select_interrupter select_interrupter;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/select_reactor.hpp b/ext/asio/asio/detail/select_reactor.hpp
index 798611b..161305f 100644
--- a/ext/asio/asio/detail/select_reactor.hpp
+++ b/ext/asio/asio/detail/select_reactor.hpp
@@ -1,8 +1,8 @@
 //
-// select_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,41 +15,38 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE))
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/io_service.hpp"
-#include "asio/detail/bind_handler.hpp"
-#include "asio/detail/fd_set_adapter.hpp"
 #include "asio/detail/mutex.hpp"
-#include "asio/detail/noncopyable.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/reactor_op_queue.hpp"
 #include "asio/detail/select_interrupter.hpp"
 #include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/signal_blocker.hpp"
-#include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
-#include "asio/detail/thread.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 #include "asio/detail/timer_queue_fwd.hpp"
 #include "asio/detail/timer_queue_set.hpp"
+#include "asio/io_service.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 
-template <bool Own_Thread>
 class select_reactor
-  : public asio::detail::service_base<select_reactor<Own_Thread> >
+  : public asio::detail::service_base<select_reactor>
 {
 public:
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -66,280 +63,91 @@ public:
   };
 
   // Constructor.
-  select_reactor(asio::io_service& io_service)
-    : asio::detail::service_base<
-        select_reactor<Own_Thread> >(io_service),
-      io_service_(use_service<io_service_impl>(io_service)),
-      mutex_(),
-      interrupter_(),
-      stop_thread_(false),
-      thread_(0),
-      shutdown_(false)
-  {
-    if (Own_Thread)
-    {
-      asio::detail::signal_blocker sb;
-      thread_ = new asio::detail::thread(
-          bind_handler(&select_reactor::call_run_thread, this));
-    }
-  }
+  ASIO_DECL select_reactor(asio::io_service& io_service);
 
   // Destructor.
-  ~select_reactor()
-  {
-    shutdown_service();
-  }
+  ASIO_DECL ~select_reactor();
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    shutdown_ = true;
-    stop_thread_ = true;
-    lock.unlock();
-
-    if (Own_Thread)
-    {
-      if (thread_)
-      {
-        interrupter_.interrupt();
-        thread_->join();
-        delete thread_;
-        thread_ = 0;
-      }
-    }
-
-    op_queue<operation> ops;
-
-    for (int i = 0; i < max_ops; ++i)
-      op_queue_[i].get_all_operations(ops);
-
-    timer_queues_.get_all_timers(ops);
-  }
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task, but only if the reactor is not in its own thread.
-  void init_task()
-  {
-    io_service_.init_task();
-  }
+  ASIO_DECL void init_task();
 
   // Register a socket with the reactor. Returns 0 on success, system error
   // code on failure.
-  int register_descriptor(socket_type, per_descriptor_data&)
+  ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op)
   {
-    return 0;
+    io_service_.post_immediate_completion(op);
   }
 
   // Start a new operation. The reactor operation will be performed when the
   // given descriptor is flagged as ready, or an error has occurred.
-  void start_op(int op_type, socket_type descriptor,
-      per_descriptor_data&, reactor_op* op, bool)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (!shutdown_)
-    {
-      bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
-      io_service_.work_started();
-      if (first)
-        interrupter_.interrupt();
-    }
-  }
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data&, reactor_op* op, bool);
 
   // Cancel all operations associated with the given descriptor. The
   // handlers associated with the descriptor will be invoked with the
   // operation_aborted error.
-  void cancel_ops(socket_type descriptor, per_descriptor_data&)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
-  }
+  ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
 
   // Cancel any operations that are running against the descriptor and remove
   // its registration from the reactor.
-  void close_descriptor(socket_type descriptor, per_descriptor_data&)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
-  }
+  ASIO_DECL void close_descriptor(socket_type descriptor,
+      per_descriptor_data&);
 
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
-  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    timer_queues_.insert(&timer_queue);
-  }
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Remove a timer queue from the reactor.
   template <typename Time_Traits>
-  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    timer_queues_.erase(&timer_queue);
-  }
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
 
   // Schedule a new operation in the given timer queue to expire at the
   // specified absolute time.
   template <typename Time_Traits>
-  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
-      const typename Time_Traits::time_type& time, timer_op* op, void* token)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (!shutdown_)
-    {
-      bool earliest = timer_queue.enqueue_timer(time, op, token);
-      io_service_.work_started();
-      if (earliest)
-        interrupter_.interrupt();
-    }
-  }
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
 
   // Cancel the timer operations associated with the given token. Returns the
   // number of operations that have been posted or dispatched.
   template <typename Time_Traits>
-  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    op_queue<operation> ops;
-    std::size_t n = timer_queue.cancel_timer(token, ops);
-    lock.unlock();
-    io_service_.post_deferred_completions(ops);
-    return n;
-  }
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer);
 
   // Run select once until interrupted or events are ready to be dispatched.
-  void run(bool block, op_queue<operation>& ops)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    // Check if the thread is supposed to stop.
-    if (Own_Thread)
-      if (stop_thread_)
-        return;
-
-    // Set up the descriptor sets.
-    fd_set_adapter fds[max_select_ops];
-    fds[read_op].set(interrupter_.read_descriptor());
-    socket_type max_fd = 0;
-    bool have_work_to_do = !timer_queues_.all_empty();
-    for (int i = 0; i < max_select_ops; ++i)
-    {
-      have_work_to_do = have_work_to_do || !op_queue_[i].empty();
-      op_queue_[i].get_descriptors(fds[i], ops);
-      if (fds[i].max_descriptor() > max_fd)
-        max_fd = fds[i].max_descriptor();
-    }
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-    // Connection operations on Windows use both except and write fd_sets.
-    have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
-    op_queue_[connect_op].get_descriptors(fds[write_op], ops);
-    if (fds[write_op].max_descriptor() > max_fd)
-      max_fd = fds[write_op].max_descriptor();
-    op_queue_[connect_op].get_descriptors(fds[except_op], ops);
-    if (fds[except_op].max_descriptor() > max_fd)
-      max_fd = fds[except_op].max_descriptor();
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
-    // We can return immediately if there's no work to do and the reactor is
-    // not supposed to block.
-    if (!block && !have_work_to_do)
-      return;
-
-    // Determine how long to block while waiting for events.
-    timeval tv_buf = { 0, 0 };
-    timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
-
-    lock.unlock();
-
-    // Block on the select call until descriptors become ready.
-    asio::error_code ec;
-    int retval = socket_ops::select(static_cast<int>(max_fd + 1),
-        fds[read_op], fds[write_op], fds[except_op], tv, ec);
-
-    // Reset the interrupter.
-    if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
-      interrupter_.reset();
-
-    lock.lock();
-
-    // Dispatch all ready operations.
-    if (retval > 0)
-    {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-      // Connection operations on Windows use both except and write fd_sets.
-      op_queue_[connect_op].perform_operations_for_descriptors(
-          fds[except_op], ops);
-      op_queue_[connect_op].perform_operations_for_descriptors(
-          fds[write_op], ops);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
-      // Exception operations must be processed first to ensure that any
-      // out-of-band data is read before normal data.
-      for (int i = max_select_ops - 1; i >= 0; --i)
-        op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
-    }
-    timer_queues_.get_ready_timers(ops);
-  }
+  ASIO_DECL void run(bool block, op_queue<operation>& ops);
 
   // Interrupt the select loop.
-  void interrupt()
-  {
-    interrupter_.interrupt();
-  }
+  ASIO_DECL void interrupt();
 
 private:
+#if defined(ASIO_HAS_IOCP)
   // Run the select loop in the thread.
-  void run_thread()
-  {
-    if (Own_Thread)
-    {
-      asio::detail::mutex::scoped_lock lock(mutex_);
-      while (!stop_thread_)
-      {
-        lock.unlock();
-        op_queue<operation> ops;
-        run(true, ops);
-        io_service_.post_deferred_completions(ops);
-        lock.lock();
-      }
-    }
-  }
+  ASIO_DECL void run_thread();
 
   // Entry point for the select loop thread.
-  static void call_run_thread(select_reactor* reactor)
-  {
-    if (Own_Thread)
-    {
-      reactor->run_thread();
-    }
-  }
+  ASIO_DECL static void call_run_thread(select_reactor* reactor);
+#endif // defined(ASIO_HAS_IOCP)
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
 
   // Get the timeout value for the select call.
-  timeval* get_timeout(timeval& tv)
-  {
-    // By default we will wait no longer than 5 minutes. This will ensure that
-    // any changes to the system clock are detected after no longer than this.
-    long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
-    tv.tv_sec = usec / 1000000;
-    tv.tv_usec = usec % 1000000;
-    return &tv;
-  }
+  ASIO_DECL timeval* get_timeout(timeval& tv);
 
   // Cancel all operations associated with the given descriptor. This function
   // does not acquire the select_reactor's mutex.
-  void cancel_ops_unlocked(socket_type descriptor,
-      const asio::error_code& ec)
-  {
-    bool need_interrupt = false;
-    op_queue<operation> ops;
-    for (int i = 0; i < max_ops; ++i)
-      need_interrupt = op_queue_[i].cancel_operations(
-          descriptor, ops, ec) || need_interrupt;
-    io_service_.post_deferred_completions(ops);
-    if (need_interrupt)
-      interrupter_.interrupt();
-  }
+  ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+      const asio::error_code& ec);
 
   // The io_service implementation used to post completions.
   io_service_impl& io_service_;
@@ -356,11 +164,13 @@ private:
   // The timer queues.
   timer_queue_set timer_queues_;
 
+#if defined(ASIO_HAS_IOCP)
   // Does the reactor loop thread need to stop.
   bool stop_thread_;
 
   // The thread that is running the reactor loop.
   asio::detail::thread* thread_;
+#endif // defined(ASIO_HAS_IOCP)
 
   // Whether the service has been shut down.
   bool shutdown_;
@@ -371,4 +181,14 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/select_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/select_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE))
+
 #endif // ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/ext/asio/asio/detail/select_reactor_fwd.hpp b/ext/asio/asio/detail/select_reactor_fwd.hpp
index 0b72e7e..04e5ecd 100644
--- a/ext/asio/asio/detail/select_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/select_reactor_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// select_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/select_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 namespace detail {
 
-template <bool Own_Thread>
 class select_reactor;
 
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/service_registry.hpp b/ext/asio/asio/detail/service_registry.hpp
index f80b4b6..34b946d 100644
--- a/ext/asio/asio/detail/service_registry.hpp
+++ b/ext/asio/asio/detail/service_registry.hpp
@@ -1,8 +1,8 @@
 //
-// service_registry.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <typeinfo>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/io_service.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/service_id.hpp"
+#include "asio/io_service.hpp"
 
 #if defined(BOOST_NO_TYPEID)
 # if !defined(ASIO_NO_TYPEID)
@@ -32,6 +27,8 @@
 # endif // !defined(ASIO_NO_TYPEID)
 #endif // defined(BOOST_NO_TYPEID)
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -55,98 +52,43 @@ class service_registry
 {
 public:
   // Constructor.
-  service_registry(asio::io_service& o)
-    : owner_(o),
-      first_service_(0)
-  {
-  }
+  ASIO_DECL service_registry(asio::io_service& o);
 
   // Destructor.
-  ~service_registry()
-  {
-    // Shutdown all services. This must be done in a separate loop before the
-    // services are destroyed since the destructors of user-defined handler
-    // objects may try to access other service objects.
-    asio::io_service::service* service = first_service_;
-    while (service)
-    {
-      service->shutdown_service();
-      service = service->next_;
-    }
-
-    // Destroy all services.
-    while (first_service_)
-    {
-      asio::io_service::service* next_service = first_service_->next_;
-      destroy(first_service_);
-      first_service_ = next_service;
-    }
-  }
+  ASIO_DECL ~service_registry();
 
   // Get the service object corresponding to the specified service type. Will
   // create a new service object automatically if no such object already
   // exists. Ownership of the service object is not transferred to the caller.
   template <typename Service>
-  Service& use_service()
-  {
-    asio::io_service::service::key key;
-    init_key(key, Service::id);
-    factory_type factory = &service_registry::create<Service>;
-    return *static_cast<Service*>(do_use_service(key, factory));
-  }
+  Service& use_service();
 
-  // Add a service object. Returns false on error, in which case ownership of
-  // the object is retained by the caller.
+  // Add a service object. Throws on error, in which case ownership of the
+  // object is retained by the caller.
   template <typename Service>
-  bool add_service(Service* new_service)
-  {
-    asio::io_service::service::key key;
-    init_key(key, Service::id);
-    return do_add_service(key, new_service);
-  }
+  void add_service(Service* new_service);
 
   // Check whether a service object of the specified type already exists.
   template <typename Service>
-  bool has_service() const
-  {
-    asio::io_service::service::key key;
-    init_key(key, Service::id);
-    return do_has_service(key);
-  }
+  bool has_service() const;
 
 private:
   // Initialise a service's key based on its id.
-  void init_key(asio::io_service::service::key& key,
-      const asio::io_service::id& id)
-  {
-    key.type_info_ = 0;
-    key.id_ = &id;
-  }
+  ASIO_DECL static void init_key(
+      asio::io_service::service::key& key,
+      const asio::io_service::id& id);
 
 #if !defined(ASIO_NO_TYPEID)
   // Initialise a service's key based on its id.
   template <typename Service>
-  void init_key(asio::io_service::service::key& key,
-      const asio::detail::service_id<Service>& /*id*/)
-  {
-    key.type_info_ = &typeid(typeid_wrapper<Service>);
-    key.id_ = 0;
-  }
+  static void init_key(asio::io_service::service::key& key,
+      const asio::detail::service_id<Service>& /*id*/);
 #endif // !defined(ASIO_NO_TYPEID)
 
   // Check if a service matches the given id.
-  static bool keys_match(
+  ASIO_DECL static bool keys_match(
       const asio::io_service::service::key& key1,
-      const asio::io_service::service::key& key2)
-  {
-    if (key1.id_ && key2.id_)
-      if (key1.id_ == key2.id_)
-        return true;
-    if (key1.type_info_ && key2.type_info_)
-      if (*key1.type_info_ == *key2.type_info_)
-        return true;
-    return false;
-  }
+      const asio::io_service::service::key& key2);
 
   // The type of a factory function used for creating a service instance.
   typedef asio::io_service::service*
@@ -155,18 +97,15 @@ private:
   // Factory function for creating a service instance.
   template <typename Service>
   static asio::io_service::service* create(
-      asio::io_service& owner)
-  {
-    return new Service(owner);
-  }
+      asio::io_service& owner);
 
   // Destroy a service instance.
-  static void destroy(asio::io_service::service* service)
-  {
-    delete service;
-  }
+  ASIO_DECL static void destroy(
+      asio::io_service::service* service);
 
   // Helper class to manage service pointers.
+  struct auto_service_ptr;
+  friend struct auto_service_ptr;
   struct auto_service_ptr
   {
     asio::io_service::service* ptr_;
@@ -176,86 +115,19 @@ private:
   // Get the service object corresponding to the specified service key. Will
   // create a new service object automatically if no such object already
   // exists. Ownership of the service object is not transferred to the caller.
-  asio::io_service::service* do_use_service(
+  ASIO_DECL asio::io_service::service* do_use_service(
       const asio::io_service::service::key& key,
-      factory_type factory)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    // First see if there is an existing service object with the given key.
-    asio::io_service::service* service = first_service_;
-    while (service)
-    {
-      if (keys_match(service->key_, key))
-        return service;
-      service = service->next_;
-    }
-
-    // Create a new service object. The service registry's mutex is not locked
-    // at this time to allow for nested calls into this function from the new
-    // service's constructor.
-    lock.unlock();
-    auto_service_ptr new_service = { factory(owner_) };
-    new_service.ptr_->key_ = key;
-    lock.lock();
-
-    // Check that nobody else created another service object of the same type
-    // while the lock was released.
-    service = first_service_;
-    while (service)
-    {
-      if (keys_match(service->key_, key))
-        return service;
-      service = service->next_;
-    }
-
-    // Service was successfully initialised, pass ownership to registry.
-    new_service.ptr_->next_ = first_service_;
-    first_service_ = new_service.ptr_;
-    new_service.ptr_ = 0;
-    return first_service_;
-  }
+      factory_type factory);
 
   // Add a service object. Returns false on error, in which case ownership of
   // the object is retained by the caller.
-  bool do_add_service(
+  ASIO_DECL void do_add_service(
       const asio::io_service::service::key& key,
-      asio::io_service::service* new_service)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    // Check if there is an existing service object with the given key.
-    asio::io_service::service* service = first_service_;
-    while (service)
-    {
-      if (keys_match(service->key_, key))
-        return false;
-      service = service->next_;
-    }
-
-    // Take ownership of the service object.
-    new_service->key_ = key;
-    new_service->next_ = first_service_;
-    first_service_ = new_service;
-
-    return true;
-  }
+      asio::io_service::service* new_service);
 
   // Check whether a service object with the specified key already exists.
-  bool do_has_service(const asio::io_service::service::key& key) const
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    asio::io_service::service* service = first_service_;
-    while (service)
-    {
-      if (keys_match(service->key_, key))
-        return true;
-      service = service->next_;
-    }
-
-    return false;
-  }
+  ASIO_DECL bool do_has_service(
+      const asio::io_service::service::key& key) const;
 
   // Mutex to protect access to internal data.
   mutable asio::detail::mutex mutex_;
@@ -272,4 +144,9 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/service_registry.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/service_registry.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/ext/asio/asio/detail/service_registry_fwd.hpp b/ext/asio/asio/detail/service_registry_fwd.hpp
index 423bb4b..4108c1a 100644
--- a/ext/asio/asio/detail/service_registry_fwd.hpp
+++ b/ext/asio/asio/detail/service_registry_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// service_registry_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/service_registry_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 namespace detail {
 
@@ -25,6 +23,4 @@ class service_registry;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
diff --git a/ext/asio/asio/detail/shared_ptr.hpp b/ext/asio/asio/detail/shared_ptr.hpp
new file mode 100644
index 0000000..cd496f5
--- /dev/null
+++ b/ext/asio/asio/detail/shared_ptr.hpp
@@ -0,0 +1,38 @@
+//
+// detail/shared_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SHARED_PTR_HPP
+#define ASIO_DETAIL_SHARED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+# include <memory>
+#else
+# include <boost/shared_ptr.hpp>
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+using std::shared_ptr;
+#else
+using boost::shared_ptr;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_SHARED_PTR_HPP
diff --git a/ext/asio/asio/detail/signal_blocker.hpp b/ext/asio/asio/detail/signal_blocker.hpp
index 52f70c8..89f45ca 100644
--- a/ext/asio/asio/detail/signal_blocker.hpp
+++ b/ext/asio/asio/detail/signal_blocker.hpp
@@ -1,8 +1,8 @@
 //
-// signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \
+  || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
 # include "asio/detail/null_signal_blocker.hpp"
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# include "asio/detail/win_signal_blocker.hpp"
 #elif defined(BOOST_HAS_PTHREADS)
 # include "asio/detail/posix_signal_blocker.hpp"
 #else
@@ -34,10 +29,9 @@
 namespace asio {
 namespace detail {
 
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \
+  || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
 typedef null_signal_blocker signal_blocker;
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-typedef win_signal_blocker signal_blocker;
 #elif defined(BOOST_HAS_PTHREADS)
 typedef posix_signal_blocker signal_blocker;
 #endif
@@ -45,6 +39,4 @@ typedef posix_signal_blocker signal_blocker;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/signal_init.hpp b/ext/asio/asio/detail/signal_init.hpp
index 12f17d3..80925f6 100644
--- a/ext/asio/asio/detail/signal_init.hpp
+++ b/ext/asio/asio/detail/signal_init.hpp
@@ -1,8 +1,8 @@
 //
-// signal_init.hpp
-// ~~~~~~~~~~~~~~~
+// detail/signal_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
-#include "asio/detail/push_options.hpp"
 #include <csignal>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -44,8 +40,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/ext/asio/asio/detail/socket_holder.hpp b/ext/asio/asio/detail/socket_holder.hpp
index 82a3884..cb40175 100644
--- a/ext/asio/asio/detail/socket_holder.hpp
+++ b/ext/asio/asio/detail/socket_holder.hpp
@@ -1,8 +1,8 @@
 //
-// socket_holder.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_ops.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -46,7 +47,8 @@ public:
     if (socket_ != invalid_socket)
     {
       asio::error_code ec;
-      socket_ops::close(socket_, ec);
+      socket_ops::state_type state = 0;
+      socket_ops::close(socket_, state, true, ec);
     }
   }
 
@@ -62,7 +64,8 @@ public:
     if (socket_ != invalid_socket)
     {
       asio::error_code ec;
-      socket_ops::close(socket_, ec);
+      socket_ops::state_type state = 0;
+      socket_ops::close(socket_, state, true, ec);
       socket_ = invalid_socket;
     }
   }
diff --git a/ext/asio/asio/detail/socket_ops.hpp b/ext/asio/asio/detail/socket_ops.hpp
index 1a863a9..8ad464c 100644
--- a/ext/asio/asio/detail/socket_ops.hpp
+++ b/ext/asio/asio/detail/socket_ops.hpp
@@ -1,8 +1,8 @@
 //
-// socket_ops.hpp
-// ~~~~~~~~~~~~~~
+// detail/socket_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,193 +15,102 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/assert.hpp>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cerrno>
-#include <boost/detail/workaround.hpp>
-#include <new>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/shared_ptr.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/detail/weak_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 namespace socket_ops {
 
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-struct msghdr { int msg_namelen; };
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+// Socket state bits.
+enum
+{
+  // The user wants a non-blocking socket.
+  user_set_non_blocking = 1,
 
-#if defined(__hpux)
-// HP-UX doesn't declare these functions extern "C", so they are declared again
-// here to avoid linker errors about undefined symbols.
-extern "C" char* if_indextoname(unsigned int, char*);
-extern "C" unsigned int if_nametoindex(const char*);
-#endif // defined(__hpux)
+  // The socket has been set non-blocking.
+  internal_non_blocking = 2,
 
-inline void clear_error(asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  WSASetLastError(0);
-#else
-  errno = 0;
-#endif
-  ec = asio::error_code();
-}
-
-template <typename ReturnType>
-inline ReturnType error_wrapper(ReturnType return_value,
-    asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  ec = asio::error_code(WSAGetLastError(),
-      asio::error::get_system_category());
-#else
-  ec = asio::error_code(errno,
-      asio::error::get_system_category());
-#endif
-  return return_value;
-}
-
-template <typename SockLenType>
-inline socket_type call_accept(SockLenType msghdr::*,
-    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
-  SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
-  socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
-  if (addrlen)
-    *addrlen = (std::size_t)tmp_addrlen;
-  return result;
-}
-
-inline socket_type accept(socket_type s, socket_addr_type* addr,
-    std::size_t* addrlen, asio::error_code& ec)
-{
-  clear_error(ec);
-
-  socket_type new_s = error_wrapper(call_accept(
-        &msghdr::msg_namelen, s, addr, addrlen), ec);
-  if (new_s == invalid_socket)
-    return new_s;
-
-#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
-  int optval = 1;
-  int result = error_wrapper(::setsockopt(new_s,
-        SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
-  if (result != 0)
-  {
-    ::close(new_s);
-    return invalid_socket;
-  }
-#endif
-
-  clear_error(ec);
-  return new_s;
-}
-
-template <typename SockLenType>
-inline int call_bind(SockLenType msghdr::*,
-    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
-{
-  return ::bind(s, addr, (SockLenType)addrlen);
-}
+  // Helper "state" used to determine whether the socket is non-blocking.
+  non_blocking = user_set_non_blocking | internal_non_blocking,
 
-inline int bind(socket_type s, const socket_addr_type* addr,
-    std::size_t addrlen, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(call_bind(
-        &msghdr::msg_namelen, s, addr, addrlen), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-inline int close(socket_type s, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  int result = error_wrapper(::closesocket(s), ec);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  int result = error_wrapper(::close(s), ec);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
+  // User wants connection_aborted errors, which are disabled by default.
+  enable_connection_aborted = 4,
 
-inline int shutdown(socket_type s, int what, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::shutdown(s, what), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-template <typename SockLenType>
-inline int call_connect(SockLenType msghdr::*,
-    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
-{
-  return ::connect(s, addr, (SockLenType)addrlen);
-}
+  // The user set the linger option. Needs to be checked when closing.
+  user_set_linger = 8,
 
-inline int connect(socket_type s, const socket_addr_type* addr,
-    std::size_t addrlen, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(call_connect(
-        &msghdr::msg_namelen, s, addr, addrlen), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-inline int socketpair(int af, int type, int protocol,
-    socket_type sv[2], asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  (void)(af);
-  (void)(type);
-  (void)(protocol);
-  (void)(sv);
-  ec = asio::error::operation_not_supported;
-  return -1;
-#else
-  clear_error(ec);
-  int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-#endif
-}
-
-inline int listen(socket_type s, int backlog, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::listen(s, backlog), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-inline void init_buf_iov_base(void*& base, void* addr)
-{
-  base = addr;
-}
+  // The socket is stream-oriented.
+  stream_oriented = 16,
 
-template <typename T>
-inline void init_buf_iov_base(T& base, void* addr)
-{
-  base = static_cast<T>(addr);
-}
+  // The socket is datagram-oriented.
+  datagram_oriented = 32
+};
+
+typedef unsigned char state_type;
+
+struct noop_deleter { void operator()(void*) {} };
+typedef shared_ptr<void> shared_cancel_token_type;
+typedef weak_ptr<void> weak_cancel_token_type;
+
+ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL socket_type sync_accept(socket_type s,
+    state_type state, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_accept(socket_type s,
+    void* output_buffer, DWORD address_length,
+    socket_addr_type* addr, std::size_t* addrlen,
+    socket_type new_socket, asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_accept(socket_type s,
+    state_type state, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, socket_type& new_socket);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int bind(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL int close(socket_type s, state_type& state,
+    bool destruction, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(socket_type s,
+    state_type& state, asio::error_code& ec);
+
+ASIO_DECL int shutdown(socket_type s,
+    int what, asio::error_code& ec);
+
+ASIO_DECL int connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_connect(
+    socket_type s, asio::error_code& ec);
+
+ASIO_DECL int socketpair(int af, int type, int protocol,
+    socket_type sv[2], asio::error_code& ec);
+
+ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec);
+
+ASIO_DECL size_t available(socket_type s, asio::error_code& ec);
+
+ASIO_DECL int listen(socket_type s,
+    int backlog, asio::error_code& ec);
 
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 typedef WSABUF buf;
@@ -209,1699 +118,163 @@ typedef WSABUF buf;
 typedef iovec buf;
 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
-inline void init_buf(buf& b, void* data, size_t size)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  b.buf = static_cast<char*>(data);
-  b.len = static_cast<u_long>(size);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  init_buf_iov_base(b.iov_base, data);
-  b.iov_len = size;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL void init_buf(buf& b, void* data, size_t size);
 
-inline void init_buf(buf& b, const void* data, size_t size)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  b.buf = static_cast<char*>(const_cast<void*>(data));
-  b.len = static_cast<u_long>(size);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  init_buf_iov_base(b.iov_base, const_cast<void*>(data));
-  b.iov_len = size;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL void init_buf(buf& b, const void* data, size_t size);
 
-inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
-{
-  name = addr;
-}
+ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags,
+    asio::error_code& ec);
 
-inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
-{
-  name = const_cast<socket_addr_type*>(addr);
-}
+ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec);
 
-template <typename T>
-inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
-{
-  name = reinterpret_cast<T>(addr);
-}
+#if defined(ASIO_HAS_IOCP)
 
-template <typename T>
-inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
-{
-  name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
-}
+ASIO_DECL void complete_iocp_recv(state_type state,
+    const weak_cancel_token_type& cancel_token, bool all_empty,
+    asio::error_code& ec, size_t bytes_transferred);
 
-inline int recv(socket_type s, buf* bufs, size_t count, int flags,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  // Receive some data.
-  DWORD recv_buf_count = static_cast<DWORD>(count);
-  DWORD bytes_transferred = 0;
-  DWORD recv_flags = flags;
-  int result = error_wrapper(::WSARecv(s, bufs,
-        recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
-  if (result != 0)
-    return -1;
-  clear_error(ec);
-  return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  msghdr msg = msghdr();
-  msg.msg_iov = bufs;
-  msg.msg_iovlen = count;
-  int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recv(socket_type s,
+    buf* bufs, size_t count, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
 
-inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
     socket_addr_type* addr, std::size_t* addrlen,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  // Receive some data.
-  DWORD recv_buf_count = static_cast<DWORD>(count);
-  DWORD bytes_transferred = 0;
-  DWORD recv_flags = flags;
-  int tmp_addrlen = (int)*addrlen;
-  int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
-        &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
-  *addrlen = (std::size_t)tmp_addrlen;
-  if (result != 0)
-    return -1;
-  clear_error(ec);
-  return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  msghdr msg = msghdr();
-  init_msghdr_msg_name(msg.msg_name, addr);
-  msg.msg_namelen = *addrlen;
-  msg.msg_iov = bufs;
-  msg.msg_iovlen = count;
-  int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
-  *addrlen = msg.msg_namelen;
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+    asio::error_code& ec);
 
-inline int send(socket_type s, const buf* bufs, size_t count, int flags,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  // Send the data.
-  DWORD send_buf_count = static_cast<DWORD>(count);
-  DWORD bytes_transferred = 0;
-  DWORD send_flags = flags;
-  int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
-        send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
-  if (result != 0)
-    return -1;
-  clear_error(ec);
-  return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  msghdr msg = msghdr();
-  msg.msg_iov = const_cast<buf*>(bufs);
-  msg.msg_iovlen = count;
-#if defined(__linux__)
-  flags |= MSG_NOSIGNAL;
-#endif // defined(__linux__)
-  int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+    buf* bufs, size_t count, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvfrom(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+    buf* bufs, size_t count, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int send(socket_type s, const buf* bufs,
+    size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_send(socket_type s, state_type state,
+    const buf* bufs, size_t count, int flags,
+    bool all_empty, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_send(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
 
-inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+ASIO_DECL bool non_blocking_send(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count,
+    int flags, const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec);
+
+ASIO_DECL size_t sync_sendto(socket_type s, state_type state,
+    const buf* bufs, size_t count, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_sendto(socket_type s,
+    const buf* bufs, size_t count, int flags,
     const socket_addr_type* addr, std::size_t addrlen,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  // Send the data.
-  DWORD send_buf_count = static_cast<DWORD>(count);
-  DWORD bytes_transferred = 0;
-  int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
-        send_buf_count, &bytes_transferred, flags, addr,
-        static_cast<int>(addrlen), 0, 0), ec);
-  if (result != 0)
-    return -1;
-  clear_error(ec);
-  return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  msghdr msg = msghdr();
-  init_msghdr_msg_name(msg.msg_name, addr);
-  msg.msg_namelen = addrlen;
-  msg.msg_iov = const_cast<buf*>(bufs);
-  msg.msg_iovlen = count;
-#if defined(__linux__)
-  flags |= MSG_NOSIGNAL;
-#endif // defined(__linux__)
-  int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+    asio::error_code& ec, size_t& bytes_transferred);
 
-inline socket_type socket(int af, int type, int protocol,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
-        WSA_FLAG_OVERLAPPED), ec);
-  if (s == invalid_socket)
-    return s;
-
-  if (af == AF_INET6)
-  {
-    // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
-    // false. This will only succeed on Windows Vista and later versions of
-    // Windows, where a dual-stack IPv4/v6 implementation is available.
-    DWORD optval = 0;
-    ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
-        reinterpret_cast<const char*>(&optval), sizeof(optval));
-  }
-
-  clear_error(ec);
-
-  return s;
-#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
-  socket_type s = error_wrapper(::socket(af, type, protocol), ec);
-  if (s == invalid_socket)
-    return s;
-
-  int optval = 1;
-  int result = error_wrapper(::setsockopt(s,
-        SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
-  if (result != 0)
-  {
-    ::close(s);
-    return invalid_socket;
-  }
-
-  return s;
-#else
-  int s = error_wrapper(::socket(af, type, protocol), ec);
-  if (s >= 0)
-    clear_error(ec);
-  return s;
-#endif
-}
-
-template <typename SockLenType>
-inline int call_setsockopt(SockLenType msghdr::*,
-    socket_type s, int level, int optname,
-    const void* optval, std::size_t optlen)
-{
-  return ::setsockopt(s, level, optname,
-      (const char*)optval, (SockLenType)optlen);
-}
+#endif // !defined(ASIO_HAS_IOCP)
 
-inline int setsockopt(socket_type s, int level, int optname,
-    const void* optval, std::size_t optlen, asio::error_code& ec)
-{
-  if (level == custom_socket_option_level && optname == always_fail_option)
-  {
-    ec = asio::error::invalid_argument;
-    return -1;
-  }
-
-#if defined(__BORLANDC__)
-  // Mysteriously, using the getsockopt and setsockopt functions directly with
-  // Borland C++ results in incorrect values being set and read. The bug can be
-  // worked around by using function addresses resolved with GetProcAddress.
-  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
-  {
-    typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
-    if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
-    {
-      clear_error(ec);
-      return error_wrapper(sso(s, level, optname,
-            reinterpret_cast<const char*>(optval),
-            static_cast<int>(optlen)), ec);
-    }
-  }
-  ec = asio::error::fault;
-  return -1;
-#else // defined(__BORLANDC__)
-  clear_error(ec);
-  int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
-        s, level, optname, optval, optlen), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-#endif // defined(__BORLANDC__)
-}
-
-template <typename SockLenType>
-inline int call_getsockopt(SockLenType msghdr::*,
-    socket_type s, int level, int optname,
-    void* optval, std::size_t* optlen)
-{
-  SockLenType tmp_optlen = (SockLenType)*optlen;
-  int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
-  *optlen = (std::size_t)tmp_optlen;
-  return result;
-}
-
-inline int getsockopt(socket_type s, int level, int optname, void* optval,
-    size_t* optlen, asio::error_code& ec)
-{
-  if (level == custom_socket_option_level && optname == always_fail_option)
-  {
-    ec = asio::error::invalid_argument;
-    return -1;
-  }
-
-#if defined(__BORLANDC__)
-  // Mysteriously, using the getsockopt and setsockopt functions directly with
-  // Borland C++ results in incorrect values being set and read. The bug can be
-  // worked around by using function addresses resolved with GetProcAddress.
-  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
-  {
-    typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
-    if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
-    {
-      clear_error(ec);
-      int tmp_optlen = static_cast<int>(*optlen);
-      int result = error_wrapper(gso(s, level, optname,
-            reinterpret_cast<char*>(optval), &tmp_optlen), ec);
-      *optlen = static_cast<size_t>(tmp_optlen);
-      if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
-          && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
-      {
-        // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
-        // only supported on Windows Vista and later. To simplify program logic
-        // we will fake success of getting this option and specify that the
-        // value is non-zero (i.e. true). This corresponds to the behavior of
-        // IPv6 sockets on Windows platforms pre-Vista.
-        *static_cast<DWORD*>(optval) = 1;
-        clear_error(ec);
-      }
-      return result;
-    }
-  }
-  ec = asio::error::fault;
-  return -1;
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  clear_error(ec);
-  int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
-        s, level, optname, optval, optlen), ec);
-  if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
-      && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
-  {
-    // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
-    // supported on Windows Vista and later. To simplify program logic we will
-    // fake success of getting this option and specify that the value is
-    // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
-    // on Windows platforms pre-Vista.
-    *static_cast<DWORD*>(optval) = 1;
-    clear_error(ec);
-  }
-  if (result == 0)
-    clear_error(ec);
-  return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  clear_error(ec);
-  int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
-        s, level, optname, optval, optlen), ec);
-#if defined(__linux__)
-  if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
-      && (optname == SO_SNDBUF || optname == SO_RCVBUF))
-  {
-    // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
-    // to set the buffer size to N*2. Linux puts additional stuff into the
-    // buffers so that only about half is actually available to the application.
-    // The retrieved value is divided by 2 here to make it appear as though the
-    // correct value has been set.
-    *static_cast<int*>(optval) /= 2;
-  }
-#endif // defined(__linux__)
-  if (result == 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL socket_type socket(int af, int type, int protocol,
+    asio::error_code& ec);
 
-template <typename SockLenType>
-inline int call_getpeername(SockLenType msghdr::*,
-    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
-  SockLenType tmp_addrlen = (SockLenType)*addrlen;
-  int result = ::getpeername(s, addr, &tmp_addrlen);
-  *addrlen = (std::size_t)tmp_addrlen;
-  return result;
-}
-
-inline int getpeername(socket_type s, socket_addr_type* addr,
-    std::size_t* addrlen, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(call_getpeername(
-        &msghdr::msg_namelen, s, addr, addrlen), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-template <typename SockLenType>
-inline int call_getsockname(SockLenType msghdr::*,
-    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
-  SockLenType tmp_addrlen = (SockLenType)*addrlen;
-  int result = ::getsockname(s, addr, &tmp_addrlen);
-  *addrlen = (std::size_t)tmp_addrlen;
-  return result;
-}
-
-inline int getsockname(socket_type s, socket_addr_type* addr,
-    std::size_t* addrlen, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(call_getsockname(
-        &msghdr::msg_namelen, s, addr, addrlen), ec);
-  if (result == 0)
-    clear_error(ec);
-  return result;
-}
-
-inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  int result = error_wrapper(::ioctl(s, cmd, arg), ec);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-}
+ASIO_DECL int setsockopt(socket_type s, state_type& state,
+    int level, int optname, const void* optval,
+    std::size_t optlen, asio::error_code& ec);
 
-inline int select(int nfds, fd_set* readfds, fd_set* writefds,
-    fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  if (!readfds && !writefds && !exceptfds && timeout)
-  {
-    DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
-    if (milliseconds == 0)
-      milliseconds = 1; // Force context switch.
-    ::Sleep(milliseconds);
-    ec = asio::error_code();
-    return 0;
-  }
-
-  // The select() call allows timeout values measured in microseconds, but the
-  // system clock (as wrapped by boost::posix_time::microsec_clock) typically
-  // has a resolution of 10 milliseconds. This can lead to a spinning select
-  // reactor, meaning increased CPU usage, when waiting for the earliest
-  // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
-  // spin we'll use a minimum timeout of 1 millisecond.
-  if (timeout && timeout->tv_sec == 0
-      && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
-    timeout->tv_usec = 1000;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ASIO_DECL int getsockopt(socket_type s, state_type state,
+    int level, int optname, void* optval,
+    size_t* optlen, asio::error_code& ec);
 
-#if defined(__hpux) && defined(__HP_aCC)
-  timespec ts;
-  ts.tv_sec = timeout ? timeout->tv_sec : 0;
-  ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
-  return error_wrapper(::pselect(nfds, readfds,
-        writefds, exceptfds, timeout ? &ts : 0, 0), ec);
-#else
-  int result = error_wrapper(::select(nfds, readfds,
-        writefds, exceptfds, timeout), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif
-}
-
-inline int poll_read(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  FD_SET fds;
-  FD_ZERO(&fds);
-  FD_SET(s, &fds);
-  clear_error(ec);
-  int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  pollfd fds;
-  fds.fd = s;
-  fds.events = POLLIN;
-  fds.revents = 0;
-  clear_error(ec);
-  int result = error_wrapper(::poll(&fds, 1, -1), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, bool cached, asio::error_code& ec);
 
-inline int poll_write(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  FD_SET fds;
-  FD_ZERO(&fds);
-  FD_SET(s, &fds);
-  clear_error(ec);
-  int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  pollfd fds;
-  fds.fd = s;
-  fds.events = POLLOUT;
-  fds.revents = 0;
-  clear_error(ec);
-  int result = error_wrapper(::poll(&fds, 1, -1), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
 
-inline int poll_connect(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  FD_SET write_fds;
-  FD_ZERO(&write_fds);
-  FD_SET(s, &write_fds);
-  FD_SET except_fds;
-  FD_ZERO(&except_fds);
-  FD_SET(s, &except_fds);
-  clear_error(ec);
-  int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  pollfd fds;
-  fds.fd = s;
-  fds.events = POLLOUT;
-  fds.revents = 0;
-  clear_error(ec);
-  int result = error_wrapper(::poll(&fds, 1, -1), ec);
-  if (result >= 0)
-    clear_error(ec);
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int ioctl(socket_type s, state_type& state,
+    int cmd, ioctl_arg_type* arg, asio::error_code& ec);
 
-inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
-    unsigned long scope_id, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  using namespace std; // For memcpy.
-
-  if (af != AF_INET && af != AF_INET6)
-  {
-    ec = asio::error::address_family_not_supported;
-    return 0;
-  }
-
-  union
-  {
-    socket_addr_type base;
-    sockaddr_storage_type storage;
-    sockaddr_in4_type v4;
-    sockaddr_in6_type v6;
-  } address;
-  DWORD address_length;
-  if (af == AF_INET)
-  {
-    address_length = sizeof(sockaddr_in4_type);
-    address.v4.sin_family = AF_INET;
-    address.v4.sin_port = 0;
-    memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
-  }
-  else // AF_INET6
-  {
-    address_length = sizeof(sockaddr_in6_type);
-    address.v6.sin6_family = AF_INET6;
-    address.v6.sin6_port = 0;
-    address.v6.sin6_flowinfo = 0;
-    address.v6.sin6_scope_id = scope_id;
-    memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
-  }
-
-  DWORD string_length = static_cast<DWORD>(length);
-#if defined(BOOST_NO_ANSI_APIS)
-  LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
-  int result = error_wrapper(::WSAAddressToStringW(&address.base,
-        address_length, 0, string_buffer, &string_length), ec);
-  ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
-#else
-  int result = error_wrapper(::WSAAddressToStringA(
-        &address.base, address_length, 0, dest, &string_length), ec);
-#endif
-
-  // Windows may set error code on success.
-  if (result != socket_error_retval)
-    clear_error(ec);
-
-  // Windows may not set an error code on failure.
-  else if (result == socket_error_retval && !ec)
-    ec = asio::error::invalid_argument;
-
-  return result == socket_error_retval ? 0 : dest;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
-  if (result == 0 && !ec)
-    ec = asio::error::invalid_argument;
-  if (result != 0 && af == AF_INET6 && scope_id != 0)
-  {
-    using namespace std; // For strcat and sprintf.
-    char if_name[IF_NAMESIZE + 1] = "%";
-    const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
-    bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
-    if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
-      sprintf(if_name + 1, "%lu", scope_id);
-    strcat(dest, if_name);
-  }
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,
+    fd_set* exceptfds, timeval* timeout, asio::error_code& ec);
 
-inline int inet_pton(int af, const char* src, void* dest,
-    unsigned long* scope_id, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  using namespace std; // For memcpy and strcmp.
-
-  if (af != AF_INET && af != AF_INET6)
-  {
-    ec = asio::error::address_family_not_supported;
-    return -1;
-  }
-
-  union
-  {
-    socket_addr_type base;
-    sockaddr_storage_type storage;
-    sockaddr_in4_type v4;
-    sockaddr_in6_type v6;
-  } address;
-  int address_length = sizeof(sockaddr_storage_type);
-#if defined(BOOST_NO_ANSI_APIS)
-  int num_wide_chars = strlen(src) + 1;
-  LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
-  ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
-  int result = error_wrapper(::WSAStringToAddressW(
-        wide_buffer, af, 0, &address.base, &address_length), ec);
-#else
-  int result = error_wrapper(::WSAStringToAddressA(
-        const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
-#endif
-
-  if (af == AF_INET)
-  {
-    if (result != socket_error_retval)
-    {
-      memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
-      clear_error(ec);
-    }
-    else if (strcmp(src, "255.255.255.255") == 0)
-    {
-      static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
-      clear_error(ec);
-    }
-  }
-  else // AF_INET6
-  {
-    if (result != socket_error_retval)
-    {
-      memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
-      if (scope_id)
-        *scope_id = address.v6.sin6_scope_id;
-      clear_error(ec);
-    }
-  }
-
-  // Windows may not set an error code on failure.
-  if (result == socket_error_retval && !ec)
-    ec = asio::error::invalid_argument;
-
-  if (result != socket_error_retval)
-    clear_error(ec);
-
-  return result == socket_error_retval ? -1 : 1;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  int result = error_wrapper(::inet_pton(af, src, dest), ec);
-  if (result <= 0 && !ec)
-    ec = asio::error::invalid_argument;
-  if (result > 0 && af == AF_INET6 && scope_id)
-  {
-    using namespace std; // For strchr and atoi.
-    *scope_id = 0;
-    if (const char* if_name = strchr(src, '%'))
-    {
-      in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
-      bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
-      if (is_link_local)
-        *scope_id = if_nametoindex(if_name + 1);
-      if (*scope_id == 0)
-        *scope_id = atoi(if_name + 1);
-    }
-  }
-  return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int poll_read(socket_type s, asio::error_code& ec);
 
-inline int gethostname(char* name, int namelen, asio::error_code& ec)
-{
-  clear_error(ec);
-  int result = error_wrapper(::gethostname(name, namelen), ec);
-#if defined(BOOST_WINDOWS)
-  if (result == 0)
-    clear_error(ec);
-#endif
-  return result;
-}
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
-  || defined(__MACH__) && defined(__APPLE__)
-
-// The following functions are only needed for emulation of getaddrinfo and
-// getnameinfo.
-
-inline asio::error_code translate_netdb_error(int error)
-{
-  switch (error)
-  {
-  case 0:
-    return asio::error_code();
-  case HOST_NOT_FOUND:
-    return asio::error::host_not_found;
-  case TRY_AGAIN:
-    return asio::error::host_not_found_try_again;
-  case NO_RECOVERY:
-    return asio::error::no_recovery;
-  case NO_DATA:
-    return asio::error::no_data;
-  default:
-    BOOST_ASSERT(false);
-    return asio::error::invalid_argument;
-  }
-}
-
-inline hostent* gethostbyaddr(const char* addr, int length, int af,
-    hostent* result, char* buffer, int buflength, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  (void)(buffer);
-  (void)(buflength);
-  hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
-  if (!retval)
-    return 0;
-  clear_error(ec);
-  *result = *retval;
-  return retval;
-#elif defined(__sun) || defined(__QNX__)
-  int error = 0;
-  hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
-        buffer, buflength, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  return retval;
-#elif defined(__MACH__) && defined(__APPLE__)
-  (void)(buffer);
-  (void)(buflength);
-  int error = 0;
-  hostent* retval = error_wrapper(::getipnodebyaddr(
-        addr, length, af, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  if (!retval)
-    return 0;
-  *result = *retval;
-  return retval;
-#else
-  hostent* retval = 0;
-  int error = 0;
-  error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
-        buflength, &retval, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  return retval;
-#endif
-}
-
-inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
-    char* buffer, int buflength, int ai_flags, asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-  (void)(buffer);
-  (void)(buflength);
-  (void)(ai_flags);
-  if (af != AF_INET)
-  {
-    ec = asio::error::address_family_not_supported;
-    return 0;
-  }
-  hostent* retval = error_wrapper(::gethostbyname(name), ec);
-  if (!retval)
-    return 0;
-  clear_error(ec);
-  *result = *retval;
-  return result;
-#elif defined(__sun) || defined(__QNX__)
-  (void)(ai_flags);
-  if (af != AF_INET)
-  {
-    ec = asio::error::address_family_not_supported;
-    return 0;
-  }
-  int error = 0;
-  hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
-        buflength, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  return retval;
-#elif defined(__MACH__) && defined(__APPLE__)
-  (void)(buffer);
-  (void)(buflength);
-  int error = 0;
-  hostent* retval = error_wrapper(::getipnodebyname(
-        name, af, ai_flags, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  if (!retval)
-    return 0;
-  *result = *retval;
-  return retval;
-#else
-  (void)(ai_flags);
-  if (af != AF_INET)
-  {
-    ec = asio::error::address_family_not_supported;
-    return 0;
-  }
-  hostent* retval = 0;
-  int error = 0;
-  error_wrapper(::gethostbyname_r(name, result,
-        buffer, buflength, &retval, &error), ec);
-  if (error)
-    ec = translate_netdb_error(error);
-  return retval;
-#endif
-}
-
-inline void freehostent(hostent* h)
-{
-#if defined(__MACH__) && defined(__APPLE__)
-  if (h)
-    ::freehostent(h);
-#else
-  (void)(h);
-#endif
-}
-
-// Emulation of getaddrinfo based on implementation in:
-// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
-
-struct gai_search
-{
-  const char* host;
-  int family;
-};
+ASIO_DECL int poll_write(socket_type s, asio::error_code& ec);
 
-inline int gai_nsearch(const char* host,
-    const addrinfo_type* hints, gai_search (&search)[2])
-{
-  int search_count = 0;
-  if (host == 0 || host[0] == '\0')
-  {
-    if (hints->ai_flags & AI_PASSIVE)
-    {
-      // No host and AI_PASSIVE implies wildcard bind.
-      switch (hints->ai_family)
-      {
-      case AF_INET:
-        search[search_count].host = "0.0.0.0";
-        search[search_count].family = AF_INET;
-        ++search_count;
-        break;
-      case AF_INET6:
-        search[search_count].host = "0::0";
-        search[search_count].family = AF_INET6;
-        ++search_count;
-        break;
-      case AF_UNSPEC:
-        search[search_count].host = "0::0";
-        search[search_count].family = AF_INET6;
-        ++search_count;
-        search[search_count].host = "0.0.0.0";
-        search[search_count].family = AF_INET;
-        ++search_count;
-        break;
-      default:
-        break;
-      }
-    }
-    else
-    {
-      // No host and not AI_PASSIVE means connect to local host.
-      switch (hints->ai_family)
-      {
-      case AF_INET:
-        search[search_count].host = "localhost";
-        search[search_count].family = AF_INET;
-        ++search_count;
-        break;
-      case AF_INET6:
-        search[search_count].host = "localhost";
-        search[search_count].family = AF_INET6;
-        ++search_count;
-        break;
-      case AF_UNSPEC:
-        search[search_count].host = "localhost";
-        search[search_count].family = AF_INET6;
-        ++search_count;
-        search[search_count].host = "localhost";
-        search[search_count].family = AF_INET;
-        ++search_count;
-        break;
-      default:
-        break;
-      }
-    }
-  }
-  else
-  {
-    // Host is specified.
-    switch (hints->ai_family)
-    {
-    case AF_INET:
-      search[search_count].host = host;
-      search[search_count].family = AF_INET;
-      ++search_count;
-      break;
-    case AF_INET6:
-      search[search_count].host = host;
-      search[search_count].family = AF_INET6;
-      ++search_count;
-      break;
-    case AF_UNSPEC:
-      search[search_count].host = host;
-      search[search_count].family = AF_INET6;
-      ++search_count;
-      search[search_count].host = host;
-      search[search_count].family = AF_INET;
-      ++search_count;
-      break;
-    default:
-      break;
-    }
-  }
-  return search_count;
-}
-
-template <typename T>
-inline T* gai_alloc(std::size_t size = sizeof(T))
-{
-  using namespace std;
-  T* p = static_cast<T*>(::operator new(size, std::nothrow));
-  if (p)
-    memset(p, 0, size);
-  return p;
-}
-
-inline void gai_free(void* p)
-{
-  ::operator delete(p);
-}
+ASIO_DECL int poll_connect(socket_type s, asio::error_code& ec);
 
-inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
-{
-  using namespace std;
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
-  strcpy_s(target, max_size, source);
-#else
-  *target = 0;
-  strncat(target, source, max_size);
-#endif
-}
-
-enum { gai_clone_flag = 1 << 30 };
-
-inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
-    const void* addr, int family)
-{
-  using namespace std;
-
-  addrinfo_type* ai = gai_alloc<addrinfo_type>();
-  if (ai == 0)
-    return EAI_MEMORY;
-
-  ai->ai_next = 0;
-  **next = ai;
-  *next = &ai->ai_next;
-
-  ai->ai_canonname = 0;
-  ai->ai_socktype = hints->ai_socktype;
-  if (ai->ai_socktype == 0)
-    ai->ai_flags |= gai_clone_flag;
-  ai->ai_protocol = hints->ai_protocol;
-  ai->ai_family = family;
-
-  switch (ai->ai_family)
-  {
-  case AF_INET:
-    {
-      sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
-      if (sinptr == 0)
-        return EAI_MEMORY;
-      sinptr->sin_family = AF_INET;
-      memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
-      ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
-      ai->ai_addrlen = sizeof(sockaddr_in4_type);
-      break;
-    }
-  case AF_INET6:
-    {
-      sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
-      if (sin6ptr == 0)
-        return EAI_MEMORY;
-      sin6ptr->sin6_family = AF_INET6;
-      memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
-      ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
-      ai->ai_addrlen = sizeof(sockaddr_in6_type);
-      break;
-    }
-  default:
-    break;
-  }
-
-  return 0;
-}
-
-inline addrinfo_type* gai_clone(addrinfo_type* ai)
-{
-  using namespace std;
+ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest,
+    size_t length, unsigned long scope_id, asio::error_code& ec);
 
-  addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
-  if (new_ai == 0)
-    return new_ai;
+ASIO_DECL int inet_pton(int af, const char* src, void* dest,
+    unsigned long* scope_id, asio::error_code& ec);
 
-  new_ai->ai_next = ai->ai_next;
-  ai->ai_next = new_ai;
+ASIO_DECL int gethostname(char* name,
+    int namelen, asio::error_code& ec);
 
-  new_ai->ai_flags = 0;
-  new_ai->ai_family = ai->ai_family;
-  new_ai->ai_socktype = ai->ai_socktype;
-  new_ai->ai_protocol = ai->ai_protocol;
-  new_ai->ai_canonname = 0;
-  new_ai->ai_addrlen = ai->ai_addrlen;
-  new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
-  memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+ASIO_DECL asio::error_code getaddrinfo(const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec);
 
-  return new_ai;
-}
+ASIO_DECL asio::error_code background_getaddrinfo(
+    const weak_cancel_token_type& cancel_token, const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec);
 
-inline int gai_port(addrinfo_type* aihead, int port, int socktype)
-{
-  int num_found = 0;
-
-  for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
-  {
-    if (ai->ai_flags & gai_clone_flag)
-    {
-      if (ai->ai_socktype != 0)
-      {
-        ai = gai_clone(ai);
-        if (ai == 0)
-          return -1;
-        // ai now points to newly cloned entry.
-      }
-    }
-    else if (ai->ai_socktype != socktype)
-    {
-      // Ignore if mismatch on socket type.
-      continue;
-    }
-
-    ai->ai_socktype = socktype;
-
-    switch (ai->ai_family)
-    {
-    case AF_INET:
-      {
-        sockaddr_in4_type* sinptr =
-          reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
-        sinptr->sin_port = port;
-        ++num_found;
-        break;
-      }
-    case AF_INET6:
-      {
-        sockaddr_in6_type* sin6ptr =
-          reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
-        sin6ptr->sin6_port = port;
-        ++num_found;
-        break;
-      }
-    default:
-      break;
-    }
-  }
-
-  return num_found;
-}
-
-inline int gai_serv(addrinfo_type* aihead,
-    const addrinfo_type* hints, const char* serv)
-{
-  using namespace std;
-
-  int num_found = 0;
-
-  if (
-#if defined(AI_NUMERICSERV)
-      (hints->ai_flags & AI_NUMERICSERV) ||
-#endif
-      isdigit(serv[0]))
-  {
-    int port = htons(atoi(serv));
-    if (hints->ai_socktype)
-    {
-      // Caller specifies socket type.
-      int rc = gai_port(aihead, port, hints->ai_socktype);
-      if (rc < 0)
-        return EAI_MEMORY;
-      num_found += rc;
-    }
-    else
-    {
-      // Caller does not specify socket type.
-      int rc = gai_port(aihead, port, SOCK_STREAM);
-      if (rc < 0)
-        return EAI_MEMORY;
-      num_found += rc;
-      rc = gai_port(aihead, port, SOCK_DGRAM);
-      if (rc < 0)
-        return EAI_MEMORY;
-      num_found += rc;
-    }
-  }
-  else
-  {
-    // Try service name with TCP first, then UDP.
-    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
-    {
-      servent* sptr = getservbyname(serv, "tcp");
-      if (sptr != 0)
-      {
-        int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
-        if (rc < 0)
-          return EAI_MEMORY;
-        num_found += rc;
-      }
-    }
-    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
-    {
-      servent* sptr = getservbyname(serv, "udp");
-      if (sptr != 0)
-      {
-        int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
-        if (rc < 0)
-          return EAI_MEMORY;
-        num_found += rc;
-      }
-    }
-  }
-
-  if (num_found == 0)
-  {
-    if (hints->ai_socktype == 0)
-    {
-      // All calls to getservbyname() failed.
-      return EAI_NONAME;
-    }
-    else
-    {
-      // Service not supported for socket type.
-      return EAI_SERVICE;
-    }
-  }
-
-  return 0;
-}
-
-inline int gai_echeck(const char* host, const char* service,
-    int flags, int family, int socktype, int protocol)
-{
-  (void)(flags);
-  (void)(protocol);
-
-  // Host or service must be specified.
-  if (host == 0 || host[0] == '\0')
-    if (service == 0 || service[0] == '\0')
-      return EAI_NONAME;
-
-  // Check combination of family and socket type.
-  switch (family)
-  {
-  case AF_UNSPEC:
-    break;
-  case AF_INET:
-  case AF_INET6:
-    if (service != 0 && service[0] != '\0')
-      if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
-        return EAI_SOCKTYPE;
-    break;
-  default:
-    return EAI_FAMILY;
-  }
-
-  return 0;
-}
-
-inline void freeaddrinfo_emulation(addrinfo_type* aihead)
-{
-  addrinfo_type* ai = aihead;
-  while (ai)
-  {
-    gai_free(ai->ai_addr);
-    gai_free(ai->ai_canonname);
-    addrinfo_type* ainext = ai->ai_next;
-    gai_free(ai);
-    ai = ainext;
-  }
-}
-
-inline int getaddrinfo_emulation(const char* host, const char* service,
-    const addrinfo_type* hintsp, addrinfo_type** result)
-{
-  // Set up linked list of addrinfo structures.
-  addrinfo_type* aihead = 0;
-  addrinfo_type** ainext = &aihead;
-  char* canon = 0;
-
-  // Supply default hints if not specified by caller.
-  addrinfo_type hints = addrinfo_type();
-  hints.ai_family = AF_UNSPEC;
-  if (hintsp)
-    hints = *hintsp;
-
-  // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
-  // and AI_ALL flags.
-#if defined(AI_V4MAPPED)
-  if (hints.ai_family != AF_INET6)
-    hints.ai_flags &= ~AI_V4MAPPED;
-#endif
-#if defined(AI_ALL)
-  if (hints.ai_family != AF_INET6)
-    hints.ai_flags &= ~AI_ALL;
-#endif
-
-  // Basic error checking.
-  int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
-      hints.ai_socktype, hints.ai_protocol);
-  if (rc != 0)
-  {
-    freeaddrinfo_emulation(aihead);
-    return rc;
-  }
-
-  gai_search search[2];
-  int search_count = gai_nsearch(host, &hints, search);
-  for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
-  {
-    // Check for IPv4 dotted decimal string.
-    in4_addr_type inaddr;
-    asio::error_code ec;
-    if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
-    {
-      if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
-      {
-        freeaddrinfo_emulation(aihead);
-        gai_free(canon);
-        return EAI_FAMILY;
-      }
-      if (sptr->family == AF_INET)
-      {
-        rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
-        if (rc != 0)
-        {
-          freeaddrinfo_emulation(aihead);
-          gai_free(canon);
-          return rc;
-        }
-      }
-      continue;
-    }
-
-    // Check for IPv6 hex string.
-    in6_addr_type in6addr;
-    if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
-    {
-      if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
-      {
-        freeaddrinfo_emulation(aihead);
-        gai_free(canon);
-        return EAI_FAMILY;
-      }
-      if (sptr->family == AF_INET6)
-      {
-        rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
-        if (rc != 0)
-        {
-          freeaddrinfo_emulation(aihead);
-          gai_free(canon);
-          return rc;
-        }
-      }
-      continue;
-    }
-
-    // Look up hostname.
-    hostent hent;
-    char hbuf[8192] = "";
-    hostent* hptr = socket_ops::gethostbyname(sptr->host,
-        sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
-    if (hptr == 0)
-    {
-      if (search_count == 2)
-      {
-        // Failure is OK if there are multiple searches.
-        continue;
-      }
-      freeaddrinfo_emulation(aihead);
-      gai_free(canon);
-      if (ec == asio::error::host_not_found)
-        return EAI_NONAME;
-      if (ec == asio::error::host_not_found_try_again)
-        return EAI_AGAIN;
-      if (ec == asio::error::no_recovery)
-        return EAI_FAIL;
-      if (ec == asio::error::no_data)
-        return EAI_NONAME;
-      return EAI_NONAME;
-    }
-
-    // Check for address family mismatch if one was specified.
-    if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
-    {
-      freeaddrinfo_emulation(aihead);
-      gai_free(canon);
-      socket_ops::freehostent(hptr);
-      return EAI_FAMILY;
-    }
-
-    // Save canonical name first time.
-    if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
-        && (hints.ai_flags & AI_CANONNAME) && canon == 0)
-    {
-      std::size_t canon_len = strlen(hptr->h_name) + 1;
-      canon = gai_alloc<char>(canon_len);
-      if (canon == 0)
-      {
-        freeaddrinfo_emulation(aihead);
-        socket_ops::freehostent(hptr);
-        return EAI_MEMORY;
-      }
-      gai_strcpy(canon, hptr->h_name, canon_len);
-    }
-
-    // Create an addrinfo structure for each returned address.
-    for (char** ap = hptr->h_addr_list; *ap; ++ap)
-    {
-      rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
-      if (rc != 0)
-      {
-        freeaddrinfo_emulation(aihead);
-        gai_free(canon);
-        socket_ops::freehostent(hptr);
-        return EAI_FAMILY;
-      }
-    }
-
-    socket_ops::freehostent(hptr);
-  }
-
-  // Check if we found anything.
-  if (aihead == 0)
-  {
-    gai_free(canon);
-    return EAI_NONAME;
-  }
-
-  // Return canonical name in first entry.
-  if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
-  {
-    if (canon)
-    {
-      aihead->ai_canonname = canon;
-      canon = 0;
-    }
-    else
-    {
-      std::size_t canonname_len = strlen(search[0].host) + 1;
-      aihead->ai_canonname = gai_alloc<char>(canonname_len);
-      if (aihead->ai_canonname == 0)
-      {
-        freeaddrinfo_emulation(aihead);
-        return EAI_MEMORY;
-      }
-      gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
-    }
-  }
-  gai_free(canon);
-
-  // Process the service name.
-  if (service != 0 && service[0] != '\0')
-  {
-    rc = gai_serv(aihead, &hints, service);
-    if (rc != 0)
-    {
-      freeaddrinfo_emulation(aihead);
-      return rc;
-    }
-  }
-
-  // Return result to caller.
-  *result = aihead;
-  return 0;
-}
-
-inline asio::error_code getnameinfo_emulation(
-    const socket_addr_type* sa, std::size_t salen, char* host,
-    std::size_t hostlen, char* serv, std::size_t servlen, int flags,
-    asio::error_code& ec)
-{
-  using namespace std;
-
-  const char* addr;
-  size_t addr_len;
-  unsigned short port;
-  switch (sa->sa_family)
-  {
-  case AF_INET:
-    if (salen != sizeof(sockaddr_in4_type))
-    {
-      return ec = asio::error::invalid_argument;
-    }
-    addr = reinterpret_cast<const char*>(
-        &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
-    addr_len = sizeof(in4_addr_type);
-    port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
-    break;
-  case AF_INET6:
-    if (salen != sizeof(sockaddr_in6_type))
-    {
-      return ec = asio::error::invalid_argument;
-    }
-    addr = reinterpret_cast<const char*>(
-        &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
-    addr_len = sizeof(in6_addr_type);
-    port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
-    break;
-  default:
-    return ec = asio::error::address_family_not_supported;
-  }
-
-  if (host && hostlen > 0)
-  {
-    if (flags & NI_NUMERICHOST)
-    {
-      if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
-      {
-        return ec;
-      }
-    }
-    else
-    {
-      hostent hent;
-      char hbuf[8192] = "";
-      hostent* hptr = socket_ops::gethostbyaddr(addr,
-          static_cast<int>(addr_len), sa->sa_family,
-          &hent, hbuf, sizeof(hbuf), ec);
-      if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
-      {
-        if (flags & NI_NOFQDN)
-        {
-          char* dot = strchr(hptr->h_name, '.');
-          if (dot)
-          {
-            *dot = 0;
-          }
-        }
-        gai_strcpy(host, hptr->h_name, hostlen);
-        socket_ops::freehostent(hptr);
-      }
-      else
-      {
-        socket_ops::freehostent(hptr);
-        if (flags & NI_NAMEREQD)
-        {
-          return ec = asio::error::host_not_found;
-        }
-        if (socket_ops::inet_ntop(sa->sa_family,
-              addr, host, hostlen, 0, ec) == 0)
-        {
-          return ec;
-        }
-      }
-    }
-  }
-
-  if (serv && servlen > 0)
-  {
-    if (flags & NI_NUMERICSERV)
-    {
-      if (servlen < 6)
-      {
-        return ec = asio::error::no_buffer_space;
-      }
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
-      sprintf_s(serv, servlen, "%u", ntohs(port));
-#else
-      sprintf(serv, "%u", ntohs(port));
-#endif
-    }
-    else
-    {
-#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
-      static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-      ::pthread_mutex_lock(&mutex);
-#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
-      servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
-      if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
-      {
-        gai_strcpy(serv, sptr->s_name, servlen);
-      }
-      else
-      {
-        if (servlen < 6)
-        {
-          return ec = asio::error::no_buffer_space;
-        }
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
-        sprintf_s(serv, servlen, "%u", ntohs(port));
-#else
-        sprintf(serv, "%u", ntohs(port));
-#endif
-      }
-#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
-      ::pthread_mutex_unlock(&mutex);
-#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
-    }
-  }
-
-  clear_error(ec);
-  return ec;
-}
+ASIO_DECL void freeaddrinfo(addrinfo_type* ai);
 
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-       //   || defined(__MACH__) && defined(__APPLE__)
+ASIO_DECL asio::error_code getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int flags, asio::error_code& ec);
 
-inline asio::error_code translate_addrinfo_error(int error)
-{
-  switch (error)
-  {
-  case 0:
-    return asio::error_code();
-  case EAI_AGAIN:
-    return asio::error::host_not_found_try_again;
-  case EAI_BADFLAGS:
-    return asio::error::invalid_argument;
-  case EAI_FAIL:
-    return asio::error::no_recovery;
-  case EAI_FAMILY:
-    return asio::error::address_family_not_supported;
-  case EAI_MEMORY:
-    return asio::error::no_memory;
-  case EAI_NONAME:
-#if defined(EAI_ADDRFAMILY)
-  case EAI_ADDRFAMILY:
-#endif
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
-  case EAI_NODATA:
-#endif
-    return asio::error::host_not_found;
-  case EAI_SERVICE:
-    return asio::error::service_not_found;
-  case EAI_SOCKTYPE:
-    return asio::error::socket_type_not_supported;
-  default: // Possibly the non-portable EAI_SYSTEM.
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-    return asio::error_code(
-        WSAGetLastError(), asio::error::get_system_category());
-#else
-    return asio::error_code(
-        errno, asio::error::get_system_category());
-#endif
-  }
-}
-
-inline asio::error_code getaddrinfo(const char* host,
-    const char* service, const addrinfo_type* hints, addrinfo_type** result,
-    asio::error_code& ec)
-{
-  clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
-  // Building for Windows XP, Windows Server 2003, or later.
-  int error = ::getaddrinfo(host, service, hints, result);
-  return ec = translate_addrinfo_error(error);
-# else
-  // Building for Windows 2000 or earlier.
-  typedef int (WSAAPI *gai_t)(const char*,
-      const char*, const addrinfo_type*, addrinfo_type**);
-  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
-  {
-    if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
-    {
-      int error = gai(host, service, hints, result);
-      return ec = translate_addrinfo_error(error);
-    }
-  }
-  int error = getaddrinfo_emulation(host, service, hints, result);
-  return ec = translate_addrinfo_error(error);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
-  int error = getaddrinfo_emulation(host, service, hints, result);
-  return ec = translate_addrinfo_error(error);
-#else
-  int error = ::getaddrinfo(host, service, hints, result);
-  return ec = translate_addrinfo_error(error);
-#endif
-}
-
-inline void freeaddrinfo(addrinfo_type* ai)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
-  // Building for Windows XP, Windows Server 2003, or later.
-  ::freeaddrinfo(ai);
-# else
-  // Building for Windows 2000 or earlier.
-  typedef int (WSAAPI *fai_t)(addrinfo_type*);
-  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
-  {
-    if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
-    {
-      fai(ai);
-      return;
-    }
-  }
-  freeaddrinfo_emulation(ai);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
-  freeaddrinfo_emulation(ai);
-#else
-  ::freeaddrinfo(ai);
-#endif
-}
-
-inline asio::error_code getnameinfo(const socket_addr_type* addr,
-    std::size_t addrlen, char* host, std::size_t hostlen,
-    char* serv, std::size_t servlen, int flags, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
-  // Building for Windows XP, Windows Server 2003, or later.
-  clear_error(ec);
-  int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
-      host, static_cast<DWORD>(hostlen),
-      serv, static_cast<DWORD>(servlen), flags);
-  return ec = translate_addrinfo_error(error);
-# else
-  // Building for Windows 2000 or earlier.
-  typedef int (WSAAPI *gni_t)(const socket_addr_type*,
-      int, char*, DWORD, char*, DWORD, int);
-  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
-  {
-    if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
-    {
-      clear_error(ec);
-      int error = gni(addr, static_cast<int>(addrlen),
-          host, static_cast<DWORD>(hostlen),
-          serv, static_cast<DWORD>(servlen), flags);
-      return ec = translate_addrinfo_error(error);
-    }
-  }
-  clear_error(ec);
-  return getnameinfo_emulation(addr, addrlen,
-      host, hostlen, serv, servlen, flags, ec);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
-  using namespace std; // For memcpy.
-  sockaddr_storage_type tmp_addr;
-  memcpy(&tmp_addr, addr, addrlen);
-  tmp_addr.ss_len = addrlen;
-  addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
-  clear_error(ec);
-  return getnameinfo_emulation(addr, addrlen,
-      host, hostlen, serv, servlen, flags, ec);
-#else
-  clear_error(ec);
-  int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
-  return ec = translate_addrinfo_error(error);
-#endif
-}
-
-inline u_long_type network_to_host_long(u_long_type value)
-{
-  return ntohl(value);
-}
+ASIO_DECL asio::error_code sync_getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec);
 
-inline u_long_type host_to_network_long(u_long_type value)
-{
-  return htonl(value);
-}
+ASIO_DECL asio::error_code background_getnameinfo(
+    const weak_cancel_token_type& cancel_token,
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec);
 
-inline u_short_type network_to_host_short(u_short_type value)
-{
-  return ntohs(value);
-}
+ASIO_DECL u_long_type network_to_host_long(u_long_type value);
 
-inline u_short_type host_to_network_short(u_short_type value)
-{
-  return htons(value);
-}
+ASIO_DECL u_long_type host_to_network_long(u_long_type value);
+
+ASIO_DECL u_short_type network_to_host_short(u_short_type value);
+
+ASIO_DECL u_short_type host_to_network_short(u_short_type value);
 
 } // namespace socket_ops
 } // namespace detail
@@ -1909,4 +282,8 @@ inline u_short_type host_to_network_short(u_short_type value)
 
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/ext/asio/asio/detail/socket_option.hpp b/ext/asio/asio/detail/socket_option.hpp
index ac070b7..c9d7896 100644
--- a/ext/asio/asio/detail/socket_option.hpp
+++ b/ext/asio/asio/detail/socket_option.hpp
@@ -1,8 +1,8 @@
 //
-// socket_option.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <stdexcept>
 #include <boost/config.hpp>
 #include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 namespace socket_option {
diff --git a/ext/asio/asio/detail/socket_select_interrupter.hpp b/ext/asio/asio/detail/socket_select_interrupter.hpp
index 62e1063..b05a4ff 100644
--- a/ext/asio/asio/detail/socket_select_interrupter.hpp
+++ b/ext/asio/asio/detail/socket_select_interrupter.hpp
@@ -1,8 +1,8 @@
 //
-// socket_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstdlib>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(BOOST_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_holder.hpp"
-#include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -35,135 +32,16 @@ class socket_select_interrupter
 {
 public:
   // Constructor.
-  socket_select_interrupter()
-  {
-    asio::error_code ec;
-    socket_holder acceptor(socket_ops::socket(
-          AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
-    if (acceptor.get() == invalid_socket)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    int opt = 1;
-    socket_ops::setsockopt(acceptor.get(),
-        SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
-
-    using namespace std; // For memset.
-    sockaddr_in4_type addr;
-    std::size_t addr_len = sizeof(addr);
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-    addr.sin_port = 0;
-    if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
-          addr_len, ec) == socket_error_retval)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
-          &addr_len, ec) == socket_error_retval)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    // Some broken firewalls on Windows will intermittently cause getsockname to
-    // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
-    // explicitly specify the target address here to work around this problem.
-    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
-    if (socket_ops::listen(acceptor.get(),
-          SOMAXCONN, ec) == socket_error_retval)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    socket_holder client(socket_ops::socket(
-          AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
-    if (client.get() == invalid_socket)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
-          addr_len, ec) == socket_error_retval)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
-    if (server.get() == invalid_socket)
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-    
-    ioctl_arg_type non_blocking = 1;
-    if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    opt = 1;
-    socket_ops::setsockopt(client.get(),
-        IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
-
-    non_blocking = 1;
-    if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
-    {
-      asio::system_error e(ec, "socket_select_interrupter");
-      boost::throw_exception(e);
-    }
-
-    opt = 1;
-    socket_ops::setsockopt(server.get(),
-        IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
-
-    read_descriptor_ = server.release();
-    write_descriptor_ = client.release();
-  }
+  ASIO_DECL socket_select_interrupter();
 
   // Destructor.
-  ~socket_select_interrupter()
-  {
-    asio::error_code ec;
-    if (read_descriptor_ != invalid_socket)
-      socket_ops::close(read_descriptor_, ec);
-    if (write_descriptor_ != invalid_socket)
-      socket_ops::close(write_descriptor_, ec);
-  }
+  ASIO_DECL ~socket_select_interrupter();
 
   // Interrupt the select call.
-  void interrupt()
-  {
-    char byte = 0;
-    socket_ops::buf b;
-    socket_ops::init_buf(b, &byte, 1);
-    asio::error_code ec;
-    socket_ops::send(write_descriptor_, &b, 1, 0, ec);
-  }
+  ASIO_DECL void interrupt();
 
   // Reset the select interrupt. Returns true if the call was interrupted.
-  bool reset()
-  {
-    char data[1024];
-    socket_ops::buf b;
-    socket_ops::init_buf(b, data, sizeof(data));
-    asio::error_code ec;
-    int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
-    bool was_interrupted = (bytes_read > 0);
-    while (bytes_read == sizeof(data))
-      bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
-    return was_interrupted;
-  }
+  ASIO_DECL bool reset();
 
   // Get the read descriptor to be passed to select.
   socket_type read_descriptor() const
@@ -189,4 +67,12 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
 #endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/socket_types.hpp b/ext/asio/asio/detail/socket_types.hpp
index 34b3d3e..4e29e51 100644
--- a/ext/asio/asio/detail/socket_types.hpp
+++ b/ext/asio/asio/detail/socket_types.hpp
@@ -1,8 +1,8 @@
 //
-// socket_types.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/socket_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,69 +15,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 # if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
 #  error WinSock.h has already been included
 # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
-# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
-#  if defined(_MSC_VER) || defined(__BORLANDC__)
-#   pragma message( \
-  "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
-  "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
-  "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
-  "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
-#  else // defined(_MSC_VER) || defined(__BORLANDC__)
-#   warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
-#   warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
-#   warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
-#  endif // defined(_MSC_VER) || defined(__BORLANDC__)
-#  define _WIN32_WINNT 0x0501
-# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
-# if defined(_MSC_VER)
-#  if defined(_WIN32) && !defined(WIN32)
-#   if !defined(_WINSOCK2API_)
-#    define WIN32 // Needed for correct types in winsock2.h
-#   else // !defined(_WINSOCK2API_)
-#    error Please define the macro WIN32 in your compiler options
-#   endif // !defined(_WINSOCK2API_)
-#  endif // defined(_WIN32) && !defined(WIN32)
-# endif // defined(_MSC_VER)
 # if defined(__BORLANDC__)
 #  include <stdlib.h> // Needed for __errno
-#  if defined(__WIN32__) && !defined(WIN32)
-#   if !defined(_WINSOCK2API_)
-#    define WIN32 // Needed for correct types in winsock2.h
-#   else // !defined(_WINSOCK2API_)
-#    error Please define the macro WIN32 in your compiler options
-#   endif // !defined(_WINSOCK2API_)
-#  endif // defined(__WIN32__) && !defined(WIN32)
 #  if !defined(_WSPIAPI_H_)
 #   define _WSPIAPI_H_
 #   define ASIO_WSPIAPI_H_DEFINED
 #  endif // !defined(_WSPIAPI_H_)
 # endif // defined(__BORLANDC__)
-# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
-#  if !defined(WIN32_LEAN_AND_MEAN)
-#   define WIN32_LEAN_AND_MEAN
-#  endif // !defined(WIN32_LEAN_AND_MEAN)
-# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
-# if !defined(ASIO_NO_NOMINMAX)
-#  if !defined(NOMINMAX)
-#   define NOMINMAX 1
-#  endif // !defined(NOMINMAX)
-# endif // !defined(ASIO_NO_NOMINMAX)
-# if defined(__CYGWIN__)
-#  if !defined(__USE_W32_SOCKETS)
-#   error You must add -D__USE_W32_SOCKETS to your compiler options.
-#  endif // !defined(__USE_W32_SOCKETS)
-# endif // defined(__CYGWIN__)
 # include <winsock2.h>
 # include <ws2tcpip.h>
 # include <mswsock.h>
@@ -96,18 +46,25 @@
 # include "asio/detail/old_win_sdk_compat.hpp"
 #else
 # include <sys/ioctl.h>
-# include <sys/poll.h>
+# if !defined(__SYMBIAN32__)
+#  include <sys/poll.h>
+# endif
 # include <sys/types.h>
-# if defined(__hpux) && !defined(__HP_aCC)
+# include <sys/stat.h>
+# include <fcntl.h>
+# if defined(__hpux)
 #  include <sys/time.h>
-# else
+# endif
+# if !defined(__hpux) || defined(__SELECT)
 #  include <sys/select.h>
 # endif
 # include <sys/socket.h>
 # include <sys/uio.h>
 # include <sys/un.h>
 # include <netinet/in.h>
-# include <netinet/tcp.h>
+# if !defined(__SYMBIAN32__)
+#  include <netinet/tcp.h>
+# endif
 # include <arpa/inet.h>
 # include <netdb.h>
 # include <net/if.h>
@@ -117,7 +74,8 @@
 #  include <sys/sockio.h>
 # endif
 #endif
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
diff --git a/ext/asio/asio/detail/solaris_fenced_block.hpp b/ext/asio/asio/detail/solaris_fenced_block.hpp
index d337f3b..411c824 100644
--- a/ext/asio/asio/detail/solaris_fenced_block.hpp
+++ b/ext/asio/asio/detail/solaris_fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// solaris_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/solaris_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(__sun)
 
-#include "asio/detail/push_options.hpp"
 #include <atomic.h>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -50,8 +46,8 @@ public:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(__sun)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(__sun)
+
 #endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/strand_service.hpp b/ext/asio/asio/detail/strand_service.hpp
index ea50f41..4885b93 100644
--- a/ext/asio/asio/detail/strand_service.hpp
+++ b/ext/asio/asio/detail/strand_service.hpp
@@ -1,8 +1,8 @@
 //
-// strand_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/functional/hash.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/scoped_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/io_service.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/operation.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -41,7 +32,10 @@ class strand_service
   : public asio::detail::service_base<strand_service>
 {
 private:
+  // Helper class to re-post the strand on exit.
   struct on_do_complete_exit;
+
+  // Helper class to re-post the strand on exit.
   struct on_dispatch_exit;
 
 public:
@@ -51,11 +45,7 @@ public:
     : public operation
   {
   public:
-    strand_impl()
-      : operation(&strand_service::do_complete),
-        count_(0)
-    {
-    }
+    strand_impl();
 
   private:
     // Only this service will have access to the internal values.
@@ -76,180 +66,29 @@ public:
   typedef strand_impl* implementation_type;
 
   // Construct a new strand service for the specified io_service.
-  explicit strand_service(asio::io_service& io_service)
-    : asio::detail::service_base<strand_service>(io_service),
-      io_service_(asio::use_service<io_service_impl>(io_service)),
-      mutex_(),
-      salt_(0)
-  {
-  }
+  ASIO_DECL explicit strand_service(asio::io_service& io_service);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    op_queue<operation> ops;
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    for (std::size_t i = 0; i < num_implementations; ++i)
-      if (strand_impl* impl = implementations_[i].get())
-        ops.push(impl->queue_);
-  }
+  ASIO_DECL void shutdown_service();
 
   // Construct a new strand implementation.
-  void construct(implementation_type& impl)
-  {
-    std::size_t index = boost::hash_value(&impl);
-    boost::hash_combine(index, salt_++);
-    index = index % num_implementations;
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    if (!implementations_[index])
-      implementations_[index].reset(new strand_impl);
-    impl = implementations_[index].get();
-  }
+  ASIO_DECL void construct(implementation_type& impl);
 
   // Destroy a strand implementation.
-  void destroy(implementation_type& impl)
-  {
-    impl = 0;
-  }
+  void destroy(implementation_type& impl);
 
   // Request the io_service to invoke the given handler.
   template <typename Handler>
-  void dispatch(implementation_type& impl, Handler handler)
-  {
-    // If we are already in the strand then the handler can run immediately.
-    if (call_stack<strand_impl>::contains(impl))
-    {
-      asio::detail::fenced_block b;
-      asio_handler_invoke_helpers::invoke(handler, handler);
-      return;
-    }
-
-    // Allocate and construct an object to wrap the handler.
-    typedef completion_handler<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    // If we are running inside the io_service, and no other handler is queued
-    // or running, then the handler can run immediately.
-    bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
-    impl->mutex_.lock();
-    bool first = (++impl->count_ == 1);
-    if (can_dispatch && first)
-    {
-      // Immediate invocation is allowed.
-      impl->mutex_.unlock();
-
-      // Memory must be releaesed before any upcall is made.
-      ptr.reset();
-
-      // Indicate that this strand is executing on the current thread.
-      call_stack<strand_impl>::context ctx(impl);
-
-      // Ensure the next handler, if any, is scheduled on block exit.
-      on_dispatch_exit on_exit = { &io_service_, impl };
-      (void)on_exit;
-
-      asio::detail::fenced_block b;
-      asio_handler_invoke_helpers::invoke(handler, handler);
-      return;
-    }
-
-    // Immediate invocation is not allowed, so enqueue for later.
-    impl->queue_.push(ptr.get());
-    impl->mutex_.unlock();
-    ptr.release();
-
-    // The first handler to be enqueued is responsible for scheduling the
-    // strand.
-    if (first)
-      io_service_.post_immediate_completion(impl);
-  }
+  void dispatch(implementation_type& impl, Handler handler);
 
   // Request the io_service to invoke the given handler and return immediately.
   template <typename Handler>
-  void post(implementation_type& impl, Handler handler)
-  {
-    // Allocate and construct an object to wrap the handler.
-    typedef completion_handler<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    // Add the handler to the queue.
-    impl->mutex_.lock();
-    bool first = (++impl->count_ == 1);
-    impl->queue_.push(ptr.get());
-    impl->mutex_.unlock();
-    ptr.release();
-
-    // The first handler to be enqueue is responsible for scheduling the strand.
-    if (first)
-      io_service_.post_immediate_completion(impl);
-  }
+  void post(implementation_type& impl, Handler handler);
 
 private:
-  static void do_complete(io_service_impl* owner, operation* base,
-      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-  {
-    if (owner)
-    {
-      strand_impl* impl = static_cast<strand_impl*>(base);
-
-      // Get the next handler to be executed.
-      impl->mutex_.lock();
-      operation* o = impl->queue_.front();
-      impl->queue_.pop();
-      impl->mutex_.unlock();
-
-      // Indicate that this strand is executing on the current thread.
-      call_stack<strand_impl>::context ctx(impl);
-
-      // Ensure the next handler, if any, is scheduled on block exit.
-      on_do_complete_exit on_exit = { owner, impl };
-      (void)on_exit;
-
-      o->complete(*owner);
-    }
-  }
-
-  // Helper class to re-post the strand on exit.
-  struct on_do_complete_exit
-  {
-    io_service_impl* owner_;
-    strand_impl* impl_;
-
-    ~on_do_complete_exit()
-    {
-      impl_->mutex_.lock();
-      bool more_handlers = (--impl_->count_ > 0);
-      impl_->mutex_.unlock();
-
-      if (more_handlers)
-        owner_->post_immediate_completion(impl_);
-    }
-  };
-
-  // Helper class to re-post the strand on exit.
-  struct on_dispatch_exit
-  {
-    io_service_impl* io_service_;
-    strand_impl* impl_;
-
-    ~on_dispatch_exit()
-    {
-      impl_->mutex_.lock();
-      bool more_handlers = (--impl_->count_ > 0);
-      impl_->mutex_.unlock();
-
-      if (more_handlers)
-        io_service_->post_immediate_completion(impl_);
-    }
-  };
+  ASIO_DECL static void do_complete(io_service_impl* owner,
+      operation* base, asio::error_code ec,
+      std::size_t bytes_transferred);
 
   // The io_service implementation used to post completions.
   io_service_impl& io_service_;
@@ -273,4 +112,9 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/strand_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/ext/asio/asio/detail/task_io_service.hpp b/ext/asio/asio/detail/task_io_service.hpp
index eb77c1d..2d69513 100644
--- a/ext/asio/asio/detail/task_io_service.hpp
+++ b/ext/asio/asio/detail/task_io_service.hpp
@@ -1,8 +1,8 @@
 //
-// task_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,180 +15,59 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
 
+#include <boost/detail/atomic_count.hpp>
 #include "asio/error_code.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/event.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/op_queue.hpp"
-#include "asio/detail/service_base.hpp"
+#include "asio/detail/reactor_fwd.hpp"
 #include "asio/detail/task_io_service_fwd.hpp"
 #include "asio/detail/task_io_service_operation.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/detail/atomic_count.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
 
-template <typename Task>
 class task_io_service
-  : public asio::detail::service_base<task_io_service<Task> >
+  : public asio::detail::service_base<task_io_service>
 {
 public:
-  typedef task_io_service_operation<Task> operation;
+  typedef task_io_service_operation operation;
 
   // Constructor.
-  task_io_service(asio::io_service& io_service)
-    : asio::detail::service_base<task_io_service<Task> >(io_service),
-      mutex_(),
-      task_(0),
-      task_interrupted_(true),
-      outstanding_work_(0),
-      stopped_(false),
-      shutdown_(false),
-      first_idle_thread_(0)
-  {
-  }
+  ASIO_DECL task_io_service(asio::io_service& io_service);
 
-  void init(size_t /*concurrency_hint*/)
-  {
-  }
+  // How many concurrent threads are likely to run the io_service.
+  ASIO_DECL void init(std::size_t concurrency_hint);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    shutdown_ = true;
-    lock.unlock();
-
-    // Destroy handler objects.
-    while (!op_queue_.empty())
-    {
-      operation* o = op_queue_.front();
-      op_queue_.pop();
-      if (o != &task_operation_)
-        o->destroy();
-    }
-
-    // Reset to initial state.
-    task_ = 0;
-  }
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task, if required.
-  void init_task()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (!shutdown_ && !task_)
-    {
-      task_ = &use_service<Task>(this->get_io_service());
-      op_queue_.push(&task_operation_);
-      wake_one_thread_and_unlock(lock);
-    }
-  }
+  ASIO_DECL void init_task();
 
   // Run the event loop until interrupted or no more work.
-  size_t run(asio::error_code& ec)
-  {
-    ec = asio::error_code();
-    if (outstanding_work_ == 0)
-    {
-      stop();
-      return 0;
-    }
-
-    typename call_stack<task_io_service>::context ctx(this);
-
-    idle_thread_info this_idle_thread;
-    this_idle_thread.next = 0;
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    size_t n = 0;
-    for (; do_one(lock, &this_idle_thread); lock.lock())
-      if (n != (std::numeric_limits<size_t>::max)())
-        ++n;
-    return n;
-  }
+  ASIO_DECL std::size_t run(asio::error_code& ec);
 
   // Run until interrupted or one operation is performed.
-  size_t run_one(asio::error_code& ec)
-  {
-    ec = asio::error_code();
-    if (outstanding_work_ == 0)
-    {
-      stop();
-      return 0;
-    }
-
-    typename call_stack<task_io_service>::context ctx(this);
-
-    idle_thread_info this_idle_thread;
-    this_idle_thread.next = 0;
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    return do_one(lock, &this_idle_thread);
-  }
+  ASIO_DECL std::size_t run_one(asio::error_code& ec);
 
   // Poll for operations without blocking.
-  size_t poll(asio::error_code& ec)
-  {
-    if (outstanding_work_ == 0)
-    {
-      stop();
-      ec = asio::error_code();
-      return 0;
-    }
-
-    typename call_stack<task_io_service>::context ctx(this);
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    size_t n = 0;
-    for (; do_one(lock, 0); lock.lock())
-      if (n != (std::numeric_limits<size_t>::max)())
-        ++n;
-    return n;
-  }
+  ASIO_DECL std::size_t poll(asio::error_code& ec);
 
   // Poll for one operation without blocking.
-  size_t poll_one(asio::error_code& ec)
-  {
-    ec = asio::error_code();
-    if (outstanding_work_ == 0)
-    {
-      stop();
-      return 0;
-    }
-
-    typename call_stack<task_io_service>::context ctx(this);
-
-    asio::detail::mutex::scoped_lock lock(mutex_);
-
-    return do_one(lock, 0);
-  }
+  ASIO_DECL std::size_t poll_one(asio::error_code& ec);
 
   // Interrupt the event processing loop.
-  void stop()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    stop_all_threads(lock);
-  }
+  ASIO_DECL void stop();
 
   // Reset in preparation for a subsequent run invocation.
-  void reset()
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    stopped_ = false;
-  }
+  ASIO_DECL void reset();
 
   // Notify that some work has started.
   void work_started()
@@ -205,228 +84,60 @@ public:
 
   // Request invocation of the given handler.
   template <typename Handler>
-  void dispatch(Handler handler)
-  {
-    if (call_stack<task_io_service>::contains(this))
-    {
-      asio::detail::fenced_block b;
-      asio_handler_invoke_helpers::invoke(handler, handler);
-    }
-    else
-      post(handler);
-  }
+  void dispatch(Handler handler);
 
   // Request invocation of the given handler and return immediately.
   template <typename Handler>
-  void post(Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef completion_handler<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    post_immediate_completion(ptr.get());
-    ptr.release();
-  }
+  void post(Handler handler);
 
   // Request invocation of the given operation and return immediately. Assumes
   // that work_started() has not yet been called for the operation.
-  void post_immediate_completion(operation* op)
-  {
-    work_started();
-    post_deferred_completion(op);
-  }
+  ASIO_DECL void post_immediate_completion(operation* op);
 
   // Request invocation of the given operation and return immediately. Assumes
   // that work_started() was previously called for the operation.
-  void post_deferred_completion(operation* op)
-  {
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    op_queue_.push(op);
-    wake_one_thread_and_unlock(lock);
-  }
+  ASIO_DECL void post_deferred_completion(operation* op);
 
   // Request invocation of the given operations and return immediately. Assumes
   // that work_started() was previously called for each operation.
-  void post_deferred_completions(op_queue<operation>& ops)
-  {
-    if (!ops.empty())
-    {
-      asio::detail::mutex::scoped_lock lock(mutex_);
-      op_queue_.push(ops);
-      wake_one_thread_and_unlock(lock);
-    }
-  }
+  ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
 
 private:
+  // Structure containing information about an idle thread.
   struct idle_thread_info;
 
-  size_t do_one(asio::detail::mutex::scoped_lock& lock,
-      idle_thread_info* this_idle_thread)
-  {
-    bool polling = !this_idle_thread;
-    bool task_has_run = false;
-    while (!stopped_)
-    {
-      if (!op_queue_.empty())
-      {
-        // Prepare to execute first handler from queue.
-        operation* o = op_queue_.front();
-        op_queue_.pop();
-        bool more_handlers = (!op_queue_.empty());
-
-        if (o == &task_operation_)
-        {
-          task_interrupted_ = more_handlers || polling;
-
-          // If the task has already run and we're polling then we're done.
-          if (task_has_run && polling)
-          {
-            task_interrupted_ = true;
-            op_queue_.push(&task_operation_);
-            return 0;
-          }
-          task_has_run = true;
-
-          if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
-            lock.unlock();
-
-          op_queue<operation> completed_ops;
-          task_cleanup c = { this, &lock, &completed_ops };
-          (void)c;
-
-          // Run the task. May throw an exception. Only block if the operation
-          // queue is empty and we're not polling, otherwise we want to return
-          // as soon as possible.
-          task_->run(!more_handlers && !polling, completed_ops);
-        }
-        else
-        {
-          if (more_handlers)
-            wake_one_thread_and_unlock(lock);
-          else
-            lock.unlock();
-
-          // Ensure the count of outstanding work is decremented on block exit.
-          work_finished_on_block_exit on_exit = { this };
-          (void)on_exit;
-
-          // Complete the operation. May throw an exception.
-          o->complete(*this); // deletes the operation object
-
-          return 1;
-        }
-      }
-      else if (this_idle_thread)
-      {
-        // Nothing to run right now, so just wait for work to do.
-        this_idle_thread->next = first_idle_thread_;
-        first_idle_thread_ = this_idle_thread;
-        this_idle_thread->wakeup_event.clear(lock);
-        this_idle_thread->wakeup_event.wait(lock);
-      }
-      else
-      {
-        return 0;
-      }
-    }
-
-    return 0;
-  }
+  // Run at most one operation. Blocks only if this_idle_thread is non-null.
+  ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock,
+      idle_thread_info* this_idle_thread);
 
   // Stop the task and all idle threads.
-  void stop_all_threads(
-      asio::detail::mutex::scoped_lock& lock)
-  {
-    stopped_ = true;
-
-    while (first_idle_thread_)
-    {
-      idle_thread_info* idle_thread = first_idle_thread_;
-      first_idle_thread_ = idle_thread->next;
-      idle_thread->next = 0;
-      idle_thread->wakeup_event.signal(lock);
-    }
-
-    if (!task_interrupted_ && task_)
-    {
-      task_interrupted_ = true;
-      task_->interrupt();
-    }
-  }
+  ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
 
   // Wakes a single idle thread and unlocks the mutex. Returns true if an idle
   // thread was found. If there is no idle thread, returns false and leaves the
   // mutex locked.
-  bool wake_one_idle_thread_and_unlock(
-      asio::detail::mutex::scoped_lock& lock)
-  {
-    if (first_idle_thread_)
-    {
-      idle_thread_info* idle_thread = first_idle_thread_;
-      first_idle_thread_ = idle_thread->next;
-      idle_thread->next = 0;
-      idle_thread->wakeup_event.signal_and_unlock(lock);
-      return true;
-    }
-    return false;
-  }
+  ASIO_DECL bool wake_one_idle_thread_and_unlock(
+      mutex::scoped_lock& lock);
 
   // Wake a single idle thread, or the task, and always unlock the mutex.
-  void wake_one_thread_and_unlock(
-      asio::detail::mutex::scoped_lock& lock)
-  {
-    if (!wake_one_idle_thread_and_unlock(lock))
-    {
-      if (!task_interrupted_ && task_)
-      {
-        task_interrupted_ = true;
-        task_->interrupt();
-      }
-      lock.unlock();
-    }
-  }
+  ASIO_DECL void wake_one_thread_and_unlock(
+      mutex::scoped_lock& lock);
 
   // Helper class to perform task-related operations on block exit.
   struct task_cleanup;
   friend struct task_cleanup;
-  struct task_cleanup
-  {
-    ~task_cleanup()
-    {
-      // Enqueue the completed operations and reinsert the task at the end of
-      // the operation queue.
-      lock_->lock();
-      task_io_service_->task_interrupted_ = true;
-      task_io_service_->op_queue_.push(*ops_);
-      task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
-    }
-
-    task_io_service* task_io_service_;
-    asio::detail::mutex::scoped_lock* lock_;
-    op_queue<operation>* ops_;
-  };
 
   // Helper class to call work_finished() on block exit.
-  struct work_finished_on_block_exit
-  {
-    ~work_finished_on_block_exit()
-    {
-      task_io_service_->work_finished();
-    }
-
-    task_io_service* task_io_service_;
-  };
+  struct work_finished_on_block_exit;
 
   // Mutex to protect access to internal data.
-  asio::detail::mutex mutex_;
+  mutex mutex_;
 
   // The task to be run by this service.
-  Task* task_;
+  reactor* task_;
 
   // Operation object to represent the position of the task in the queue.
-  struct task_operation : public operation
+  struct task_operation : operation
   {
     task_operation() : operation(0) {}
   } task_operation_;
@@ -446,13 +157,6 @@ private:
   // Flag to indicate that the dispatcher has been shut down.
   bool shutdown_;
 
-  // Structure containing information about an idle thread.
-  struct idle_thread_info
-  {
-    event wakeup_event;
-    idle_thread_info* next;
-  };
-
   // The threads that are currently idle.
   idle_thread_info* first_idle_thread_;
 };
@@ -462,4 +166,11 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/task_io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/task_io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/task_io_service_fwd.hpp b/ext/asio/asio/detail/task_io_service_fwd.hpp
index 5b18d1d..b66cb07 100644
--- a/ext/asio/asio/detail/task_io_service_fwd.hpp
+++ b/ext/asio/asio/detail/task_io_service_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// task_io_service_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 namespace detail {
 
-template <typename Task>
 class task_io_service;
 
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
diff --git a/ext/asio/asio/detail/task_io_service_operation.hpp b/ext/asio/asio/detail/task_io_service_operation.hpp
index 6776f69..dd4384a 100644
--- a/ext/asio/asio/detail/task_io_service_operation.hpp
+++ b/ext/asio/asio/detail/task_io_service_operation.hpp
@@ -1,8 +1,8 @@
 //
-// task_io_service_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,21 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 #include "asio/error_code.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/task_io_service_fwd.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
 // Base class for all operations. A function pointer is used instead of virtual
 // functions to avoid the associated overhead.
-template <typename Task>
 class task_io_service_operation
 {
 public:
-  void complete(task_io_service<Task>& owner)
+  void complete(task_io_service& owner)
   {
     func_(&owner, this, asio::error_code(), 0);
   }
@@ -41,8 +40,9 @@ public:
   }
 
 protected:
-  typedef void (*func_type)(task_io_service<Task>*,
-      task_io_service_operation*, asio::error_code, std::size_t);
+  typedef void (*func_type)(task_io_service*,
+      task_io_service_operation*,
+      asio::error_code, std::size_t);
 
   task_io_service_operation(func_type func)
     : next_(0),
diff --git a/ext/asio/asio/detail/thread.hpp b/ext/asio/asio/detail/thread.hpp
index 3c9280b..7c4103b 100644
--- a/ext/asio/asio/detail/thread.hpp
+++ b/ext/asio/asio/detail/thread.hpp
@@ -1,8 +1,8 @@
 //
-// thread.hpp
-// ~~~~~~~~~~
+// detail/thread.hpp
+// ~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 # include "asio/detail/null_thread.hpp"
@@ -53,6 +49,4 @@ typedef posix_thread thread;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_THREAD_HPP
diff --git a/ext/asio/asio/detail/throw_error.hpp b/ext/asio/asio/detail/throw_error.hpp
index 51d6e48..d39aa92 100644
--- a/ext/asio/asio/detail/throw_error.hpp
+++ b/ext/asio/asio/detail/throw_error.hpp
@@ -1,8 +1,8 @@
 //
-// throw_error.hpp
-// ~~~~~~~~~~~~~~~
+// detail/throw_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,30 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
-#include "asio/system_error.hpp"
 
 namespace asio {
 namespace detail {
 
+ASIO_DECL void do_throw_error(const asio::error_code& err);
+
+ASIO_DECL void do_throw_error(const asio::error_code& err,
+    const char* location);
+
 inline void throw_error(const asio::error_code& err)
 {
   if (err)
-  {
-    asio::system_error e(err);
-    boost::throw_exception(e);
-  }
+    do_throw_error(err);
+}
+
+inline void throw_error(const asio::error_code& err,
+    const char* location)
+{
+  if (err)
+    do_throw_error(err, location);
 }
 
 } // namespace detail
@@ -41,4 +46,8 @@ inline void throw_error(const asio::error_code& err)
 
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/throw_error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/ext/asio/asio/detail/timer_op.hpp b/ext/asio/asio/detail/timer_op.hpp
index bf3c3ae..62cd292 100644
--- a/ext/asio/asio/detail/timer_op.hpp
+++ b/ext/asio/asio/detail/timer_op.hpp
@@ -1,8 +1,8 @@
 //
-// timer_op.hpp
-// ~~~~~~~~~~~~
+// detail/timer_op.hpp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/operation.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/timer_queue.hpp b/ext/asio/asio/detail/timer_queue.hpp
index 2e4d2d5..514c434 100644
--- a/ext/asio/asio/detail/timer_queue.hpp
+++ b/ext/asio/asio/detail/timer_queue.hpp
@@ -1,8 +1,8 @@
 //
-// timer_queue.hpp
-// ~~~~~~~~~~~~~~~
+// detail/timer_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,22 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <memory>
 #include <vector>
 #include <boost/config.hpp>
 #include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/detail/hash_map.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
+#include "asio/error.hpp"
+#include "asio/time_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -45,6 +46,26 @@ public:
   // The duration type.
   typedef typename Time_Traits::duration_type duration_type;
 
+  // Per-timer data.
+  class per_timer_data
+  {
+  public:
+    per_timer_data() : next_(0), prev_(0) {}
+
+  private:
+    friend class timer_queue;
+
+    // The operations waiting on the timer.
+    op_queue<timer_op> op_queue_;
+
+    // The index of the timer in the heap.
+    std::size_t heap_index_;
+
+    // Pointers to adjacent timers in a linked list.
+    per_timer_data* next_;
+    per_timer_data* prev_;
+  };
+
   // Constructor.
   timer_queue()
     : timers_(),
@@ -55,35 +76,45 @@ public:
   // Add a new timer to the queue. Returns true if this is the timer that is
   // earliest in the queue, in which case the reactor's event demultiplexing
   // function call may need to be interrupted and restarted.
-  bool enqueue_timer(const time_type& time, timer_op* op, void* token)
+  bool enqueue_timer(const time_type& time, per_timer_data& timer, timer_op* op)
   {
-    // Ensure that there is space for the timer in the heap. We reserve here so
-    // that the push_back below will not throw due to a reallocation failure.
-    heap_.reserve(heap_.size() + 1);
-
-    // Insert the new timer into the hash.
-    typedef typename hash_map<void*, timer>::iterator iterator;
-    typedef typename hash_map<void*, timer>::value_type value_type;
-    std::pair<iterator, bool> result =
-      timers_.insert(value_type(token, timer()));
-    result.first->second.op_queue_.push(op);
-    if (result.second)
+    // Enqueue the timer object.
+    if (timer.prev_ == 0 && &timer != timers_)
     {
-      // Put the new timer at the correct position in the heap.
-      result.first->second.time_ = time;
-      result.first->second.heap_index_ = heap_.size();
-      result.first->second.token_ = token;
-      heap_.push_back(&result.first->second);
-      up_heap(heap_.size() - 1);
+      if (this->is_positive_infinity(time))
+      {
+        // No heap entry is required for timers that never expire.
+        timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+      }
+      else
+      {
+        // Put the new timer at the correct position in the heap. This is done
+        // first since push_back() can throw due to allocation failure.
+        timer.heap_index_ = heap_.size();
+        heap_entry entry = { time, &timer };
+        heap_.push_back(entry);
+        up_heap(heap_.size() - 1);
+      }
+
+      // Insert the new timer into the linked list of active timers.
+      timer.next_ = timers_;
+      timer.prev_ = 0;
+      if (timers_)
+        timers_->prev_ = &timer;
+      timers_ = &timer;
     }
 
-    return (heap_[0] == &result.first->second);
+    // Enqueue the individual timer operation.
+    timer.op_queue_.push(op);
+
+    // Interrupt reactor only if newly added timer is first to expire.
+    return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
   }
 
   // Whether there are no timers in the queue.
   virtual bool empty() const
   {
-    return heap_.empty();
+    return timers_ == 0;
   }
 
   // Get the time for the timer that is earliest in the queue.
@@ -93,12 +124,14 @@ public:
       return max_duration;
 
     boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
-        Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+        Time_Traits::subtract(heap_[0].time_, Time_Traits::now()));
 
     if (duration > boost::posix_time::milliseconds(max_duration))
       duration = boost::posix_time::milliseconds(max_duration);
-    else if (duration < boost::posix_time::milliseconds(0))
+    else if (duration <= boost::posix_time::milliseconds(0))
       duration = boost::posix_time::milliseconds(0);
+    else if (duration < boost::posix_time::milliseconds(1))
+      duration = boost::posix_time::milliseconds(1);
 
     return duration.total_milliseconds();
   }
@@ -110,12 +143,14 @@ public:
       return max_duration;
 
     boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
-        Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+        Time_Traits::subtract(heap_[0].time_, Time_Traits::now()));
 
     if (duration > boost::posix_time::microseconds(max_duration))
       duration = boost::posix_time::microseconds(max_duration);
-    else if (duration < boost::posix_time::microseconds(0))
+    else if (duration <= boost::posix_time::microseconds(0))
       duration = boost::posix_time::microseconds(0);
+    else if (duration < boost::posix_time::microseconds(1))
+      duration = boost::posix_time::microseconds(1);
 
     return duration.total_microseconds();
   }
@@ -124,77 +159,54 @@ public:
   virtual void get_ready_timers(op_queue<operation>& ops)
   {
     const time_type now = Time_Traits::now();
-    while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
+    while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))
     {
-      timer* t = heap_[0];
-      ops.push(t->op_queue_);
-      remove_timer(t);
+      per_timer_data* timer = heap_[0].timer_;
+      ops.push(timer->op_queue_);
+      remove_timer(*timer);
     }
   }
 
   // Dequeue all timers.
   virtual void get_all_timers(op_queue<operation>& ops)
   {
-    typename hash_map<void*, timer>::iterator i = timers_.begin();
-    typename hash_map<void*, timer>::iterator end = timers_.end();
-    while (i != end)
+    while (timers_)
     {
-      ops.push(i->second.op_queue_);
-      typename hash_map<void*, timer>::iterator old_i = i++;
-      timers_.erase(old_i);
+      per_timer_data* timer = timers_;
+      timers_ = timers_->next_;
+      ops.push(timer->op_queue_);
+      timer->next_ = 0;
+      timer->prev_ = 0;
     }
 
     heap_.clear();
-    timers_.clear();
   }
 
   // Cancel and dequeue the timers with the given token.
-  std::size_t cancel_timer(void* timer_token, op_queue<operation>& ops)
+  std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops)
   {
     std::size_t num_cancelled = 0;
-    typedef typename hash_map<void*, timer>::iterator iterator;
-    iterator it = timers_.find(timer_token);
-    if (it != timers_.end())
+    if (timer.prev_ != 0 || &timer == timers_)
     {
-      while (timer_op* op = it->second.op_queue_.front())
+      while (timer_op* op = timer.op_queue_.front())
       {
         op->ec_ = asio::error::operation_aborted;
-        it->second.op_queue_.pop();
+        timer.op_queue_.pop();
         ops.push(op);
         ++num_cancelled;
       }
-      remove_timer(&it->second);
+      remove_timer(timer);
     }
     return num_cancelled;
   }
 
 private:
-  // Structure representing a single outstanding timer.
-  struct timer
-  {
-    timer() {}
-    timer(const timer&) {}
-    void operator=(const timer&) {}
-
-    // The time when the timer should fire.
-    time_type time_;
-
-    // The operations waiting on the timer.
-    op_queue<timer_op> op_queue_;
-
-    // The index of the timer in the heap.
-    size_t heap_index_;
-
-    // The token associated with the timer.
-    void* token_;
-  };
-
   // Move the item at the given index up the heap to its correct position.
-  void up_heap(size_t index)
+  void up_heap(std::size_t index)
   {
-    size_t parent = (index - 1) / 2;
+    std::size_t parent = (index - 1) / 2;
     while (index > 0
-        && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
+        && Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))
     {
       swap_heap(index, parent);
       index = parent;
@@ -203,16 +215,16 @@ private:
   }
 
   // Move the item at the given index down the heap to its correct position.
-  void down_heap(size_t index)
+  void down_heap(std::size_t index)
   {
-    size_t child = index * 2 + 1;
+    std::size_t child = index * 2 + 1;
     while (child < heap_.size())
     {
-      size_t min_child = (child + 1 == heap_.size()
+      std::size_t min_child = (child + 1 == heap_.size()
           || Time_Traits::less_than(
-            heap_[child]->time_, heap_[child + 1]->time_))
+            heap_[child].time_, heap_[child + 1].time_))
         ? child : child + 1;
-      if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
+      if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))
         break;
       swap_heap(index, min_child);
       index = min_child;
@@ -221,20 +233,20 @@ private:
   }
 
   // Swap two entries in the heap.
-  void swap_heap(size_t index1, size_t index2)
+  void swap_heap(std::size_t index1, std::size_t index2)
   {
-    timer* tmp = heap_[index1];
+    heap_entry tmp = heap_[index1];
     heap_[index1] = heap_[index2];
     heap_[index2] = tmp;
-    heap_[index1]->heap_index_ = index1;
-    heap_[index2]->heap_index_ = index2;
+    heap_[index1].timer_->heap_index_ = index1;
+    heap_[index2].timer_->heap_index_ = index2;
   }
 
   // Remove a timer from the heap and list of timers.
-  void remove_timer(timer* t)
+  void remove_timer(per_timer_data& timer)
   {
     // Remove the timer from the heap.
-    size_t index = t->heap_index_;
+    std::size_t index = timer.heap_index_;
     if (!heap_.empty() && index < heap_.size())
     {
       if (index == heap_.size() - 1)
@@ -245,29 +257,112 @@ private:
       {
         swap_heap(index, heap_.size() - 1);
         heap_.pop_back();
-        size_t parent = (index - 1) / 2;
+        std::size_t parent = (index - 1) / 2;
         if (index > 0 && Time_Traits::less_than(
-              heap_[index]->time_, heap_[parent]->time_))
+              heap_[index].time_, heap_[parent].time_))
           up_heap(index);
         else
           down_heap(index);
       }
     }
 
-    // Remove the timer from the hash.
-    typedef typename hash_map<void*, timer>::iterator iterator;
-    iterator it = timers_.find(t->token_);
-    if (it != timers_.end())
-      timers_.erase(it);
+    // Remove the timer from the linked list of active timers.
+    if (timers_ == &timer)
+      timers_ = timer.next_;
+    if (timer.prev_)
+      timer.prev_->next_ = timer.next_;
+    if (timer.next_)
+      timer.next_->prev_= timer.prev_;
+    timer.next_ = 0;
+    timer.prev_ = 0;
+  }
+
+  // Determine if the specified absolute time is positive infinity.
+  template <typename Time_Type>
+  static bool is_positive_infinity(const Time_Type&)
+  {
+    return false;
+  }
+
+  // Determine if the specified absolute time is positive infinity.
+  static bool is_positive_infinity(const boost::posix_time::ptime& time)
+  {
+    return time == boost::posix_time::pos_infin;
   }
 
-  // A hash of timer token to linked lists of timers.
-  hash_map<void*, timer> timers_;
+  // The head of a linked list of all active timers.
+  per_timer_data* timers_;
+
+  struct heap_entry
+  {
+    // The time when the timer should fire.
+    time_type time_;
+
+    // The associated timer with enqueued operations.
+    per_timer_data* timer_;
+  };
 
   // The heap of timers, with the earliest timer at the front.
-  std::vector<timer*> heap_;
+  std::vector<heap_entry> heap_;
 };
 
+#if !defined(ASIO_HEADER_ONLY)
+
+struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {};
+
+// Template specialisation for the commonly used instantation.
+template <>
+class timer_queue<time_traits<boost::posix_time::ptime> >
+  : public timer_queue_base
+{
+public:
+  // The time type.
+  typedef boost::posix_time::ptime time_type;
+
+  // The duration type.
+  typedef boost::posix_time::time_duration duration_type;
+
+  // Per-timer data.
+  typedef timer_queue<forwarding_posix_time_traits>::per_timer_data
+    per_timer_data;
+
+  // Constructor.
+  ASIO_DECL timer_queue();
+
+  // Destructor.
+  ASIO_DECL virtual ~timer_queue();
+
+  // Add a new timer to the queue. Returns true if this is the timer that is
+  // earliest in the queue, in which case the reactor's event demultiplexing
+  // function call may need to be interrupted and restarted.
+  ASIO_DECL bool enqueue_timer(const time_type& time,
+      per_timer_data& timer, timer_op* op);
+
+  // Whether there are no timers in the queue.
+  ASIO_DECL virtual bool empty() const;
+
+  // Get the time for the timer that is earliest in the queue.
+  ASIO_DECL virtual long wait_duration_msec(long max_duration) const;
+
+  // Get the time for the timer that is earliest in the queue.
+  ASIO_DECL virtual long wait_duration_usec(long max_duration) const;
+
+  // Dequeue all timers not later than the current time.
+  ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops);
+
+  // Dequeue all timers.
+  ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops);
+
+  // Cancel and dequeue the timers with the given token.
+  ASIO_DECL std::size_t cancel_timer(
+      per_timer_data& timer, op_queue<operation>& ops);
+
+private:
+  timer_queue<forwarding_posix_time_traits> impl_;
+};
+
+#endif // !defined(ASIO_HEADER_ONLY)
+
 } // namespace detail
 } // namespace asio
 
diff --git a/ext/asio/asio/detail/timer_queue_base.hpp b/ext/asio/asio/detail/timer_queue_base.hpp
index f978667..0e8d4c7 100644
--- a/ext/asio/asio/detail/timer_queue_base.hpp
+++ b/ext/asio/asio/detail/timer_queue_base.hpp
@@ -1,8 +1,8 @@
 //
-// timer_queue_base.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/op_queue.hpp"
 #include "asio/detail/operation.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/timer_queue_fwd.hpp b/ext/asio/asio/detail/timer_queue_fwd.hpp
index 5317244..0cca967 100644
--- a/ext/asio/asio/detail/timer_queue_fwd.hpp
+++ b/ext/asio/asio/detail/timer_queue_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// timer_queue_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 namespace asio {
 namespace detail {
 
@@ -26,6 +24,4 @@ class timer_queue;
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_TIMER_QUEUE_FWD_HPP
diff --git a/ext/asio/asio/detail/timer_queue_set.hpp b/ext/asio/asio/detail/timer_queue_set.hpp
index 6860867..9e8d428 100644
--- a/ext/asio/asio/detail/timer_queue_set.hpp
+++ b/ext/asio/asio/detail/timer_queue_set.hpp
@@ -1,8 +1,8 @@
 //
-// timer_queue_set.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_set.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -26,82 +27,28 @@ class timer_queue_set
 {
 public:
   // Constructor.
-  timer_queue_set()
-    : first_(0)
-  {
-  }
+  ASIO_DECL timer_queue_set();
 
   // Add a timer queue to the set.
-  void insert(timer_queue_base* q)
-  {
-    q->next_ = first_;
-    first_ = q;
-  }
+  ASIO_DECL void insert(timer_queue_base* q);
 
   // Remove a timer queue from the set.
-  void erase(timer_queue_base* q)
-  {
-    if (first_)
-    {
-      if (q == first_)
-      {
-        first_ = q->next_;
-        q->next_ = 0;
-        return;
-      }
-
-      for (timer_queue_base* p = first_; p->next_; p = p->next_)
-      {
-        if (p->next_ == q)
-        {
-          p->next_ = q->next_;
-          q->next_ = 0;
-          return;
-        }
-      }
-    }
-  }
+  ASIO_DECL void erase(timer_queue_base* q);
 
   // Determine whether all queues are empty.
-  bool all_empty() const
-  {
-    for (timer_queue_base* p = first_; p; p = p->next_)
-      if (!p->empty())
-        return false;
-    return true;
-  }
+  ASIO_DECL bool all_empty() const;
 
   // Get the wait duration in milliseconds.
-  long wait_duration_msec(long max_duration) const
-  {
-    long min_duration = max_duration;
-    for (timer_queue_base* p = first_; p; p = p->next_)
-      min_duration = p->wait_duration_msec(min_duration);
-    return min_duration;
-  }
+  ASIO_DECL long wait_duration_msec(long max_duration) const;
 
   // Get the wait duration in microseconds.
-  long wait_duration_usec(long max_duration) const
-  {
-    long min_duration = max_duration;
-    for (timer_queue_base* p = first_; p; p = p->next_)
-      min_duration = p->wait_duration_usec(min_duration);
-    return min_duration;
-  }
+  ASIO_DECL long wait_duration_usec(long max_duration) const;
 
   // Dequeue all ready timers.
-  void get_ready_timers(op_queue<operation>& ops)
-  {
-    for (timer_queue_base* p = first_; p; p = p->next_)
-      p->get_ready_timers(ops);
-  }
+  ASIO_DECL void get_ready_timers(op_queue<operation>& ops);
 
   // Dequeue all timers.
-  void get_all_timers(op_queue<operation>& ops)
-  {
-    for (timer_queue_base* p = first_; p; p = p->next_)
-      p->get_all_timers(ops);
-  }
+  ASIO_DECL void get_all_timers(op_queue<operation>& ops);
 
 private:
   timer_queue_base* first_;
@@ -112,4 +59,8 @@ private:
 
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_set.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP
diff --git a/ext/asio/asio/detail/timer_scheduler.hpp b/ext/asio/asio/detail/timer_scheduler.hpp
index 6822d3f..1222e63 100644
--- a/ext/asio/asio/detail/timer_scheduler.hpp
+++ b/ext/asio/asio/detail/timer_scheduler.hpp
@@ -1,8 +1,8 @@
 //
-// timer_scheduler.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/timer_scheduler_fwd.hpp"
 
 #if defined(ASIO_HAS_IOCP)
@@ -31,6 +30,4 @@
 # include "asio/detail/select_reactor.hpp"
 #endif
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP
diff --git a/ext/asio/asio/detail/timer_scheduler_fwd.hpp b/ext/asio/asio/detail/timer_scheduler_fwd.hpp
index d766a87..5fced50 100644
--- a/ext/asio/asio/detail/timer_scheduler_fwd.hpp
+++ b/ext/asio/asio/detail/timer_scheduler_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// timer_scheduler_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/timer_scheduler_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
-#include "asio/detail/epoll_reactor_fwd.hpp"
-#include "asio/detail/kqueue_reactor_fwd.hpp"
-#include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service_fwd.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor_fwd.hpp"
+#else
+# include "asio/detail/select_reactor_fwd.hpp"
+#endif
 
 namespace asio {
 namespace detail {
@@ -35,12 +41,10 @@ typedef kqueue_reactor timer_scheduler;
 #elif defined(ASIO_HAS_DEV_POLL)
 typedef dev_poll_reactor timer_scheduler;
 #else
-typedef select_reactor<false> timer_scheduler;
+typedef select_reactor timer_scheduler;
 #endif
 
 } // namespace detail
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
diff --git a/ext/asio/asio/detail/tss_ptr.hpp b/ext/asio/asio/detail/tss_ptr.hpp
index ac67d9f..0218f5f 100644
--- a/ext/asio/asio/detail/tss_ptr.hpp
+++ b/ext/asio/asio/detail/tss_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// tss_ptr.hpp
-// ~~~~~~~~~~~
+// detail/tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
 # include "asio/detail/null_tss_ptr.hpp"
@@ -31,6 +27,8 @@
 # error Only Windows and POSIX are supported!
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
diff --git a/ext/asio/asio/detail/wait_handler.hpp b/ext/asio/asio/detail/wait_handler.hpp
new file mode 100644
index 0000000..0df16cb
--- /dev/null
+++ b/ext/asio/asio/detail/wait_handler.hpp
@@ -0,0 +1,76 @@
+//
+// detail/wait_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WAIT_HANDLER_HPP
+#define ASIO_DETAIL_WAIT_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/timer_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class wait_handler : public timer_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(wait_handler);
+
+  wait_handler(Handler h)
+    : timer_op(&wait_handler::do_complete),
+      handler_(h)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    wait_handler* h(static_cast<wait_handler*>(base));
+    ptr p = { boost::addressof(h->handler_), h, h };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(h->handler_, h->ec_);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_HANDLER_HPP
diff --git a/ext/asio/asio/detail/weak_ptr.hpp b/ext/asio/asio/detail/weak_ptr.hpp
new file mode 100644
index 0000000..35dca19
--- /dev/null
+++ b/ext/asio/asio/detail/weak_ptr.hpp
@@ -0,0 +1,39 @@
+//
+// detail/weak_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WEAK_PTR_HPP
+#define ASIO_DETAIL_WEAK_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/version.hpp>
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+# include <memory>
+#else
+# include <boost/weak_ptr.hpp>
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+using std::weak_ptr;
+#else
+using boost::weak_ptr;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_WEAK_PTR_HPP
diff --git a/ext/asio/asio/detail/win_event.hpp b/ext/asio/asio/detail/win_event.hpp
index cabb2c3..71ad7e0 100644
--- a/ext/asio/asio/detail/win_event.hpp
+++ b/ext/asio/asio/detail/win_event.hpp
@@ -1,8 +1,8 @@
 //
-// win_event.hpp
-// ~~~~~~~~~~~~~
+// detail/win_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
+#include <boost/assert.hpp>
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_types.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/assert.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -41,19 +33,7 @@ class win_event
 {
 public:
   // Constructor.
-  win_event()
-    : event_(::CreateEvent(0, true, false, 0))
-  {
-    if (!event_)
-    {
-      DWORD last_error = ::GetLastError();
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "event");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL win_event();
 
   // Destructor.
   ~win_event()
@@ -105,8 +85,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
 #endif // ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/ext/asio/asio/detail/win_fd_set_adapter.hpp b/ext/asio/asio/detail/win_fd_set_adapter.hpp
index 012a10f..0cb9d8c 100644
--- a/ext/asio/asio/detail/win_fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/win_fd_set_adapter.hpp
@@ -1,8 +1,8 @@
 //
-// win_fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
 #include "asio/detail/socket_types.hpp"
 
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -81,8 +83,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/win_fenced_block.hpp b/ext/asio/asio/detail/win_fenced_block.hpp
index 6338488..011f44b 100644
--- a/ext/asio/asio/detail/win_fenced_block.hpp
+++ b/ext/asio/asio/detail/win_fenced_block.hpp
@@ -1,8 +1,8 @@
 //
-// win_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/win_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
 
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -35,7 +33,10 @@ public:
   // Constructor.
   win_fenced_block()
   {
-#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#if defined(__BORLANDC__)
+    LONG barrier = 0;
+    ::InterlockedExchange(&barrier, 1);
+#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier))
 # if defined(_M_IX86)
 #  pragma warning(push)
 #  pragma warning(disable:4793)
@@ -43,15 +44,18 @@ public:
     __asm { xchg barrier, eax }
 #  pragma warning(pop)
 # endif // defined(_M_IX86)
-#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#else
     MemoryBarrier();
-#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#endif
   }
 
   // Destructor.
   ~win_fenced_block()
   {
-#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#if defined(__BORLANDC__)
+    LONG barrier = 0;
+    ::InterlockedExchange(&barrier, 1);
+#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier))
 # if defined(_M_IX86)
 #  pragma warning(push)
 #  pragma warning(disable:4793)
@@ -59,17 +63,17 @@ public:
     __asm { xchg barrier, eax }
 #  pragma warning(pop)
 # endif // defined(_M_IX86)
-#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#else
     MemoryBarrier();
-#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#endif
   }
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
 #endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_read_op.hpp b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp
new file mode 100644
index 0000000..fb358be
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp
@@ -0,0 +1,101 @@
+//
+// detail/win_iocp_handle_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_handle_read_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);
+
+  win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler)
+    : operation(&win_iocp_handle_read_op::do_complete),
+      buffers_(buffers),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (owner)
+    {
+      // Check whether buffers are still valid.
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    // Map non-portable errors to their portable counterparts.
+    if (ec.value() == ERROR_HANDLE_EOF)
+      ec = asio::error::eof;
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  MutableBufferSequence buffers_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_service.hpp b/ext/asio/asio/detail/win_iocp_handle_service.hpp
index bfc159c..34f725f 100644
--- a/ext/asio/asio/detail/win_iocp_handle_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_handle_service.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,26 +16,23 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 
-#include "asio/detail/push_options.hpp"
 #include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/bind_handler.hpp"
 #include "asio/detail/buffer_sequence_adapter.hpp"
 #include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/operation.hpp"
+#include "asio/detail/win_iocp_handle_read_op.hpp"
+#include "asio/detail/win_iocp_handle_write_op.hpp"
 #include "asio/detail/win_iocp_io_service.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -76,75 +73,20 @@ public:
     implementation_type* prev_;
   };
 
-  win_iocp_handle_service(asio::io_service& io_service)
-    : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
-      mutex_(),
-      impl_list_(0)
-  {
-  }
+  ASIO_DECL win_iocp_handle_service(asio::io_service& io_service);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    // Close all implementations, causing all operations to complete.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    implementation_type* impl = impl_list_;
-    while (impl)
-    {
-      close_for_destruction(*impl);
-      impl = impl->next_;
-    }
-  }
+  ASIO_DECL void shutdown_service();
 
   // Construct a new handle implementation.
-  void construct(implementation_type& impl)
-  {
-    impl.handle_ = INVALID_HANDLE_VALUE;
-    impl.safe_cancellation_thread_id_ = 0;
-
-    // Insert implementation into linked list of all implementations.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    impl.next_ = impl_list_;
-    impl.prev_ = 0;
-    if (impl_list_)
-      impl_list_->prev_ = &impl;
-    impl_list_ = &impl;
-  }
+  ASIO_DECL void construct(implementation_type& impl);
 
   // Destroy a handle implementation.
-  void destroy(implementation_type& impl)
-  {
-    close_for_destruction(impl);
-    
-    // Remove implementation from linked list of all implementations.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (impl_list_ == &impl)
-      impl_list_ = impl.next_;
-    if (impl.prev_)
-      impl.prev_->next_ = impl.next_;
-    if (impl.next_)
-      impl.next_->prev_= impl.prev_;
-    impl.next_ = 0;
-    impl.prev_ = 0;
-  }
+  ASIO_DECL void destroy(implementation_type& impl);
 
   // Assign a native handle to a handle implementation.
-  asio::error_code assign(implementation_type& impl,
-      const native_type& native_handle, asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    if (iocp_service_.register_handle(native_handle, ec))
-      return ec;
-
-    impl.handle_ = native_handle;
-    ec = asio::error_code();
-    return ec;
-  }
+  ASIO_DECL asio::error_code assign(implementation_type& impl,
+      const native_type& native_handle, asio::error_code& ec);
 
   // Determine whether the handle is open.
   bool is_open(const implementation_type& impl) const
@@ -153,26 +95,8 @@ public:
   }
 
   // Destroy a handle implementation.
-  asio::error_code close(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      if (!::CloseHandle(impl.handle_))
-      {
-        DWORD last_error = ::GetLastError();
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-        return ec;
-      }
-
-      impl.handle_ = INVALID_HANDLE_VALUE;
-      impl.safe_cancellation_thread_id_ = 0;
-    }
-
-    ec = asio::error_code();
-    return ec;
-  }
+  ASIO_DECL asio::error_code close(implementation_type& impl,
+      asio::error_code& ec);
 
   // Get the native handle representation.
   native_type native(const implementation_type& impl) const
@@ -181,106 +105,8 @@ public:
   }
 
   // Cancel all operations associated with the handle.
-  asio::error_code cancel(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-    }
-    else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
-          ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
-    {
-      // The version of Windows supports cancellation from any thread.
-      typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
-      cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
-      if (!cancel_io_ex(impl.handle_, 0))
-      {
-        DWORD last_error = ::GetLastError();
-        if (last_error == ERROR_NOT_FOUND)
-        {
-          // ERROR_NOT_FOUND means that there were no operations to be
-          // cancelled. We swallow this error to match the behaviour on other
-          // platforms.
-          ec = asio::error_code();
-        }
-        else
-        {
-          ec = asio::error_code(last_error,
-              asio::error::get_system_category());
-        }
-      }
-      else
-      {
-        ec = asio::error_code();
-      }
-    }
-    else if (impl.safe_cancellation_thread_id_ == 0)
-    {
-      // No operations have been started, so there's nothing to cancel.
-      ec = asio::error_code();
-    }
-    else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
-    {
-      // Asynchronous operations have been started from the current thread only,
-      // so it is safe to try to cancel them using CancelIo.
-      if (!::CancelIo(impl.handle_))
-      {
-        DWORD last_error = ::GetLastError();
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-      }
-      else
-      {
-        ec = asio::error_code();
-      }
-    }
-    else
-    {
-      // Asynchronous operations have been started from more than one thread,
-      // so cancellation is not safe.
-      ec = asio::error::operation_not_supported;
-    }
-
-    return ec;
-  }
-
-  class overlapped_wrapper
-    : public OVERLAPPED
-  {
-  public:
-    explicit overlapped_wrapper(asio::error_code& ec)
-    {
-      Internal = 0;
-      InternalHigh = 0;
-      Offset = 0;
-      OffsetHigh = 0;
-
-      // Create a non-signalled manual-reset event, for GetOverlappedResult.
-      hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
-      if (hEvent)
-      {
-        // As documented in GetQueuedCompletionStatus, setting the low order
-        // bit of this event prevents our synchronous writes from being treated
-        // as completion port events.
-        *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
-      }
-      else
-      {
-        DWORD last_error = ::GetLastError();
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-      }
-    }
-
-    ~overlapped_wrapper()
-    {
-      if (hEvent)
-      {
-        ::CloseHandle(hEvent);
-      }
-    }
-  };
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
 
   // Write the given data. Returns the number of bytes written.
   template <typename ConstBufferSequence>
@@ -296,109 +122,13 @@ public:
   size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
       const ConstBufferSequence& buffers, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     asio::const_buffer buffer =
       buffer_sequence_adapter<asio::const_buffer,
         ConstBufferSequence>::first(buffers);
 
-    // A request to write 0 bytes on a handle is a no-op.
-    if (asio::buffer_size(buffer) == 0)
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    overlapped_wrapper overlapped(ec);
-    if (ec)
-    {
-      return 0;
-    }
-
-    // Write the data. 
-    overlapped.Offset = offset & 0xFFFFFFFF;
-    overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
-    BOOL ok = ::WriteFile(impl.handle_,
-        asio::buffer_cast<LPCVOID>(buffer),
-        static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
-    if (!ok) 
-    {
-      DWORD last_error = ::GetLastError();
-      if (last_error != ERROR_IO_PENDING)
-      {
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-        return 0;
-      }
-    }
-
-    // Wait for the operation to complete.
-    DWORD bytes_transferred = 0;
-    ok = ::GetOverlappedResult(impl.handle_,
-        &overlapped, &bytes_transferred, TRUE);
-    if (!ok)
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return 0;
-    }
-
-    ec = asio::error_code();
-    return bytes_transferred;
+    return do_write(impl, offset, buffer, ec);
   }
 
-  template <typename ConstBufferSequence, typename Handler>
-  class write_op : public operation
-  {
-  public:
-    write_op(const ConstBufferSequence& buffers, Handler handler)
-      : operation(&write_op::do_complete),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      write_op* o(static_cast<write_op*>(base));
-      typedef handler_alloc_traits<Handler, write_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::const_buffer,
-            ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    ConstBufferSequence buffers_;
-    Handler handler_;
-  };
-
   // Start an asynchronous write. The data being written must be valid for the
   // lifetime of the asynchronous operation.
   template <typename ConstBufferSequence, typename Handler>
@@ -415,15 +145,16 @@ public:
       const ConstBufferSequence& buffers, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef write_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
+    typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(buffers, handler);
 
     start_write_op(impl, offset,
         buffer_sequence_adapter<asio::const_buffer,
-          ConstBufferSequence>::first(buffers), ptr.get());
-    ptr.release();
+          ConstBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
   }
 
   // Read some data. Returns the number of bytes received.
@@ -439,129 +170,13 @@ public:
   size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
       const MutableBufferSequence& buffers, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-    
     asio::mutable_buffer buffer =
       buffer_sequence_adapter<asio::mutable_buffer,
         MutableBufferSequence>::first(buffers);
 
-    // A request to read 0 bytes on a stream handle is a no-op.
-    if (asio::buffer_size(buffer) == 0)
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    overlapped_wrapper overlapped(ec);
-    if (ec)
-    {
-      return 0;
-    }
-
-    // Read some data.
-    overlapped.Offset = offset & 0xFFFFFFFF;
-    overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
-    BOOL ok = ::ReadFile(impl.handle_,
-        asio::buffer_cast<LPVOID>(buffer),
-        static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
-    if (!ok) 
-    {
-      DWORD last_error = ::GetLastError();
-      if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
-      {
-        if (last_error == ERROR_HANDLE_EOF)
-        {
-          ec = asio::error::eof;
-        }
-        else
-        {
-          ec = asio::error_code(last_error,
-              asio::error::get_system_category());
-        }
-        return 0;
-      }
-    }
-
-    // Wait for the operation to complete.
-    DWORD bytes_transferred = 0;
-    ok = ::GetOverlappedResult(impl.handle_,
-        &overlapped, &bytes_transferred, TRUE);
-    if (!ok)
-    {
-      DWORD last_error = ::GetLastError();
-      if (last_error == ERROR_HANDLE_EOF)
-      {
-        ec = asio::error::eof;
-      }
-      else
-      {
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-      }
-      return 0;
-    }
-
-    ec = asio::error_code();
-    return bytes_transferred;
+    return do_read(impl, offset, buffer, ec);
   }
 
-  template <typename MutableBufferSequence, typename Handler>
-  class read_op : public operation
-  {
-  public:
-    read_op(const MutableBufferSequence& buffers, Handler handler)
-      : operation(&read_op::do_complete),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      read_op* o(static_cast<read_op*>(base));
-      typedef handler_alloc_traits<Handler, read_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::mutable_buffer,
-            MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Map non-portable errors to their portable counterparts.
-        if (ec.value() == ERROR_HANDLE_EOF)
-        {
-          ec = asio::error::eof;
-        }
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    MutableBufferSequence buffers_;
-    Handler handler_;
-  };
-
   // Start an asynchronous read. The buffer for the data being received must be
   // valid for the lifetime of the asynchronous operation.
   template <typename MutableBufferSequence, typename Handler>
@@ -579,15 +194,16 @@ public:
       const MutableBufferSequence& buffers, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef read_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
+    typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(buffers, handler);
 
     start_read_op(impl, offset,
         buffer_sequence_adapter<asio::mutable_buffer,
-          MutableBufferSequence>::first(buffers), ptr.get());
-    ptr.release();
+          MutableBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
   }
 
 private:
@@ -613,113 +229,42 @@ private:
   void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
       const null_buffers& buffers, Handler handler);
 
+  // Helper class for waiting for synchronous operations to complete.
+  class overlapped_wrapper;
+
+  // Helper function to perform a synchronous write operation.
+  ASIO_DECL size_t do_write(implementation_type& impl,
+      boost::uint64_t offset, const asio::const_buffer& buffer,
+      asio::error_code& ec);
+
   // Helper function to start a write operation.
-  void start_write_op(implementation_type& impl, boost::uint64_t offset,
-      const asio::const_buffer& buffer, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
+  ASIO_DECL void start_write_op(implementation_type& impl,
+      boost::uint64_t offset, const asio::const_buffer& buffer,
+      operation* op);
 
-    if (!is_open(impl))
-    {
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    }
-    else if (asio::buffer_size(buffer) == 0)
-    {
-      // A request to write 0 bytes on a handle is a no-op.
-      iocp_service_.on_completion(op);
-    }
-    else
-    {
-      DWORD bytes_transferred = 0;
-      op->Offset = offset & 0xFFFFFFFF;
-      op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
-      BOOL ok = ::WriteFile(impl.handle_,
-          asio::buffer_cast<LPCVOID>(buffer),
-          static_cast<DWORD>(asio::buffer_size(buffer)),
-          &bytes_transferred, op);
-      DWORD last_error = ::GetLastError();
-      if (!ok && last_error != ERROR_IO_PENDING
-          && last_error != ERROR_MORE_DATA)
-      {
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      }
-      else
-      {
-        iocp_service_.on_pending(op);
-      }
-    }
-  }
+  // Helper function to perform a synchronous write operation.
+  ASIO_DECL size_t do_read(implementation_type& impl,
+      boost::uint64_t offset, const asio::mutable_buffer& buffer,
+      asio::error_code& ec);
 
   // Helper function to start a read operation.
-  void start_read_op(implementation_type& impl, boost::uint64_t offset,
-      const asio::mutable_buffer& buffer, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
-
-    if (!is_open(impl))
-    {
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    }
-    else if (asio::buffer_size(buffer) == 0)
-    {
-      // A request to read 0 bytes on a handle is a no-op.
-      iocp_service_.on_completion(op);
-    }
-    else
-    {
-      DWORD bytes_transferred = 0;
-      op->Offset = offset & 0xFFFFFFFF;
-      op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
-      BOOL ok = ::ReadFile(impl.handle_,
-          asio::buffer_cast<LPVOID>(buffer),
-          static_cast<DWORD>(asio::buffer_size(buffer)),
-          &bytes_transferred, op);
-      DWORD last_error = ::GetLastError();
-      if (!ok && last_error != ERROR_IO_PENDING
-          && last_error != ERROR_MORE_DATA)
-      {
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      }
-      else
-      {
-        iocp_service_.on_pending(op);
-      }
-    }
-  }
+  ASIO_DECL void start_read_op(implementation_type& impl,
+      boost::uint64_t offset, const asio::mutable_buffer& buffer,
+      operation* op);
 
   // Update the ID of the thread from which cancellation is safe.
-  void update_cancellation_thread_id(implementation_type& impl)
-  {
-#if defined(ASIO_ENABLE_CANCELIO)
-    if (impl.safe_cancellation_thread_id_ == 0)
-      impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
-    else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
-      impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#else // defined(ASIO_ENABLE_CANCELIO)
-    (void)impl;
-#endif // defined(ASIO_ENABLE_CANCELIO)
-  }
+  ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);
 
   // Helper function to close a handle when the associated object is being
   // destroyed.
-  void close_for_destruction(implementation_type& impl)
-  {
-    if (is_open(impl))
-    {
-      ::CloseHandle(impl.handle_);
-      impl.handle_ = INVALID_HANDLE_VALUE;
-      impl.safe_cancellation_thread_id_ = 0;
-    }
-  }
+  ASIO_DECL void close_for_destruction(implementation_type& impl);
 
   // The IOCP service used for running asynchronous operations and dispatching
   // handlers.
   win_iocp_io_service& iocp_service_;
 
   // Mutex to protect access to the linked list of implementations.
-  asio::detail::mutex mutex_;
+  mutex mutex_;
 
   // The head of a linked list of all implementations.
   implementation_type* impl_list_;
@@ -728,8 +273,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_write_op.hpp b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp
new file mode 100644
index 0000000..ddfe8fc
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp
@@ -0,0 +1,97 @@
+//
+// detail/win_iocp_handle_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_handle_write_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);
+
+  win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler)
+    : operation(&win_iocp_handle_write_op::do_complete),
+      buffers_(buffers),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (owner)
+    {
+      // Check whether buffers are still valid.
+      buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  ConstBufferSequence buffers_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_io_service.hpp b/ext/asio/asio/detail/win_iocp_io_service.hpp
index fd899c1..c8974b6 100644
--- a/ext/asio/asio/detail/win_iocp_io_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_io_service.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,33 +15,24 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 
-#include "asio/detail/push_options.hpp"
-#include <boost/limits.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include <boost/scoped_ptr.hpp>
 #include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/op_queue.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/detail/timer_op.hpp"
 #include "asio/detail/timer_queue_base.hpp"
 #include "asio/detail/timer_queue_fwd.hpp"
 #include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
 #include "asio/detail/win_iocp_operation.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -52,69 +43,13 @@ class win_iocp_io_service
   : public asio::detail::service_base<win_iocp_io_service>
 {
 public:
-  typedef win_iocp_operation operation;
-
   // Constructor.
-  win_iocp_io_service(asio::io_service& io_service)
-    : asio::detail::service_base<win_iocp_io_service>(io_service),
-      iocp_(),
-      outstanding_work_(0),
-      stopped_(0),
-      shutdown_(0),
-      timer_thread_(0),
-      timer_interrupt_issued_(false)
-  {
-  }
+  ASIO_DECL win_iocp_io_service(asio::io_service& io_service);
 
-  void init(size_t concurrency_hint)
-  {
-    iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
-        static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
-    if (!iocp_.handle)
-    {
-      DWORD last_error = ::GetLastError();
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "iocp");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL void init(size_t concurrency_hint);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-    ::InterlockedExchange(&shutdown_, 1);
-
-    while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
-    {
-      op_queue<operation> ops;
-      timer_queues_.get_all_timers(ops);
-      ops.push(completed_ops_);
-      if (!ops.empty())
-      {
-        while (operation* op = ops.front())
-        {
-          ops.pop();
-          ::InterlockedDecrement(&outstanding_work_);
-          op->destroy();
-        }
-      }
-      else
-      {
-        DWORD bytes_transferred = 0;
-        dword_ptr_t completion_key = 0;
-        LPOVERLAPPED overlapped = 0;
-        ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
-            &completion_key, &overlapped, max_timeout);
-        if (overlapped)
-        {
-          ::InterlockedDecrement(&outstanding_work_);
-          static_cast<operation*>(overlapped)->destroy();
-        }
-      }
-    }
-  }
+  ASIO_DECL void shutdown_service();
 
   // Initialise the task. Nothing to do here.
   void init_task()
@@ -122,106 +57,23 @@ public:
   }
 
   // Register a handle with the IO completion port.
-  asio::error_code register_handle(
-      HANDLE handle, asio::error_code& ec)
-  {
-    if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-    }
-    else
-    {
-      ec = asio::error_code();
-    }
-    return ec;
-  }
+  ASIO_DECL asio::error_code register_handle(
+      HANDLE handle, asio::error_code& ec);
 
   // Run the event loop until stopped or no more work.
-  size_t run(asio::error_code& ec)
-  {
-    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
-    {
-      stop();
-      ec = asio::error_code();
-      return 0;
-    }
-
-    call_stack<win_iocp_io_service>::context ctx(this);
-
-    size_t n = 0;
-    while (do_one(true, ec))
-      if (n != (std::numeric_limits<size_t>::max)())
-        ++n;
-    return n;
-  }
+  ASIO_DECL size_t run(asio::error_code& ec);
 
   // Run until stopped or one operation is performed.
-  size_t run_one(asio::error_code& ec)
-  {
-    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
-    {
-      stop();
-      ec = asio::error_code();
-      return 0;
-    }
-
-    call_stack<win_iocp_io_service>::context ctx(this);
-
-    return do_one(true, ec);
-  }
+  ASIO_DECL size_t run_one(asio::error_code& ec);
 
   // Poll for operations without blocking.
-  size_t poll(asio::error_code& ec)
-  {
-    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
-    {
-      stop();
-      ec = asio::error_code();
-      return 0;
-    }
-
-    call_stack<win_iocp_io_service>::context ctx(this);
-
-    size_t n = 0;
-    while (do_one(false, ec))
-      if (n != (std::numeric_limits<size_t>::max)())
-        ++n;
-    return n;
-  }
+  ASIO_DECL size_t poll(asio::error_code& ec);
 
   // Poll for one operation without blocking.
-  size_t poll_one(asio::error_code& ec)
-  {
-    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
-    {
-      stop();
-      ec = asio::error_code();
-      return 0;
-    }
-
-    call_stack<win_iocp_io_service>::context ctx(this);
-
-    return do_one(false, ec);
-  }
+  ASIO_DECL size_t poll_one(asio::error_code& ec);
 
   // Stop the event processing loop.
-  void stop()
-  {
-    if (::InterlockedExchange(&stopped_, 1) == 0)
-    {
-      if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
-      {
-        DWORD last_error = ::GetLastError();
-        asio::system_error e(
-            asio::error_code(last_error,
-              asio::error::get_system_category()),
-            "pqcs");
-        boost::throw_exception(e);
-      }
-    }
-  }
+  ASIO_DECL void stop();
 
   // Reset in preparation for a subsequent run invocation.
   void reset()
@@ -244,34 +96,15 @@ public:
 
   // Request invocation of the given handler.
   template <typename Handler>
-  void dispatch(Handler handler)
-  {
-    if (call_stack<win_iocp_io_service>::contains(this))
-    {
-      asio::detail::fenced_block b;
-      asio_handler_invoke_helpers::invoke(handler, handler);
-    }
-    else
-      post(handler);
-  }
+  void dispatch(Handler handler);
 
   // Request invocation of the given handler and return immediately.
   template <typename Handler>
-  void post(Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef completion_handler<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    post_immediate_completion(ptr.get());
-    ptr.release();
-  }
+  void post(Handler handler);
 
   // Request invocation of the given operation and return immediately. Assumes
   // that work_started() has not yet been called for the operation.
-  void post_immediate_completion(operation* op)
+  void post_immediate_completion(win_iocp_operation* op)
   {
     work_started();
     post_deferred_completion(op);
@@ -279,170 +112,50 @@ public:
 
   // Request invocation of the given operation and return immediately. Assumes
   // that work_started() was previously called for the operation.
-  void post_deferred_completion(operation* op)
-  {
-    // Flag the operation as ready.
-    op->ready_ = 1;
-
-    // Enqueue the operation on the I/O completion port.
-    if (!::PostQueuedCompletionStatus(iocp_.handle,
-          0, overlapped_contains_result, op))
-    {
-      // Out of resources. Put on completed queue instead.
-      asio::detail::mutex::scoped_lock lock(timer_mutex_);
-      completed_ops_.push(op);
-    }
-  }
+  ASIO_DECL void post_deferred_completion(win_iocp_operation* op);
 
   // Request invocation of the given operation and return immediately. Assumes
   // that work_started() was previously called for the operations.
-  void post_deferred_completions(op_queue<operation>& ops)
-  {
-    while (operation* op = ops.front())
-    {
-      ops.pop();
-
-      // Flag the operation as ready.
-      op->ready_ = 1;
-
-      // Enqueue the operation on the I/O completion port.
-      if (!::PostQueuedCompletionStatus(iocp_.handle,
-            0, overlapped_contains_result, op))
-      {
-        // Out of resources. Put on completed queue instead.
-        asio::detail::mutex::scoped_lock lock(timer_mutex_);
-        completed_ops_.push(op);
-        completed_ops_.push(ops);
-      }
-    }
-  }
+  ASIO_DECL void post_deferred_completions(
+      op_queue<win_iocp_operation>& ops);
 
   // Called after starting an overlapped I/O operation that did not complete
   // immediately. The caller must have already called work_started() prior to
   // starting the operation.
-  void on_pending(operation* op)
-  {
-    if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
-    {
-      // Enqueue the operation on the I/O completion port.
-      if (!::PostQueuedCompletionStatus(iocp_.handle,
-            0, overlapped_contains_result, op))
-      {
-        // Out of resources. Put on completed queue instead.
-        asio::detail::mutex::scoped_lock lock(timer_mutex_);
-        completed_ops_.push(op);
-      }
-    }
-  }
+  ASIO_DECL void on_pending(win_iocp_operation* op);
 
   // Called after starting an overlapped I/O operation that completed
   // immediately. The caller must have already called work_started() prior to
   // starting the operation.
-  void on_completion(operation* op,
-      DWORD last_error = 0, DWORD bytes_transferred = 0)
-  {
-    // Flag that the operation is ready for invocation.
-    op->ready_ = 1;
-
-    // Store results in the OVERLAPPED structure.
-    op->Internal = asio::error::get_system_category();
-    op->Offset = last_error;
-    op->OffsetHigh = bytes_transferred;
-
-    // Enqueue the operation on the I/O completion port.
-    if (!::PostQueuedCompletionStatus(iocp_.handle,
-          0, overlapped_contains_result, op))
-    {
-      // Out of resources. Put on completed queue instead.
-      asio::detail::mutex::scoped_lock lock(timer_mutex_);
-      completed_ops_.push(op);
-    }
-  }
+  ASIO_DECL void on_completion(win_iocp_operation* op,
+      DWORD last_error = 0, DWORD bytes_transferred = 0);
 
   // Called after starting an overlapped I/O operation that completed
   // immediately. The caller must have already called work_started() prior to
   // starting the operation.
-  void on_completion(operation* op,
-      const asio::error_code& ec, DWORD bytes_transferred = 0)
-  {
-    // Flag that the operation is ready for invocation.
-    op->ready_ = 1;
-
-    // Store results in the OVERLAPPED structure.
-    op->Internal = ec.category();
-    op->Offset = ec.value();
-    op->OffsetHigh = bytes_transferred;
-
-    // Enqueue the operation on the I/O completion port.
-    if (!::PostQueuedCompletionStatus(iocp_.handle,
-          0, overlapped_contains_result, op))
-    {
-      // Out of resources. Put on completed queue instead.
-      asio::detail::mutex::scoped_lock lock(timer_mutex_);
-      completed_ops_.push(op);
-    }
-  }
+  ASIO_DECL void on_completion(win_iocp_operation* op,
+      const asio::error_code& ec, DWORD bytes_transferred = 0);
 
   // Add a new timer queue to the service.
   template <typename Time_Traits>
-  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(timer_mutex_);
-    timer_queues_.insert(&timer_queue);
-  }
+  void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
 
   // Remove a timer queue from the service.
   template <typename Time_Traits>
-  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
-  {
-    asio::detail::mutex::scoped_lock lock(timer_mutex_);
-    timer_queues_.erase(&timer_queue);
-  }
+  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
 
   // Schedule a new operation in the given timer queue to expire at the
   // specified absolute time.
   template <typename Time_Traits>
-  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
-      const typename Time_Traits::time_type& time, timer_op* op, void* token)
-  {
-    // If the service has been shut down we silently discard the timer.
-    if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
-      return;
-
-    asio::detail::mutex::scoped_lock lock(timer_mutex_);
-    bool interrupt = timer_queue.enqueue_timer(time, op, token);
-    work_started();
-    if (interrupt && !timer_interrupt_issued_)
-    {
-      timer_interrupt_issued_ = true;
-      lock.unlock();
-      ::PostQueuedCompletionStatus(iocp_.handle,
-          0, steal_timer_dispatching, 0);
-    }
-  }
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
 
   // Cancel the timer associated with the given token. Returns the number of
   // handlers that have been posted or dispatched.
   template <typename Time_Traits>
-  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
-  {
-    // If the service has been shut down we silently ignore the cancellation.
-    if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
-      return 0;
-
-    asio::detail::mutex::scoped_lock lock(timer_mutex_);
-    op_queue<operation> ops;
-    std::size_t n = timer_queue.cancel_timer(token, ops);
-    post_deferred_completions(ops);
-    if (n > 0 && !timer_interrupt_issued_)
-    {
-      timer_interrupt_issued_ = true;
-      lock.unlock();
-      ::PostQueuedCompletionStatus(iocp_.handle,
-          0, steal_timer_dispatching, 0);
-    }
-    return n;
-  }
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer);
 
 private:
 #if defined(WINVER) && (WINVER < 0x0500)
@@ -456,181 +169,30 @@ private:
   // Dequeues at most one operation from the I/O completion port, and then
   // executes it. Returns the number of operations that were dequeued (i.e.
   // either 0 or 1).
-  size_t do_one(bool block, asio::error_code& ec)
-  {
-    long this_thread_id = static_cast<long>(::GetCurrentThreadId());
-
-    for (;;)
-    {
-      // Try to acquire responsibility for dispatching timers.
-      bool dispatching_timers = (::InterlockedCompareExchange(
-            &timer_thread_, this_thread_id, 0) == 0);
-
-      // Calculate timeout for GetQueuedCompletionStatus call.
-      DWORD timeout = max_timeout;
-      if (dispatching_timers)
-      {
-        asio::detail::mutex::scoped_lock lock(timer_mutex_);
-        timer_interrupt_issued_ = false;
-        timeout = get_timeout();
-      }
-
-      // Get the next operation from the queue.
-      DWORD bytes_transferred = 0;
-      dword_ptr_t completion_key = 0;
-      LPOVERLAPPED overlapped = 0;
-      ::SetLastError(0);
-      BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
-          &completion_key, &overlapped, block ? timeout : 0);
-      DWORD last_error = ::GetLastError();
-
-      // Dispatch any pending timers.
-      if (dispatching_timers)
-      {
-        asio::detail::mutex::scoped_lock lock(timer_mutex_);
-        op_queue<operation> ops;
-        ops.push(completed_ops_);
-        timer_queues_.get_ready_timers(ops);
-        post_deferred_completions(ops);
-      }
-
-      if (!ok && overlapped == 0)
-      {
-        if (block && last_error == WAIT_TIMEOUT)
-        {
-          // Relinquish responsibility for dispatching timers.
-          if (dispatching_timers)
-          {
-            ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
-          }
-
-          continue;
-        }
-
-        // Transfer responsibility for dispatching timers to another thread.
-        if (dispatching_timers && ::InterlockedCompareExchange(
-              &timer_thread_, 0, this_thread_id) == this_thread_id)
-        {
-          ::PostQueuedCompletionStatus(iocp_.handle,
-              0, transfer_timer_dispatching, 0);
-        }
-
-        ec = asio::error_code();
-        return 0;
-      }
-      else if (overlapped)
-      {
-        operation* op = static_cast<operation*>(overlapped);
-        asio::error_code result_ec(last_error,
-            asio::error::get_system_category());
-
-        // Transfer responsibility for dispatching timers to another thread.
-        if (dispatching_timers && ::InterlockedCompareExchange(
-              &timer_thread_, 0, this_thread_id) == this_thread_id)
-        {
-          ::PostQueuedCompletionStatus(iocp_.handle,
-              0, transfer_timer_dispatching, 0);
-        }
-
-        // We may have been passed the last_error and bytes_transferred in the
-        // OVERLAPPED structure itself.
-        if (completion_key == overlapped_contains_result)
-        {
-          result_ec = asio::error_code(static_cast<int>(op->Offset),
-              static_cast<asio::error_category>(op->Internal));
-          bytes_transferred = op->OffsetHigh;
-        }
-
-        // Otherwise ensure any result has been saved into the OVERLAPPED
-        // structure.
-        else
-        {
-          op->Internal = result_ec.category();
-          op->Offset = result_ec.value();
-          op->OffsetHigh = bytes_transferred;
-        }
-
-        // Dispatch the operation only if ready. The operation may not be ready
-        // if the initiating function (e.g. a call to WSARecv) has not yet
-        // returned. This is because the initiating function still wants access
-        // to the operation's OVERLAPPED structure.
-        if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
-        {
-          // Ensure the count of outstanding work is decremented on block exit.
-          work_finished_on_block_exit on_exit = { this };
-          (void)on_exit;
-
-          op->complete(*this, result_ec, bytes_transferred);
-          ec = asio::error_code();
-          return 1;
-        }
-      }
-      else if (completion_key == transfer_timer_dispatching)
-      {
-        // Woken up to try to acquire responsibility for dispatching timers.
-        ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
-      }
-      else if (completion_key == steal_timer_dispatching)
-      {
-        // Woken up to steal responsibility for dispatching timers.
-        ::InterlockedExchange(&timer_thread_, 0);
-      }
-      else
-      {
-        // Relinquish responsibility for dispatching timers. If the io_service
-        // is not being stopped then the thread will get an opportunity to
-        // reacquire timer responsibility on the next loop iteration.
-        if (dispatching_timers)
-        {
-          ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
-        }
-
-        // The stopped_ flag is always checked to ensure that any leftover
-        // interrupts from a previous run invocation are ignored.
-        if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
-        {
-          // Wake up next thread that is blocked on GetQueuedCompletionStatus.
-          if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
-          {
-            last_error = ::GetLastError();
-            ec = asio::error_code(last_error,
-                asio::error::get_system_category());
-            return 0;
-          }
-
-          ec = asio::error_code();
-          return 0;
-        }
-      }
-    }
-  }
+  ASIO_DECL size_t do_one(bool block, asio::error_code& ec);
 
-  // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
-  // value is returned as a number of milliseconds. We will wait no longer than
-  // 1000 milliseconds.
-  DWORD get_timeout()
-  {
-    return timer_queues_.wait_duration_msec(max_timeout);
-  }
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Called to recalculate and update the timeout.
+  ASIO_DECL void update_timeout();
 
   // Helper class to call work_finished() on block exit.
-  struct work_finished_on_block_exit
-  {
-    ~work_finished_on_block_exit()
-    {
-      io_service_->work_finished();
-    }
+  struct work_finished_on_block_exit;
 
-    win_iocp_io_service* io_service_;
+  // Helper class for managing a HANDLE.
+  struct auto_handle
+  {
+    HANDLE handle;
+    auto_handle() : handle(0) {}
+    ~auto_handle() { if (handle) ::CloseHandle(handle); }
   };
 
   // The IO completion port used for queueing operations.
-  struct iocp_holder
-  {
-    HANDLE handle;
-    iocp_holder() : handle(0) {}
-    ~iocp_holder() { if (handle) ::CloseHandle(handle); }
-  } iocp_;
+  auto_handle iocp_;
 
   // The count of unfinished work.
   long outstanding_work_;
@@ -643,44 +205,61 @@ private:
 
   enum
   {
-    // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
-    max_timeout = 500,
+    // Timeout to use with GetQueuedCompletionStatus. Some versions of windows
+    // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck
+    // even though there are events waiting on the queue. Using a timeout helps
+    // to work around the issue.
+    gqcs_timeout = 500,
+
+    // Maximum waitable timer timeout, in milliseconds.
+    max_timeout_msec = 5 * 60 * 1000,
 
-    // Completion key value to indicate that responsibility for dispatching
-    // timers is being cooperatively transferred from one thread to another.
-    transfer_timer_dispatching = 1,
+    // Maximum waitable timer timeout, in microseconds.
+    max_timeout_usec = max_timeout_msec * 1000,
 
-    // Completion key value to indicate that responsibility for dispatching
-    // timers should be stolen from another thread.
-    steal_timer_dispatching = 2,
+    // Completion key value used to wake up a thread to dispatch timers or
+    // completed operations.
+    wake_for_dispatch = 1,
 
     // Completion key value to indicate that an operation has posted with the
     // original last_error and bytes_transferred values stored in the fields of
     // the OVERLAPPED structure.
-    overlapped_contains_result = 3
+    overlapped_contains_result = 2
   };
 
-  // The thread that's currently in charge of dispatching timers.
-  long timer_thread_;
+  // Function object for processing timeouts in a background thread.
+  struct timer_thread_function;
+  friend struct timer_thread_function;
+
+  // Background thread used for processing timeouts.
+  boost::scoped_ptr<thread> timer_thread_;
+
+  // A waitable timer object used for waiting for timeouts.
+  auto_handle waitable_timer_;
 
-  // Mutex for protecting access to the timer queues.
-  mutex timer_mutex_;
+  // Non-zero if timers or completed operations need to be dispatched.
+  long dispatch_required_;
 
-  // Whether a thread has been interrupted to process a new timeout.
-  bool timer_interrupt_issued_;
+  // Mutex for protecting access to the timer queues and completed operations.
+  mutex dispatch_mutex_;
 
   // The timer queues.
   timer_queue_set timer_queues_;
 
   // The operations that are ready to dispatch.
-  op_queue<operation> completed_ops_;
+  op_queue<win_iocp_operation> completed_ops_;
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/impl/win_iocp_io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
index 29d2a05..9f03743 100644
--- a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
+++ b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_io_service_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,9 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/socket_types.hpp"
-
-// This service is only supported on Win32 (NT4 and later).
-#if !defined(ASIO_DISABLE_IOCP)
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
-#if !defined(UNDER_CE)
-
-// Define this to indicate that IOCP is supported on the target platform.
-#define ASIO_HAS_IOCP 1
+#if defined(ASIO_HAS_IOCP)
 
 namespace asio {
 namespace detail {
@@ -41,11 +28,6 @@ class win_iocp_overlapped_ptr;
 } // namespace detail
 } // namespace asio
 
-#endif // !defined(UNDER_CE)
-#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_IOCP)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_IOCP)
 
 #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
diff --git a/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
new file mode 100644
index 0000000..e39fff7
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
@@ -0,0 +1,112 @@
+//
+// detail/win_iocp_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_null_buffers_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);
+
+  win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,
+      Handler handler)
+    : reactor_op(&win_iocp_null_buffers_op::do_perform,
+        &win_iocp_null_buffers_op::do_complete),
+      cancel_token_(cancel_token),
+      handler_(handler)
+  {
+  }
+
+  static bool do_perform(reactor_op*)
+  {
+    return true;
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // The reactor may have stored a result in the operation object.
+    if (o->ec_)
+      ec = o->ec_;
+
+    // Map non-portable errors to their portable counterparts.
+    if (ec.value() == ERROR_NETNAME_DELETED)
+    {
+      if (o->cancel_token_.expired())
+        ec = asio::error::operation_aborted;
+      else
+        ec = asio::error::connection_reset;
+    }
+    else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    {
+      ec = asio::error::connection_refused;
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_operation.hpp b/ext/asio/asio/detail/win_iocp_operation.hpp
index ac81062..649edd1 100644
--- a/ext/asio/asio/detail/win_iocp_operation.hpp
+++ b/ext/asio/asio/detail/win_iocp_operation.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 
-#include "asio/error_code.hpp"
 #include "asio/detail/op_queue.hpp"
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -82,8 +83,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
diff --git a/ext/asio/asio/detail/win_iocp_overlapped_op.hpp b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp
new file mode 100644
index 0000000..f2b7ddf
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp
@@ -0,0 +1,84 @@
+//
+// detail/win_iocp_overlapped_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_overlapped_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op);
+
+  win_iocp_overlapped_op(Handler handler)
+    : operation(&win_iocp_overlapped_op::do_complete),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
index 47a3f70..919affe 100644
--- a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
+++ b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_overlapped_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 
-#include "asio/detail/fenced_block.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/io_service.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/detail/win_iocp_overlapped_op.hpp"
 #include "asio/detail/win_iocp_io_service.hpp"
-#include "asio/detail/win_iocp_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -74,13 +76,15 @@ public:
   template <typename Handler>
   void reset(asio::io_service& io_service, Handler handler)
   {
-    typedef overlapped_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef win_iocp_overlapped_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(handler);
     io_service.impl_.work_started();
     reset();
-    ptr_ = ptr.release();
+    ptr_ = p.p;
+    p.v = p.p = 0;
     iocp_service_ = &io_service.impl_;
   }
 
@@ -122,44 +126,6 @@ public:
   }
 
 private:
-  template <typename Handler>
-  struct overlapped_op : public win_iocp_operation
-  {
-    overlapped_op(Handler handler)
-      : win_iocp_operation(&overlapped_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      overlapped_op* o(static_cast<overlapped_op*>(base));
-      typedef handler_alloc_traits<Handler, overlapped_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   win_iocp_operation* ptr_;
   win_iocp_io_service* iocp_service_;
 };
@@ -167,8 +133,8 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
diff --git a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
index ed5f75e..bf3a692 100644
--- a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_serial_port_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,21 +16,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <string>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
-#if defined(ASIO_HAS_IOCP)
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
 
+#include <string>
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/detail/win_iocp_handle_service.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -38,133 +34,56 @@ namespace detail {
 class win_iocp_serial_port_service
 {
 public:
-  // The native type of a stream handle.
+  // The native type of a serial port.
   typedef win_iocp_handle_service::native_type native_type;
 
-  // The implementation type of the stream handle.
+  // The implementation type of the serial port.
   typedef win_iocp_handle_service::implementation_type implementation_type;
 
-  win_iocp_serial_port_service(asio::io_service& io_service)
-    : handle_service_(io_service)
-  {
-  }
+  // Constructor.
+  ASIO_DECL win_iocp_serial_port_service(
+      asio::io_service& io_service);
 
   // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
-  {
-  }
+  ASIO_DECL void shutdown_service();
 
-  // Construct a new handle implementation.
+  // Construct a new serial port implementation.
   void construct(implementation_type& impl)
   {
     handle_service_.construct(impl);
   }
 
-  // Destroy a handle implementation.
+  // Destroy a serial port implementation.
   void destroy(implementation_type& impl)
   {
     handle_service_.destroy(impl);
   }
 
   // Open the serial port using the specified device name.
-  asio::error_code open(implementation_type& impl,
-      const std::string& device, asio::error_code& ec)
-  {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    // For convenience, add a leading \\.\ sequence if not already present.
-    std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
-
-    // Open a handle to the serial port.
-    ::HANDLE handle = ::CreateFileA(name.c_str(),
-        GENERIC_READ | GENERIC_WRITE, 0, 0,
-        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
-    if (handle == INVALID_HANDLE_VALUE)
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    // Determine the initial serial port parameters.
-    using namespace std; // For memcpy.
-    ::DCB dcb;
-    memset(&dcb, 0, sizeof(DCB));
-    dcb.DCBlength = sizeof(DCB);
-    if (!::GetCommState(handle, &dcb))
-    {
-      DWORD last_error = ::GetLastError();
-      ::CloseHandle(handle);
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    // Set some default serial port parameters. This implementation does not
-    // support changing these, so they might as well be in a known state.
-    dcb.fBinary = TRUE; // Win32 only supports binary mode.
-    dcb.fDsrSensitivity = FALSE;
-    dcb.fNull = FALSE; // Do not ignore NULL characters.
-    dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
-    if (!::SetCommState(handle, &dcb))
-    {
-      DWORD last_error = ::GetLastError();
-      ::CloseHandle(handle);
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    // Set up timeouts so that the serial port will behave similarly to a
-    // network socket. Reads wait for at least one byte, then return with
-    // whatever they have. Writes return once everything is out the door.
-    ::COMMTIMEOUTS timeouts;
-    timeouts.ReadIntervalTimeout = 1;
-    timeouts.ReadTotalTimeoutMultiplier = 0;
-    timeouts.ReadTotalTimeoutConstant = 0;
-    timeouts.WriteTotalTimeoutMultiplier = 0;
-    timeouts.WriteTotalTimeoutConstant = 0;
-    if (!::SetCommTimeouts(handle, &timeouts))
-    {
-      DWORD last_error = ::GetLastError();
-      ::CloseHandle(handle);
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    // We're done. Take ownership of the serial port handle.
-    if (handle_service_.assign(impl, handle, ec))
-      ::CloseHandle(handle);
-    return ec;
-  }
+  ASIO_DECL asio::error_code open(implementation_type& impl,
+      const std::string& device, asio::error_code& ec);
 
-  // Assign a native handle to a handle implementation.
+  // Assign a native handle to a serial port implementation.
   asio::error_code assign(implementation_type& impl,
       const native_type& native_handle, asio::error_code& ec)
   {
     return handle_service_.assign(impl, native_handle, ec);
   }
 
-  // Determine whether the handle is open.
+  // Determine whether the serial port is open.
   bool is_open(const implementation_type& impl) const
   {
     return handle_service_.is_open(impl);
   }
 
-  // Destroy a handle implementation.
+  // Destroy a serial port implementation.
   asio::error_code close(implementation_type& impl,
       asio::error_code& ec)
   {
     return handle_service_.close(impl, ec);
   }
 
-  // Get the native handle representation.
+  // Get the native serial port representation.
   native_type native(implementation_type& impl)
   {
     return handle_service_.native(impl);
@@ -182,32 +101,9 @@ public:
   asio::error_code set_option(implementation_type& impl,
       const SettableSerialPortOption& option, asio::error_code& ec)
   {
-    using namespace std; // For memcpy.
-
-    ::DCB dcb;
-    memset(&dcb, 0, sizeof(DCB));
-    dcb.DCBlength = sizeof(DCB);
-    if (!::GetCommState(handle_service_.native(impl), &dcb))
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    if (option.store(dcb, ec))
-      return ec;
-
-    if (!::SetCommState(handle_service_.native(impl), &dcb))
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    ec = asio::error_code();
-    return ec;
+    return do_set_option(impl,
+        &win_iocp_serial_port_service::store_option<SettableSerialPortOption>,
+        &option, ec);
   }
 
   // Get an option from the serial port.
@@ -215,20 +111,9 @@ public:
   asio::error_code get_option(const implementation_type& impl,
       GettableSerialPortOption& option, asio::error_code& ec) const
   {
-    using namespace std; // For memcpy.
-
-    ::DCB dcb;
-    memset(&dcb, 0, sizeof(DCB));
-    dcb.DCBlength = sizeof(DCB);
-    if (!::GetCommState(handle_service_.native(impl), &dcb))
-    {
-      DWORD last_error = ::GetLastError();
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return ec;
-    }
-
-    return option.load(dcb, ec);
+    return do_get_option(impl,
+        &win_iocp_serial_port_service::load_option<GettableSerialPortOption>,
+        &option, ec);
   }
 
   // Send a break sequence to the serial port.
@@ -274,6 +159,41 @@ public:
   }
 
 private:
+  // Function pointer type for storing a serial port option.
+  typedef asio::error_code (*store_function_type)(
+      const void*, ::DCB&, asio::error_code&);
+
+  // Helper function template to store a serial port option.
+  template <typename SettableSerialPortOption>
+  static asio::error_code store_option(const void* option,
+      ::DCB& storage, asio::error_code& ec)
+  {
+    return static_cast<const SettableSerialPortOption*>(option)->store(
+        storage, ec);
+  }
+
+  // Helper function to set a serial port option.
+  ASIO_DECL asio::error_code do_set_option(
+      implementation_type& impl, store_function_type store,
+      const void* option, asio::error_code& ec);
+
+  // Function pointer type for loading a serial port option.
+  typedef asio::error_code (*load_function_type)(
+      void*, const ::DCB&, asio::error_code&);
+
+  // Helper function template to load a serial port option.
+  template <typename GettableSerialPortOption>
+  static asio::error_code load_option(void* option,
+      const ::DCB& storage, asio::error_code& ec)
+  {
+    return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+  }
+
+  // Helper function to get a serial port option.
+  ASIO_DECL asio::error_code do_get_option(
+      const implementation_type& impl, load_function_type load,
+      void* option, asio::error_code& ec) const;
+
   // The implementation used for initiating asynchronous operations.
   win_iocp_handle_service handle_service_;
 };
@@ -281,8 +201,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
 #endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
new file mode 100644
index 0000000..a71c7c0
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
@@ -0,0 +1,158 @@
+//
+// detail/win_iocp_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol, typename Handler>
+class win_iocp_socket_accept_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
+
+  win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,
+      socket_type socket, Socket& peer, const Protocol& protocol,
+      typename Protocol::endpoint* peer_endpoint,
+      bool enable_connection_aborted, Handler handler)
+    : operation(&win_iocp_socket_accept_op::do_complete),
+      socket_service_(socket_service),
+      socket_(socket),
+      peer_(peer),
+      protocol_(protocol),
+      peer_endpoint_(peer_endpoint),
+      enable_connection_aborted_(enable_connection_aborted),
+      handler_(handler)
+  {
+  }
+
+  socket_holder& new_socket()
+  {
+    return new_socket_;
+  }
+
+  void* output_buffer()
+  {
+    return output_buffer_;
+  }
+
+  DWORD address_length()
+  {
+    return sizeof(sockaddr_storage_type) + 16;
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the operation object.
+    win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+    if (owner)
+    {
+      typename Protocol::endpoint peer_endpoint;
+      std::size_t addr_len = peer_endpoint.capacity();
+      socket_ops::complete_iocp_accept(o->socket_,
+          o->output_buffer(), o->address_length(),
+          peer_endpoint.data(), &addr_len,
+          o->new_socket_.get(), ec);
+
+      // Restart the accept operation if we got the connection_aborted error
+      // and the enable_connection_aborted socket option is not set.
+      if (ec == asio::error::connection_aborted
+          && !o->enable_connection_aborted_)
+      {
+        o->reset();
+        o->socket_service_.restart_accept_op(o->socket_,
+            o->new_socket_, o->protocol_.family(),
+            o->protocol_.type(), o->protocol_.protocol(),
+            o->output_buffer(), o->address_length(), o);
+        p.v = p.p = 0;
+        return;
+      }
+
+      // If the socket was successfully accepted, transfer ownership of the
+      // socket to the peer object.
+      if (!ec)
+      {
+        o->peer_.assign(o->protocol_,
+            typename Socket::native_type(
+              o->new_socket_.get(), peer_endpoint), ec);
+        if (!ec)
+          o->new_socket_.release();
+      }
+
+      // Pass endpoint back to caller.
+      if (o->peer_endpoint_)
+        *o->peer_endpoint_ = peer_endpoint;
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, ec);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  win_iocp_socket_service_base& socket_service_;
+  socket_type socket_;
+  socket_holder new_socket_;
+  Socket& peer_;
+  Protocol protocol_;
+  typename Protocol::endpoint* peer_endpoint_;
+  unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+  bool enable_connection_aborted_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
new file mode 100644
index 0000000..3ab4fcb
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
@@ -0,0 +1,108 @@
+//
+// detail/win_iocp_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_socket_recv_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op);
+
+  win_iocp_socket_recv_op(socket_ops::state_type state,
+      socket_ops::weak_cancel_token_type cancel_token,
+      const MutableBufferSequence& buffers, Handler handler)
+    : operation(&win_iocp_socket_recv_op::do_complete),
+      state_(state),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_recv(o->state_, o->cancel_token_,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::all_empty(o->buffers_),
+        ec, bytes_transferred);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  socket_ops::state_type state_;
+  socket_ops::weak_cancel_token_type cancel_token_;
+  MutableBufferSequence buffers_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..d1e2ece
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
@@ -0,0 +1,116 @@
+//
+// detail/win_iocp_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class win_iocp_socket_recvfrom_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op);
+
+  win_iocp_socket_recvfrom_op(Endpoint& endpoint,
+      socket_ops::weak_cancel_token_type cancel_token,
+      const MutableBufferSequence& buffers, Handler handler)
+    : operation(&win_iocp_socket_recvfrom_op::do_complete),
+      endpoint_(endpoint),
+      endpoint_size_(static_cast<int>(endpoint.capacity())),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(handler)
+  {
+  }
+
+  int& endpoint_size()
+  {
+    return endpoint_size_;
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_socket_recvfrom_op* o(
+        static_cast<win_iocp_socket_recvfrom_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec);
+
+    // Record the size of the endpoint returned by the operation.
+    o->endpoint_.resize(o->endpoint_size_);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  Endpoint& endpoint_;
+  int endpoint_size_;
+  socket_ops::weak_cancel_token_type cancel_token_;
+  MutableBufferSequence buffers_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_send_op.hpp b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp
new file mode 100644
index 0000000..56f3f2d
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp
@@ -0,0 +1,102 @@
+//
+// detail/win_iocp_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_socket_send_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);
+
+  win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,
+      const ConstBufferSequence& buffers, Handler handler)
+    : operation(&win_iocp_socket_send_op::do_complete),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(handler)
+  {
+  }
+
+  static void do_complete(io_service_impl* owner, operation* base,
+      asio::error_code ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
+    ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_send(o->cancel_token_, ec);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = boost::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      asio::detail::fenced_block b;
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  ConstBufferSequence buffers_;
+  Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_service.hpp b/ext/asio/asio/detail/win_iocp_socket_service.hpp
index cb1d203..b476f8b 100644
--- a/ext/asio/asio/detail/win_iocp_socket_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_socket_service.hpp
@@ -1,8 +1,8 @@
 //
-// win_iocp_socket_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 
-#include "asio/detail/push_options.hpp"
 #include <cstring>
-#include <boost/shared_ptr.hpp>
-#include <boost/type_traits/is_same.hpp>
-#include <boost/weak_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include <boost/utility/addressof.hpp>
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/socket_base.hpp"
@@ -37,20 +30,27 @@
 #include "asio/detail/handler_alloc_helpers.hpp"
 #include "asio/detail/handler_invoke_helpers.hpp"
 #include "asio/detail/mutex.hpp"
-#include "asio/detail/null_buffers_op.hpp"
 #include "asio/detail/operation.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
 #include "asio/detail/reactor.hpp"
 #include "asio/detail/reactor_op.hpp"
 #include "asio/detail/socket_holder.hpp"
 #include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/detail/win_iocp_io_service.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_accept_op.hpp"
+#include "asio/detail/win_iocp_socket_recvfrom_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace detail {
 
 template <typename Protocol>
-class win_iocp_socket_service
+class win_iocp_socket_service : public win_iocp_socket_service_base
 {
 public:
   // The protocol type.
@@ -59,10 +59,6 @@ public:
   // The endpoint type.
   typedef typename Protocol::endpoint endpoint_type;
 
-  struct noop_deleter { void operator()(void*) {} };
-  typedef boost::shared_ptr<void> shared_cancel_token_type;
-  typedef boost::weak_ptr<void> weak_cancel_token_type;
-
   // The native type of a socket.
   class native_type
   {
@@ -92,11 +88,6 @@ public:
       return socket_;
     }
 
-    HANDLE as_handle() const
-    {
-      return reinterpret_cast<HANDLE>(socket_);
-    }
-
     bool have_remote_endpoint() const
     {
       return have_remote_endpoint_;
@@ -114,148 +105,44 @@ public:
   };
 
   // The implementation type of the socket.
-  class implementation_type
+  struct implementation_type :
+    win_iocp_socket_service_base::base_implementation_type
   {
-  public:
     // Default constructor.
     implementation_type()
-      : socket_(invalid_socket),
-        flags_(0),
-        cancel_token_(),
-        protocol_(endpoint_type().protocol()),
-        next_(0),
-        prev_(0)
+      : protocol_(endpoint_type().protocol()),
+        have_remote_endpoint_(false),
+        remote_endpoint_()
     {
     }
 
-  private:
-    // Only this service will have access to the internal values.
-    friend class win_iocp_socket_service;
-
-    // The native socket representation.
-    native_type socket_;
-
-    enum
-    {
-      enable_connection_aborted = 1, // User wants connection_aborted errors.
-      close_might_block = 2, // User set linger option for blocking close.
-      user_set_non_blocking = 4 // The user wants a non-blocking socket.
-    };
-
-    // Flags indicating the current state of the socket.
-    unsigned char flags_;
-
-    // We use a shared pointer as a cancellation token here to work around the
-    // broken Windows support for cancellation. MSDN says that when you call
-    // closesocket any outstanding WSARecv or WSASend operations will complete
-    // with the error ERROR_OPERATION_ABORTED. In practice they complete with
-    // ERROR_NETNAME_DELETED, which means you can't tell the difference between
-    // a local cancellation and the socket being hard-closed by the peer.
-    shared_cancel_token_type cancel_token_;
-
     // The protocol associated with the socket.
     protocol_type protocol_;
 
-    // Per-descriptor data used by the reactor.
-    reactor::per_descriptor_data reactor_data_;
-
-#if defined(ASIO_ENABLE_CANCELIO)
-    // The ID of the thread from which it is safe to cancel asynchronous
-    // operations. 0 means no asynchronous operations have been started yet.
-    // ~0 means asynchronous operations have been started from more than one
-    // thread, and cancellation is not supported for the socket.
-    DWORD safe_cancellation_thread_id_;
-#endif // defined(ASIO_ENABLE_CANCELIO)
+    // Whether we have a cached remote endpoint.
+    bool have_remote_endpoint_;
 
-    // Pointers to adjacent socket implementations in linked list.
-    implementation_type* next_;
-    implementation_type* prev_;
+    // A cached remote endpoint.
+    endpoint_type remote_endpoint_;
   };
 
   // Constructor.
   win_iocp_socket_service(asio::io_service& io_service)
-    : io_service_(io_service),
-      iocp_service_(use_service<win_iocp_io_service>(io_service)),
-      reactor_(0),
-      mutex_(),
-      impl_list_(0)
-  {
-  }
-
-  // Destroy all user-defined handler objects owned by the service.
-  void shutdown_service()
+    : win_iocp_socket_service_base(io_service)
   {
-    // Close all implementations, causing all operations to complete.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    implementation_type* impl = impl_list_;
-    while (impl)
-    {
-      asio::error_code ignored_ec;
-      close_for_destruction(*impl);
-      impl = impl->next_;
-    }
-  }
-
-  // Construct a new socket implementation.
-  void construct(implementation_type& impl)
-  {
-    impl.socket_ = invalid_socket;
-    impl.flags_ = 0;
-    impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
-    impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
-
-    // Insert implementation into linked list of all implementations.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    impl.next_ = impl_list_;
-    impl.prev_ = 0;
-    if (impl_list_)
-      impl_list_->prev_ = &impl;
-    impl_list_ = &impl;
-  }
-
-  // Destroy a socket implementation.
-  void destroy(implementation_type& impl)
-  {
-    close_for_destruction(impl);
-
-    // Remove implementation from linked list of all implementations.
-    asio::detail::mutex::scoped_lock lock(mutex_);
-    if (impl_list_ == &impl)
-      impl_list_ = impl.next_;
-    if (impl.prev_)
-      impl.prev_->next_ = impl.next_;
-    if (impl.next_)
-      impl.next_->prev_= impl.prev_;
-    impl.next_ = 0;
-    impl.prev_ = 0;
   }
 
   // Open a new socket implementation.
   asio::error_code open(implementation_type& impl,
       const protocol_type& protocol, asio::error_code& ec)
   {
-    if (is_open(impl))
+    if (!do_open(impl, protocol.family(),
+          protocol.type(), protocol.protocol(), ec))
     {
-      ec = asio::error::already_open;
-      return ec;
+      impl.protocol_ = protocol;
+      impl.have_remote_endpoint_ = false;
+      impl.remote_endpoint_ = endpoint_type();
     }
-
-    socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(),
-          protocol.protocol(), ec));
-    if (sock.get() == invalid_socket)
-      return ec;
-
-    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
-    if (iocp_service_.register_handle(sock_as_handle, ec))
-      return ec;
-
-    impl.socket_ = sock.release();
-    impl.flags_ = 0;
-    impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
-    impl.protocol_ = protocol;
-    ec = asio::error_code();
     return ec;
   }
 
@@ -264,247 +151,40 @@ public:
       const protocol_type& protocol, const native_type& native_socket,
       asio::error_code& ec)
   {
-    if (is_open(impl))
-    {
-      ec = asio::error::already_open;
-      return ec;
-    }
-
-    if (iocp_service_.register_handle(native_socket.as_handle(), ec))
-      return ec;
-
-    impl.socket_ = native_socket;
-    impl.flags_ = 0;
-    impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
-    impl.protocol_ = protocol;
-    ec = asio::error_code();
-    return ec;
-  }
-
-  // Determine whether the socket is open.
-  bool is_open(const implementation_type& impl) const
-  {
-    return impl.socket_ != invalid_socket;
-  }
-
-  // Destroy a socket implementation.
-  asio::error_code close(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (is_open(impl))
+    if (!do_assign(impl, protocol.type(), native_socket, ec))
     {
-      // Check if the reactor was created, in which case we need to close the
-      // socket on the reactor as well to cancel any operations that might be
-      // running there.
-      reactor* r = static_cast<reactor*>(
-            interlocked_compare_exchange_pointer(
-              reinterpret_cast<void**>(&reactor_), 0, 0));
-      if (r)
-        r->close_descriptor(impl.socket_, impl.reactor_data_);
-
-      if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
-        return ec;
-
-      impl.socket_ = invalid_socket;
-      impl.flags_ = 0;
-      impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
-      impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
+      impl.protocol_ = protocol;
+      impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();
+      impl.remote_endpoint_ = native_socket.remote_endpoint();
     }
-
-    ec = asio::error_code();
     return ec;
   }
 
   // Get the native socket representation.
   native_type native(implementation_type& impl)
   {
-    return impl.socket_;
-  }
-
-  // Cancel all operations associated with the socket.
-  asio::error_code cancel(implementation_type& impl,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-    else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
-          ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
-    {
-      // The version of Windows supports cancellation from any thread.
-      typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
-      cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
-      socket_type sock = impl.socket_;
-      HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
-      if (!cancel_io_ex(sock_as_handle, 0))
-      {
-        DWORD last_error = ::GetLastError();
-        if (last_error == ERROR_NOT_FOUND)
-        {
-          // ERROR_NOT_FOUND means that there were no operations to be
-          // cancelled. We swallow this error to match the behaviour on other
-          // platforms.
-          ec = asio::error_code();
-        }
-        else
-        {
-          ec = asio::error_code(last_error,
-              asio::error::get_system_category());
-        }
-      }
-      else
-      {
-        ec = asio::error_code();
-      }
-    }
-#if defined(ASIO_ENABLE_CANCELIO)
-    else if (impl.safe_cancellation_thread_id_ == 0)
-    {
-      // No operations have been started, so there's nothing to cancel.
-      ec = asio::error_code();
-    }
-    else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
-    {
-      // Asynchronous operations have been started from the current thread only,
-      // so it is safe to try to cancel them using CancelIo.
-      socket_type sock = impl.socket_;
-      HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
-      if (!::CancelIo(sock_as_handle))
-      {
-        DWORD last_error = ::GetLastError();
-        ec = asio::error_code(last_error,
-            asio::error::get_system_category());
-      }
-      else
-      {
-        ec = asio::error_code();
-      }
-    }
-    else
-    {
-      // Asynchronous operations have been started from more than one thread,
-      // so cancellation is not safe.
-      ec = asio::error::operation_not_supported;
-    }
-#else // defined(ASIO_ENABLE_CANCELIO)
-    else
-    {
-      // Cancellation is not supported as CancelIo may not be used.
-      ec = asio::error::operation_not_supported;
-    }
-#endif // defined(ASIO_ENABLE_CANCELIO)
-
-    return ec;
-  }
-
-  // Determine whether the socket is at the out-of-band data mark.
-  bool at_mark(const implementation_type& impl,
-      asio::error_code& ec) const
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return false;
-    }
-
-    asio::detail::ioctl_arg_type value = 0;
-    socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
-    return ec ? false : value != 0;
-  }
-
-  // Determine the number of bytes available for reading.
-  std::size_t available(const implementation_type& impl,
-      asio::error_code& ec) const
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    asio::detail::ioctl_arg_type value = 0;
-    socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
-    return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+    if (impl.have_remote_endpoint_)
+      return native_type(impl.socket_, impl.remote_endpoint_);
+    return native_type(impl.socket_);
   }
 
   // Bind the socket to the specified local endpoint.
   asio::error_code bind(implementation_type& impl,
       const endpoint_type& endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
     socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
     return ec;
   }
 
-  // Place the socket into the state where it will listen for new connections.
-  asio::error_code listen(implementation_type& impl, int backlog,
-      asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::listen(impl.socket_, backlog, ec);
-    return ec;
-  }
-
   // Set a socket option.
   template <typename Option>
   asio::error_code set_option(implementation_type& impl,
       const Option& option, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    if (option.level(impl.protocol_) == custom_socket_option_level
-        && option.name(impl.protocol_) == enable_connection_aborted_option)
-    {
-      if (option.size(impl.protocol_) != sizeof(int))
-      {
-        ec = asio::error::invalid_argument;
-      }
-      else
-      {
-        if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
-          impl.flags_ |= implementation_type::enable_connection_aborted;
-        else
-          impl.flags_ &= ~implementation_type::enable_connection_aborted;
-        ec = asio::error_code();
-      }
-      return ec;
-    }
-    else
-    {
-      if (option.level(impl.protocol_) == SOL_SOCKET
-          && option.name(impl.protocol_) == SO_LINGER)
-      {
-        const ::linger* linger_option =
-          reinterpret_cast<const ::linger*>(option.data(impl.protocol_));
-        if (linger_option->l_onoff != 0 && linger_option->l_linger != 0)
-          impl.flags_ |= implementation_type::close_might_block;
-        else
-          impl.flags_ &= ~implementation_type::close_might_block;
-      }
-
-      socket_ops::setsockopt(impl.socket_,
-          option.level(impl.protocol_), option.name(impl.protocol_),
-          option.data(impl.protocol_), option.size(impl.protocol_), ec);
-      return ec;
-    }
+    socket_ops::setsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), option.size(impl.protocol_), ec);
+    return ec;
   }
 
   // Set a socket option.
@@ -512,65 +192,12 @@ public:
   asio::error_code get_option(const implementation_type& impl,
       Option& option, asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    if (option.level(impl.protocol_) == custom_socket_option_level
-        && option.name(impl.protocol_) == enable_connection_aborted_option)
-    {
-      if (option.size(impl.protocol_) != sizeof(int))
-      {
-        ec = asio::error::invalid_argument;
-      }
-      else
-      {
-        int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
-        if (impl.flags_ & implementation_type::enable_connection_aborted)
-          *target = 1;
-        else
-          *target = 0;
-        option.resize(impl.protocol_, sizeof(int));
-        ec = asio::error_code();
-      }
-      return ec;
-    }
-    else
-    {
-      size_t size = option.size(impl.protocol_);
-      socket_ops::getsockopt(impl.socket_,
-          option.level(impl.protocol_), option.name(impl.protocol_),
-          option.data(impl.protocol_), &size, ec);
-      if (!ec)
-        option.resize(impl.protocol_, size);
-      return ec;
-    }
-  }
-
-  // Perform an IO control command on the socket.
-  template <typename IO_Control_Command>
-  asio::error_code io_control(implementation_type& impl,
-      IO_Control_Command& command, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::ioctl(impl.socket_, command.name(),
-        static_cast<ioctl_arg_type*>(command.data()), ec);
-
-    if (!ec && command.name() == static_cast<int>(FIONBIO))
-    {
-      if (*static_cast<ioctl_arg_type*>(command.data()))
-        impl.flags_ |= implementation_type::user_set_non_blocking;
-      else
-        impl.flags_ &= ~implementation_type::user_set_non_blocking;
-    }
-
+    std::size_t size = option.size(impl.protocol_);
+    socket_ops::getsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), &size, ec);
+    if (!ec)
+      option.resize(impl.protocol_, size);
     return ec;
   }
 
@@ -578,12 +205,6 @@ public:
   endpoint_type local_endpoint(const implementation_type& impl,
       asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return endpoint_type();
-    }
-
     endpoint_type endpoint;
     std::size_t addr_len = endpoint.capacity();
     if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
@@ -596,210 +217,13 @@ public:
   endpoint_type remote_endpoint(const implementation_type& impl,
       asio::error_code& ec) const
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
+    endpoint_type endpoint = impl.remote_endpoint_;
+    std::size_t addr_len = endpoint.capacity();
+    if (socket_ops::getpeername(impl.socket_, endpoint.data(),
+          &addr_len, impl.have_remote_endpoint_, ec))
       return endpoint_type();
-    }
-
-    if (impl.socket_.have_remote_endpoint())
-    {
-      // Check if socket is still connected.
-      DWORD connect_time = 0;
-      size_t connect_time_len = sizeof(connect_time);
-      if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME,
-            &connect_time, &connect_time_len, ec) == socket_error_retval)
-      {
-        return endpoint_type();
-      }
-      if (connect_time == 0xFFFFFFFF)
-      {
-        ec = asio::error::not_connected;
-        return endpoint_type();
-      }
-
-      ec = asio::error_code();
-      return impl.socket_.remote_endpoint();
-    }
-    else
-    {
-      endpoint_type endpoint;
-      std::size_t addr_len = endpoint.capacity();
-      if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
-        return endpoint_type();
-      endpoint.resize(addr_len);
-      return endpoint;
-    }
-  }
-
-  /// Disable sends or receives on the socket.
-  asio::error_code shutdown(implementation_type& impl,
-      socket_base::shutdown_type what, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    socket_ops::shutdown(impl.socket_, what, ec);
-    return ec;
-  }
-
-  // Send the given data to the peer. Returns the number of bytes sent.
-  template <typename ConstBufferSequence>
-  size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
-      socket_base::message_flags flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    buffer_sequence_adapter<asio::const_buffer,
-        ConstBufferSequence> bufs(buffers);
-
-    // A request to receive 0 bytes on a stream socket is a no-op.
-    if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Send the data.
-    DWORD bytes_transferred = 0;
-    int result = ::WSASend(impl.socket_, bufs.buffers(),
-        bufs.count(), &bytes_transferred, flags, 0, 0);
-    if (result != 0)
-    {
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_NETNAME_DELETED)
-        last_error = WSAECONNRESET;
-      else if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return 0;
-    }
-
-    ec = asio::error_code();
-    return bytes_transferred;
-  }
-
-  // Wait until data can be sent without blocking.
-  size_t send(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    // Wait for socket to become ready.
-    socket_ops::poll_write(impl.socket_, ec);
-
-    return 0;
-  }
-
-  template <typename ConstBufferSequence, typename Handler>
-  class send_op : public operation
-  {
-  public:
-    send_op(weak_cancel_token_type cancel_token,
-        const ConstBufferSequence& buffers, Handler handler)
-      : operation(&send_op::do_complete),
-        cancel_token_(cancel_token),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      send_op* o(static_cast<send_op*>(base));
-      typedef handler_alloc_traits<Handler, send_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::const_buffer,
-            ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Map non-portable errors to their portable counterparts.
-        if (ec.value() == ERROR_NETNAME_DELETED)
-        {
-          if (o->cancel_token_.expired())
-            ec = asio::error::operation_aborted;
-          else
-            ec = asio::error::connection_reset;
-        }
-        else if (ec.value() == ERROR_PORT_UNREACHABLE)
-        {
-          ec = asio::error::connection_refused;
-        }
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    weak_cancel_token_type cancel_token_;
-    ConstBufferSequence buffers_;
-    Handler handler_;
-  };
-
-  // Start an asynchronous send. The data being sent must be valid for the
-  // lifetime of the asynchronous operation.
-  template <typename ConstBufferSequence, typename Handler>
-  void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
-      socket_base::message_flags flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef send_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl.cancel_token_, buffers, handler);
-
-    buffer_sequence_adapter<asio::const_buffer,
-        ConstBufferSequence> bufs(buffers);
-
-    start_send_op(impl, bufs.buffers(), bufs.count(), flags,
-        impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get());
-    ptr.release();
-  }
-
-  // Start an asynchronous wait until data can be sent without blocking.
-  template <typename Handler>
-  void async_send(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    start_reactor_op(impl, reactor::write_op, ptr.get());
-    ptr.release();
+    endpoint.resize(addr_len);
+    return endpoint;
   }
 
   // Send a datagram to the specified endpoint. Returns the number of bytes
@@ -809,107 +233,25 @@ public:
       const endpoint_type& destination, socket_base::message_flags flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::const_buffer,
         ConstBufferSequence> bufs(buffers);
 
-    // Send the data.
-    DWORD bytes_transferred = 0;
-    int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(),
-        &bytes_transferred, flags, destination.data(),
-        static_cast<int>(destination.size()), 0, 0);
-    if (result != 0)
-    {
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return 0;
-    }
-
-    ec = asio::error_code();
-    return bytes_transferred;
+    return socket_ops::sync_sendto(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags,
+        destination.data(), destination.size(), ec);
   }
 
   // Wait until data can be sent without blocking.
   size_t send_to(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, const endpoint_type&,
+      const endpoint_type&, socket_base::message_flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for socket to become ready.
     socket_ops::poll_write(impl.socket_, ec);
 
     return 0;
   }
 
-  template <typename ConstBufferSequence, typename Handler>
-  class send_to_op : public operation
-  {
-  public:
-    send_to_op(weak_cancel_token_type cancel_token,
-        const ConstBufferSequence& buffers, Handler handler)
-      : operation(&send_to_op::do_complete),
-        cancel_token_(cancel_token),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      send_to_op* o(static_cast<send_to_op*>(base));
-      typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::const_buffer,
-            ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Map non-portable errors to their portable counterparts.
-        if (ec.value() == ERROR_PORT_UNREACHABLE)
-        {
-          ec = asio::error::connection_refused;
-        }
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    weak_cancel_token_type cancel_token_;
-    ConstBufferSequence buffers_;
-    Handler handler_;
-  };
-
   // Start an asynchronous send. The data being sent must be valid for the
   // lifetime of the asynchronous operation.
   template <typename ConstBufferSequence, typename Handler>
@@ -918,233 +260,35 @@ public:
       socket_base::message_flags flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef send_to_op<ConstBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        impl.cancel_token_, buffers, handler);
+    typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
 
     buffer_sequence_adapter<asio::const_buffer,
         ConstBufferSequence> bufs(buffers);
 
-    start_send_to_op(impl, bufs.buffers(),
-        bufs.count(), destination, flags, ptr.get());
-    ptr.release();
+    start_send_to_op(impl, bufs.buffers(), bufs.count(),
+        destination.data(), static_cast<int>(destination.size()),
+        flags, p.p);
+    p.v = p.p = 0;
   }
 
   // Start an asynchronous wait until data can be sent without blocking.
   template <typename Handler>
   void async_send_to(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, const endpoint_type&, Handler handler)
-  {
-    // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-    start_reactor_op(impl, reactor::write_op, ptr.get());
-    ptr.release();
-  }
-
-  // Receive some data from the peer. Returns the number of bytes received.
-  template <typename MutableBufferSequence>
-  size_t receive(implementation_type& impl,
-      const MutableBufferSequence& buffers,
-      socket_base::message_flags flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    buffer_sequence_adapter<asio::mutable_buffer,
-        MutableBufferSequence> bufs(buffers);
-
-    // A request to receive 0 bytes on a stream socket is a no-op.
-    if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
-    {
-      ec = asio::error_code();
-      return 0;
-    }
-
-    // Receive some data.
-    DWORD bytes_transferred = 0;
-    DWORD recv_flags = flags;
-    int result = ::WSARecv(impl.socket_, bufs.buffers(),
-        bufs.count(), &bytes_transferred, &recv_flags, 0, 0);
-    if (result != 0)
-    {
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_NETNAME_DELETED)
-        last_error = WSAECONNRESET;
-      else if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return 0;
-    }
-    if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
-    {
-      ec = asio::error::eof;
-      return 0;
-    }
-
-    ec = asio::error_code();
-    return bytes_transferred;
-  }
-
-  // Wait until data can be received without blocking.
-  size_t receive(implementation_type& impl, const null_buffers&,
-      socket_base::message_flags, asio::error_code& ec)
-  {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
-    // Wait for socket to become ready.
-    socket_ops::poll_read(impl.socket_, ec);
-
-    return 0;
-  }
-
-  template <typename MutableBufferSequence, typename Handler>
-  class receive_op : public operation
-  {
-  public:
-    receive_op(int protocol_type, weak_cancel_token_type cancel_token,
-        const MutableBufferSequence& buffers, Handler handler)
-      : operation(&receive_op::do_complete),
-        protocol_type_(protocol_type),
-        cancel_token_(cancel_token),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      receive_op* o(static_cast<receive_op*>(base));
-      typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::mutable_buffer,
-            MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Map non-portable errors to their portable counterparts.
-        if (ec.value() == ERROR_NETNAME_DELETED)
-        {
-          if (o->cancel_token_.expired())
-            ec = asio::error::operation_aborted;
-          else
-            ec = asio::error::connection_reset;
-        }
-        else if (ec.value() == ERROR_PORT_UNREACHABLE)
-        {
-          ec = asio::error::connection_refused;
-        }
-
-        // Check for connection closed.
-        else if (!ec && bytes_transferred == 0
-            && o->protocol_type_ == SOCK_STREAM
-            && !buffer_sequence_adapter<asio::mutable_buffer,
-                MutableBufferSequence>::all_empty(o->buffers_)
-            && !boost::is_same<MutableBufferSequence, null_buffers>::value)
-        {
-          ec = asio::error::eof;
-        }
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    int protocol_type_;
-    weak_cancel_token_type cancel_token_;
-    MutableBufferSequence buffers_;
-    Handler handler_;
-  };
-
-  // Start an asynchronous receive. The buffer for the data being received
-  // must be valid for the lifetime of the asynchronous operation.
-  template <typename MutableBufferSequence, typename Handler>
-  void async_receive(implementation_type& impl,
-      const MutableBufferSequence& buffers,
-      socket_base::message_flags flags, Handler handler)
+      const endpoint_type&, socket_base::message_flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef receive_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    int protocol_type = impl.protocol_.type();
-    handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
-        impl.cancel_token_, buffers, handler);
-
-    buffer_sequence_adapter<asio::mutable_buffer,
-        MutableBufferSequence> bufs(buffers);
+    typedef win_iocp_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler);
 
-    start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
-        protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get());
-    ptr.release();
-  }
-
-  // Wait until data can be received without blocking.
-  template <typename Handler>
-  void async_receive(implementation_type& impl, const null_buffers& buffers,
-      socket_base::message_flags flags, Handler handler)
-  {
-    if (impl.protocol_.type() == SOCK_STREAM)
-    {
-      // For stream sockets on Windows, we may issue a 0-byte overlapped
-      // WSARecv to wait until there is data available on the socket.
-
-      // Allocate and construct an operation to wrap the handler.
-      typedef receive_op<null_buffers, Handler> value_type;
-      typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-      raw_handler_ptr<alloc_traits> raw_ptr(handler);
-      int protocol_type = impl.protocol_.type();
-      handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
-          impl.cancel_token_, buffers, handler);
-
-      ::WSABUF buf = { 0, 0 };
-      start_receive_op(impl, &buf, 1, flags, false, ptr.get());
-      ptr.release();
-    }
-    else
-    {
-      // Allocate and construct an operation to wrap the handler.
-      typedef null_buffers_op<Handler> value_type;
-      typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-      raw_handler_ptr<alloc_traits> raw_ptr(handler);
-      handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
-      start_reactor_op(impl,
-          (flags & socket_base::message_out_of_band)
-            ? reactor::except_op : reactor::read_op,
-          ptr.get());
-      ptr.release();
-    }
+    start_reactor_op(impl, reactor::write_op, p.p);
+    p.v = p.p = 0;
   }
 
   // Receive a datagram with the endpoint of the sender. Returns the number of
@@ -1155,41 +299,18 @@ public:
       endpoint_type& sender_endpoint, socket_base::message_flags flags,
       asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     buffer_sequence_adapter<asio::mutable_buffer,
         MutableBufferSequence> bufs(buffers);
 
-    // Receive some data.
-    DWORD bytes_transferred = 0;
-    DWORD recv_flags = flags;
-    int endpoint_size = static_cast<int>(sender_endpoint.capacity());
-    int result = ::WSARecvFrom(impl.socket_, bufs.buffers(),
-        bufs.count(), &bytes_transferred, &recv_flags,
-        sender_endpoint.data(), &endpoint_size, 0, 0);
-    if (result != 0)
-    {
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      ec = asio::error_code(last_error,
-          asio::error::get_system_category());
-      return 0;
-    }
-    if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
-    {
-      ec = asio::error::eof;
-      return 0;
-    }
+    std::size_t addr_len = sender_endpoint.capacity();
+    std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+        impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+        flags, sender_endpoint.data(), &addr_len, ec);
 
-    sender_endpoint.resize(static_cast<std::size_t>(endpoint_size));
+    if (!ec)
+      sender_endpoint.resize(addr_len);
 
-    ec = asio::error_code();
-    return bytes_transferred;
+    return bytes_recvd;
   }
 
   // Wait until data can be received without blocking.
@@ -1197,12 +318,6 @@ public:
       const null_buffers&, endpoint_type& sender_endpoint,
       socket_base::message_flags, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return 0;
-    }
-
     // Wait for socket to become ready.
     socket_ops::poll_read(impl.socket_, ec);
 
@@ -1212,75 +327,6 @@ public:
     return 0;
   }
 
-  template <typename MutableBufferSequence, typename Handler>
-  class receive_from_op : public operation
-  {
-  public:
-    receive_from_op(int protocol_type, endpoint_type& endpoint,
-        const MutableBufferSequence& buffers, Handler handler)
-      : operation(&receive_from_op::do_complete),
-        protocol_type_(protocol_type),
-        endpoint_(endpoint),
-        endpoint_size_(static_cast<int>(endpoint.capacity())),
-        buffers_(buffers),
-        handler_(handler)
-    {
-    }
-
-    int& endpoint_size()
-    {
-      return endpoint_size_;
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t bytes_transferred)
-    {
-      // Take ownership of the operation object.
-      receive_from_op* o(static_cast<receive_from_op*>(base));
-      typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-        // Check whether buffers are still valid.
-        buffer_sequence_adapter<asio::mutable_buffer,
-            MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
-        // Map non-portable errors to their portable counterparts.
-        if (ec.value() == ERROR_PORT_UNREACHABLE)
-        {
-          ec = asio::error::connection_refused;
-        }
-
-        // Record the size of the endpoint returned by the operation.
-        o->endpoint_.resize(o->endpoint_size_);
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder2<Handler, asio::error_code, std::size_t>
-          handler(o->handler_, ec, bytes_transferred);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    int protocol_type_;
-    endpoint_type& endpoint_;
-    int endpoint_size_;
-    weak_cancel_token_type cancel_token_;
-    MutableBufferSequence buffers_;
-    Handler handler_;
-  };
-
   // Start an asynchronous receive. The buffer for the data being received and
   // the sender_endpoint object must both be valid for the lifetime of the
   // asynchronous operation.
@@ -1290,19 +336,19 @@ public:
       socket_base::message_flags flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef receive_from_op<MutableBufferSequence, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    int protocol_type = impl.protocol_.type();
-    handler_ptr<alloc_traits> ptr(raw_ptr,
-        protocol_type, sender_endp, buffers, handler);
+    typedef win_iocp_socket_recvfrom_op<
+      MutableBufferSequence, endpoint_type, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
 
     buffer_sequence_adapter<asio::mutable_buffer,
         MutableBufferSequence> bufs(buffers);
 
     start_receive_from_op(impl, bufs.buffers(), bufs.count(),
-        sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get());
-    ptr.release();
+        sender_endp.data(), flags, &p.p->endpoint_size(), p.p);
+    p.v = p.p = 0;
   }
 
   // Wait until data can be received without blocking.
@@ -1312,19 +358,17 @@ public:
       socket_base::message_flags flags, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef null_buffers_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+    typedef win_iocp_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler);
 
     // Reset endpoint since it can be given no sensible value at this time.
     sender_endpoint = endpoint_type();
 
-    start_reactor_op(impl,
-        (flags & socket_base::message_out_of_band)
-          ? reactor::except_op : reactor::read_op,
-        ptr.get());
-    ptr.release();
+    start_null_buffers_receive_op(impl, flags, p.p);
+    p.v = p.p = 0;
   }
 
   // Accept a new connection.
@@ -1332,12 +376,6 @@ public:
   asio::error_code accept(implementation_type& impl, Socket& peer,
       endpoint_type* peer_endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
     // We cannot accept a socket that is already open.
     if (peer.is_open())
     {
@@ -1345,222 +383,22 @@ public:
       return ec;
     }
 
-    for (;;)
-    {
-      socket_holder new_socket;
-      std::size_t addr_len = 0;
-      if (peer_endpoint)
-      {
-        addr_len = peer_endpoint->capacity();
-        new_socket.reset(socket_ops::accept(impl.socket_,
-              peer_endpoint->data(), &addr_len, ec));
-      }
-      else
-      {
-        new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
-      }
-
-      if (ec)
-      {
-        if (ec == asio::error::connection_aborted
-            && !(impl.flags_ & implementation_type::enable_connection_aborted))
-        {
-          // Retry accept operation.
-          continue;
-        }
-        else
-        {
-          return ec;
-        }
-      }
+    std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+    socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+          impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+          peer_endpoint ? &addr_len : 0, ec));
 
+    // On success, assign new connection to peer socket object.
+    if (new_socket.get() >= 0)
+    {
       if (peer_endpoint)
         peer_endpoint->resize(addr_len);
-
-      peer.assign(impl.protocol_, new_socket.get(), ec);
-      if (!ec)
+      if (!peer.assign(impl.protocol_, new_socket.get(), ec))
         new_socket.release();
-      return ec;
-    }
-  }
-
-  template <typename Socket, typename Handler>
-  class accept_op : public operation
-  {
-  public:
-    accept_op(win_iocp_io_service& iocp_service, socket_type socket,
-        Socket& peer, const protocol_type& protocol,
-        endpoint_type* peer_endpoint, bool enable_connection_aborted,
-        Handler handler)
-      : operation(&accept_op::do_complete),
-        iocp_service_(iocp_service),
-        socket_(socket),
-        peer_(peer),
-        protocol_(protocol),
-        peer_endpoint_(peer_endpoint),
-        enable_connection_aborted_(enable_connection_aborted),
-        handler_(handler)
-    {
     }
 
-    socket_holder& new_socket()
-    {
-      return new_socket_;
-    }
-
-    void* output_buffer()
-    {
-      return output_buffer_;
-    }
-
-    DWORD address_length()
-    {
-      return sizeof(sockaddr_storage_type) + 16;
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code ec, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      accept_op* o(static_cast<accept_op*>(base));
-      typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
-        if (ec.value() == ERROR_NETNAME_DELETED)
-        {
-          ec = asio::error::connection_aborted;
-        }
-
-        // Restart the accept operation if we got the connection_aborted error
-        // and the enable_connection_aborted socket option is not set.
-        if (ec == asio::error::connection_aborted
-            && !o->enable_connection_aborted_)
-        {
-          // Reset OVERLAPPED structure.
-          o->reset();
-
-          // Create a new socket for the next connection, since the AcceptEx
-          // call fails with WSAEINVAL if we try to reuse the same socket.
-          o->new_socket_.reset();
-          o->new_socket_.reset(socket_ops::socket(o->protocol_.family(),
-                o->protocol_.type(), o->protocol_.protocol(), ec));
-          if (o->new_socket_.get() != invalid_socket)
-          {
-            // Accept a connection.
-            DWORD bytes_read = 0;
-            BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(),
-                o->output_buffer(), 0, o->address_length(),
-                o->address_length(), &bytes_read, o);
-            DWORD last_error = ::WSAGetLastError();
-            ec = asio::error_code(last_error,
-                asio::error::get_system_category());
-
-            // Check if the operation completed immediately.
-            if (!result && last_error != WSA_IO_PENDING)
-            {
-              if (last_error == ERROR_NETNAME_DELETED
-                  || last_error == WSAECONNABORTED)
-              {
-                // Post this handler so that operation will be restarted again.
-                o->iocp_service_.work_started();
-                o->iocp_service_.on_completion(o, ec);
-                ptr.release();
-                return;
-              }
-              else
-              {
-                // Operation already complete. Continue with rest of this
-                // handler.
-              }
-            }
-            else
-            {
-              // Asynchronous operation has been successfully restarted.
-              o->iocp_service_.work_started();
-              o->iocp_service_.on_pending(o);
-              ptr.release();
-              return;
-            }
-          }
-        }
-
-        // Get the address of the peer.
-        endpoint_type peer_endpoint;
-        if (!ec)
-        {
-          LPSOCKADDR local_addr = 0;
-          int local_addr_length = 0;
-          LPSOCKADDR remote_addr = 0;
-          int remote_addr_length = 0;
-          GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(),
-              o->address_length(), &local_addr, &local_addr_length,
-              &remote_addr, &remote_addr_length);
-          if (static_cast<std::size_t>(remote_addr_length)
-              > peer_endpoint.capacity())
-          {
-            ec = asio::error::invalid_argument;
-          }
-          else
-          {
-            using namespace std; // For memcpy.
-            memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
-            peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
-          }
-        }
-
-        // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
-        // and getpeername will work on the accepted socket.
-        if (!ec)
-        {
-          SOCKET update_ctx_param = o->socket_;
-          socket_ops::setsockopt(o->new_socket_.get(),
-                SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
-                &update_ctx_param, sizeof(SOCKET), ec);
-        }
-
-        // If the socket was successfully accepted, transfer ownership of the
-        // socket to the peer object.
-        if (!ec)
-        {
-          o->peer_.assign(o->protocol_,
-              native_type(o->new_socket_.get(), peer_endpoint), ec);
-          if (!ec)
-            o->new_socket_.release();
-        }
-
-        // Pass endpoint back to caller.
-        if (o->peer_endpoint_)
-          *o->peer_endpoint_ = peer_endpoint;
-
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder1<Handler, asio::error_code>
-          handler(o->handler_, ec);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    win_iocp_io_service& iocp_service_;
-    socket_type socket_;
-    socket_holder new_socket_;
-    Socket& peer_;
-    protocol_type protocol_;
-    endpoint_type* peer_endpoint_;
-    unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
-    bool enable_connection_aborted_;
-    Handler handler_;
-  };
+    return ec;
+  }
 
   // Start an asynchronous accept. The peer and peer_endpoint objects
   // must be valid until the accept's handler is invoked.
@@ -1569,442 +407,54 @@ public:
       endpoint_type* peer_endpoint, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef accept_op<Socket, Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
+    typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
     bool enable_connection_aborted =
-      (impl.flags_ & implementation_type::enable_connection_aborted);
-    handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, impl.socket_, peer,
-        impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+      (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+    p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
+        peer_endpoint, enable_connection_aborted, handler);
 
-    start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(),
-        ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get());
-    ptr.release();
+    start_accept_op(impl, peer.is_open(), p.p->new_socket(),
+        impl.protocol_.family(), impl.protocol_.type(),
+        impl.protocol_.protocol(), p.p->output_buffer(),
+        p.p->address_length(), p.p);
+    p.v = p.p = 0;
   }
 
   // Connect the socket to the specified endpoint.
   asio::error_code connect(implementation_type& impl,
       const endpoint_type& peer_endpoint, asio::error_code& ec)
   {
-    if (!is_open(impl))
-    {
-      ec = asio::error::bad_descriptor;
-      return ec;
-    }
-
-    // Perform the connect operation.
-    socket_ops::connect(impl.socket_,
+    socket_ops::sync_connect(impl.socket_,
         peer_endpoint.data(), peer_endpoint.size(), ec);
     return ec;
   }
 
-  class connect_op_base : public reactor_op
-  {
-  public:
-    connect_op_base(socket_type socket, func_type complete_func)
-      : reactor_op(&connect_op_base::do_perform, complete_func),
-        socket_(socket)
-    {
-    }
-
-    static bool do_perform(reactor_op* base)
-    {
-      connect_op_base* o(static_cast<connect_op_base*>(base));
-
-      // Get the error code from the connect operation.
-      int connect_error = 0;
-      size_t connect_error_len = sizeof(connect_error);
-      if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
-            &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
-        return true;
-
-      // The connection failed so the handler will be posted with an error code.
-      if (connect_error)
-      {
-        o->ec_ = asio::error_code(connect_error,
-            asio::error::get_system_category());
-      }
-
-      return true;
-    }
-
-  private:
-    socket_type socket_;
-  };
-
-  template <typename Handler>
-  class connect_op : public connect_op_base
-  {
-  public:
-    connect_op(socket_type socket, Handler handler)
-      : connect_op_base(socket, &connect_op::do_complete),
-        handler_(handler)
-    {
-    }
-
-    static void do_complete(io_service_impl* owner, operation* base,
-        asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
-    {
-      // Take ownership of the handler object.
-      connect_op* o(static_cast<connect_op*>(base));
-      typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
-      handler_ptr<alloc_traits> ptr(o->handler_, o);
-
-      // Make the upcall if required.
-      if (owner)
-      {
-        // Make a copy of the handler so that the memory can be deallocated
-        // before the upcall is made. Even if we're not about to make an
-        // upcall, a sub-object of the handler may be the true owner of the
-        // memory associated with the handler. Consequently, a local copy of
-        // the handler is required to ensure that any owning sub-object remains
-        // valid until after we have deallocated the memory here.
-        detail::binder1<Handler, asio::error_code>
-          handler(o->handler_, o->ec_);
-        ptr.reset();
-        asio::detail::fenced_block b;
-        asio_handler_invoke_helpers::invoke(handler, handler);
-      }
-    }
-
-  private:
-    Handler handler_;
-  };
-
   // Start an asynchronous connect.
   template <typename Handler>
   void async_connect(implementation_type& impl,
       const endpoint_type& peer_endpoint, Handler handler)
   {
     // Allocate and construct an operation to wrap the handler.
-    typedef connect_op<Handler> value_type;
-    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
-    raw_handler_ptr<alloc_traits> raw_ptr(handler);
-    handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler);
-
-    start_connect_op(impl, ptr.get(), peer_endpoint);
-    ptr.release();
-  }
-
-private:
-  // Helper function to start an asynchronous send operation.
-  void start_send_op(implementation_type& impl, WSABUF* buffers,
-      std::size_t buffer_count, socket_base::message_flags flags,
-      bool noop, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
-
-    if (noop)
-      iocp_service_.on_completion(op);
-    else if (!is_open(impl))
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    else
-    {
-      DWORD bytes_transferred = 0;
-      int result = ::WSASend(impl.socket_, buffers,
-          buffer_count, &bytes_transferred, flags, op, 0);
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      if (result != 0 && last_error != WSA_IO_PENDING)
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      else
-        iocp_service_.on_pending(op);
-    }
-  }
-
-  // Helper function to start an asynchronous send_to operation.
-  void start_send_to_op(implementation_type& impl, WSABUF* buffers,
-      std::size_t buffer_count, const endpoint_type& destination,
-      socket_base::message_flags flags, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
+    typedef reactive_socket_connect_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.socket_, handler);
 
-    if (!is_open(impl))
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    else
-    {
-      DWORD bytes_transferred = 0;
-      int result = ::WSASendTo(impl.socket_, buffers, buffer_count,
-          &bytes_transferred, flags, destination.data(),
-          static_cast<int>(destination.size()), op, 0);
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      if (result != 0 && last_error != WSA_IO_PENDING)
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      else
-        iocp_service_.on_pending(op);
-    }
+    start_connect_op(impl, p.p, peer_endpoint.data(),
+        static_cast<int>(peer_endpoint.size()));
+    p.v = p.p = 0;
   }
-
-  // Helper function to start an asynchronous receive operation.
-  void start_receive_op(implementation_type& impl, WSABUF* buffers,
-      std::size_t buffer_count, socket_base::message_flags flags,
-      bool noop, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
-
-    if (noop)
-      iocp_service_.on_completion(op);
-    else if (!is_open(impl))
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    else
-    {
-      DWORD bytes_transferred = 0;
-      DWORD recv_flags = flags;
-      int result = ::WSARecv(impl.socket_, buffers, buffer_count,
-          &bytes_transferred, &recv_flags, op, 0);
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_NETNAME_DELETED)
-        last_error = WSAECONNRESET;
-      else if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      if (result != 0 && last_error != WSA_IO_PENDING)
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      else
-        iocp_service_.on_pending(op);
-    }
-  }
-
-  // Helper function to start an asynchronous receive_from operation.
-  void start_receive_from_op(implementation_type& impl, WSABUF* buffers,
-      std::size_t buffer_count, endpoint_type& sender_endpoint,
-      socket_base::message_flags flags, int* endpoint_size, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
-
-    if (!is_open(impl))
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    else
-    {
-      DWORD bytes_transferred = 0;
-      DWORD recv_flags = flags;
-      int result = ::WSARecvFrom(impl.socket_, buffers,
-          buffer_count, &bytes_transferred, &recv_flags,
-          sender_endpoint.data(), endpoint_size, op, 0);
-      DWORD last_error = ::WSAGetLastError();
-      if (last_error == ERROR_PORT_UNREACHABLE)
-        last_error = WSAECONNREFUSED;
-      if (result != 0 && last_error != WSA_IO_PENDING)
-        iocp_service_.on_completion(op, last_error, bytes_transferred);
-      else
-        iocp_service_.on_pending(op);
-    }
-  }
-
-  // Helper function to start an asynchronous receive_from operation.
-  void start_accept_op(implementation_type& impl,
-      bool peer_is_open, socket_holder& new_socket,
-      void* output_buffer, DWORD address_length, operation* op)
-  {
-    update_cancellation_thread_id(impl);
-    iocp_service_.work_started();
-
-    if (!is_open(impl))
-      iocp_service_.on_completion(op, asio::error::bad_descriptor);
-    else if (peer_is_open)
-      iocp_service_.on_completion(op, asio::error::already_open);
-    else
-    {
-      asio::error_code ec;
-      new_socket.reset(socket_ops::socket(impl.protocol_.family(),
-            impl.protocol_.type(), impl.protocol_.protocol(), ec));
-      if (new_socket.get() == invalid_socket)
-        iocp_service_.on_completion(op, ec);
-      else
-      {
-        DWORD bytes_read = 0;
-        BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
-            0, address_length, address_length, &bytes_read, op);
-        DWORD last_error = ::WSAGetLastError();
-        if (!result && last_error != WSA_IO_PENDING)
-          iocp_service_.on_completion(op, last_error);
-        else
-          iocp_service_.on_pending(op);
-      }
-    }
-  }
-
-  // Start an asynchronous read or write operation using the the reactor.
-  void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op)
-  {
-    reactor& r = get_reactor();
-    update_cancellation_thread_id(impl);
-
-    if (is_open(impl))
-    {
-      r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
-      return;
-    }
-    else
-      op->ec_ = asio::error::bad_descriptor;
-
-    iocp_service_.post_immediate_completion(op);
-  }
-
-  // Start the asynchronous connect operation using the reactor.
-  void start_connect_op(implementation_type& impl,
-      reactor_op* op, const endpoint_type& peer_endpoint)
-  {
-    reactor& r = get_reactor();
-    update_cancellation_thread_id(impl);
-
-    if (is_open(impl))
-    {
-      ioctl_arg_type non_blocking = 1;
-      if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_))
-      {
-        if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
-              peer_endpoint.size(), op->ec_) != 0)
-        {
-          if (!op->ec_
-              && !(impl.flags_ & implementation_type::user_set_non_blocking))
-          {
-            non_blocking = 0;
-            socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_);
-          }
-
-          if (op->ec_ == asio::error::in_progress
-              || op->ec_ == asio::error::would_block)
-          {
-            op->ec_ = asio::error_code();
-            r.start_op(reactor::connect_op, impl.socket_,
-                impl.reactor_data_, op, true);
-            return;
-          }
-        }
-      }
-    }
-    else
-      op->ec_ = asio::error::bad_descriptor;
-
-    iocp_service_.post_immediate_completion(op);
-  }
-
-  // Helper function to close a socket when the associated object is being
-  // destroyed.
-  void close_for_destruction(implementation_type& impl)
-  {
-    if (is_open(impl))
-    {
-      // Check if the reactor was created, in which case we need to close the
-      // socket on the reactor as well to cancel any operations that might be
-      // running there.
-      reactor* r = static_cast<reactor*>(
-            interlocked_compare_exchange_pointer(
-              reinterpret_cast<void**>(&reactor_), 0, 0));
-      if (r)
-        r->close_descriptor(impl.socket_, impl.reactor_data_);
-
-      // The socket destructor must not block. If the user has changed the
-      // linger option to block in the foreground, we will change it back to the
-      // default so that the closure is performed in the background.
-      if (impl.flags_ & implementation_type::close_might_block)
-      {
-        ::linger opt;
-        opt.l_onoff = 0;
-        opt.l_linger = 0;
-        asio::error_code ignored_ec;
-        socket_ops::setsockopt(impl.socket_,
-            SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
-      }
-
-      asio::error_code ignored_ec;
-      socket_ops::close(impl.socket_, ignored_ec);
-      impl.socket_ = invalid_socket;
-      impl.flags_ = 0;
-      impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
-      impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
-    }
-  }
-
-  // Update the ID of the thread from which cancellation is safe.
-  void update_cancellation_thread_id(implementation_type& impl)
-  {
-#if defined(ASIO_ENABLE_CANCELIO)
-    if (impl.safe_cancellation_thread_id_ == 0)
-      impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
-    else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
-      impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#else // defined(ASIO_ENABLE_CANCELIO)
-    (void)impl;
-#endif // defined(ASIO_ENABLE_CANCELIO)
-  }
-
-  // Helper function to get the reactor. If no reactor has been created yet, a
-  // new one is obtained from the io_service and a pointer to it is cached in
-  // this service.
-  reactor& get_reactor()
-  {
-    reactor* r = static_cast<reactor*>(
-          interlocked_compare_exchange_pointer(
-            reinterpret_cast<void**>(&reactor_), 0, 0));
-    if (!r)
-    {
-      r = &(use_service<reactor>(io_service_));
-      interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
-    }
-    return *r;
-  }
-
-  // Helper function to emulate InterlockedCompareExchangePointer functionality
-  // for:
-  // - very old Platform SDKs; and
-  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
-  void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp)
-  {
-#if defined(_M_IX86)
-    return reinterpret_cast<void*>(InterlockedCompareExchange(
-          reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
-          reinterpret_cast<LONG>(cmp)));
-#else
-    return InterlockedCompareExchangePointer(dest, exch, cmp);
-#endif
-  }
-
-  // Helper function to emulate InterlockedExchangePointer functionality for:
-  // - very old Platform SDKs; and
-  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
-  void* interlocked_exchange_pointer(void** dest, void* val)
-  {
-#if defined(_M_IX86)
-    return reinterpret_cast<void*>(InterlockedExchange(
-          reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
-#else
-    return InterlockedExchangePointer(dest, val);
-#endif
-  }
-
-  // The io_service used to obtain the reactor, if required.
-  asio::io_service& io_service_;
-
-  // The IOCP service used for running asynchronous operations and dispatching
-  // handlers.
-  win_iocp_io_service& iocp_service_;
-
-  // The reactor used for performing connect operations. This object is created
-  // only if needed.
-  reactor* reactor_;
-
-  // Mutex to protect access to the linked list of implementations. 
-  asio::detail::mutex mutex_;
-
-  // The head of a linked list of all implementations.
-  implementation_type* impl_list_;
 };
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(ASIO_HAS_IOCP)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_IOCP)
+
 #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_service_base.hpp b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp
new file mode 100644
index 0000000..62010b3
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp
@@ -0,0 +1,385 @@
+//
+// detail/win_iocp_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_recv_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_service_base
+{
+public:
+  // The implementation type of the socket.
+  struct base_implementation_type
+  {
+    // The native socket representation.
+    socket_type socket_;
+
+    // The current state of the socket.
+    socket_ops::state_type state_;
+
+    // We use a shared pointer as a cancellation token here to work around the
+    // broken Windows support for cancellation. MSDN says that when you call
+    // closesocket any outstanding WSARecv or WSASend operations will complete
+    // with the error ERROR_OPERATION_ABORTED. In practice they complete with
+    // ERROR_NETNAME_DELETED, which means you can't tell the difference between
+    // a local cancellation and the socket being hard-closed by the peer.
+    socket_ops::shared_cancel_token_type cancel_token_;
+
+    // Per-descriptor data used by the reactor.
+    reactor::per_descriptor_data reactor_data_;
+
+#if defined(ASIO_ENABLE_CANCELIO)
+    // The ID of the thread from which it is safe to cancel asynchronous
+    // operations. 0 means no asynchronous operations have been started yet.
+    // ~0 means asynchronous operations have been started from more than one
+    // thread, and cancellation is not supported for the socket.
+    DWORD safe_cancellation_thread_id_;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+    // Pointers to adjacent socket implementations in linked list.
+    base_implementation_type* next_;
+    base_implementation_type* prev_;
+  };
+
+  // Constructor.
+  ASIO_DECL win_iocp_socket_service_base(
+      asio::io_service& io_service);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown_service();
+
+  // Construct a new socket implementation.
+  ASIO_DECL void construct(base_implementation_type& impl);
+
+  // Destroy a socket implementation.
+  ASIO_DECL void destroy(base_implementation_type& impl);
+
+  // Determine whether the socket is open.
+  bool is_open(const base_implementation_type& impl) const
+  {
+    return impl.socket_ != invalid_socket;
+  }
+
+  // Destroy a socket implementation.
+  ASIO_DECL asio::error_code close(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Cancel all operations associated with the socket.
+  ASIO_DECL asio::error_code cancel(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::sockatmark(impl.socket_, ec);
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::available(impl.socket_, ec);
+  }
+
+  // Place the socket into the state where it will listen for new connections.
+  asio::error_code listen(base_implementation_type& impl,
+      int backlog, asio::error_code& ec)
+  {
+    socket_ops::listen(impl.socket_, backlog, ec);
+    return ec;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(base_implementation_type& impl,
+      IO_Control_Command& command, asio::error_code& ec)
+  {
+    socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+    return ec;
+  }
+
+  /// Disable sends or receives on the socket.
+  asio::error_code shutdown(base_implementation_type& impl,
+      socket_base::shutdown_type what, asio::error_code& ec)
+  {
+    socket_ops::shutdown(impl.socket_, what, ec);
+    return ec;
+  }
+
+  // Send the given data to the peer. Returns the number of bytes sent.
+  template <typename ConstBufferSequence>
+  size_t send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_send(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler>
+  void async_send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    start_send_op(impl, bufs.buffers(), bufs.count(), flags,
+        (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+        p.p);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler>
+  void async_send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler);
+
+    start_reactor_op(impl, reactor::write_op, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_recv(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence, typename Handler>
+  void async_receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler);
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
+        (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+        p.p);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler>
+  void async_receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags flags, Handler handler)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler> op;
+    typename op::ptr p = { boost::addressof(handler),
+      asio_handler_alloc_helpers::allocate(
+        sizeof(op), handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler);
+
+    start_null_buffers_receive_op(impl, flags, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Helper function to restart an asynchronous accept operation.
+  ASIO_DECL void restart_accept_op(socket_type s,
+      socket_holder& new_socket, int family, int type, int protocol,
+      void* output_buffer, DWORD address_length, operation* op);
+
+protected:
+  // Open a new socket implementation.
+  ASIO_DECL asio::error_code do_open(
+      base_implementation_type& impl, int family, int type,
+      int protocol, asio::error_code& ec);
+
+  // Assign a native socket to a socket implementation.
+  ASIO_DECL asio::error_code do_assign(
+      base_implementation_type& impl, int type,
+      socket_type native_socket, asio::error_code& ec);
+
+  // Helper function to start an asynchronous send operation.
+  ASIO_DECL void start_send_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      socket_base::message_flags flags, bool noop, operation* op);
+
+  // Helper function to start an asynchronous send_to operation.
+  ASIO_DECL void start_send_to_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      const socket_addr_type* addr, int addrlen,
+      socket_base::message_flags flags, operation* op);
+
+  // Helper function to start an asynchronous receive operation.
+  ASIO_DECL void start_receive_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      socket_base::message_flags flags, bool noop, operation* op);
+
+  // Helper function to start an asynchronous null_buffers receive operation.
+  ASIO_DECL void start_null_buffers_receive_op(
+      base_implementation_type& impl,
+      socket_base::message_flags flags, reactor_op* op);
+
+  // Helper function to start an asynchronous receive_from operation.
+  ASIO_DECL void start_receive_from_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+      socket_base::message_flags flags, int* addrlen, operation* op);
+
+  // Helper function to start an asynchronous accept operation.
+  ASIO_DECL void start_accept_op(base_implementation_type& impl,
+      bool peer_is_open, socket_holder& new_socket, int family, int type,
+      int protocol, void* output_buffer, DWORD address_length, operation* op);
+
+  // Start an asynchronous read or write operation using the the reactor.
+  ASIO_DECL void start_reactor_op(base_implementation_type& impl,
+      int op_type, reactor_op* op);
+
+  // Start the asynchronous connect operation using the reactor.
+  ASIO_DECL void start_connect_op(base_implementation_type& impl,
+      reactor_op* op, const socket_addr_type* addr, std::size_t addrlen);
+
+  // Helper function to close a socket when the associated object is being
+  // destroyed.
+  ASIO_DECL void close_for_destruction(base_implementation_type& impl);
+
+  // Update the ID of the thread from which cancellation is safe.
+  ASIO_DECL void update_cancellation_thread_id(
+      base_implementation_type& impl);
+
+  // Helper function to get the reactor. If no reactor has been created yet, a
+  // new one is obtained from the io_service and a pointer to it is cached in
+  // this service.
+  ASIO_DECL reactor& get_reactor();
+
+  // Helper function to emulate InterlockedCompareExchangePointer functionality
+  // for:
+  // - very old Platform SDKs; and
+  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+  ASIO_DECL void* interlocked_compare_exchange_pointer(
+      void** dest, void* exch, void* cmp);
+
+  // Helper function to emulate InterlockedExchangePointer functionality for:
+  // - very old Platform SDKs; and
+  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+  ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
+
+  // The io_service used to obtain the reactor, if required.
+  asio::io_service& io_service_;
+
+  // The IOCP service used for running asynchronous operations and dispatching
+  // handlers.
+  win_iocp_io_service& iocp_service_;
+
+  // The reactor used for performing connect operations. This object is created
+  // only if needed.
+  reactor* reactor_;
+
+  // Mutex to protect access to the linked list of implementations. 
+  asio::detail::mutex mutex_;
+
+  // The head of a linked list of all implementations.
+  base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/win_mutex.hpp b/ext/asio/asio/detail/win_mutex.hpp
index 1280a4e..59ad697 100644
--- a/ext/asio/asio/detail/win_mutex.hpp
+++ b/ext/asio/asio/detail/win_mutex.hpp
@@ -1,8 +1,8 @@
 //
-// win_mutex.hpp
-// ~~~~~~~~~~~~~
+// detail/win_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
 #include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/socket_types.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -43,18 +35,7 @@ public:
   typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
 
   // Constructor.
-  win_mutex()
-  {
-    int error = do_init();
-    if (error != 0)
-    {
-      asio::system_error e(
-          asio::error_code(error,
-            asio::error::get_system_category()),
-          "mutex");
-      boost::throw_exception(e);
-    }
-  }
+  ASIO_DECL win_mutex();
 
   // Destructor.
   ~win_mutex()
@@ -78,35 +59,7 @@ private:
   // Initialisation must be performed in a separate function to the constructor
   // since the compiler does not support the use of structured exceptions and
   // C++ exceptions in the same function.
-  int do_init()
-  {
-#if defined(__MINGW32__)
-    // Not sure if MinGW supports structured exception handling, so for now
-    // we'll just call the Windows API and hope.
-# if defined(UNDER_CE)
-    ::InitializeCriticalSection(&crit_section_);
-# else
-    ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
-# endif
-    return 0;
-#else
-    __try
-    {
-# if defined(UNDER_CE)
-      ::InitializeCriticalSection(&crit_section_);
-# else
-      ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
-# endif
-    }
-    __except(GetExceptionCode() == STATUS_NO_MEMORY
-        ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
-    {
-      return ERROR_OUTOFMEMORY;
-    }
-
-    return 0;
-#endif
-  }
+  ASIO_DECL int do_init();
 
   ::CRITICAL_SECTION crit_section_;
 };
@@ -114,8 +67,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
 #endif // ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/ext/asio/asio/detail/win_thread.hpp b/ext/asio/asio/detail/win_thread.hpp
index 9bf0665..e73d1a4 100644
--- a/ext/asio/asio/detail/win_thread.hpp
+++ b/ext/asio/asio/detail/win_thread.hpp
@@ -1,8 +1,8 @@
 //
-// win_thread.hpp
-// ~~~~~~~~~~~~~~
+// detail/win_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,34 +15,24 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_types.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <memory>
-#include <process.h>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
 
-unsigned int __stdcall win_thread_function(void* arg);
+ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
 
 #if defined(WINVER) && (WINVER < 0x0500)
-void __stdcall apc_function(ULONG data);
+ASIO_DECL void __stdcall apc_function(ULONG data);
 #else
-void __stdcall apc_function(ULONG_PTR data);
+ASIO_DECL void __stdcall apc_function(ULONG_PTR data);
 #endif
 
 template <typename T>
@@ -73,92 +63,26 @@ class win_thread
 public:
   // Constructor.
   template <typename Function>
-  win_thread(Function f)
-    : exit_event_(0)
+  win_thread(Function f, unsigned int stack_size = 0)
+    : thread_(0),
+      exit_event_(0)
   {
-    std::auto_ptr<func_base> arg(new func<Function>(f));
-
-    ::HANDLE entry_event = 0;
-    arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
-    if (!entry_event)
-    {
-      DWORD last_error = ::GetLastError();
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "thread.entry_event");
-      boost::throw_exception(e);
-    }
-
-    arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
-    if (!exit_event_)
-    {
-      DWORD last_error = ::GetLastError();
-      ::CloseHandle(entry_event);
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "thread.exit_event");
-      boost::throw_exception(e);
-    }
-
-    unsigned int thread_id = 0;
-    thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
-          win_thread_function, arg.get(), 0, &thread_id));
-    if (!thread_)
-    {
-      DWORD last_error = ::GetLastError();
-      if (entry_event)
-        ::CloseHandle(entry_event);
-      if (exit_event_)
-        ::CloseHandle(exit_event_);
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "thread");
-      boost::throw_exception(e);
-    }
-    arg.release();
-
-    if (entry_event)
-    {
-      ::WaitForSingleObject(entry_event, INFINITE);
-      ::CloseHandle(entry_event);
-    }
+    start_thread(new func<Function>(f), stack_size);
   }
 
   // Destructor.
-  ~win_thread()
-  {
-    ::CloseHandle(thread_);
-
-    // The exit_event_ handle is deliberately allowed to leak here since it
-    // is an error for the owner of an internal thread not to join() it.
-  }
+  ASIO_DECL ~win_thread();
 
   // Wait for the thread to exit.
-  void join()
-  {
-    ::WaitForSingleObject(exit_event_, INFINITE);
-    ::CloseHandle(exit_event_);
-    if (terminate_threads())
-    {
-      ::TerminateThread(thread_, 0);
-    }
-    else
-    {
-      ::QueueUserAPC(apc_function, thread_, 0);
-      ::WaitForSingleObject(thread_, INFINITE);
-    }
-  }
+  ASIO_DECL void join();
 
 private:
-  friend unsigned int __stdcall win_thread_function(void* arg);
+  friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
 
 #if defined(WINVER) && (WINVER < 0x0500)
-  friend void __stdcall apc_function(ULONG);
+  friend ASIO_DECL void __stdcall apc_function(ULONG);
 #else
-  friend void __stdcall apc_function(ULONG_PTR);
+  friend ASIO_DECL void __stdcall apc_function(ULONG_PTR);
 #endif
 
   class func_base
@@ -170,6 +94,12 @@ private:
     ::HANDLE exit_event_;
   };
 
+  struct auto_func_base_ptr
+  {
+    func_base* ptr;
+    ~auto_func_base_ptr() { delete ptr; }
+  };
+
   template <typename Function>
   class func
     : public func_base
@@ -189,44 +119,21 @@ private:
     Function f_;
   };
 
+  ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size);
+
   ::HANDLE thread_;
   ::HANDLE exit_event_;
 };
 
-inline unsigned int __stdcall win_thread_function(void* arg)
-{
-  std::auto_ptr<win_thread::func_base> func(
-      static_cast<win_thread::func_base*>(arg));
-
-  ::SetEvent(func->entry_event_);
-
-  func->run();
-
-  // Signal that the thread has finished its work, but rather than returning go
-  // to sleep to put the thread into a well known state. If the thread is being
-  // joined during global object destruction then it may be killed using
-  // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
-  // call will be interrupted using QueueUserAPC and the thread will shut down
-  // cleanly.
-  HANDLE exit_event = func->exit_event_;
-  func.reset();
-  ::SetEvent(exit_event);
-  ::SleepEx(INFINITE, TRUE);
-
-  return 0;
-}
-
-#if defined(WINVER) && (WINVER < 0x0500)
-inline void __stdcall apc_function(ULONG) {}
-#else
-inline void __stdcall apc_function(ULONG_PTR) {}
-#endif
-
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
 #endif // ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/ext/asio/asio/detail/win_tss_ptr.hpp b/ext/asio/asio/detail/win_tss_ptr.hpp
index 5a4ed33..fb055f6 100644
--- a/ext/asio/asio/detail/win_tss_ptr.hpp
+++ b/ext/asio/asio/detail/win_tss_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// win_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~
+// detail/win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,50 +15,30 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_types.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
 
+// Helper function to create thread-specific storage.
+ASIO_DECL DWORD win_tss_ptr_create();
+
 template <typename T>
 class win_tss_ptr
   : private noncopyable
 {
 public:
-#if defined(UNDER_CE)
-  enum { out_of_indexes = 0xFFFFFFFF };
-#else
-  enum { out_of_indexes = TLS_OUT_OF_INDEXES };
-#endif
-
   // Constructor.
   win_tss_ptr()
+    : tss_key_(win_tss_ptr_create())
   {
-    tss_key_ = ::TlsAlloc();
-    if (tss_key_ == out_of_indexes)
-    {
-      DWORD last_error = ::GetLastError();
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "tss");
-      boost::throw_exception(e);
-    }
   }
 
   // Destructor.
@@ -88,8 +68,12 @@ private:
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
 #endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/wince_thread.hpp b/ext/asio/asio/detail/wince_thread.hpp
index 0b6de48..1dc9990 100644
--- a/ext/asio/asio/detail/wince_thread.hpp
+++ b/ext/asio/asio/detail/wince_thread.hpp
@@ -1,8 +1,8 @@
 //
-// wince_thread.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/wince_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) && defined(UNDER_CE)
 
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
+#include <memory>
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
 
 #include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <memory>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace detail {
@@ -53,11 +47,9 @@ public:
     if (!thread_)
     {
       DWORD last_error = ::GetLastError();
-      asio::system_error e(
-          asio::error_code(last_error,
-            asio::error::get_system_category()),
-          "thread");
-      boost::throw_exception(e);
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "thread");
     }
     arg.release();
   }
@@ -117,8 +109,8 @@ inline DWORD WINAPI wince_thread_function(LPVOID arg)
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
-
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
 #endif // ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/ext/asio/asio/detail/winsock_init.hpp b/ext/asio/asio/detail/winsock_init.hpp
index ae5c4bf..a410859 100644
--- a/ext/asio/asio/detail/winsock_init.hpp
+++ b/ext/asio/asio/detail/winsock_init.hpp
@@ -1,8 +1,8 @@
 //
-// winsock_init.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/winsock_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,106 +15,76 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
 #include "asio/detail/push_options.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
 
 namespace asio {
 namespace detail {
 
-template <int Major = 2, int Minor = 0>
-class winsock_init
-  : private noncopyable
+class winsock_init_base
 {
-private:
-  // Structure to perform the actual initialisation.
-  struct do_init
+protected:
+  // Structure to track result of initialisation and number of uses. POD is used
+  // to ensure that the values are zero-initialised prior to any code being run.
+  struct data
   {
-    do_init()
-    {
-      WSADATA wsa_data;
-      result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);
-    }
-
-    ~do_init()
-    {
-      ::WSACleanup();
-    }
-
-    int result() const
-    {
-      return result_;
-    }
-
-    // Helper function to manage a do_init singleton. The static instance of the
-    // winsock_init object ensures that this function is always called before
-    // main, and therefore before any other threads can get started. The do_init
-    // instance must be static in this function to ensure that it gets
-    // initialised before any other global objects try to use it.
-    static boost::shared_ptr<do_init> instance()
-    {
-      static boost::shared_ptr<do_init> init(new do_init);
-      return init;
-    }
-
-  private:
-    int result_;
+    long init_count_;
+    long result_;
   };
 
+  ASIO_DECL static void startup(data& d,
+      unsigned char major, unsigned char minor);
+
+  ASIO_DECL static void cleanup(data& d);
+
+  ASIO_DECL static void throw_on_error(data& d);
+};
+
+template <int Major = 2, int Minor = 0>
+class winsock_init : private winsock_init_base
+{
 public:
-  // Constructor.
-  winsock_init()
-    : ref_(do_init::instance())
+  winsock_init(bool allow_throw = true)
+  {
+    startup(data_, Major, Minor);
+    if (allow_throw)
+      throw_on_error(data_);
+  }
+
+  winsock_init(const winsock_init&)
   {
-    // Check whether winsock was successfully initialised. This check is not
-    // performed for the global instance since there will be nobody around to
-    // catch the exception.
-    if (this != &instance_ && ref_->result() != 0)
-    {
-      asio::system_error e(
-          asio::error_code(ref_->result(),
-            asio::error::get_system_category()),
-          "winsock");
-      boost::throw_exception(e);
-    }
+    startup(data_, Major, Minor);
+    throw_on_error(data_);
   }
 
-  // Destructor.
   ~winsock_init()
   {
+    cleanup(data_);
   }
 
 private:
-  // Instance to force initialisation of winsock at global scope.
-  static winsock_init instance_;
-
-  // Reference to singleton do_init object to ensure that winsock does not get
-  // cleaned up until the last user has finished with it.
-  boost::shared_ptr<do_init> ref_;
+  static data data_;
 };
 
 template <int Major, int Minor>
-winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;
+winsock_init_base::data winsock_init<Major, Minor>::data_;
+
+// Static variable to ensure that winsock is initialised before main, and
+// therefore before any other threads can get started.
+static const winsock_init<>& winsock_init_instance = winsock_init<>(false);
 
 } // namespace detail
 } // namespace asio
 
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winsock_init.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
 #endif // ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/ext/asio/asio/detail/wrapped_handler.hpp b/ext/asio/asio/detail/wrapped_handler.hpp
index e40a7f1..bcebf6e 100644
--- a/ext/asio/asio/detail/wrapped_handler.hpp
+++ b/ext/asio/asio/detail/wrapped_handler.hpp
@@ -1,8 +1,8 @@
 //
-// wrapped_handler.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/type_traits/add_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/bind_handler.hpp"
 #include "asio/detail/handler_alloc_helpers.hpp"
 #include "asio/detail/handler_invoke_helpers.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace detail {
 
@@ -34,9 +30,7 @@ class wrapped_handler
 public:
   typedef void result_type;
 
-  wrapped_handler(
-      typename boost::add_reference<Dispatcher>::type dispatcher,
-      Handler handler)
+  wrapped_handler(Dispatcher dispatcher, Handler handler)
     : dispatcher_(dispatcher),
       handler_(handler)
   {
diff --git a/ext/asio/asio/error.hpp b/ext/asio/asio/error.hpp
index 73caac6..138b5d7 100644
--- a/ext/asio/asio/error.hpp
+++ b/ext/asio/asio/error.hpp
@@ -2,7 +2,7 @@
 // error.hpp
 // ~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cerrno>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
-#include "asio/detail/socket_types.hpp"
+#include "asio/detail/config.hpp"
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include <winerror.h>
+#else
+# include <cerrno>
+# include <netdb.h>
+#endif
 
 #if defined(GENERATING_DOCUMENTATION)
 /// INTERNAL ONLY.
@@ -50,6 +48,8 @@
 # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace error {
 
@@ -212,7 +212,21 @@ enum ssl_errors
 {
 };
 
-// boostify: error category definitions go here.
+// boostify: error category definitions start here.
+
+} // namespace error
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+// boostify: error category definitions end here.
 
 inline asio::error_code make_error_code(basic_errors e)
 {
@@ -247,14 +261,16 @@ inline asio::error_code make_error_code(ssl_errors e)
 } // namespace error
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #undef ASIO_NATIVE_ERROR
 #undef ASIO_SOCKET_ERROR
 #undef ASIO_NETDB_ERROR
 #undef ASIO_GETADDRINFO_ERROR
 #undef ASIO_WIN_OR_POSIX
 
-#include "asio/impl/error_code.ipp"
-
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
 
 #endif // ASIO_ERROR_HPP
diff --git a/ext/asio/asio/error_code.hpp b/ext/asio/asio/error_code.hpp
index 6657f3f..1af449b 100644
--- a/ext/asio/asio/error_code.hpp
+++ b/ext/asio/asio/error_code.hpp
@@ -2,7 +2,7 @@
 // error_code.hpp
 // ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,8 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <string>
-#include "asio/detail/pop_options.hpp"
 
 #if defined(GENERATING_DOCUMENTATION)
 # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined
@@ -30,6 +26,8 @@
 # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 namespace error
@@ -106,7 +104,7 @@ public:
   }
 
   /// Get the message associated with the error.
-  std::string message() const;
+  ASIO_DECL std::string message() const;
 
   struct unspecified_bool_type_t
   {
@@ -114,14 +112,12 @@ public:
 
   typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
 
-  static void unspecified_bool_true(unspecified_bool_type_t)
-  {
-  }
+  static void unspecified_bool_true(unspecified_bool_type_t) {}
 
   /// Operator returns non-null if there is a non-success error code.
   operator unspecified_bool_type() const
   {
-    if (value_ == 0)
+    if (!value_)
       return 0;
     else
       return &error_code::unspecified_bool_true;
@@ -130,7 +126,7 @@ public:
   /// Operator to test if the error represents success.
   bool operator!() const
   {
-    return value_ == 0;
+    return !value_;
   }
 
   /// Equality operator to compare two error objects.
@@ -155,10 +151,12 @@ private:
 
 } // namespace asio
 
-#undef ASIO_WIN_OR_POSIX
+#include "asio/detail/pop_options.hpp"
 
-#include "asio/error.hpp"
+#undef ASIO_WIN_OR_POSIX
 
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error_code.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
 
 #endif // ASIO_ERROR_CODE_HPP
diff --git a/ext/asio/asio/handler_alloc_hook.hpp b/ext/asio/asio/handler_alloc_hook.hpp
index 87783cd..dd930b6 100644
--- a/ext/asio/asio/handler_alloc_hook.hpp
+++ b/ext/asio/asio/handler_alloc_hook.hpp
@@ -2,7 +2,7 @@
 // handler_alloc_hook.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <cstddef>
 
 #include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/handler_invoke_hook.hpp b/ext/asio/asio/handler_invoke_hook.hpp
index b3d7e45..ef22359 100644
--- a/ext/asio/asio/handler_invoke_hook.hpp
+++ b/ext/asio/asio/handler_invoke_hook.hpp
@@ -2,7 +2,7 @@
 // handler_invoke_hook.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,6 +15,8 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
+#include "asio/detail/config.hpp"
+
 #include "asio/detail/push_options.hpp"
 
 namespace asio {
diff --git a/ext/asio/asio/impl/error.ipp b/ext/asio/asio/impl/error.ipp
new file mode 100644
index 0000000..54388b3
--- /dev/null
+++ b/ext/asio/asio/impl/error.ipp
@@ -0,0 +1,33 @@
+//
+// impl/error.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_ERROR_IPP
+#define ASIO_IMPL_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+// boostify: error category function definitions go here.
+
+} // namespace error
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_ERROR_IPP
diff --git a/ext/asio/asio/impl/error_code.ipp b/ext/asio/asio/impl/error_code.ipp
index 614925d..ed37a17 100644
--- a/ext/asio/asio/impl/error_code.ipp
+++ b/ext/asio/asio/impl/error_code.ipp
@@ -1,50 +1,55 @@
 //
-// error_code.ipp
-// ~~~~~~~~~~~~~~
+// impl/error_code.ipp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 
-#ifndef ASIO_ERROR_CODE_IPP
-#define ASIO_ERROR_CODE_IPP
+#ifndef ASIO_IMPL_ERROR_CODE_IPP
+#define ASIO_IMPL_ERROR_CODE_IPP
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <cerrno>
-#include <cstring>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
 #include "asio/detail/local_free_on_block_exit.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
-inline std::string error_code::message() const
+std::string error_code::message() const
 {
-  if (*this == error::already_open)
-    return "Already open.";
-  if (*this == error::not_found)
-    return "Not found.";
-  if (*this == error::fd_set_failure)
-    return "The descriptor does not fit into the select call's fd_set.";
+  if (category_ == error::get_misc_category())
+  {
+    if (value_ == error::already_open)
+      return "Already open.";
+    if (value_ == error::not_found)
+      return "Not found.";
+    if (value_ == error::fd_set_failure)
+      return "The descriptor does not fit into the select call's fd_set.";
+    if (value_ == error::not_found)
+      return "Element not found.";
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+    if (value_ == error::eof)
+      return "End of file.";
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+  }
   if (category_ == error::get_ssl_category())
     return "SSL error.";
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
   value_type value = value_;
-  if (category() != error::get_system_category() && *this != error::eof)
-    return "asio error";
-  if (*this == error::eof)
+  if (category_ == error::get_misc_category() && value_ == error::eof)
     value = ERROR_HANDLE_EOF;
+  else if (category_ != error::get_system_category())
+    return "asio error";
   char* msg = 0;
   DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
       | FORMAT_MESSAGE_FROM_SYSTEM
@@ -60,29 +65,31 @@ inline std::string error_code::message() const
   else
     return "asio error";
 #else // defined(BOOST_WINDOWS)
-  if (*this == error::eof)
-    return "End of file.";
-  if (*this == error::host_not_found)
-    return "Host not found (authoritative).";
-  if (*this == error::host_not_found_try_again)
-    return "Host not found (non-authoritative), try again later.";
-  if (*this == error::no_recovery)
-    return "A non-recoverable error occurred during database lookup.";
-  if (*this == error::no_data)
-    return "The query is valid, but it does not have associated data.";
-  if (*this == error::not_found)
-    return "Element not found.";
+  if (category_ == error::get_netdb_category())
+  {
+    if (value_ == error::host_not_found)
+      return "Host not found (authoritative).";
+    if (value_ == error::host_not_found_try_again)
+      return "Host not found (non-authoritative), try again later.";
+    if (value_ == error::no_recovery)
+      return "A non-recoverable error occurred during database lookup.";
+    if (value_ == error::no_data)
+      return "The query is valid, but it does not have associated data.";
+  }
+  if (category_ == error::get_addrinfo_category())
+  {
+    if (value_ == error::service_not_found)
+      return "Service not found.";
+    if (value_ == error::socket_type_not_supported)
+      return "Socket type not supported.";
+  }
+  if (category_ != error::get_system_category())
+    return "asio error";
 #if !defined(__sun)
-  if (*this == error::operation_aborted)
+  if (value_ == error::operation_aborted)
     return "Operation aborted.";
 #endif // !defined(__sun)
-  if (*this == error::service_not_found)
-    return "Service not found.";
-  if (*this == error::socket_type_not_supported)
-    return "Socket type not supported.";
-  if (category() != error::get_system_category())
-    return "asio error";
-#if defined(__sun) || defined(__QNX__)
+#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__)
   using namespace std;
   return strerror(value_);
 #elif defined(__MACH__) && defined(__APPLE__) \
@@ -102,4 +109,4 @@ inline std::string error_code::message() const
 
 #include "asio/detail/pop_options.hpp"
 
-#endif // ASIO_ERROR_CODE_IPP
+#endif // ASIO_IMPL_ERROR_CODE_IPP
diff --git a/ext/asio/asio/impl/io_service.hpp b/ext/asio/asio/impl/io_service.hpp
new file mode 100644
index 0000000..f0c1730
--- /dev/null
+++ b/ext/asio/asio/impl/io_service.hpp
@@ -0,0 +1,132 @@
+//
+// impl/io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_IO_SERVICE_HPP
+#define ASIO_IMPL_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Service>
+inline Service& use_service(io_service& ios)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+  (void)static_cast<const io_service::id*>(&Service::id);
+
+  return ios.service_registry_->template use_service<Service>();
+}
+
+template <typename Service>
+inline void add_service(io_service& ios, Service* svc)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+  (void)static_cast<const io_service::id*>(&Service::id);
+
+  ios.service_registry_->template add_service<Service>(svc);
+}
+
+template <typename Service>
+inline bool has_service(io_service& ios)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+  (void)static_cast<const io_service::id*>(&Service::id);
+
+  return ios.service_registry_->template has_service<Service>();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service.hpp"
+#else
+# include "asio/detail/task_io_service.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Handler>
+inline void io_service::dispatch(Handler handler)
+{
+  impl_.dispatch(handler);
+}
+
+template <typename Handler>
+inline void io_service::post(Handler handler)
+{
+  impl_.post(handler);
+}
+
+template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+unspecified
+#else
+inline detail::wrapped_handler<io_service&, Handler>
+#endif
+io_service::wrap(Handler handler)
+{
+  return detail::wrapped_handler<io_service&, Handler>(*this, handler);
+}
+
+inline io_service::work::work(asio::io_service& io_service)
+  : io_service_(io_service)
+{
+  io_service_.impl_.work_started();
+}
+
+inline io_service::work::work(const work& other)
+  : io_service_(other.io_service_)
+{
+  io_service_.impl_.work_started();
+}
+
+inline io_service::work::~work()
+{
+  io_service_.impl_.work_finished();
+}
+
+inline asio::io_service& io_service::work::io_service()
+{
+  return io_service_;
+}
+
+inline asio::io_service& io_service::work::get_io_service()
+{
+  return io_service_;
+}
+
+inline asio::io_service& io_service::service::io_service()
+{
+  return owner_;
+}
+
+inline asio::io_service& io_service::service::get_io_service()
+{
+  return owner_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_IO_SERVICE_HPP
diff --git a/ext/asio/asio/impl/io_service.ipp b/ext/asio/asio/impl/io_service.ipp
index c3fed3b..eb19b8f 100644
--- a/ext/asio/asio/impl/io_service.ipp
+++ b/ext/asio/asio/impl/io_service.ipp
@@ -1,26 +1,23 @@
 //
-// io_service.ipp
-// ~~~~~~~~~~~~~~
+// impl/io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 
-#ifndef ASIO_IO_SERVICE_IPP
-#define ASIO_IO_SERVICE_IPP
+#ifndef ASIO_IMPL_IO_SERVICE_IPP
+#define ASIO_IMPL_IO_SERVICE_IPP
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/io_service.hpp"
 #include "asio/detail/service_registry.hpp"
 #include "asio/detail/throw_error.hpp"
 
@@ -28,31 +25,32 @@
 # include "asio/detail/win_iocp_io_service.hpp"
 #else
 # include "asio/detail/task_io_service.hpp"
-# include "asio/detail/reactor.hpp"
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
-inline io_service::io_service()
+io_service::io_service()
   : service_registry_(new asio::detail::service_registry(*this)),
     impl_(service_registry_->use_service<impl_type>())
 {
   impl_.init((std::numeric_limits<std::size_t>::max)());
 }
 
-inline io_service::io_service(std::size_t concurrency_hint)
+io_service::io_service(std::size_t concurrency_hint)
   : service_registry_(new asio::detail::service_registry(*this)),
     impl_(service_registry_->use_service<impl_type>())
 {
   impl_.init(concurrency_hint);
 }
 
-inline io_service::~io_service()
+io_service::~io_service()
 {
   delete service_registry_;
 }
 
-inline std::size_t io_service::run()
+std::size_t io_service::run()
 {
   asio::error_code ec;
   std::size_t s = impl_.run(ec);
@@ -60,12 +58,12 @@ inline std::size_t io_service::run()
   return s;
 }
 
-inline std::size_t io_service::run(asio::error_code& ec)
+std::size_t io_service::run(asio::error_code& ec)
 {
   return impl_.run(ec);
 }
 
-inline std::size_t io_service::run_one()
+std::size_t io_service::run_one()
 {
   asio::error_code ec;
   std::size_t s = impl_.run_one(ec);
@@ -73,12 +71,12 @@ inline std::size_t io_service::run_one()
   return s;
 }
 
-inline std::size_t io_service::run_one(asio::error_code& ec)
+std::size_t io_service::run_one(asio::error_code& ec)
 {
   return impl_.run_one(ec);
 }
 
-inline std::size_t io_service::poll()
+std::size_t io_service::poll()
 {
   asio::error_code ec;
   std::size_t s = impl_.poll(ec);
@@ -86,12 +84,12 @@ inline std::size_t io_service::poll()
   return s;
 }
 
-inline std::size_t io_service::poll(asio::error_code& ec)
+std::size_t io_service::poll(asio::error_code& ec)
 {
   return impl_.poll(ec);
 }
 
-inline std::size_t io_service::poll_one()
+std::size_t io_service::poll_one()
 {
   asio::error_code ec;
   std::size_t s = impl_.poll_one(ec);
@@ -99,126 +97,43 @@ inline std::size_t io_service::poll_one()
   return s;
 }
 
-inline std::size_t io_service::poll_one(asio::error_code& ec)
+std::size_t io_service::poll_one(asio::error_code& ec)
 {
   return impl_.poll_one(ec);
 }
 
-inline void io_service::stop()
+void io_service::stop()
 {
   impl_.stop();
 }
 
-inline void io_service::reset()
+void io_service::reset()
 {
   impl_.reset();
 }
 
-template <typename Handler>
-inline void io_service::dispatch(Handler handler)
-{
-  impl_.dispatch(handler);
-}
-
-template <typename Handler>
-inline void io_service::post(Handler handler)
-{
-  impl_.post(handler);
-}
-
-template <typename Handler>
-#if defined(GENERATING_DOCUMENTATION)
-unspecified
-#else
-inline detail::wrapped_handler<io_service&, Handler>
-#endif
-io_service::wrap(Handler handler)
-{
-  return detail::wrapped_handler<io_service&, Handler>(*this, handler);
-}
-
-inline io_service::work::work(asio::io_service& io_service)
-  : io_service_(io_service)
-{
-  io_service_.impl_.work_started();
-}
-
-inline io_service::work::work(const work& other)
-  : io_service_(other.io_service_)
-{
-  io_service_.impl_.work_started();
-}
-
-inline io_service::work::~work()
-{
-  io_service_.impl_.work_finished();
-}
-
-inline asio::io_service& io_service::work::io_service()
-{
-  return io_service_;
-}
-
-inline asio::io_service& io_service::work::get_io_service()
-{
-  return io_service_;
-}
-
-inline io_service::service::service(asio::io_service& owner)
+io_service::service::service(asio::io_service& owner)
   : owner_(owner),
     next_(0)
 {
 }
 
-inline io_service::service::~service()
-{
-}
-
-inline asio::io_service& io_service::service::io_service()
-{
-  return owner_;
-}
-
-inline asio::io_service& io_service::service::get_io_service()
+io_service::service::~service()
 {
-  return owner_;
 }
 
-template <typename Service>
-inline Service& use_service(io_service& ios)
+service_already_exists::service_already_exists()
+  : std::logic_error("Service already exists.")
 {
-  // Check that Service meets the necessary type requirements.
-  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
-  (void)static_cast<const io_service::id*>(&Service::id);
-
-  return ios.service_registry_->template use_service<Service>();
 }
 
-template <typename Service>
-void add_service(io_service& ios, Service* svc)
+invalid_service_owner::invalid_service_owner()
+  : std::logic_error("Invalid service owner.")
 {
-  // Check that Service meets the necessary type requirements.
-  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
-  (void)static_cast<const io_service::id*>(&Service::id);
-
-  if (&ios != &svc->io_service())
-    boost::throw_exception(invalid_service_owner());
-  if (!ios.service_registry_->template add_service<Service>(svc))
-    boost::throw_exception(service_already_exists());
-}
-
-template <typename Service>
-bool has_service(io_service& ios)
-{
-  // Check that Service meets the necessary type requirements.
-  (void)static_cast<io_service::service*>(static_cast<Service*>(0));
-  (void)static_cast<const io_service::id*>(&Service::id);
-
-  return ios.service_registry_->template has_service<Service>();
 }
 
 } // namespace asio
 
 #include "asio/detail/pop_options.hpp"
 
-#endif // ASIO_IO_SERVICE_IPP
+#endif // ASIO_IMPL_IO_SERVICE_IPP
diff --git a/ext/asio/asio/impl/read.hpp b/ext/asio/asio/impl/read.hpp
new file mode 100644
index 0000000..bd5d7b5
--- /dev/null
+++ b/ext/asio/asio/impl/read.hpp
@@ -0,0 +1,386 @@
+//
+// impl/read.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_HPP
+#define ASIO_IMPL_READ_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  asio::detail::consuming_buffers<
+    mutable_buffer, MutableBufferSequence> tmp(buffers);
+  std::size_t total_transferred = 0;
+  tmp.prepare(detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred)));
+  while (tmp.begin() != tmp.end())
+  {
+    std::size_t bytes_transferred = s.read_some(tmp, ec);
+    tmp.consume(bytes_transferred);
+    total_transferred += bytes_transferred;
+    tmp.prepare(detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred)));
+  }
+  return total_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  std::size_t total_transferred = 0;
+  std::size_t max_size = detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred));
+  std::size_t bytes_available = read_size_helper(b, max_size);
+  while (bytes_available > 0)
+  {
+    std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
+    b.commit(bytes_transferred);
+    total_transferred += bytes_transferred;
+    max_size = detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred));
+    bytes_available = read_size_helper(b, max_size);
+  }
+  return total_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, b, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, b, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename CompletionCondition, typename ReadHandler>
+  class read_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
+        CompletionCondition completion_condition, ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+        for (;;)
+        {
+          stream_.async_read_some(buffers_, *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.consume(bytes_transferred);
+          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+          if ((!ec && bytes_transferred == 0)
+              || buffers_.begin() == buffers_.end())
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::detail::consuming_buffers<
+      mutable_buffer, MutableBufferSequence> buffers_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream,
+      typename CompletionCondition, typename ReadHandler>
+  class read_op<AsyncReadStream, asio::mutable_buffers_1,
+      CompletionCondition, ReadHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_op(AsyncReadStream& stream,
+        const asio::mutable_buffers_1& buffers,
+        CompletionCondition completion_condition,
+        ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          stream_.async_read_some(asio::buffer(
+                buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::mutable_buffer buffer_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename CompletionCondition, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_op<AsyncReadStream, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename CompletionCondition, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_op<AsyncReadStream, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename MutableBufferSequence, typename CompletionCondition,
+      typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_op<AsyncReadStream, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, ReadHandler handler)
+{
+  detail::read_op<AsyncReadStream, MutableBufferSequence,
+    CompletionCondition, ReadHandler>(
+      s, buffers, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    ReadHandler handler)
+{
+  async_read(s, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  class read_streambuf_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_streambuf_op(AsyncReadStream& stream,
+        basic_streambuf<Allocator>& streambuf,
+        CompletionCondition completion_condition, ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        streambuf_(streambuf),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size, bytes_available;
+      switch (start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, total_transferred_);
+        bytes_available = read_size_helper(streambuf_, max_size);
+        for (;;)
+        {
+          stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          streambuf_.commit(bytes_transferred);
+          max_size = this->check_for_completion(ec, total_transferred_);
+          bytes_available = read_size_helper(streambuf_, max_size);
+          if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_streambuf_op<AsyncReadStream, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_streambuf_op<AsyncReadStream, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename Allocator, typename CompletionCondition, typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_streambuf_op<AsyncReadStream, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator,
+    typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, ReadHandler handler)
+{
+  detail::read_streambuf_op<AsyncReadStream,
+    Allocator, CompletionCondition, ReadHandler>(
+      s, b, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, ReadHandler handler)
+{
+  async_read(s, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_HPP
diff --git a/ext/asio/asio/impl/read_at.hpp b/ext/asio/asio/impl/read_at.hpp
new file mode 100644
index 0000000..da57fe3
--- /dev/null
+++ b/ext/asio/asio/impl/read_at.hpp
@@ -0,0 +1,410 @@
+//
+// impl/read_at.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_AT_HPP
+#define ASIO_IMPL_READ_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  asio::detail::consuming_buffers<
+    mutable_buffer, MutableBufferSequence> tmp(buffers);
+  std::size_t total_transferred = 0;
+  tmp.prepare(detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred)));
+  while (tmp.begin() != tmp.end())
+  {
+    std::size_t bytes_transferred = d.read_some_at(
+        offset + total_transferred, tmp, ec);
+    tmp.consume(bytes_transferred);
+    total_transferred += bytes_transferred;
+    tmp.prepare(detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred)));
+  }
+  return total_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, const MutableBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, buffers, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  std::size_t total_transferred = 0;
+  std::size_t max_size = detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred));
+  std::size_t bytes_available = read_size_helper(b, max_size);
+  while (bytes_available > 0)
+  {
+    std::size_t bytes_transferred = d.read_some_at(
+        offset + total_transferred, b.prepare(bytes_available), ec);
+    b.commit(bytes_transferred);
+    total_transferred += bytes_transferred;
+    max_size = detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred));
+    bytes_available = read_size_helper(b, max_size);
+  }
+  return total_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, b, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, b, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename CompletionCondition,
+      typename ReadHandler>
+  class read_at_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_at_op(AsyncRandomAccessReadDevice& device,
+        boost::uint64_t offset, const MutableBufferSequence& buffers,
+        CompletionCondition completion_condition, ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffers_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+        for (;;)
+        {
+          device_.async_read_some_at(
+              offset_ + total_transferred_, buffers_, *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.consume(bytes_transferred);
+          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+          if ((!ec && bytes_transferred == 0)
+              || buffers_.begin() == buffers_.end())
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessReadDevice& device_;
+    boost::uint64_t offset_;
+    asio::detail::consuming_buffers<
+      mutable_buffer, MutableBufferSequence> buffers_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename CompletionCondition, typename ReadHandler>
+  class read_at_op<AsyncRandomAccessReadDevice,
+      asio::mutable_buffers_1, CompletionCondition, ReadHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_at_op(AsyncRandomAccessReadDevice& device,
+        boost::uint64_t offset, const asio::mutable_buffers_1& buffers,
+        CompletionCondition completion_condition, ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          device_.async_read_some_at(offset_ + total_transferred_,
+              asio::buffer(buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessReadDevice& device_;
+    boost::uint64_t offset_;
+    asio::mutable_buffer buffer_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename CompletionCondition,
+      typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename CompletionCondition,
+      typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename CompletionCondition,
+      typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition, typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, ReadHandler handler)
+{
+  detail::read_at_op<AsyncRandomAccessReadDevice,
+    MutableBufferSequence, CompletionCondition, ReadHandler>(
+      d, offset, buffers, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, const MutableBufferSequence& buffers,
+    ReadHandler handler)
+{
+  async_read_at(d, offset, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  class read_at_streambuf_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
+        boost::uint64_t offset, basic_streambuf<Allocator>& streambuf,
+        CompletionCondition completion_condition, ReadHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        streambuf_(streambuf),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size, bytes_available;
+      switch (start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, total_transferred_);
+        bytes_available = read_size_helper(streambuf_, max_size);
+        for (;;)
+        {
+          device_.async_read_some_at(offset_ + total_transferred_,
+              streambuf_.prepare(bytes_available), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          streambuf_.commit(bytes_transferred);
+          max_size = this->check_for_completion(ec, total_transferred_);
+          bytes_available = read_size_helper(streambuf_, max_size);
+          if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessReadDevice& device_;
+    boost::uint64_t offset_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename Allocator, typename CompletionCondition, typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition, typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, ReadHandler handler)
+{
+  detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+    Allocator, CompletionCondition, ReadHandler>(
+      d, offset, b, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+    typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    ReadHandler handler)
+{
+  async_read_at(d, offset, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_AT_HPP
diff --git a/ext/asio/asio/impl/read_until.hpp b/ext/asio/asio/impl/read_until.hpp
new file mode 100644
index 0000000..ceacca7
--- /dev/null
+++ b/ext/asio/asio/impl/read_until.hpp
@@ -0,0 +1,902 @@
+//
+// impl/read_until.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_UNTIL_HPP
+#define ASIO_IMPL_READ_UNTIL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/limits.hpp>
+#include "asio/buffer.hpp"
+#include "asio/buffers_iterator.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s, b, delim, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim,
+    asio::error_code& ec)
+{
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename asio::basic_streambuf<
+      Allocator>::const_buffers_type const_buffers_type;
+    typedef asio::buffers_iterator<const_buffers_type> iterator;
+    const_buffers_type buffers = b.data();
+    iterator begin = iterator::begin(buffers);
+    iterator start = begin + search_position;
+    iterator end = iterator::end(buffers);
+
+    // Look for a match.
+    iterator iter = std::find(start, end, delim);
+    if (iter != end)
+    {
+      // Found a match. We're done.
+      ec = asio::error_code();
+      return iter - begin + 1;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = read_size_helper(b, 65536);
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const std::string& delim)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s, b, delim, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+namespace detail
+{
+  // Algorithm that finds a subsequence of equal values in a sequence. Returns
+  // (iterator,true) if a full match was found, in which case the iterator
+  // points to the beginning of the match. Returns (iterator,false) if a
+  // partial match was found at the end of the first sequence, in which case
+  // the iterator points to the beginning of the partial match. Returns
+  // (last1,false) if no full or partial match was found.
+  template <typename Iterator1, typename Iterator2>
+  std::pair<Iterator1, bool> partial_search(
+      Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+  {
+    for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
+    {
+      Iterator1 test_iter1 = iter1;
+      Iterator2 test_iter2 = first2;
+      for (;; ++test_iter1, ++test_iter2)
+      {
+        if (test_iter2 == last2)
+          return std::make_pair(iter1, true);
+        if (test_iter1 == last1)
+        {
+          if (test_iter2 != first2)
+            return std::make_pair(iter1, false);
+          else
+            break;
+        }
+        if (*test_iter1 != *test_iter2)
+          break;
+      }
+    }
+    return std::make_pair(last1, false);
+  }
+} // namespace detail
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const std::string& delim,
+    asio::error_code& ec)
+{
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename asio::basic_streambuf<
+      Allocator>::const_buffers_type const_buffers_type;
+    typedef asio::buffers_iterator<const_buffers_type> iterator;
+    const_buffers_type buffers = b.data();
+    iterator begin = iterator::begin(buffers);
+    iterator start = begin + search_position;
+    iterator end = iterator::end(buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = detail::partial_search(
+        start, end, delim.begin(), delim.end());
+    if (result.first != end)
+    {
+      if (result.second)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return result.first - begin + delim.length();
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = result.first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = read_size_helper(b, 65536);
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s, b, expr, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    asio::error_code& ec)
+{
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename asio::basic_streambuf<
+      Allocator>::const_buffers_type const_buffers_type;
+    typedef asio::buffers_iterator<const_buffers_type> iterator;
+    const_buffers_type buffers = b.data();
+    iterator begin = iterator::begin(buffers);
+    iterator start = begin + search_position;
+    iterator end = iterator::end(buffers);
+
+    // Look for a match.
+    boost::match_results<iterator,
+      typename std::vector<boost::sub_match<iterator> >::allocator_type>
+        match_results;
+    if (regex_search(start, end, match_results, expr,
+          boost::match_default | boost::match_partial))
+    {
+      if (match_results[0].matched)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return match_results[0].second - begin;
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = match_results[0].first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = read_size_helper(b, 65536);
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename asio::basic_streambuf<
+      Allocator>::const_buffers_type const_buffers_type;
+    typedef asio::buffers_iterator<const_buffers_type> iterator;
+    const_buffers_type buffers = b.data();
+    iterator begin = iterator::begin(buffers);
+    iterator start = begin + search_position;
+    iterator end = iterator::end(buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = match_condition(start, end);
+    if (result.second)
+    {
+      // Full match. We're done.
+      ec = asio::error_code();
+      return result.first - begin;
+    }
+    else if (result.first != end)
+    {
+      // Partial match. Next search needs to start from beginning of match.
+      search_position = result.first - begin;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = read_size_helper(b, 65536);
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
+    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  class read_until_delim_op
+  {
+  public:
+    read_until_delim_op(AsyncReadStream& stream,
+        asio::basic_streambuf<Allocator>& streambuf,
+        char delim, ReadHandler handler)
+      : stream_(stream),
+        streambuf_(streambuf),
+        delim_(delim),
+        search_position_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename asio::basic_streambuf<
+              Allocator>::const_buffers_type const_buffers_type;
+            typedef asio::buffers_iterator<const_buffers_type> iterator;
+            const_buffers_type buffers = streambuf_.data();
+            iterator begin = iterator::begin(buffers);
+            iterator start = begin + search_position_;
+            iterator end = iterator::end(buffers);
+
+            // Look for a match.
+            iterator iter = std::find(start, end, delim_);
+            if (iter != end)
+            {
+              // Found a match. We're done.
+              search_position_ = iter - begin + 1;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (streambuf_.size() == streambuf_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              // Next search can start with the new data.
+              search_position_ = end - begin;
+              bytes_to_read = read_size_helper(streambuf_, 65536);
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+          return; default:
+          streambuf_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    char delim_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_until_delim_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream, typename Allocator,
+      typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_until_delim_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler)
+{
+  detail::read_until_delim_op<
+    AsyncReadStream, Allocator, ReadHandler>(
+      s, b, delim, handler)(
+        asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  class read_until_delim_string_op
+  {
+  public:
+    read_until_delim_string_op(AsyncReadStream& stream,
+        asio::basic_streambuf<Allocator>& streambuf,
+        const std::string& delim, ReadHandler handler)
+      : stream_(stream),
+        streambuf_(streambuf),
+        delim_(delim),
+        search_position_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename asio::basic_streambuf<
+              Allocator>::const_buffers_type const_buffers_type;
+            typedef asio::buffers_iterator<const_buffers_type> iterator;
+            const_buffers_type buffers = streambuf_.data();
+            iterator begin = iterator::begin(buffers);
+            iterator start = begin + search_position_;
+            iterator end = iterator::end(buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = detail::partial_search(
+                start, end, delim_.begin(), delim_.end());
+            if (result.first != end && result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin + delim_.length();
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (streambuf_.size() == streambuf_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = read_size_helper(streambuf_, 65536);
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+          return; default:
+          streambuf_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    std::string delim_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_until_delim_string_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_string_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename Allocator, typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_until_delim_string_op<AsyncReadStream,
+        Allocator, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const std::string& delim,
+    ReadHandler handler)
+{
+  detail::read_until_delim_string_op<
+    AsyncReadStream, Allocator, ReadHandler>(
+      s, b, delim, handler)(
+        asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename Allocator,
+      typename RegEx, typename ReadHandler>
+  class read_until_expr_op
+  {
+  public:
+    read_until_expr_op(AsyncReadStream& stream,
+        asio::basic_streambuf<Allocator>& streambuf,
+        const boost::regex& expr, ReadHandler handler)
+      : stream_(stream),
+        streambuf_(streambuf),
+        expr_(expr),
+        search_position_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename asio::basic_streambuf<
+              Allocator>::const_buffers_type const_buffers_type;
+            typedef asio::buffers_iterator<const_buffers_type> iterator;
+            const_buffers_type buffers = streambuf_.data();
+            iterator begin = iterator::begin(buffers);
+            iterator start = begin + search_position_;
+            iterator end = iterator::end(buffers);
+
+            // Look for a match.
+            boost::match_results<iterator,
+              typename std::vector<boost::sub_match<iterator> >::allocator_type>
+                match_results;
+            bool match = regex_search(start, end, match_results, expr_,
+                boost::match_default | boost::match_partial);
+            if (match && match_results[0].matched)
+            {
+              // Full match. We're done.
+              search_position_ = match_results[0].second - begin;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (streambuf_.size() == streambuf_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (match)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = match_results[0].first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = read_size_helper(streambuf_, 65536);
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+          return; default:
+          streambuf_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    RegEx expr_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename RegEx, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_until_expr_op<AsyncReadStream,
+        Allocator, RegEx, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename RegEx, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_expr_op<AsyncReadStream,
+        Allocator, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream, typename Allocator,
+      typename RegEx, typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_until_expr_op<AsyncReadStream,
+        Allocator, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    ReadHandler handler)
+{
+  detail::read_until_expr_op<AsyncReadStream,
+    Allocator, boost::regex, ReadHandler>(
+      s, b, expr, handler)(
+        asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename Allocator,
+      typename MatchCondition, typename ReadHandler>
+  class read_until_match_op
+  {
+  public:
+    read_until_match_op(AsyncReadStream& stream,
+        asio::basic_streambuf<Allocator>& streambuf,
+        MatchCondition match_condition, ReadHandler handler)
+      : stream_(stream),
+        streambuf_(streambuf),
+        match_condition_(match_condition),
+        search_position_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename asio::basic_streambuf<
+              Allocator>::const_buffers_type const_buffers_type;
+            typedef asio::buffers_iterator<const_buffers_type> iterator;
+            const_buffers_type buffers = streambuf_.data();
+            iterator begin = iterator::begin(buffers);
+            iterator start = begin + search_position_;
+            iterator end = iterator::end(buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = match_condition_(start, end);
+            if (result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (streambuf_.size() == streambuf_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = read_size_helper(streambuf_, 65536);
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+          return; default:
+          streambuf_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    MatchCondition match_condition_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename MatchCondition, typename ReadHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      read_until_match_op<AsyncReadStream,
+        Allocator, MatchCondition, ReadHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncReadStream, typename Allocator,
+      typename MatchCondition, typename ReadHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_match_op<AsyncReadStream,
+        Allocator, MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream, typename Allocator,
+      typename MatchCondition, typename ReadHandler>
+  inline void asio_handler_invoke(const Function& function,
+      read_until_match_op<AsyncReadStream,
+        Allocator, MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator,
+    typename MatchCondition, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition, ReadHandler handler,
+    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+  detail::read_until_match_op<
+    AsyncReadStream, Allocator, MatchCondition, ReadHandler>(
+      s, b, match_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_UNTIL_HPP
diff --git a/ext/asio/asio/impl/serial_port_base.hpp b/ext/asio/asio/impl/serial_port_base.hpp
new file mode 100644
index 0000000..758e652
--- /dev/null
+++ b/ext/asio/asio/impl/serial_port_base.hpp
@@ -0,0 +1,59 @@
+//
+// impl/serial_port_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_SERIAL_PORT_BASE_HPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
+  : value_(rate)
+{
+}
+
+inline unsigned int serial_port_base::baud_rate::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::flow_control::type
+serial_port_base::flow_control::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::parity::type serial_port_base::parity::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::stop_bits::type
+serial_port_base::stop_bits::value() const
+{
+  return value_;
+}
+
+inline unsigned int serial_port_base::character_size::value() const
+{
+  return value_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP
diff --git a/ext/asio/asio/impl/serial_port_base.ipp b/ext/asio/asio/impl/serial_port_base.ipp
index 64ab6a4..4d3204d 100644
--- a/ext/asio/asio/impl/serial_port_base.ipp
+++ b/ext/asio/asio/impl/serial_port_base.ipp
@@ -1,40 +1,43 @@
 //
-// serial_port_base.ipp
-// ~~~~~~~~~~~~~~~~~~~~
+// impl/serial_port_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 
-#ifndef ASIO_SERIAL_PORT_BASE_IPP
-#define ASIO_SERIAL_PORT_BASE_IPP
+#ifndef ASIO_IMPL_SERIAL_PORT_BASE_IPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_IPP
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
+#if defined(ASIO_HAS_SERIAL_PORT)
+
+#include <stdexcept>
 #include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/error.hpp"
+#include "asio/serial_port_base.hpp"
 
-namespace asio {
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_OPTION_STORAGE implementation_defined
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_OPTION_STORAGE DCB
+#else
+# define ASIO_OPTION_STORAGE termios
+#endif
 
-inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
-  : value_(rate)
-{
-}
+#include "asio/detail/push_options.hpp"
 
-inline unsigned int serial_port_base::baud_rate::value() const
-{
-  return value_;
-}
+namespace asio {
 
-inline asio::error_code serial_port_base::baud_rate::store(
+asio::error_code serial_port_base::baud_rate::store(
     ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -122,7 +125,7 @@ inline asio::error_code serial_port_base::baud_rate::store(
   return ec;
 }
 
-inline asio::error_code serial_port_base::baud_rate::load(
+asio::error_code serial_port_base::baud_rate::load(
     const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -204,7 +207,7 @@ inline asio::error_code serial_port_base::baud_rate::load(
   return ec;
 }
 
-inline serial_port_base::flow_control::flow_control(
+serial_port_base::flow_control::flow_control(
     serial_port_base::flow_control::type t)
   : value_(t)
 {
@@ -215,13 +218,7 @@ inline serial_port_base::flow_control::flow_control(
   }
 }
 
-inline serial_port_base::flow_control::type
-serial_port_base::flow_control::value() const
-{
-  return value_;
-}
-
-inline asio::error_code serial_port_base::flow_control::store(
+asio::error_code serial_port_base::flow_control::store(
     ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -255,12 +252,16 @@ inline asio::error_code serial_port_base::flow_control::store(
     storage.c_iflag &= ~(IXOFF | IXON);
 # if defined(_BSD_SOURCE)
     storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+    storage.c_cflag &= ~(IHFLOW | OHFLOW);
 # endif
     break;
   case software:
     storage.c_iflag |= IXOFF | IXON;
 # if defined(_BSD_SOURCE)
     storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+    storage.c_cflag &= ~(IHFLOW | OHFLOW);
 # endif
     break;
   case hardware:
@@ -268,6 +269,10 @@ inline asio::error_code serial_port_base::flow_control::store(
     storage.c_iflag &= ~(IXOFF | IXON);
     storage.c_cflag |= CRTSCTS;
     break;
+# elif defined(__QNXNTO__)
+    storage.c_iflag &= ~(IXOFF | IXON);
+    storage.c_cflag |= (IHFLOW | OHFLOW);
+    break;
 # else
     ec = asio::error::operation_not_supported;
     return ec;
@@ -280,7 +285,7 @@ inline asio::error_code serial_port_base::flow_control::store(
   return ec;
 }
 
-inline asio::error_code serial_port_base::flow_control::load(
+asio::error_code serial_port_base::flow_control::load(
     const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -306,6 +311,11 @@ inline asio::error_code serial_port_base::flow_control::load(
   {
     value_ = hardware;
   }
+# elif defined(__QNXNTO__)
+  else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)
+  {
+    value_ = hardware;
+  }
 # endif
   else
   {
@@ -316,7 +326,7 @@ inline asio::error_code serial_port_base::flow_control::load(
   return ec;
 }
 
-inline serial_port_base::parity::parity(serial_port_base::parity::type t)
+serial_port_base::parity::parity(serial_port_base::parity::type t)
   : value_(t)
 {
   if (t != none && t != odd && t != even)
@@ -326,12 +336,7 @@ inline serial_port_base::parity::parity(serial_port_base::parity::type t)
   }
 }
 
-inline serial_port_base::parity::type serial_port_base::parity::value() const
-{
-  return value_;
-}
-
-inline asio::error_code serial_port_base::parity::store(
+asio::error_code serial_port_base::parity::store(
     ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -378,7 +383,7 @@ inline asio::error_code serial_port_base::parity::store(
   return ec;
 }
 
-inline asio::error_code serial_port_base::parity::load(
+asio::error_code serial_port_base::parity::load(
     const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -415,7 +420,7 @@ inline asio::error_code serial_port_base::parity::load(
   return ec;
 }
 
-inline serial_port_base::stop_bits::stop_bits(
+serial_port_base::stop_bits::stop_bits(
     serial_port_base::stop_bits::type t)
   : value_(t)
 {
@@ -426,13 +431,7 @@ inline serial_port_base::stop_bits::stop_bits(
   }
 }
 
-inline serial_port_base::stop_bits::type
-serial_port_base::stop_bits::value() const
-{
-  return value_;
-}
-
-inline asio::error_code serial_port_base::stop_bits::store(
+asio::error_code serial_port_base::stop_bits::store(
     ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -468,7 +467,7 @@ inline asio::error_code serial_port_base::stop_bits::store(
   return ec;
 }
 
-inline asio::error_code serial_port_base::stop_bits::load(
+asio::error_code serial_port_base::stop_bits::load(
     const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -495,7 +494,7 @@ inline asio::error_code serial_port_base::stop_bits::load(
   return ec;
 }
 
-inline serial_port_base::character_size::character_size(unsigned int t)
+serial_port_base::character_size::character_size(unsigned int t)
   : value_(t)
 {
   if (t < 5 || t > 8)
@@ -505,12 +504,7 @@ inline serial_port_base::character_size::character_size(unsigned int t)
   }
 }
 
-inline unsigned int serial_port_base::character_size::value() const
-{
-  return value_;
-}
-
-inline asio::error_code serial_port_base::character_size::store(
+asio::error_code serial_port_base::character_size::store(
     ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -530,7 +524,7 @@ inline asio::error_code serial_port_base::character_size::store(
   return ec;
 }
 
-inline asio::error_code serial_port_base::character_size::load(
+asio::error_code serial_port_base::character_size::load(
     const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
 {
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -554,4 +548,8 @@ inline asio::error_code serial_port_base::character_size::load(
 
 #include "asio/detail/pop_options.hpp"
 
-#endif // ASIO_SERIAL_PORT_BASE_IPP
+#undef ASIO_OPTION_STORAGE
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP
diff --git a/ext/asio/asio/impl/src.cpp b/ext/asio/asio/impl/src.cpp
new file mode 100644
index 0000000..1dac400
--- /dev/null
+++ b/ext/asio/asio/impl/src.cpp
@@ -0,0 +1,25 @@
+//
+// impl/src.cpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#if defined(_MSC_VER) \
+  || defined(__BORLANDC__) \
+  || defined(__DMC__)
+# pragma message ( \
+    "This file is deprecated. " \
+    "Please #include <asio/impl/src.hpp> instead.")
+#elif defined(__GNUC__) \
+  || defined(__HP_aCC) \
+  || defined(__SUNPRO_CC) \
+  || defined(__IBMCPP__)
+# warning "This file is deprecated."
+# warning "Please #include <asio/impl/src.hpp> instead."
+#endif
+
+#include "asio/impl/src.hpp"
diff --git a/ext/asio/asio/impl/src.hpp b/ext/asio/asio/impl/src.hpp
new file mode 100644
index 0000000..b37eabd
--- /dev/null
+++ b/ext/asio/asio/impl/src.hpp
@@ -0,0 +1,65 @@
+//
+// impl/src.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_SRC_HPP
+#define ASIO_IMPL_SRC_HPP
+
+#define ASIO_SOURCE
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined
+#endif
+
+#include "asio/impl/error.ipp"
+#include "asio/impl/error_code.ipp"
+#include "asio/impl/io_service.ipp"
+#include "asio/impl/serial_port_base.ipp"
+#include "asio/detail/impl/descriptor_ops.ipp"
+#include "asio/detail/impl/dev_poll_reactor.ipp"
+#include "asio/detail/impl/epoll_reactor.ipp"
+#include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#include "asio/detail/impl/kqueue_reactor.ipp"
+#include "asio/detail/impl/pipe_select_interrupter.ipp"
+#include "asio/detail/impl/posix_event.ipp"
+#include "asio/detail/impl/posix_mutex.ipp"
+#include "asio/detail/impl/posix_thread.ipp"
+#include "asio/detail/impl/posix_tss_ptr.ipp"
+#include "asio/detail/impl/reactive_descriptor_service.ipp"
+#include "asio/detail/impl/reactive_serial_port_service.ipp"
+#include "asio/detail/impl/reactive_socket_service_base.ipp"
+#include "asio/detail/impl/resolver_service_base.ipp"
+#include "asio/detail/impl/select_reactor.ipp"
+#include "asio/detail/impl/service_registry.ipp"
+#include "asio/detail/impl/socket_ops.ipp"
+#include "asio/detail/impl/socket_select_interrupter.ipp"
+#include "asio/detail/impl/strand_service.ipp"
+#include "asio/detail/impl/task_io_service.ipp"
+#include "asio/detail/impl/throw_error.ipp"
+#include "asio/detail/impl/timer_queue.ipp"
+#include "asio/detail/impl/timer_queue_set.ipp"
+#include "asio/detail/impl/win_iocp_handle_service.ipp"
+#include "asio/detail/impl/win_iocp_io_service.ipp"
+#include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#include "asio/detail/impl/win_event.ipp"
+#include "asio/detail/impl/win_mutex.ipp"
+#include "asio/detail/impl/win_thread.ipp"
+#include "asio/detail/impl/win_tss_ptr.ipp"
+#include "asio/detail/impl/winsock_init.ipp"
+#include "asio/ip/impl/address.ipp"
+#include "asio/ip/impl/address_v4.ipp"
+#include "asio/ip/impl/address_v6.ipp"
+#include "asio/ip/impl/host_name.ipp"
+#include "asio/ip/detail/impl/endpoint.ipp"
+#include "asio/local/detail/impl/endpoint.ipp"
+
+#endif // ASIO_IMPL_SRC_HPP
diff --git a/ext/asio/asio/impl/write.hpp b/ext/asio/asio/impl/write.hpp
new file mode 100644
index 0000000..91cb65e
--- /dev/null
+++ b/ext/asio/asio/impl/write.hpp
@@ -0,0 +1,396 @@
+//
+// impl/write.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_WRITE_HPP
+#define ASIO_IMPL_WRITE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  asio::detail::consuming_buffers<
+    const_buffer, ConstBufferSequence> tmp(buffers);
+  std::size_t total_transferred = 0;
+  tmp.prepare(detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred)));
+  while (tmp.begin() != tmp.end())
+  {
+    std::size_t bytes_transferred = s.write_some(tmp, ec);
+    tmp.consume(bytes_transferred);
+    total_transferred += bytes_transferred;
+    tmp.prepare(detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred)));
+  }
+  return total_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, buffers, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec);
+  b.consume(bytes_transferred);
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, b, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, b, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  class write_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,
+        CompletionCondition completion_condition, WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+        for (;;)
+        {
+          stream_.async_write_some(buffers_, *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.consume(bytes_transferred);
+          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+          if ((!ec && bytes_transferred == 0)
+              || buffers_.begin() == buffers_.end())
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncWriteStream& stream_;
+    asio::detail::consuming_buffers<
+      const_buffer, ConstBufferSequence> buffers_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream,
+      typename CompletionCondition, typename WriteHandler>
+  class write_op<AsyncWriteStream, asio::mutable_buffers_1,
+      CompletionCondition, WriteHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_op(AsyncWriteStream& stream,
+        const asio::mutable_buffers_1& buffers,
+        CompletionCondition completion_condition,
+        WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          stream_.async_write_some(asio::buffer(
+                buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncWriteStream& stream_;
+    asio::mutable_buffer buffer_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream,
+      typename CompletionCondition, typename WriteHandler>
+  class write_op<AsyncWriteStream, asio::const_buffers_1,
+      CompletionCondition, WriteHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_op(AsyncWriteStream& stream,
+        const asio::const_buffers_1& buffers,
+        CompletionCondition completion_condition,
+        WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          stream_.async_write_some(asio::buffer(
+                buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncWriteStream& stream_;
+    asio::const_buffer buffer_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      write_op<AsyncWriteStream, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      write_op<AsyncWriteStream, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename ConstBufferSequence, typename CompletionCondition,
+      typename WriteHandler>
+  inline void asio_handler_invoke(const Function& function,
+      write_op<AsyncWriteStream, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+  typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, WriteHandler handler)
+{
+  detail::write_op<AsyncWriteStream, ConstBufferSequence,
+    CompletionCondition, WriteHandler>(
+      s, buffers, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+    typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    WriteHandler handler)
+{
+  async_write(s, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncWriteStream, typename Allocator,
+      typename WriteHandler>
+  class write_streambuf_handler
+  {
+  public:
+    write_streambuf_handler(asio::basic_streambuf<Allocator>& streambuf,
+        WriteHandler handler)
+      : streambuf_(streambuf),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        const std::size_t bytes_transferred)
+    {
+      streambuf_.consume(bytes_transferred);
+      handler_(ec, bytes_transferred);
+    }
+
+  //private:
+    asio::basic_streambuf<Allocator>& streambuf_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream, typename Allocator,
+      typename WriteHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      write_streambuf_handler<AsyncWriteStream,
+        Allocator, WriteHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncWriteStream, typename Allocator,
+      typename WriteHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      write_streambuf_handler<AsyncWriteStream,
+        Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncWriteStream, typename Allocator,
+      typename WriteHandler>
+  inline void asio_handler_invoke(const Function& function,
+      write_streambuf_handler<AsyncWriteStream,
+        Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename Allocator,
+    typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, WriteHandler handler)
+{
+  async_write(s, b.data(), completion_condition,
+      detail::write_streambuf_handler<
+        AsyncWriteStream, Allocator, WriteHandler>(b, handler));
+}
+
+template <typename AsyncWriteStream, typename Allocator, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b, WriteHandler handler)
+{
+  async_write(s, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_HPP
diff --git a/ext/asio/asio/impl/write_at.hpp b/ext/asio/asio/impl/write_at.hpp
new file mode 100644
index 0000000..1de6800
--- /dev/null
+++ b/ext/asio/asio/impl/write_at.hpp
@@ -0,0 +1,417 @@
+//
+// impl/write_at.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_WRITE_AT_HPP
+#define ASIO_IMPL_WRITE_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  asio::detail::consuming_buffers<
+    const_buffer, ConstBufferSequence> tmp(buffers);
+  std::size_t total_transferred = 0;
+  tmp.prepare(detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred)));
+  while (tmp.begin() != tmp.end())
+  {
+    std::size_t bytes_transferred = d.write_some_at(
+        offset + total_transferred, tmp, ec);
+    tmp.consume(bytes_transferred);
+    total_transferred += bytes_transferred;
+    tmp.prepare(detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred)));
+  }
+  return total_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, const ConstBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(
+      d, offset, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(
+      d, offset, buffers, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  std::size_t bytes_transferred = write_at(
+      d, offset, b.data(), completion_condition, ec);
+  b.consume(bytes_transferred);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(
+      d, offset, b, completion_condition, ec);
+  asio::detail::throw_error(ec);
+  return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  class write_at_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_at_op(AsyncRandomAccessWriteDevice& device,
+        boost::uint64_t offset, const ConstBufferSequence& buffers,
+        CompletionCondition completion_condition, WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffers_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+        for (;;)
+        {
+          device_.async_write_some_at(
+              offset_ + total_transferred_, buffers_, *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.consume(bytes_transferred);
+          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+          if ((!ec && bytes_transferred == 0)
+              || buffers_.begin() == buffers_.end())
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessWriteDevice& device_;
+    boost::uint64_t offset_;
+    asio::detail::consuming_buffers<
+      const_buffer, ConstBufferSequence> buffers_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename CompletionCondition, typename WriteHandler>
+  class write_at_op<AsyncRandomAccessWriteDevice,
+      asio::mutable_buffers_1, CompletionCondition, WriteHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_at_op(AsyncRandomAccessWriteDevice& device,
+        boost::uint64_t offset, const asio::mutable_buffers_1& buffers,
+        CompletionCondition completion_condition,
+        WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          device_.async_write_some_at(offset_ + total_transferred_,
+              asio::buffer(buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessWriteDevice& device_;
+    boost::uint64_t offset_;
+    asio::mutable_buffer buffer_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename CompletionCondition, typename WriteHandler>
+  class write_at_op<AsyncRandomAccessWriteDevice, asio::const_buffers_1,
+      CompletionCondition, WriteHandler>
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_at_op(AsyncRandomAccessWriteDevice& device,
+        boost::uint64_t offset, const asio::const_buffers_1& buffers,
+        CompletionCondition completion_condition,
+        WriteHandler handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffer_(buffers),
+        total_transferred_(0),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t n = 0;
+      switch (start)
+      {
+        case 1:
+        n = this->check_for_completion(ec, total_transferred_);
+        for (;;)
+        {
+          device_.async_write_some_at(offset_ + total_transferred_,
+              asio::buffer(buffer_ + total_transferred_, n), *this);
+          return; default:
+          total_transferred_ += bytes_transferred;
+          if ((!ec && bytes_transferred == 0)
+              || (n = this->check_for_completion(ec, total_transferred_)) == 0
+              || total_transferred_ == asio::buffer_size(buffer_))
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessWriteDevice& device_;
+    boost::uint64_t offset_;
+    asio::const_buffer buffer_;
+    std::size_t total_transferred_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+      typename CompletionCondition, typename WriteHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename CompletionCondition,
+      typename WriteHandler>
+  inline void asio_handler_invoke(const Function& function,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition, typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, WriteHandler handler)
+{
+  detail::write_at_op<AsyncRandomAccessWriteDevice,
+    ConstBufferSequence, CompletionCondition, WriteHandler>(
+      d, offset, buffers, completion_condition, handler)(
+        asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, const ConstBufferSequence& buffers,
+    WriteHandler handler)
+{
+  async_write_at(d, offset, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessWriteDevice,
+      typename Allocator, typename WriteHandler>
+  class write_at_streambuf_op
+  {
+  public:
+    write_at_streambuf_op(
+        asio::basic_streambuf<Allocator>& streambuf,
+        WriteHandler handler)
+      : streambuf_(streambuf),
+        handler_(handler)
+    {
+    }
+
+    void operator()(const asio::error_code& ec,
+        const std::size_t bytes_transferred)
+    {
+      streambuf_.consume(bytes_transferred);
+      handler_(ec, bytes_transferred);
+    }
+
+  //private:
+    asio::basic_streambuf<Allocator>& streambuf_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+      typename WriteHandler>
+  inline void* asio_handler_allocate(std::size_t size,
+      write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+        Allocator, WriteHandler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+      typename WriteHandler>
+  inline void asio_handler_deallocate(void* pointer, std::size_t size,
+      write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+        Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessWriteDevice,
+      typename Allocator, typename WriteHandler>
+  inline void asio_handler_invoke(const Function& function,
+      write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+        Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition, typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, WriteHandler handler)
+{
+  async_write_at(d, offset, b.data(), completion_condition,
+      detail::write_at_streambuf_op<
+        AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler));
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+    typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+    boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    WriteHandler handler)
+{
+  async_write_at(d, offset, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_AT_HPP
diff --git a/ext/asio/asio/io_service.hpp b/ext/asio/asio/io_service.hpp
index 62d9e54..4fc3e05 100644
--- a/ext/asio/asio/io_service.hpp
+++ b/ext/asio/asio/io_service.hpp
@@ -2,7 +2,7 @@
 // io_service.hpp
 // ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,29 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <stdexcept>
 #include <typeinfo>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
 #include "asio/detail/noncopyable.hpp"
-#include "asio/detail/reactor_fwd.hpp"
 #include "asio/detail/service_registry_fwd.hpp"
-#include "asio/detail/signal_init.hpp"
-#include "asio/detail/task_io_service_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
-#include "asio/detail/winsock_init.hpp"
 #include "asio/detail/wrapped_handler.hpp"
+#include "asio/error_code.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service_fwd.hpp"
+#else
+# include "asio/detail/task_io_service_fwd.hpp"
+#endif
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/winsock_init.hpp"
+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
+  || defined(__osf__)
+# include "asio/detail/signal_init.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
@@ -45,7 +49,7 @@ template <typename Service> bool has_service(io_service& ios);
 #if defined(ASIO_HAS_IOCP)
 namespace detail { typedef win_iocp_io_service io_service_impl; }
 #else
-namespace detail { typedef task_io_service<reactor> io_service_impl; }
+namespace detail { typedef task_io_service io_service_impl; }
 #endif
 
 /// Provides core I/O functionality.
@@ -196,7 +200,7 @@ public:
   class strand;
 
   /// Constructor.
-  io_service();
+  ASIO_DECL io_service();
 
   /// Constructor.
   /**
@@ -205,7 +209,7 @@ public:
    * @param concurrency_hint A suggestion to the implementation on how many
    * threads it should allow to run simultaneously.
    */
-  explicit io_service(std::size_t concurrency_hint);
+  ASIO_DECL explicit io_service(std::size_t concurrency_hint);
 
   /// Destructor.
   /**
@@ -239,7 +243,7 @@ public:
    * destructor defined above destroys all handlers, causing all @c shared_ptr
    * references to all connection objects to be destroyed.
    */
-  ~io_service();
+  ASIO_DECL ~io_service();
 
   /// Run the io_service object's event processing loop.
   /**
@@ -265,7 +269,7 @@ public:
    * The poll() function may also be used to dispatch ready handlers, but
    * without blocking.
    */
-  std::size_t run();
+  ASIO_DECL std::size_t run();
 
   /// Run the io_service object's event processing loop.
   /**
@@ -291,7 +295,7 @@ public:
    * The poll() function may also be used to dispatch ready handlers, but
    * without blocking.
    */
-  std::size_t run(asio::error_code& ec);
+  ASIO_DECL std::size_t run(asio::error_code& ec);
 
   /// Run the io_service object's event processing loop to execute at most one
   /// handler.
@@ -303,7 +307,7 @@ public:
    *
    * @throws asio::system_error Thrown on failure.
    */
-  std::size_t run_one();
+  ASIO_DECL std::size_t run_one();
 
   /// Run the io_service object's event processing loop to execute at most one
   /// handler.
@@ -315,7 +319,7 @@ public:
    *
    * @return The number of handlers that were executed.
    */
-  std::size_t run_one(asio::error_code& ec);
+  ASIO_DECL std::size_t run_one(asio::error_code& ec);
 
   /// Run the io_service object's event processing loop to execute ready
   /// handlers.
@@ -327,7 +331,7 @@ public:
    *
    * @throws asio::system_error Thrown on failure.
    */
-  std::size_t poll();
+  ASIO_DECL std::size_t poll();
 
   /// Run the io_service object's event processing loop to execute ready
   /// handlers.
@@ -339,7 +343,7 @@ public:
    *
    * @return The number of handlers that were executed.
    */
-  std::size_t poll(asio::error_code& ec);
+  ASIO_DECL std::size_t poll(asio::error_code& ec);
 
   /// Run the io_service object's event processing loop to execute one ready
   /// handler.
@@ -351,7 +355,7 @@ public:
    *
    * @throws asio::system_error Thrown on failure.
    */
-  std::size_t poll_one();
+  ASIO_DECL std::size_t poll_one();
 
   /// Run the io_service object's event processing loop to execute one ready
   /// handler.
@@ -363,7 +367,7 @@ public:
    *
    * @return The number of handlers that were executed.
    */
-  std::size_t poll_one(asio::error_code& ec);
+  ASIO_DECL std::size_t poll_one(asio::error_code& ec);
 
   /// Stop the io_service object's event processing loop.
   /**
@@ -372,7 +376,7 @@ public:
    * return as soon as possible. Subsequent calls to run(), run_one(), poll()
    * or poll_one() will return immediately until reset() is called.
    */
-  void stop();
+  ASIO_DECL void stop();
 
   /// Reset the io_service in preparation for a subsequent run() invocation.
   /**
@@ -385,7 +389,7 @@ public:
    * This function must not be called while there are any unfinished calls to
    * the run(), run_one(), poll() or poll_one() functions.
    */
-  void reset();
+  ASIO_DECL void reset();
 
   /// Request the io_service to invoke the given handler.
   /**
@@ -605,10 +609,10 @@ protected:
   /**
    * @param owner The io_service object that owns the service.
    */
-  service(asio::io_service& owner);
+  ASIO_DECL service(asio::io_service& owner);
 
   /// Destructor.
-  virtual ~service();
+  ASIO_DECL virtual ~service();
 
 private:
   /// Destroy all user-defined handler objects owned by the service.
@@ -631,10 +635,7 @@ class service_already_exists
   : public std::logic_error
 {
 public:
-  service_already_exists()
-    : std::logic_error("Service already exists.")
-  {
-  }
+  ASIO_DECL service_already_exists();
 };
 
 /// Exception thrown when trying to add a service object to an io_service where
@@ -643,16 +644,44 @@ class invalid_service_owner
   : public std::logic_error
 {
 public:
-  invalid_service_owner()
-    : std::logic_error("Invalid service owner.")
+  ASIO_DECL invalid_service_owner();
+};
+
+namespace detail {
+
+// Special derived service id type to keep classes header-file only.
+template <typename Type>
+class service_id
+  : public asio::io_service::id
+{
+};
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class service_base
+  : public asio::io_service::service
+{
+public:
+  static asio::detail::service_id<Type> id;
+
+  // Constructor.
+  service_base(asio::io_service& io_service)
+    : asio::io_service::service(io_service)
   {
   }
 };
 
-} // namespace asio
+template <typename Type>
+asio::detail::service_id<Type> service_base<Type>::id;
 
-#include "asio/impl/io_service.ipp"
+} // namespace detail
+} // namespace asio
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/impl/io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_IO_SERVICE_HPP
diff --git a/ext/asio/asio/ip/address.hpp b/ext/asio/asio/ip/address.hpp
index 92ee4ae..47683db 100644
--- a/ext/asio/asio/ip/address.hpp
+++ b/ext/asio/asio/ip/address.hpp
@@ -1,8 +1,8 @@
 //
-// address.hpp
-// ~~~~~~~~~~~
+// ip/address.hpp
+// ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v6.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
 #if !defined(BOOST_NO_IOSTREAM)
 # include <iosfwd>
 #endif // !defined(BOOST_NO_IOSTREAM)
-#include <string>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
-#include "asio/error.hpp"
-#include "asio/ip/address_v4.hpp"
-#include "asio/ip/address_v6.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
@@ -47,63 +43,27 @@ class address
 {
 public:
   /// Default constructor.
-  address()
-    : type_(ipv4),
-      ipv4_address_(),
-      ipv6_address_()
-  {
-  }
+  ASIO_DECL address();
 
   /// Construct an address from an IPv4 address.
-  address(const asio::ip::address_v4& ipv4_address)
-    : type_(ipv4),
-      ipv4_address_(ipv4_address),
-      ipv6_address_()
-  {
-  }
+  ASIO_DECL address(const asio::ip::address_v4& ipv4_address);
 
   /// Construct an address from an IPv6 address.
-  address(const asio::ip::address_v6& ipv6_address)
-    : type_(ipv6),
-      ipv4_address_(),
-      ipv6_address_(ipv6_address)
-  {
-  }
+  ASIO_DECL address(const asio::ip::address_v6& ipv6_address);
 
   /// Copy constructor.
-  address(const address& other)
-    : type_(other.type_),
-      ipv4_address_(other.ipv4_address_),
-      ipv6_address_(other.ipv6_address_)
-  {
-  }
+  ASIO_DECL address(const address& other);
 
   /// Assign from another address.
-  address& operator=(const address& other)
-  {
-    type_ = other.type_;
-    ipv4_address_ = other.ipv4_address_;
-    ipv6_address_ = other.ipv6_address_;
-    return *this;
-  }
+  ASIO_DECL address& operator=(const address& other);
 
   /// Assign from an IPv4 address.
-  address& operator=(const asio::ip::address_v4& ipv4_address)
-  {
-    type_ = ipv4;
-    ipv4_address_ = ipv4_address;
-    ipv6_address_ = asio::ip::address_v6();
-    return *this;
-  }
+  ASIO_DECL address& operator=(
+      const asio::ip::address_v4& ipv4_address);
 
   /// Assign from an IPv6 address.
-  address& operator=(const asio::ip::address_v6& ipv6_address)
-  {
-    type_ = ipv6;
-    ipv4_address_ = asio::ip::address_v4();
-    ipv6_address_ = ipv6_address;
-    return *this;
-  }
+  ASIO_DECL address& operator=(
+      const asio::ip::address_v6& ipv6_address);
 
   /// Get whether the address is an IP version 4 address.
   bool is_v4() const
@@ -118,127 +78,63 @@ public:
   }
 
   /// Get the address as an IP version 4 address.
-  asio::ip::address_v4 to_v4() const
-  {
-    if (type_ != ipv4)
-    {
-      asio::system_error e(
-          asio::error::address_family_not_supported);
-      boost::throw_exception(e);
-    }
-    return ipv4_address_;
-  }
+  ASIO_DECL asio::ip::address_v4 to_v4() const;
 
   /// Get the address as an IP version 6 address.
-  asio::ip::address_v6 to_v6() const
-  {
-    if (type_ != ipv6)
-    {
-      asio::system_error e(
-          asio::error::address_family_not_supported);
-      boost::throw_exception(e);
-    }
-    return ipv6_address_;
-  }
+  ASIO_DECL asio::ip::address_v6 to_v6() const;
 
   /// Get the address as a string in dotted decimal format.
-  std::string to_string() const
-  {
-    if (type_ == ipv6)
-      return ipv6_address_.to_string();
-    return ipv4_address_.to_string();
-  }
+  ASIO_DECL std::string to_string() const;
 
   /// Get the address as a string in dotted decimal format.
-  std::string to_string(asio::error_code& ec) const
-  {
-    if (type_ == ipv6)
-      return ipv6_address_.to_string(ec);
-    return ipv4_address_.to_string(ec);
-  }
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
 
   /// Create an address from an IPv4 address string in dotted decimal form,
   /// or from an IPv6 address in hexadecimal notation.
-  static address from_string(const char* str)
-  {
-    asio::error_code ec;
-    address addr = from_string(str, ec);
-    asio::detail::throw_error(ec);
-    return addr;
-  }
+  ASIO_DECL static address from_string(const char* str);
 
   /// Create an address from an IPv4 address string in dotted decimal form,
   /// or from an IPv6 address in hexadecimal notation.
-  static address from_string(const char* str, asio::error_code& ec)
-  {
-    asio::ip::address_v6 ipv6_address =
-      asio::ip::address_v6::from_string(str, ec);
-    if (!ec)
-    {
-      address tmp;
-      tmp.type_ = ipv6;
-      tmp.ipv6_address_ = ipv6_address;
-      return tmp;
-    }
-
-    asio::ip::address_v4 ipv4_address =
-      asio::ip::address_v4::from_string(str, ec);
-    if (!ec)
-    {
-      address tmp;
-      tmp.type_ = ipv4;
-      tmp.ipv4_address_ = ipv4_address;
-      return tmp;
-    }
-
-    return address();
-  }
+  ASIO_DECL static address from_string(
+      const char* str, asio::error_code& ec);
 
   /// Create an address from an IPv4 address string in dotted decimal form,
   /// or from an IPv6 address in hexadecimal notation.
-  static address from_string(const std::string& str)
-  {
-    return from_string(str.c_str());
-  }
+  ASIO_DECL static address from_string(const std::string& str);
 
   /// Create an address from an IPv4 address string in dotted decimal form,
   /// or from an IPv6 address in hexadecimal notation.
-  static address from_string(const std::string& str,
-      asio::error_code& ec)
+  ASIO_DECL static address from_string(
+      const std::string& str, asio::error_code& ec);
+
+  /// Compare two addresses for equality.
+  ASIO_DECL friend bool operator==(const address& a1, const address& a2);
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const address& a1, const address& a2)
   {
-    return from_string(str.c_str(), ec);
+    return !(a1 == a2);
   }
 
-  /// Compare two addresses for equality.
-  friend bool operator==(const address& a1, const address& a2)
+  /// Compare addresses for ordering.
+  ASIO_DECL friend bool operator<(const address& a1, const address& a2);
+
+  /// Compare addresses for ordering.
+  friend bool operator>(const address& a1, const address& a2)
   {
-    if (a1.type_ != a2.type_)
-      return false;
-    if (a1.type_ == ipv6)
-      return a1.ipv6_address_ == a2.ipv6_address_;
-    return a1.ipv4_address_ == a2.ipv4_address_;
+    return a2 < a1;
   }
 
-  /// Compare two addresses for inequality.
-  friend bool operator!=(const address& a1, const address& a2)
+  /// Compare addresses for ordering.
+  friend bool operator<=(const address& a1, const address& a2)
   {
-    if (a1.type_ != a2.type_)
-      return true;
-    if (a1.type_ == ipv6)
-      return a1.ipv6_address_ != a2.ipv6_address_;
-    return a1.ipv4_address_ != a2.ipv4_address_;
+    return !(a2 < a1);
   }
 
   /// Compare addresses for ordering.
-  friend bool operator<(const address& a1, const address& a2)
+  friend bool operator>=(const address& a1, const address& a2)
   {
-    if (a1.type_ < a2.type_)
-      return true;
-    if (a1.type_ > a2.type_)
-      return false;
-    if (a1.type_ == ipv6)
-      return a1.ipv6_address_ < a2.ipv6_address_;
-    return a1.ipv4_address_ < a2.ipv4_address_;
+    return !(a1 < a2);
   }
 
 private:
@@ -268,11 +164,7 @@ private:
  */
 template <typename Elem, typename Traits>
 std::basic_ostream<Elem, Traits>& operator<<(
-    std::basic_ostream<Elem, Traits>& os, const address& addr)
-{
-  os << addr.to_string();
-  return os;
-}
+    std::basic_ostream<Elem, Traits>& os, const address& addr);
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
@@ -281,4 +173,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/ip/impl/address.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_IP_ADDRESS_HPP
diff --git a/ext/asio/asio/ip/address_v4.hpp b/ext/asio/asio/ip/address_v4.hpp
index 1b49556..7567ef9 100644
--- a/ext/asio/asio/ip/address_v4.hpp
+++ b/ext/asio/asio/ip/address_v4.hpp
@@ -1,8 +1,8 @@
 //
-// address_v4.hpp
-// ~~~~~~~~~~~~~~
+// ip/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include <boost/array.hpp>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
 #if !defined(BOOST_NO_IOSTREAM)
 # include <iosfwd>
 #endif // !defined(BOOST_NO_IOSTREAM)
-#include <climits>
-#include <string>
-#include <stdexcept>
-#include <boost/array.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
@@ -59,34 +53,10 @@ public:
   }
 
   /// Construct an address from raw bytes.
-  explicit address_v4(const bytes_type& bytes)
-  {
-#if UCHAR_MAX > 0xFF
-    if (bytes[0] > 0xFF || bytes[1] > 0xFF
-        || bytes[2] > 0xFF || bytes[3] > 0xFF)
-    {
-      std::out_of_range ex("address_v4 from bytes_type");
-      boost::throw_exception(ex);
-    }
-#endif // UCHAR_MAX > 0xFF
-
-    using namespace std; // For memcpy.
-    memcpy(&addr_.s_addr, bytes.elems, 4);
-  }
+  ASIO_DECL explicit address_v4(const bytes_type& bytes);
 
   /// Construct an address from a unsigned long in host byte order.
-  explicit address_v4(unsigned long addr)
-  {
-#if ULONG_MAX > 0xFFFFFFFF
-    if (addr > 0xFFFFFFFF)
-    {
-      std::out_of_range ex("address_v4 from unsigned long");
-      boost::throw_exception(ex);
-    }
-#endif // ULONG_MAX > 0xFFFFFFFF
-
-    addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
-  }
+  ASIO_DECL explicit address_v4(unsigned long addr);
 
   /// Copy constructor.
   address_v4(const address_v4& other)
@@ -102,96 +72,42 @@ public:
   }
 
   /// Get the address in bytes, in network byte order.
-  bytes_type to_bytes() const
-  {
-    using namespace std; // For memcpy.
-    bytes_type bytes;
-    memcpy(bytes.elems, &addr_.s_addr, 4);
-    return bytes;
-  }
+  ASIO_DECL bytes_type to_bytes() const;
 
   /// Get the address as an unsigned long in host byte order
-  unsigned long to_ulong() const
-  {
-    return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
-  }
+  ASIO_DECL unsigned long to_ulong() const;
 
   /// Get the address as a string in dotted decimal format.
-  std::string to_string() const
-  {
-    asio::error_code ec;
-    std::string addr = to_string(ec);
-    asio::detail::throw_error(ec);
-    return addr;
-  }
+  ASIO_DECL std::string to_string() const;
 
   /// Get the address as a string in dotted decimal format.
-  std::string to_string(asio::error_code& ec) const
-  {
-    char addr_str[asio::detail::max_addr_v4_str_len];
-    const char* addr =
-      asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
-          asio::detail::max_addr_v4_str_len, 0, ec);
-    if (addr == 0)
-      return std::string();
-    return addr;
-  }
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
 
   /// Create an address from an IP address string in dotted decimal form.
-  static address_v4 from_string(const char* str)
-  {
-    asio::error_code ec;
-    address_v4 addr = from_string(str, ec);
-    asio::detail::throw_error(ec);
-    return addr;
-  }
+  ASIO_DECL static address_v4 from_string(const char* str);
 
   /// Create an address from an IP address string in dotted decimal form.
-  static address_v4 from_string(const char* str, asio::error_code& ec)
-  {
-    address_v4 tmp;
-    if (asio::detail::socket_ops::inet_pton(
-          AF_INET, str, &tmp.addr_, 0, ec) <= 0)
-      return address_v4();
-    return tmp;
-  }
+  ASIO_DECL static address_v4 from_string(
+      const char* str, asio::error_code& ec);
 
   /// Create an address from an IP address string in dotted decimal form.
-  static address_v4 from_string(const std::string& str)
-  {
-    return from_string(str.c_str());
-  }
+  ASIO_DECL static address_v4 from_string(const std::string& str);
 
   /// Create an address from an IP address string in dotted decimal form.
-  static address_v4 from_string(const std::string& str,
-      asio::error_code& ec)
-  {
-    return from_string(str.c_str(), ec);
-  }
+  ASIO_DECL static address_v4 from_string(
+      const std::string& str, asio::error_code& ec);
 
   /// Determine whether the address is a class A address.
-  bool is_class_a() const
-  {
-    return IN_CLASSA(to_ulong());
-  }
+  ASIO_DECL bool is_class_a() const;
 
   /// Determine whether the address is a class B address.
-  bool is_class_b() const
-  {
-    return IN_CLASSB(to_ulong());
-  }
+  ASIO_DECL bool is_class_b() const;
 
   /// Determine whether the address is a class C address.
-  bool is_class_c() const
-  {
-    return IN_CLASSC(to_ulong());
-  }
+  ASIO_DECL bool is_class_c() const;
 
   /// Determine whether the address is a multicast address.
-  bool is_multicast() const
-  {
-    return IN_MULTICAST(to_ulong());
-  }
+  ASIO_DECL bool is_multicast() const;
 
   /// Compare two addresses for equality.
   friend bool operator==(const address_v4& a1, const address_v4& a2)
@@ -249,23 +165,12 @@ public:
 
   /// Obtain an address object that represents the broadcast address that
   /// corresponds to the specified address and netmask.
-  static address_v4 broadcast(const address_v4& addr, const address_v4& mask)
-  {
-    return address_v4(addr.to_ulong() | ~mask.to_ulong());
-  }
+  ASIO_DECL static address_v4 broadcast(
+      const address_v4& addr, const address_v4& mask);
 
   /// Obtain the netmask that corresponds to the address, based on its address
   /// class.
-  static address_v4 netmask(const address_v4& addr)
-  {
-    if (addr.is_class_a())
-      return address_v4(0xFF000000);
-    if (addr.is_class_b())
-      return address_v4(0xFFFF0000);
-    if (addr.is_class_c())
-      return address_v4(0xFFFFFF00);
-    return address_v4(0xFFFFFFFF);
-  }
+  ASIO_DECL static address_v4 netmask(const address_v4& addr);
 
 private:
   // The underlying IPv4 address.
@@ -288,22 +193,7 @@ private:
  */
 template <typename Elem, typename Traits>
 std::basic_ostream<Elem, Traits>& operator<<(
-    std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
-{
-  asio::error_code ec;
-  std::string s = addr.to_string(ec);
-  if (ec)
-  {
-    if (os.exceptions() & std::ios::failbit)
-      asio::detail::throw_error(ec);
-    else
-      os.setstate(std::ios_base::failbit);
-  }
-  else
-    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
-      os << os.widen(*i);
-  return os;
-}
+    std::basic_ostream<Elem, Traits>& os, const address_v4& addr);
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
@@ -312,4 +202,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/ip/impl/address_v4.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v4.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_IP_ADDRESS_V4_HPP
diff --git a/ext/asio/asio/ip/address_v6.hpp b/ext/asio/asio/ip/address_v6.hpp
index 8d2c083..261c651 100644
--- a/ext/asio/asio/ip/address_v6.hpp
+++ b/ext/asio/asio/ip/address_v6.hpp
@@ -1,8 +1,8 @@
 //
-// address_v6.hpp
-// ~~~~~~~~~~~~~~
+// ip/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include <boost/array.hpp>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
 #if !defined(BOOST_NO_IOSTREAM)
 # include <iosfwd>
 #endif // !defined(BOOST_NO_IOSTREAM)
-#include <cstring>
-#include <string>
-#include <stdexcept>
-#include <typeinfo>
-#include <boost/array.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
 
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
-#include "asio/ip/address_v4.hpp"
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
@@ -55,46 +48,17 @@ public:
   typedef boost::array<unsigned char, 16> bytes_type;
 
   /// Default constructor.
-  address_v6()
-    : scope_id_(0)
-  {
-    asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
-    addr_ = tmp_addr;
-  }
+  ASIO_DECL address_v6();
 
   /// Construct an address from raw bytes and scope ID.
-  explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
-    : scope_id_(scope_id)
-  {
-#if UCHAR_MAX > 0xFF
-    for (std::size_t i = 0; i < bytes.size(); ++i)
-    {
-      if (bytes[i] > 0xFF)
-      {
-        std::out_of_range ex("address_v6 from bytes_type");
-        boost::throw_exception(ex);
-      }
-    }
-#endif // UCHAR_MAX > 0xFF
-
-    using namespace std; // For memcpy.
-    memcpy(addr_.s6_addr, bytes.elems, 16);
-  }
+  ASIO_DECL explicit address_v6(const bytes_type& bytes,
+      unsigned long scope_id = 0);
 
   /// Copy constructor.
-  address_v6(const address_v6& other)
-    : addr_(other.addr_),
-      scope_id_(other.scope_id_)
-  {
-  }
+  ASIO_DECL address_v6(const address_v6& other);
 
   /// Assign from another address.
-  address_v6& operator=(const address_v6& other)
-  {
-    addr_ = other.addr_;
-    scope_id_ = other.scope_id_;
-    return *this;
-  }
+  ASIO_DECL address_v6& operator=(const address_v6& other);
 
   /// The scope ID of the address.
   /**
@@ -115,217 +79,80 @@ public:
   }
 
   /// Get the address in bytes, in network byte order.
-  bytes_type to_bytes() const
-  {
-    using namespace std; // For memcpy.
-    bytes_type bytes;
-    memcpy(bytes.elems, addr_.s6_addr, 16);
-    return bytes;
-  }
+  ASIO_DECL bytes_type to_bytes() const;
 
   /// Get the address as a string.
-  std::string to_string() const
-  {
-    asio::error_code ec;
-    std::string addr = to_string(ec);
-    asio::detail::throw_error(ec);
-    return addr;
-  }
+  ASIO_DECL std::string to_string() const;
 
   /// Get the address as a string.
-  std::string to_string(asio::error_code& ec) const
-  {
-    char addr_str[asio::detail::max_addr_v6_str_len];
-    const char* addr =
-      asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
-          asio::detail::max_addr_v6_str_len, scope_id_, ec);
-    if (addr == 0)
-      return std::string();
-    return addr;
-  }
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
 
   /// Create an address from an IP address string.
-  static address_v6 from_string(const char* str)
-  {
-    asio::error_code ec;
-    address_v6 addr = from_string(str, ec);
-    asio::detail::throw_error(ec);
-    return addr;
-  }
+  ASIO_DECL static address_v6 from_string(const char* str);
 
   /// Create an address from an IP address string.
-  static address_v6 from_string(const char* str, asio::error_code& ec)
-  {
-    address_v6 tmp;
-    if (asio::detail::socket_ops::inet_pton(
-          AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0)
-      return address_v6();
-    return tmp;
-  }
+  ASIO_DECL static address_v6 from_string(
+      const char* str, asio::error_code& ec);
 
   /// Create an address from an IP address string.
-  static address_v6 from_string(const std::string& str)
-  {
-    return from_string(str.c_str());
-  }
+  ASIO_DECL static address_v6 from_string(const std::string& str);
 
   /// Create an address from an IP address string.
-  static address_v6 from_string(const std::string& str,
-      asio::error_code& ec)
-  {
-    return from_string(str.c_str(), ec);
-  }
+  ASIO_DECL static address_v6 from_string(
+      const std::string& str, asio::error_code& ec);
 
   /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address.
-  address_v4 to_v4() const
-  {
-    if (!is_v4_mapped() && !is_v4_compatible())
-    {
-      std::bad_cast ex;
-      boost::throw_exception(ex);
-    }
-
-    address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
-      addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
-    return address_v4(v4_bytes);
-  }
+  ASIO_DECL address_v4 to_v4() const;
 
   /// Determine whether the address is a loopback address.
-  bool is_loopback() const
-  {
-#if defined(__BORLANDC__)
-    return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
-        && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
-        && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
-        && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
-        && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
-        && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
-        && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
-        && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
-#else
-    using namespace asio::detail;
-    return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
-#endif
-  }
+  ASIO_DECL bool is_loopback() const;
 
   /// Determine whether the address is unspecified.
-  bool is_unspecified() const
-  {
-#if defined(__BORLANDC__)
-    return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
-        && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
-        && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
-        && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
-        && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
-        && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
-        && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
-        && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
-#else
-    using namespace asio::detail;
-    return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
-#endif
-  }
+  ASIO_DECL bool is_unspecified() const;
 
   /// Determine whether the address is link local.
-  bool is_link_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_link_local() const;
 
   /// Determine whether the address is site local.
-  bool is_site_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_site_local() const;
 
   /// Determine whether the address is a mapped IPv4 address.
-  bool is_v4_mapped() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
-  }
+  ASIO_DECL bool is_v4_mapped() const;
 
   /// Determine whether the address is an IPv4-compatible address.
-  bool is_v4_compatible() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
-  }
+  ASIO_DECL bool is_v4_compatible() const;
 
   /// Determine whether the address is a multicast address.
-  bool is_multicast() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast() const;
 
   /// Determine whether the address is a global multicast address.
-  bool is_multicast_global() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast_global() const;
 
   /// Determine whether the address is a link-local multicast address.
-  bool is_multicast_link_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast_link_local() const;
 
   /// Determine whether the address is a node-local multicast address.
-  bool is_multicast_node_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast_node_local() const;
 
   /// Determine whether the address is a org-local multicast address.
-  bool is_multicast_org_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast_org_local() const;
 
   /// Determine whether the address is a site-local multicast address.
-  bool is_multicast_site_local() const
-  {
-    using namespace asio::detail;
-    return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
-  }
+  ASIO_DECL bool is_multicast_site_local() const;
 
   /// Compare two addresses for equality.
-  friend bool operator==(const address_v6& a1, const address_v6& a2)
-  {
-    using namespace std; // For memcmp.
-    return memcmp(&a1.addr_, &a2.addr_,
-        sizeof(asio::detail::in6_addr_type)) == 0
-      && a1.scope_id_ == a2.scope_id_;
-  }
+  ASIO_DECL friend bool operator==(
+      const address_v6& a1, const address_v6& a2);
 
   /// Compare two addresses for inequality.
   friend bool operator!=(const address_v6& a1, const address_v6& a2)
   {
-    using namespace std; // For memcmp.
-    return memcmp(&a1.addr_, &a2.addr_,
-        sizeof(asio::detail::in6_addr_type)) != 0
-      || a1.scope_id_ != a2.scope_id_;
+    return !(a1 == a2);
   }
 
   /// Compare addresses for ordering.
-  friend bool operator<(const address_v6& a1, const address_v6& a2)
-  {
-    using namespace std; // For memcmp.
-    int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
-        sizeof(asio::detail::in6_addr_type));
-    if (memcmp_result < 0)
-      return true;
-    if (memcmp_result > 0)
-      return false;
-    return a1.scope_id_ < a2.scope_id_;
-  }
+  ASIO_DECL friend bool operator<(
+      const address_v6& a1, const address_v6& a2);
 
   /// Compare addresses for ordering.
   friend bool operator>(const address_v6& a1, const address_v6& a2)
@@ -352,31 +179,13 @@ public:
   }
 
   /// Obtain an address object that represents the loopback address.
-  static address_v6 loopback()
-  {
-    address_v6 tmp;
-    asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT;
-    tmp.addr_ = tmp_addr;
-    return tmp;
-  }
+  ASIO_DECL static address_v6 loopback();
 
   /// Create an IPv4-mapped IPv6 address.
-  static address_v6 v4_mapped(const address_v4& addr)
-  {
-    address_v4::bytes_type v4_bytes = addr.to_bytes();
-    bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
-      v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
-    return address_v6(v6_bytes);
-  }
+  ASIO_DECL static address_v6 v4_mapped(const address_v4& addr);
 
   /// Create an IPv4-compatible IPv6 address.
-  static address_v6 v4_compatible(const address_v4& addr)
-  {
-    address_v4::bytes_type v4_bytes = addr.to_bytes();
-    bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-      v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
-    return address_v6(v6_bytes);
-  }
+  ASIO_DECL static address_v6 v4_compatible(const address_v4& addr);
 
 private:
   // The underlying IPv6 address.
@@ -402,22 +211,7 @@ private:
  */
 template <typename Elem, typename Traits>
 std::basic_ostream<Elem, Traits>& operator<<(
-    std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
-{
-  asio::error_code ec;
-  std::string s = addr.to_string(ec);
-  if (ec)
-  {
-    if (os.exceptions() & std::ios::failbit)
-      asio::detail::throw_error(ec);
-    else
-      os.setstate(std::ios_base::failbit);
-  }
-  else
-    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
-      os << os.widen(*i);
-  return os;
-}
+    std::basic_ostream<Elem, Traits>& os, const address_v6& addr);
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
@@ -426,4 +220,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/ip/impl/address_v6.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v6.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_IP_ADDRESS_V6_HPP
diff --git a/ext/asio/asio/ip/basic_endpoint.hpp b/ext/asio/asio/ip/basic_endpoint.hpp
index 4ad3f68..5e5ef0b 100644
--- a/ext/asio/asio/ip/basic_endpoint.hpp
+++ b/ext/asio/asio/ip/basic_endpoint.hpp
@@ -1,8 +1,8 @@
 //
-// basic_endpoint.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ip/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/detail/endpoint.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include <boost/detail/workaround.hpp>
-#include <cstring>
 #if !defined(BOOST_NO_IOSTREAM)
-# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-#  include <ostream>
-# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-# include <sstream>
+# include <iosfwd>
 #endif // !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
 
-#include "asio/error.hpp"
-#include "asio/ip/address.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
@@ -67,11 +57,8 @@ public:
 
   /// Default constructor.
   basic_endpoint()
-    : data_()
+    : impl_()
   {
-    data_.v4.sin_family = AF_INET;
-    data_.v4.sin_port = 0;
-    data_.v4.sin_addr.s_addr = INADDR_ANY;
   }
 
   /// Construct an endpoint using a port number, specified in the host's byte
@@ -91,74 +78,35 @@ public:
    * @endcode
    */
   basic_endpoint(const InternetProtocol& protocol, unsigned short port_num)
-    : data_()
+    : impl_(protocol.family(), port_num)
   {
-    using namespace std; // For memcpy.
-    if (protocol.family() == PF_INET)
-    {
-      data_.v4.sin_family = AF_INET;
-      data_.v4.sin_port =
-        asio::detail::socket_ops::host_to_network_short(port_num);
-      data_.v4.sin_addr.s_addr = INADDR_ANY;
-    }
-    else
-    {
-      data_.v6.sin6_family = AF_INET6;
-      data_.v6.sin6_port =
-        asio::detail::socket_ops::host_to_network_short(port_num);
-      data_.v6.sin6_flowinfo = 0;
-      asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
-      data_.v6.sin6_addr = tmp_addr;
-      data_.v6.sin6_scope_id = 0;
-    }
   }
 
   /// Construct an endpoint using a port number and an IP address. This
   /// constructor may be used for accepting connections on a specific interface
   /// or for making a connection to a remote endpoint.
   basic_endpoint(const asio::ip::address& addr, unsigned short port_num)
-    : data_()
+    : impl_(addr, port_num)
   {
-    using namespace std; // For memcpy.
-    if (addr.is_v4())
-    {
-      data_.v4.sin_family = AF_INET;
-      data_.v4.sin_port =
-        asio::detail::socket_ops::host_to_network_short(port_num);
-      data_.v4.sin_addr.s_addr =
-        asio::detail::socket_ops::host_to_network_long(
-            addr.to_v4().to_ulong());
-    }
-    else
-    {
-      data_.v6.sin6_family = AF_INET6;
-      data_.v6.sin6_port =
-        asio::detail::socket_ops::host_to_network_short(port_num);
-      data_.v6.sin6_flowinfo = 0;
-      asio::ip::address_v6 v6_addr = addr.to_v6();
-      asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
-      memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
-      data_.v6.sin6_scope_id = v6_addr.scope_id();
-    }
   }
 
   /// Copy constructor.
   basic_endpoint(const basic_endpoint& other)
-    : data_(other.data_)
+    : impl_(other.impl_)
   {
   }
 
   /// Assign from another endpoint.
   basic_endpoint& operator=(const basic_endpoint& other)
   {
-    data_ = other.data_;
+    impl_ = other.impl_;
     return *this;
   }
 
   /// The protocol associated with the endpoint.
   protocol_type protocol() const
   {
-    if (is_v4())
+    if (impl_.is_v4())
       return InternetProtocol::v4();
     return InternetProtocol::v6();
   }
@@ -166,137 +114,104 @@ public:
   /// Get the underlying endpoint in the native type.
   data_type* data()
   {
-    return &data_.base;
+    return impl_.data();
   }
 
   /// Get the underlying endpoint in the native type.
   const data_type* data() const
   {
-    return &data_.base;
+    return impl_.data();
   }
 
   /// Get the underlying size of the endpoint in the native type.
   std::size_t size() const
   {
-    if (is_v4())
-      return sizeof(asio::detail::sockaddr_in4_type);
-    else
-      return sizeof(asio::detail::sockaddr_in6_type);
+    return impl_.size();
   }
 
   /// Set the underlying size of the endpoint in the native type.
   void resize(std::size_t size)
   {
-    if (size > sizeof(asio::detail::sockaddr_storage_type))
-    {
-      asio::system_error e(asio::error::invalid_argument);
-      boost::throw_exception(e);
-    }
+    impl_.resize(size);
   }
 
   /// Get the capacity of the endpoint in the native type.
   std::size_t capacity() const
   {
-    return sizeof(asio::detail::sockaddr_storage_type);
+    return impl_.capacity();
   }
 
   /// Get the port associated with the endpoint. The port number is always in
   /// the host's byte order.
   unsigned short port() const
   {
-    if (is_v4())
-    {
-      return asio::detail::socket_ops::network_to_host_short(
-          data_.v4.sin_port);
-    }
-    else
-    {
-      return asio::detail::socket_ops::network_to_host_short(
-          data_.v6.sin6_port);
-    }
+    return impl_.port();
   }
 
   /// Set the port associated with the endpoint. The port number is always in
   /// the host's byte order.
   void port(unsigned short port_num)
   {
-    if (is_v4())
-    {
-      data_.v4.sin_port
-        = asio::detail::socket_ops::host_to_network_short(port_num);
-    }
-    else
-    {
-      data_.v6.sin6_port
-        = asio::detail::socket_ops::host_to_network_short(port_num);
-    }
+    impl_.port(port_num);
   }
 
   /// Get the IP address associated with the endpoint.
   asio::ip::address address() const
   {
-    using namespace std; // For memcpy.
-    if (is_v4())
-    {
-      return asio::ip::address_v4(
-          asio::detail::socket_ops::network_to_host_long(
-            data_.v4.sin_addr.s_addr));
-    }
-    else
-    {
-      asio::ip::address_v6::bytes_type bytes;
-      memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
-      return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
-    }
+    return impl_.address();
   }
 
   /// Set the IP address associated with the endpoint.
   void address(const asio::ip::address& addr)
   {
-    basic_endpoint<InternetProtocol> tmp_endpoint(addr, port());
-    data_ = tmp_endpoint.data_;
+    impl_.address(addr);
   }
 
   /// Compare two endpoints for equality.
   friend bool operator==(const basic_endpoint<InternetProtocol>& e1,
       const basic_endpoint<InternetProtocol>& e2)
   {
-    return e1.address() == e2.address() && e1.port() == e2.port();
+    return e1.impl_ == e2.impl_;
   }
 
   /// Compare two endpoints for inequality.
   friend bool operator!=(const basic_endpoint<InternetProtocol>& e1,
       const basic_endpoint<InternetProtocol>& e2)
   {
-    return e1.address() != e2.address() || e1.port() != e2.port();
+    return !(e1 == e2);
   }
 
   /// Compare endpoints for ordering.
   friend bool operator<(const basic_endpoint<InternetProtocol>& e1,
       const basic_endpoint<InternetProtocol>& e2)
   {
-    if (e1.address() < e2.address())
-      return true;
-    if (e1.address() != e2.address())
-      return false;
-    return e1.port() < e2.port();
+    return e1.impl_ < e2.impl_;
   }
 
-private:
-  // Helper function to determine whether the endpoint is IPv4.
-  bool is_v4() const
+  /// Compare endpoints for ordering.
+  friend bool operator>(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2)
+  {
+    return e2.impl_ < e1.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<=(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2)
   {
-    return data_.base.sa_family == AF_INET;
+    return !(e2 < e1);
   }
 
-  // The underlying IP socket address.
-  union data_union
+  /// Compare endpoints for ordering.
+  friend bool operator>=(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2)
   {
-    asio::detail::socket_addr_type base;
-    asio::detail::sockaddr_storage_type storage;
-    asio::detail::sockaddr_in4_type v4;
-    asio::detail::sockaddr_in6_type v6;
-  } data_;
+    return !(e1 < e2);
+  }
+
+private:
+  // The underlying IP endpoint.
+  asio::ip::detail::endpoint impl_;
 };
 
 #if !defined(BOOST_NO_IOSTREAM)
@@ -313,64 +228,10 @@ private:
  *
  * @relates asio::ip::basic_endpoint
  */
-#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-template <typename InternetProtocol>
-std::ostream& operator<<(std::ostream& os,
-    const basic_endpoint<InternetProtocol>& endpoint)
-{
-  const address& addr = endpoint.address();
-  asio::error_code ec;
-  std::string a = addr.to_string(ec);
-  if (ec)
-  {
-    if (os.exceptions() & std::ios::failbit)
-      asio::detail::throw_error(ec);
-    else
-      os.setstate(std::ios_base::failbit);
-  }
-  else
-  {
-    std::ostringstream tmp_os;
-    tmp_os.imbue(std::locale::classic());
-    if (addr.is_v4())
-      tmp_os << a;
-    else
-      tmp_os << '[' << a << ']';
-    tmp_os << ':' << endpoint.port();
-    os << tmp_os.str();
-  }
-  return os;
-}
-#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
 template <typename Elem, typename Traits, typename InternetProtocol>
 std::basic_ostream<Elem, Traits>& operator<<(
     std::basic_ostream<Elem, Traits>& os,
-    const basic_endpoint<InternetProtocol>& endpoint)
-{
-  const address& addr = endpoint.address();
-  asio::error_code ec;
-  std::string a = addr.to_string(ec);
-  if (ec)
-  {
-    if (os.exceptions() & std::ios::failbit)
-      asio::detail::throw_error(ec);
-    else
-      os.setstate(std::ios_base::failbit);
-  }
-  else
-  {
-    std::ostringstream tmp_os;
-    tmp_os.imbue(std::locale::classic());
-    if (addr.is_v4())
-      tmp_os << a;
-    else
-      tmp_os << '[' << a << ']';
-    tmp_os << ':' << endpoint.port();
-    os << tmp_os.str();
-  }
-  return os;
-}
-#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+    const basic_endpoint<InternetProtocol>& endpoint);
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
@@ -379,4 +240,6 @@ std::basic_ostream<Elem, Traits>& operator<<(
 
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/ip/impl/basic_endpoint.hpp"
+
 #endif // ASIO_IP_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/basic_resolver.hpp b/ext/asio/asio/ip/basic_resolver.hpp
index 43a37af..c8847e1 100644
--- a/ext/asio/asio/ip/basic_resolver.hpp
+++ b/ext/asio/asio/ip/basic_resolver.hpp
@@ -1,8 +1,8 @@
 //
-// basic_resolver.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
 #include "asio/ip/resolver_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/basic_resolver_entry.hpp b/ext/asio/asio/ip/basic_resolver_entry.hpp
index 09b144b..4117b7b 100644
--- a/ext/asio/asio/ip/basic_resolver_entry.hpp
+++ b/ext/asio/asio/ip/basic_resolver_entry.hpp
@@ -1,8 +1,8 @@
 //
-// basic_resolver_entry.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_entry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
 
 #include "asio/detail/push_options.hpp"
-#include <string>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/basic_resolver_iterator.hpp b/ext/asio/asio/ip/basic_resolver_iterator.hpp
index 1982d62..033b7e0 100644
--- a/ext/asio/asio/ip/basic_resolver_iterator.hpp
+++ b/ext/asio/asio/ip/basic_resolver_iterator.hpp
@@ -1,8 +1,8 @@
 //
-// basic_resolver_iterator.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/iterator.hpp>
-#include <boost/shared_ptr.hpp>
 #include <cstring>
 #include <string>
 #include <vector>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/shared_ptr.hpp"
 #include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
 #include "asio/ip/basic_resolver_entry.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 
@@ -176,7 +174,7 @@ private:
   }
 
   typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
-  boost::shared_ptr<values_type> values_;
+  asio::detail::shared_ptr<values_type> values_;
   std::size_t index_;
 };
 
diff --git a/ext/asio/asio/ip/basic_resolver_query.hpp b/ext/asio/asio/ip/basic_resolver_query.hpp
index 3cbb335..22ab643 100644
--- a/ext/asio/asio/ip/basic_resolver_query.hpp
+++ b/ext/asio/asio/ip/basic_resolver_query.hpp
@@ -1,8 +1,8 @@
 //
-// basic_resolver_query.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_query.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <string>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/socket_ops.hpp"
 #include "asio/ip/resolver_query_base.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 
diff --git a/ext/asio/asio/ip/detail/endpoint.hpp b/ext/asio/asio/ip/detail/endpoint.hpp
new file mode 100644
index 0000000..fbea71e
--- /dev/null
+++ b/ext/asio/asio/ip/detail/endpoint.hpp
@@ -0,0 +1,140 @@
+//
+// ip/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_DETAIL_ENDPOINT_HPP
+#define ASIO_IP_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+// Helper class for implementating an IP endpoint.
+class endpoint
+{
+public:
+  // Default constructor.
+  ASIO_DECL endpoint();
+
+  // Construct an endpoint using a family and port number.
+  ASIO_DECL endpoint(int family, unsigned short port_num);
+
+  // Construct an endpoint using an address and port number.
+  ASIO_DECL endpoint(const asio::ip::address& addr,
+      unsigned short port_num);
+
+  // Copy constructor.
+  endpoint(const endpoint& other)
+    : data_(other.data_)
+  {
+  }
+
+  // Assign from another endpoint.
+  endpoint& operator=(const endpoint& other)
+  {
+    data_ = other.data_;
+    return *this;
+  }
+
+  // Get the underlying endpoint in the native type.
+  asio::detail::socket_addr_type* data()
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying endpoint in the native type.
+  const asio::detail::socket_addr_type* data() const
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    if (is_v4())
+      return sizeof(asio::detail::sockaddr_in4_type);
+    else
+      return sizeof(asio::detail::sockaddr_in6_type);
+  }
+
+  // Set the underlying size of the endpoint in the native type.
+  ASIO_DECL void resize(std::size_t size);
+
+  // Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return sizeof(asio::detail::sockaddr_storage_type);
+  }
+
+  // Get the port associated with the endpoint.
+  ASIO_DECL unsigned short port() const;
+
+  // Set the port associated with the endpoint.
+  ASIO_DECL void port(unsigned short port_num);
+
+  // Get the IP address associated with the endpoint.
+  ASIO_DECL asio::ip::address address() const;
+
+  // Set the IP address associated with the endpoint.
+  ASIO_DECL void address(const asio::ip::address& addr);
+
+  // Compare two endpoints for equality.
+  ASIO_DECL friend bool operator==(
+      const endpoint& e1, const endpoint& e2);
+
+  // Compare endpoints for ordering.
+  ASIO_DECL friend bool operator<(
+      const endpoint& e1, const endpoint& e2);
+
+  // Determine whether the endpoint is IPv4.
+  bool is_v4() const
+  {
+    return data_.base.sa_family == AF_INET;
+  }
+
+#if !defined(BOOST_NO_IOSTREAM)
+  // Convert to a string.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+private:
+  // The underlying IP socket address.
+  union data_union
+  {
+    asio::detail::socket_addr_type base;
+    asio::detail::sockaddr_storage_type storage;
+    asio::detail::sockaddr_in4_type v4;
+    asio::detail::sockaddr_in6_type v6;
+  } data_;
+};
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_DETAIL_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/detail/impl/endpoint.ipp b/ext/asio/asio/ip/detail/impl/endpoint.ipp
new file mode 100644
index 0000000..b1469c8
--- /dev/null
+++ b/ext/asio/asio/ip/detail/impl/endpoint.ipp
@@ -0,0 +1,202 @@
+//
+// ip/detail/impl/endpoint.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#if !defined(BOOST_NO_IOSTREAM)
+# include <sstream>
+#endif // !defined(BOOST_NO_IOSTREAM)
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+ASIO_DECL
+endpoint::endpoint()
+  : data_()
+{
+  data_.v4.sin_family = AF_INET;
+  data_.v4.sin_port = 0;
+  data_.v4.sin_addr.s_addr = INADDR_ANY;
+}
+
+ASIO_DECL
+endpoint::endpoint(int family, unsigned short port_num)
+  : data_()
+{
+  using namespace std; // For memcpy.
+  if (family == PF_INET)
+  {
+    data_.v4.sin_family = AF_INET;
+    data_.v4.sin_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v4.sin_addr.s_addr = INADDR_ANY;
+  }
+  else
+  {
+    data_.v6.sin6_family = AF_INET6;
+    data_.v6.sin6_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v6.sin6_flowinfo = 0;
+    asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+    data_.v6.sin6_addr = tmp_addr;
+    data_.v6.sin6_scope_id = 0;
+  }
+}
+
+ASIO_DECL
+endpoint::endpoint(const asio::ip::address& addr,
+    unsigned short port_num)
+  : data_()
+{
+  using namespace std; // For memcpy.
+  if (addr.is_v4())
+  {
+    data_.v4.sin_family = AF_INET;
+    data_.v4.sin_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v4.sin_addr.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          addr.to_v4().to_ulong());
+  }
+  else
+  {
+    data_.v6.sin6_family = AF_INET6;
+    data_.v6.sin6_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v6.sin6_flowinfo = 0;
+    asio::ip::address_v6 v6_addr = addr.to_v6();
+    asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
+    memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
+    data_.v6.sin6_scope_id = v6_addr.scope_id();
+  }
+}
+
+ASIO_DECL
+void endpoint::resize(std::size_t size)
+{
+  if (size > sizeof(asio::detail::sockaddr_storage_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+}
+
+ASIO_DECL
+unsigned short endpoint::port() const
+{
+  if (is_v4())
+  {
+    return asio::detail::socket_ops::network_to_host_short(
+        data_.v4.sin_port);
+  }
+  else
+  {
+    return asio::detail::socket_ops::network_to_host_short(
+        data_.v6.sin6_port);
+  }
+}
+
+ASIO_DECL
+void endpoint::port(unsigned short port_num)
+{
+  if (is_v4())
+  {
+    data_.v4.sin_port
+      = asio::detail::socket_ops::host_to_network_short(port_num);
+  }
+  else
+  {
+    data_.v6.sin6_port
+      = asio::detail::socket_ops::host_to_network_short(port_num);
+  }
+}
+
+ASIO_DECL
+asio::ip::address endpoint::address() const
+{
+  using namespace std; // For memcpy.
+  if (is_v4())
+  {
+    return asio::ip::address_v4(
+        asio::detail::socket_ops::network_to_host_long(
+          data_.v4.sin_addr.s_addr));
+  }
+  else
+  {
+    asio::ip::address_v6::bytes_type bytes;
+    memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
+    return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
+  }
+}
+
+ASIO_DECL
+void endpoint::address(const asio::ip::address& addr)
+{
+  endpoint tmp_endpoint(addr, port());
+  data_ = tmp_endpoint.data_;
+}
+
+ASIO_DECL
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+  return e1.address() == e2.address() && e1.port() == e2.port();
+}
+
+ASIO_DECL
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+  if (e1.address() < e2.address())
+    return true;
+  if (e1.address() != e2.address())
+    return false;
+  return e1.port() < e2.port();
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+ASIO_DECL
+std::string endpoint::to_string(asio::error_code& ec) const
+{
+  std::string a = address().to_string(ec);
+  if (ec)
+    return std::string();
+
+  std::ostringstream tmp_os;
+  tmp_os.imbue(std::locale::classic());
+  if (is_v4())
+    tmp_os << a;
+  else
+    tmp_os << '[' << a << ']';
+  tmp_os << ':' << port();
+
+  return tmp_os.str();
+}
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/ext/asio/asio/ip/detail/socket_option.hpp b/ext/asio/asio/ip/detail/socket_option.hpp
index 00045f8..e370b11 100644
--- a/ext/asio/asio/ip/detail/socket_option.hpp
+++ b/ext/asio/asio/ip/detail/socket_option.hpp
@@ -1,8 +1,8 @@
 //
-// socket_option.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <cstring>
-#include <boost/config.hpp>
 #include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/ip/address.hpp"
 #include "asio/detail/socket_ops.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/host_name.hpp b/ext/asio/asio/ip/host_name.hpp
index f24ce1a..8bfaae9 100644
--- a/ext/asio/asio/ip/host_name.hpp
+++ b/ext/asio/asio/ip/host_name.hpp
@@ -1,8 +1,8 @@
 //
-// host_name.hpp
-// ~~~~~~~~~~~~~
+// ip/host_name.hpp
+// ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,48 +15,28 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <string>
-#include "asio/detail/pop_options.hpp"
+#include "asio/error_code.hpp"
 
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
 
 /// Get the current host name.
-std::string host_name();
+ASIO_DECL std::string host_name();
 
 /// Get the current host name.
-std::string host_name(asio::error_code& ec);
-
-inline std::string host_name()
-{
-  char name[1024];
-  asio::error_code ec;
-  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
-  {
-    asio::detail::throw_error(ec);
-    return std::string();
-  }
-  return std::string(name);
-}
-
-inline std::string host_name(asio::error_code& ec)
-{
-  char name[1024];
-  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
-    return std::string();
-  return std::string(name);
-}
+ASIO_DECL std::string host_name(asio::error_code& ec);
 
 } // namespace ip
 } // namespace asio
 
 #include "asio/detail/pop_options.hpp"
 
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/host_name.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // ASIO_IP_HOST_NAME_HPP
diff --git a/ext/asio/asio/ip/icmp.hpp b/ext/asio/asio/ip/icmp.hpp
index d76b4d1..59df5b0 100644
--- a/ext/asio/asio/ip/icmp.hpp
+++ b/ext/asio/asio/ip/icmp.hpp
@@ -1,8 +1,8 @@
 //
-// icmp.hpp
-// ~~~~~~~~
+// ip/icmp.hpp
+// ~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_types.hpp"
 #include "asio/basic_raw_socket.hpp"
 #include "asio/ip/basic_endpoint.hpp"
 #include "asio/ip/basic_resolver.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/impl/address.hpp b/ext/asio/asio/ip/impl/address.hpp
new file mode 100644
index 0000000..0983d24
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_HPP
+#define ASIO_IP_IMPL_ADDRESS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_HPP
diff --git a/ext/asio/asio/ip/impl/address.ipp b/ext/asio/asio/ip/impl/address.ipp
new file mode 100644
index 0000000..24916ab
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address.ipp
@@ -0,0 +1,203 @@
+//
+// ip/impl/address.ipp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_IPP
+#define ASIO_IP_IMPL_ADDRESS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address::address()
+  : type_(ipv4),
+    ipv4_address_(),
+    ipv6_address_()
+{
+}
+
+ASIO_DECL
+address::address(const asio::ip::address_v4& ipv4_address)
+  : type_(ipv4),
+    ipv4_address_(ipv4_address),
+    ipv6_address_()
+{
+}
+
+ASIO_DECL
+address::address(const asio::ip::address_v6& ipv6_address)
+  : type_(ipv6),
+    ipv4_address_(),
+    ipv6_address_(ipv6_address)
+{
+}
+
+ASIO_DECL
+address::address(const address& other)
+  : type_(other.type_),
+    ipv4_address_(other.ipv4_address_),
+    ipv6_address_(other.ipv6_address_)
+{
+}
+
+ASIO_DECL
+address& address::operator=(const address& other)
+{
+  type_ = other.type_;
+  ipv4_address_ = other.ipv4_address_;
+  ipv6_address_ = other.ipv6_address_;
+  return *this;
+}
+
+ASIO_DECL
+address& address::operator=(const asio::ip::address_v4& ipv4_address)
+{
+  type_ = ipv4;
+  ipv4_address_ = ipv4_address;
+  ipv6_address_ = asio::ip::address_v6();
+  return *this;
+}
+
+ASIO_DECL
+address& address::operator=(const asio::ip::address_v6& ipv6_address)
+{
+  type_ = ipv6;
+  ipv4_address_ = asio::ip::address_v4();
+  ipv6_address_ = ipv6_address;
+  return *this;
+}
+
+ASIO_DECL
+asio::ip::address_v4 address::to_v4() const
+{
+  if (type_ != ipv4)
+  {
+    std::bad_cast ex;
+    boost::throw_exception(ex);
+  }
+  return ipv4_address_;
+}
+
+ASIO_DECL
+asio::ip::address_v6 address::to_v6() const
+{
+  if (type_ != ipv6)
+  {
+    std::bad_cast ex;
+    boost::throw_exception(ex);
+  }
+  return ipv6_address_;
+}
+
+ASIO_DECL
+std::string address::to_string() const
+{
+  if (type_ == ipv6)
+    return ipv6_address_.to_string();
+  return ipv4_address_.to_string();
+}
+
+ASIO_DECL
+std::string address::to_string(asio::error_code& ec) const
+{
+  if (type_ == ipv6)
+    return ipv6_address_.to_string(ec);
+  return ipv4_address_.to_string(ec);
+}
+
+ASIO_DECL
+address address::from_string(const char* str)
+{
+  asio::error_code ec;
+  address addr = from_string(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+ASIO_DECL
+address address::from_string(const char* str, asio::error_code& ec)
+{
+  asio::ip::address_v6 ipv6_address =
+    asio::ip::address_v6::from_string(str, ec);
+  if (!ec)
+  {
+    address tmp;
+    tmp.type_ = ipv6;
+    tmp.ipv6_address_ = ipv6_address;
+    return tmp;
+  }
+
+  asio::ip::address_v4 ipv4_address =
+    asio::ip::address_v4::from_string(str, ec);
+  if (!ec)
+  {
+    address tmp;
+    tmp.type_ = ipv4;
+    tmp.ipv4_address_ = ipv4_address;
+    return tmp;
+  }
+
+  return address();
+}
+
+ASIO_DECL
+address address::from_string(const std::string& str)
+{
+  return from_string(str.c_str());
+}
+
+ASIO_DECL
+address address::from_string(const std::string& str,
+    asio::error_code& ec)
+{
+  return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+bool operator==(const address& a1, const address& a2)
+{
+  if (a1.type_ != a2.type_)
+    return false;
+  if (a1.type_ == address::ipv6)
+    return a1.ipv6_address_ == a2.ipv6_address_;
+  return a1.ipv4_address_ == a2.ipv4_address_;
+}
+
+ASIO_DECL
+bool operator<(const address& a1, const address& a2)
+{
+  if (a1.type_ < a2.type_)
+    return true;
+  if (a1.type_ > a2.type_)
+    return false;
+  if (a1.type_ == address::ipv6)
+    return a1.ipv6_address_ < a2.ipv6_address_;
+  return a1.ipv4_address_ < a2.ipv4_address_;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_IPP
diff --git a/ext/asio/asio/ip/impl/address_v4.hpp b/ext/asio/asio/ip/impl/address_v4.hpp
new file mode 100644
index 0000000..bbe0882
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v4.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V4_HPP
+#define ASIO_IP_IMPL_ADDRESS_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_HPP
diff --git a/ext/asio/asio/ip/impl/address_v4.ipp b/ext/asio/asio/ip/impl/address_v4.ipp
new file mode 100644
index 0000000..2c8e9aa
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v4.ipp
@@ -0,0 +1,178 @@
+//
+// ip/impl/address_v4.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V4_IPP
+#define ASIO_IP_IMPL_ADDRESS_V4_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <stdexcept>
+#include <boost/throw_exception.hpp>
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address_v4::address_v4(const address_v4::bytes_type& bytes)
+{
+#if UCHAR_MAX > 0xFF
+  if (bytes[0] > 0xFF || bytes[1] > 0xFF
+      || bytes[2] > 0xFF || bytes[3] > 0xFF)
+  {
+    std::out_of_range ex("address_v4 from bytes_type");
+    boost::throw_exception(ex);
+  }
+#endif // UCHAR_MAX > 0xFF
+
+  using namespace std; // For memcpy.
+  memcpy(&addr_.s_addr, bytes.elems, 4);
+}
+
+ASIO_DECL
+address_v4::address_v4(unsigned long addr)
+{
+#if ULONG_MAX > 0xFFFFFFFF
+  if (addr > 0xFFFFFFFF)
+  {
+    std::out_of_range ex("address_v4 from unsigned long");
+    boost::throw_exception(ex);
+  }
+#endif // ULONG_MAX > 0xFFFFFFFF
+
+  addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
+}
+
+ASIO_DECL
+address_v4::bytes_type address_v4::to_bytes() const
+{
+  using namespace std; // For memcpy.
+  bytes_type bytes;
+  memcpy(bytes.elems, &addr_.s_addr, 4);
+  return bytes;
+}
+
+ASIO_DECL
+unsigned long address_v4::to_ulong() const
+{
+  return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
+}
+
+ASIO_DECL
+std::string address_v4::to_string() const
+{
+  asio::error_code ec;
+  std::string addr = to_string(ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+ASIO_DECL
+std::string address_v4::to_string(asio::error_code& ec) const
+{
+  char addr_str[asio::detail::max_addr_v4_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
+        asio::detail::max_addr_v4_str_len, 0, ec);
+  if (addr == 0)
+    return std::string();
+  return addr;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(const char* str)
+{
+  asio::error_code ec;
+  address_v4 addr = from_string(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(
+    const char* str, asio::error_code& ec)
+{
+  address_v4 tmp;
+  if (asio::detail::socket_ops::inet_pton(
+        AF_INET, str, &tmp.addr_, 0, ec) <= 0)
+    return address_v4();
+  return tmp;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(const std::string& str)
+{
+  return from_string(str.c_str());
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(
+    const std::string& str, asio::error_code& ec)
+{
+  return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+bool address_v4::is_class_a() const
+{
+  return IN_CLASSA(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_class_b() const
+{
+  return IN_CLASSB(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_class_c() const
+{
+  return IN_CLASSC(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_multicast() const
+{
+  return IN_MULTICAST(to_ulong());
+}
+
+ASIO_DECL
+address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask)
+{
+  return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF));
+}
+
+ASIO_DECL
+address_v4 address_v4::netmask(const address_v4& addr)
+{
+  if (addr.is_class_a())
+    return address_v4(0xFF000000);
+  if (addr.is_class_b())
+    return address_v4(0xFFFF0000);
+  if (addr.is_class_c())
+    return address_v4(0xFFFFFF00);
+  return address_v4(0xFFFFFFFF);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_IPP
diff --git a/ext/asio/asio/ip/impl/address_v6.hpp b/ext/asio/asio/ip/impl/address_v6.hpp
new file mode 100644
index 0000000..796a505
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v6.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V6_HPP
+#define ASIO_IP_IMPL_ADDRESS_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_HPP
diff --git a/ext/asio/asio/ip/impl/address_v6.ipp b/ext/asio/asio/ip/impl/address_v6.ipp
new file mode 100644
index 0000000..17b6382
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v6.ipp
@@ -0,0 +1,313 @@
+//
+// ip/impl/address_v6.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V6_IPP
+#define ASIO_IP_IMPL_ADDRESS_V6_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#include <stdexcept>
+#include <typeinfo>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address_v6.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address_v6::address_v6()
+  : scope_id_(0)
+{
+  asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+  addr_ = tmp_addr;
+}
+
+ASIO_DECL
+address_v6::address_v6(const address_v6::bytes_type& bytes,
+    unsigned long scope_id)
+  : scope_id_(scope_id)
+{
+#if UCHAR_MAX > 0xFF
+  for (std::size_t i = 0; i < bytes.size(); ++i)
+  {
+    if (bytes[i] > 0xFF)
+    {
+      std::out_of_range ex("address_v6 from bytes_type");
+      boost::throw_exception(ex);
+    }
+  }
+#endif // UCHAR_MAX > 0xFF
+
+  using namespace std; // For memcpy.
+  memcpy(addr_.s6_addr, bytes.elems, 16);
+}
+
+ASIO_DECL
+address_v6::address_v6(const address_v6& other)
+  : addr_(other.addr_),
+    scope_id_(other.scope_id_)
+{
+}
+
+ASIO_DECL
+address_v6& address_v6::operator=(const address_v6& other)
+{
+  addr_ = other.addr_;
+  scope_id_ = other.scope_id_;
+  return *this;
+}
+
+ASIO_DECL
+address_v6::bytes_type address_v6::to_bytes() const
+{
+  using namespace std; // For memcpy.
+  bytes_type bytes;
+  memcpy(bytes.elems, addr_.s6_addr, 16);
+  return bytes;
+}
+
+ASIO_DECL
+std::string address_v6::to_string() const
+{
+  asio::error_code ec;
+  std::string addr = to_string(ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+ASIO_DECL
+std::string address_v6::to_string(asio::error_code& ec) const
+{
+  char addr_str[asio::detail::max_addr_v6_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
+        asio::detail::max_addr_v6_str_len, scope_id_, ec);
+  if (addr == 0)
+    return std::string();
+  return addr;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(const char* str)
+{
+  asio::error_code ec;
+  address_v6 addr = from_string(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(
+    const char* str, asio::error_code& ec)
+{
+  address_v6 tmp;
+  if (asio::detail::socket_ops::inet_pton(
+        AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0)
+    return address_v6();
+  return tmp;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(const std::string& str)
+{
+  return from_string(str.c_str());
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(
+    const std::string& str, asio::error_code& ec)
+{
+  return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+address_v4 address_v6::to_v4() const
+{
+  if (!is_v4_mapped() && !is_v4_compatible())
+  {
+    std::bad_cast ex;
+    boost::throw_exception(ex);
+  }
+
+  address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
+    addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
+  return address_v4(v4_bytes);
+}
+
+ASIO_DECL
+bool address_v6::is_loopback() const
+{
+#if defined(__BORLANDC__)
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+      && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+      && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
+#else
+  using namespace asio::detail;
+  return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
+#endif
+}
+
+ASIO_DECL
+bool address_v6::is_unspecified() const
+{
+#if defined(__BORLANDC__)
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+      && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+      && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
+#else
+  using namespace asio::detail;
+  return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
+#endif
+}
+
+ASIO_DECL
+bool address_v6::is_link_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_site_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_v4_mapped() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_v4_compatible() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_global() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_link_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_node_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_org_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_site_local() const
+{
+  using namespace asio::detail;
+  return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool operator==(const address_v6& a1, const address_v6& a2)
+{
+  using namespace std; // For memcmp.
+  return memcmp(&a1.addr_, &a2.addr_,
+      sizeof(asio::detail::in6_addr_type)) == 0
+    && a1.scope_id_ == a2.scope_id_;
+}
+
+ASIO_DECL
+bool operator<(const address_v6& a1, const address_v6& a2)
+{
+  using namespace std; // For memcmp.
+  int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
+      sizeof(asio::detail::in6_addr_type));
+  if (memcmp_result < 0)
+    return true;
+  if (memcmp_result > 0)
+    return false;
+  return a1.scope_id_ < a2.scope_id_;
+}
+
+ASIO_DECL
+address_v6 address_v6::loopback()
+{
+  address_v6 tmp;
+  asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT;
+  tmp.addr_ = tmp_addr;
+  return tmp;
+}
+
+ASIO_DECL
+address_v6 address_v6::v4_mapped(const address_v4& addr)
+{
+  address_v4::bytes_type v4_bytes = addr.to_bytes();
+  bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
+    v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+  return address_v6(v6_bytes);
+}
+
+ASIO_DECL
+address_v6 address_v6::v4_compatible(const address_v4& addr)
+{
+  address_v4::bytes_type v4_bytes = addr.to_bytes();
+  bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+  return address_v6(v6_bytes);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_IPP
diff --git a/ext/asio/asio/ip/impl/basic_endpoint.hpp b/ext/asio/asio/ip/impl/basic_endpoint.hpp
new file mode 100644
index 0000000..db7d5fb
--- /dev/null
+++ b/ext/asio/asio/ip/impl/basic_endpoint.hpp
@@ -0,0 +1,55 @@
+//
+// ip/impl/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+#define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits, typename InternetProtocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os,
+    const basic_endpoint<InternetProtocol>& endpoint)
+{
+  asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port());
+  asio::error_code ec;
+  std::string s = tmp_ep.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/impl/host_name.ipp b/ext/asio/asio/ip/impl/host_name.ipp
new file mode 100644
index 0000000..5bf5cca
--- /dev/null
+++ b/ext/asio/asio/ip/impl/host_name.ipp
@@ -0,0 +1,56 @@
+//
+// ip/impl/host_name.ipp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_HOST_NAME_IPP
+#define ASIO_IP_IMPL_HOST_NAME_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/ip/host_name.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+std::string host_name()
+{
+  char name[1024];
+  asio::error_code ec;
+  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+  {
+    asio::detail::throw_error(ec);
+    return std::string();
+  }
+  return std::string(name);
+}
+
+ASIO_DECL
+std::string host_name(asio::error_code& ec)
+{
+  char name[1024];
+  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+    return std::string();
+  return std::string(name);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_HOST_NAME_IPP
diff --git a/ext/asio/asio/ip/multicast.hpp b/ext/asio/asio/ip/multicast.hpp
index eeedc6c..f2193c0 100644
--- a/ext/asio/asio/ip/multicast.hpp
+++ b/ext/asio/asio/ip/multicast.hpp
@@ -1,8 +1,8 @@
 //
-// multicast.hpp
-// ~~~~~~~~~~~~~
+// ip/multicast.hpp
+// ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/ip/detail/socket_option.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 namespace multicast {
diff --git a/ext/asio/asio/ip/resolver_query_base.hpp b/ext/asio/asio/ip/resolver_query_base.hpp
index 5a0acea..8963f41 100644
--- a/ext/asio/asio/ip/resolver_query_base.hpp
+++ b/ext/asio/asio/ip/resolver_query_base.hpp
@@ -1,8 +1,8 @@
 //
-// resolver_query_base.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// ip/resolver_query_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 
diff --git a/ext/asio/asio/ip/resolver_service.hpp b/ext/asio/asio/ip/resolver_service.hpp
index 75f6b2c..0d866d6 100644
--- a/ext/asio/asio/ip/resolver_service.hpp
+++ b/ext/asio/asio/ip/resolver_service.hpp
@@ -1,8 +1,8 @@
 //
-// resolver_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// ip/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/resolver_service.hpp"
 #include "asio/io_service.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/resolver_service.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
@@ -72,13 +72,14 @@ public:
   explicit resolver_service(asio::io_service& io_service)
     : asio::detail::service_base<
         resolver_service<InternetProtocol> >(io_service),
-      service_impl_(asio::use_service<service_impl_type>(io_service))
+      service_impl_(io_service)
   {
   }
 
   /// Destroy all user-defined handler objects owned by the service.
   void shutdown_service()
   {
+    service_impl_.shutdown_service();
   }
 
   /// Construct a new resolver implementation.
@@ -130,8 +131,8 @@ public:
   }
 
 private:
-  // The service that provides the platform-specific implementation.
-  service_impl_type& service_impl_;
+  // The platform-specific implementation.
+  service_impl_type service_impl_;
 };
 
 } // namespace ip
diff --git a/ext/asio/asio/ip/tcp.hpp b/ext/asio/asio/ip/tcp.hpp
index a2e9ac9..67fb09f 100644
--- a/ext/asio/asio/ip/tcp.hpp
+++ b/ext/asio/asio/ip/tcp.hpp
@@ -1,8 +1,8 @@
 //
-// tcp.hpp
-// ~~~~~~~
+// ip/tcp.hpp
+// ~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_socket_acceptor.hpp"
 #include "asio/basic_socket_iostream.hpp"
 #include "asio/basic_stream_socket.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
 #include "asio/ip/basic_endpoint.hpp"
 #include "asio/ip/basic_resolver.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_option.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/udp.hpp b/ext/asio/asio/ip/udp.hpp
index fb26118..ca3ac78 100644
--- a/ext/asio/asio/ip/udp.hpp
+++ b/ext/asio/asio/ip/udp.hpp
@@ -1,8 +1,8 @@
 //
-// udp.hpp
-// ~~~~~~~
+// ip/udp.hpp
+// ~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_datagram_socket.hpp"
+#include "asio/detail/socket_types.hpp"
 #include "asio/ip/basic_endpoint.hpp"
 #include "asio/ip/basic_resolver.hpp"
 #include "asio/ip/basic_resolver_iterator.hpp"
 #include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ip {
diff --git a/ext/asio/asio/ip/unicast.hpp b/ext/asio/asio/ip/unicast.hpp
index 46d7239..e3d04e5 100644
--- a/ext/asio/asio/ip/unicast.hpp
+++ b/ext/asio/asio/ip/unicast.hpp
@@ -1,8 +1,8 @@
 //
-// unicast.hpp
-// ~~~~~~~~~~~
+// ip/unicast.hpp
+// ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/ip/detail/socket_option.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 namespace unicast {
diff --git a/ext/asio/asio/ip/v6_only.hpp b/ext/asio/asio/ip/v6_only.hpp
index 928caff..5ac6a37 100644
--- a/ext/asio/asio/ip/v6_only.hpp
+++ b/ext/asio/asio/ip/v6_only.hpp
@@ -1,8 +1,8 @@
 //
-// v6_only.hpp
-// ~~~~~~~~~~~
+// ip/v6_only.hpp
+// ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/socket_option.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ip {
 
diff --git a/ext/asio/asio/is_read_buffered.hpp b/ext/asio/asio/is_read_buffered.hpp
index 8d97174..e48de55 100644
--- a/ext/asio/asio/is_read_buffered.hpp
+++ b/ext/asio/asio/is_read_buffered.hpp
@@ -2,7 +2,7 @@
 // is_read_buffered.hpp
 // ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/buffered_read_stream_fwd.hpp"
 #include "asio/buffered_stream_fwd.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 namespace detail {
diff --git a/ext/asio/asio/is_write_buffered.hpp b/ext/asio/asio/is_write_buffered.hpp
index 5d16b1c..c681a2b 100644
--- a/ext/asio/asio/is_write_buffered.hpp
+++ b/ext/asio/asio/is_write_buffered.hpp
@@ -2,7 +2,7 @@
 // is_write_buffered.hpp
 // ~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/buffered_stream_fwd.hpp"
 #include "asio/buffered_write_stream_fwd.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 namespace detail {
diff --git a/ext/asio/asio/local/basic_endpoint.hpp b/ext/asio/asio/local/basic_endpoint.hpp
index 81e6a7e..d2d0a02 100644
--- a/ext/asio/asio/local/basic_endpoint.hpp
+++ b/ext/asio/asio/local/basic_endpoint.hpp
@@ -1,8 +1,8 @@
 //
-// basic_endpoint.hpp
-// ~~~~~~~~~~~~~~~~~~
+// local/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Derived from a public domain implementation written by Daniel Casimiro.
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,30 +16,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <cstddef>
-#include <cstring>
-#include <ostream>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
-
-#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
-# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#  define ASIO_HAS_LOCAL_SOCKETS 1
-# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_LOCAL_SOCKETS) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include "asio/local/detail/endpoint.hpp"
+
+#if !defined(BOOST_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace local {
@@ -74,34 +62,30 @@ public:
   /// Default constructor.
   basic_endpoint()
   {
-    init("", 0);
   }
 
   /// Construct an endpoint using the specified path name.
   basic_endpoint(const char* path)
+    : impl_(path)
   {
-    using namespace std; // For strlen.
-    init(path, strlen(path));
   }
 
   /// Construct an endpoint using the specified path name.
   basic_endpoint(const std::string& path)
+    : impl_(path)
   {
-    init(path.data(), path.length());
   }
 
   /// Copy constructor.
   basic_endpoint(const basic_endpoint& other)
-    : data_(other.data_),
-      path_length_(other.path_length_)
+    : impl_(other.impl_)
   {
   }
 
   /// Assign from another endpoint.
   basic_endpoint& operator=(const basic_endpoint& other)
   {
-    data_ = other.data_;
-    path_length_ = other.path_length_;
+    impl_ = other.impl_;
     return *this;
   }
 
@@ -114,123 +98,96 @@ public:
   /// Get the underlying endpoint in the native type.
   data_type* data()
   {
-    return &data_.base;
+    return impl_.data();
   }
 
   /// Get the underlying endpoint in the native type.
   const data_type* data() const
   {
-    return &data_.base;
+    return impl_.data();
   }
 
   /// Get the underlying size of the endpoint in the native type.
   std::size_t size() const
   {
-    return path_length_
-      + offsetof(asio::detail::sockaddr_un_type, sun_path);
+    return impl_.size();
   }
 
   /// Set the underlying size of the endpoint in the native type.
   void resize(std::size_t size)
   {
-    if (size > sizeof(asio::detail::sockaddr_un_type))
-    {
-      asio::system_error e(asio::error::invalid_argument);
-      boost::throw_exception(e);
-    }
-    else if (size == 0)
-    {
-      path_length_ = 0;
-    }
-    else
-    {
-      path_length_ = size
-        - offsetof(asio::detail::sockaddr_un_type, sun_path);
-
-      // The path returned by the operating system may be NUL-terminated.
-      if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
-        --path_length_;
-    }
+    impl_.resize(size);
   }
 
   /// Get the capacity of the endpoint in the native type.
   std::size_t capacity() const
   {
-    return sizeof(asio::detail::sockaddr_un_type);
+    return impl_.capacity();
   }
 
   /// Get the path associated with the endpoint.
   std::string path() const
   {
-    return std::string(data_.local.sun_path, path_length_);
+    return impl_.path();
   }
 
   /// Set the path associated with the endpoint.
   void path(const char* p)
   {
-    using namespace std; // For strlen.
-    init(p, strlen(p));
+    impl_.path(p);
   }
 
   /// Set the path associated with the endpoint.
   void path(const std::string& p)
   {
-    init(p.data(), p.length());
+    impl_.path(p);
   }
 
   /// Compare two endpoints for equality.
   friend bool operator==(const basic_endpoint<Protocol>& e1,
       const basic_endpoint<Protocol>& e2)
   {
-    return e1.path() == e2.path();
+    return e1.impl_ == e2.impl_;
   }
 
   /// Compare two endpoints for inequality.
   friend bool operator!=(const basic_endpoint<Protocol>& e1,
       const basic_endpoint<Protocol>& e2)
   {
-    return e1.path() != e2.path();
+    return !(e1.impl_ == e2.impl_);
   }
 
   /// Compare endpoints for ordering.
   friend bool operator<(const basic_endpoint<Protocol>& e1,
       const basic_endpoint<Protocol>& e2)
   {
-    return e1.path() < e2.path();
+    return e1.impl_ < e2.impl_;
   }
 
-private:
-  // The underlying UNIX socket address.
-  union data_union
+  /// Compare endpoints for ordering.
+  friend bool operator>(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
   {
-    asio::detail::socket_addr_type base;
-    asio::detail::sockaddr_un_type local;
-  } data_;
+    return e2.impl_ < e1.impl_;
+  }
 
-  // The length of the path associated with the endpoint.
-  std::size_t path_length_;
+  /// Compare endpoints for ordering.
+  friend bool operator<=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e2 < e1);
+  }
 
-  // Initialise with a specified path.
-  void init(const char* path, std::size_t path_length)
+  /// Compare endpoints for ordering.
+  friend bool operator>=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
   {
-    if (path_length > sizeof(data_.local.sun_path) - 1)
-    {
-      // The buffer is not large enough to store this address.
-      asio::error_code ec(asio::error::name_too_long);
-      asio::detail::throw_error(ec);
-    }
-
-    using namespace std; // For memcpy.
-    data_.local = asio::detail::sockaddr_un_type();
-    data_.local.sun_family = AF_UNIX;
-    memcpy(data_.local.sun_path, path, path_length);
-    path_length_ = path_length;
-
-    // NUL-terminate normal path names. Names that start with a NUL are in the
-    // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
-    if (path_length > 0 && data_.local.sun_path[0] == 0)
-      data_.local.sun_path[path_length] = 0;
+    return !(e1 < e2);
   }
+
+private:
+  // The underlying UNIX domain endpoint.
+  asio::local::detail::endpoint impl_;
 };
 
 /// Output an endpoint as a string.
@@ -257,9 +214,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
 } // namespace local
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_LOCAL_SOCKETS)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/local/connect_pair.hpp b/ext/asio/asio/local/connect_pair.hpp
index da1d4fc..4a58247 100644
--- a/ext/asio/asio/local/connect_pair.hpp
+++ b/ext/asio/asio/local/connect_pair.hpp
@@ -1,8 +1,8 @@
 //
-// connect_pair.hpp
-// ~~~~~~~~~~~~~~~~
+// local/connect_pair.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/basic_socket.hpp"
-#include "asio/error.hpp"
-#include "asio/local/basic_endpoint.hpp"
 #include "asio/detail/socket_ops.hpp"
 #include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/basic_endpoint.hpp"
 
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace local {
@@ -73,8 +75,9 @@ inline asio::error_code connect_pair(
   if (socket1.assign(protocol, sv[0], ec))
   {
     asio::error_code temp_ec;
-    asio::detail::socket_ops::close(sv[0], temp_ec);
-    asio::detail::socket_ops::close(sv[1], temp_ec);
+    asio::detail::socket_ops::state_type state[2] = { 0, 0 };
+    asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec);
+    asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec);
     return ec;
   }
 
@@ -82,7 +85,8 @@ inline asio::error_code connect_pair(
   {
     asio::error_code temp_ec;
     socket1.close(temp_ec);
-    asio::detail::socket_ops::close(sv[1], temp_ec);
+    asio::detail::socket_ops::state_type state = 0;
+    asio::detail::socket_ops::close(sv[1], state, true, temp_ec);
     return ec;
   }
 
@@ -92,9 +96,9 @@ inline asio::error_code connect_pair(
 } // namespace local
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_LOCAL_SOCKETS)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_LOCAL_CONNECT_PAIR_HPP
diff --git a/ext/asio/asio/local/datagram_protocol.hpp b/ext/asio/asio/local/datagram_protocol.hpp
index 0340180..39f47ce 100644
--- a/ext/asio/asio/local/datagram_protocol.hpp
+++ b/ext/asio/asio/local/datagram_protocol.hpp
@@ -1,8 +1,8 @@
 //
-// datagram_protocol.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// local/datagram_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/basic_datagram_socket.hpp"
-#include "asio/local/basic_endpoint.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
 
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace local {
@@ -70,9 +72,9 @@ public:
 } // namespace local
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_LOCAL_SOCKETS)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
diff --git a/ext/asio/asio/local/detail/endpoint.hpp b/ext/asio/asio/local/detail/endpoint.hpp
new file mode 100644
index 0000000..05fc992
--- /dev/null
+++ b/ext/asio/asio/local/detail/endpoint.hpp
@@ -0,0 +1,133 @@
+//
+// local/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+#define ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstddef>
+#include <string>
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+// Helper class for implementing a UNIX domain endpoint.
+class endpoint
+{
+public:
+  // Default constructor.
+  ASIO_DECL endpoint();
+
+  // Construct an endpoint using the specified path name.
+  ASIO_DECL endpoint(const char* path);
+
+  // Construct an endpoint using the specified path name.
+  ASIO_DECL endpoint(const std::string& path);
+
+  // Copy constructor.
+  endpoint(const endpoint& other)
+    : data_(other.data_),
+      path_length_(other.path_length_)
+  {
+  }
+
+  // Assign from another endpoint.
+  endpoint& operator=(const endpoint& other)
+  {
+    data_ = other.data_;
+    path_length_ = other.path_length_;
+    return *this;
+  }
+
+  // Get the underlying endpoint in the native type.
+  asio::detail::socket_addr_type* data()
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying endpoint in the native type.
+  const asio::detail::socket_addr_type* data() const
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    return path_length_
+      + offsetof(asio::detail::sockaddr_un_type, sun_path);
+  }
+
+  // Set the underlying size of the endpoint in the native type.
+  ASIO_DECL void resize(std::size_t size);
+
+  // Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return sizeof(asio::detail::sockaddr_un_type);
+  }
+
+  // Get the path associated with the endpoint.
+  ASIO_DECL std::string path() const;
+
+  // Set the path associated with the endpoint.
+  ASIO_DECL void path(const char* p);
+
+  // Set the path associated with the endpoint.
+  ASIO_DECL void path(const std::string& p);
+
+  // Compare two endpoints for equality.
+  ASIO_DECL friend bool operator==(
+      const endpoint& e1, const endpoint& e2);
+
+  // Compare endpoints for ordering.
+  ASIO_DECL friend bool operator<(
+      const endpoint& e1, const endpoint& e2);
+
+private:
+  // The underlying UNIX socket address.
+  union data_union
+  {
+    asio::detail::socket_addr_type base;
+    asio::detail::sockaddr_un_type local;
+  } data_;
+
+  // The length of the path associated with the endpoint.
+  std::size_t path_length_;
+
+  // Initialise with a specified path.
+  ASIO_DECL void init(const char* path, std::size_t path_length);
+};
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/local/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP
diff --git a/ext/asio/asio/local/detail/impl/endpoint.ipp b/ext/asio/asio/local/detail/impl/endpoint.ipp
new file mode 100644
index 0000000..1bc2c94
--- /dev/null
+++ b/ext/asio/asio/local/detail/impl/endpoint.ipp
@@ -0,0 +1,138 @@
+//
+// local/detail/impl/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstring>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+ASIO_DECL
+endpoint::endpoint()
+{
+  init("", 0);
+}
+
+ASIO_DECL
+endpoint::endpoint(const char* path)
+{
+  using namespace std; // For strlen.
+  init(path, strlen(path));
+}
+
+ASIO_DECL
+endpoint::endpoint(const std::string& path)
+{
+  init(path.data(), path.length());
+}
+
+ASIO_DECL
+void endpoint::resize(std::size_t size)
+{
+  if (size > sizeof(asio::detail::sockaddr_un_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+  else if (size == 0)
+  {
+    path_length_ = 0;
+  }
+  else
+  {
+    path_length_ = size
+      - offsetof(asio::detail::sockaddr_un_type, sun_path);
+
+    // The path returned by the operating system may be NUL-terminated.
+    if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
+      --path_length_;
+  }
+}
+
+ASIO_DECL
+std::string endpoint::path() const
+{
+  return std::string(data_.local.sun_path, path_length_);
+}
+
+ASIO_DECL
+void endpoint::path(const char* p)
+{
+  using namespace std; // For strlen.
+  init(p, strlen(p));
+}
+
+ASIO_DECL
+void endpoint::path(const std::string& p)
+{
+  init(p.data(), p.length());
+}
+
+ASIO_DECL
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+  return e1.path() == e2.path();
+}
+
+ASIO_DECL
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+  return e1.path() < e2.path();
+}
+
+ASIO_DECL
+void endpoint::init(const char* path, std::size_t path_length)
+{
+  if (path_length > sizeof(data_.local.sun_path) - 1)
+  {
+    // The buffer is not large enough to store this address.
+    asio::error_code ec(asio::error::name_too_long);
+    asio::detail::throw_error(ec);
+  }
+
+  using namespace std; // For memcpy.
+  data_.local = asio::detail::sockaddr_un_type();
+  data_.local.sun_family = AF_UNIX;
+  memcpy(data_.local.sun_path, path, path_length);
+  path_length_ = path_length;
+
+  // NUL-terminate normal path names. Names that start with a NUL are in the
+  // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
+  if (path_length > 0 && data_.local.sun_path[0] == 0)
+    data_.local.sun_path[path_length] = 0;
+}
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/ext/asio/asio/local/stream_protocol.hpp b/ext/asio/asio/local/stream_protocol.hpp
index 47fe42f..e65a2f6 100644
--- a/ext/asio/asio/local/stream_protocol.hpp
+++ b/ext/asio/asio/local/stream_protocol.hpp
@@ -1,8 +1,8 @@
 //
-// stream_protocol.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// local/stream_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/basic_socket_acceptor.hpp"
 #include "asio/basic_socket_iostream.hpp"
 #include "asio/basic_stream_socket.hpp"
-#include "asio/local/basic_endpoint.hpp"
 #include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
 
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace local {
@@ -80,9 +82,9 @@ public:
 } // namespace local
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_LOCAL_SOCKETS)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP
diff --git a/ext/asio/asio/placeholders.hpp b/ext/asio/asio/placeholders.hpp
index 70e69fc..6fda487 100644
--- a/ext/asio/asio/placeholders.hpp
+++ b/ext/asio/asio/placeholders.hpp
@@ -2,7 +2,7 @@
 // placeholders.hpp
 // ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/bind/arg.hpp>
 #include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace placeholders {
diff --git a/ext/asio/asio/posix/basic_descriptor.hpp b/ext/asio/asio/posix/basic_descriptor.hpp
index 37bcc94..591e65a 100644
--- a/ext/asio/asio/posix/basic_descriptor.hpp
+++ b/ext/asio/asio/posix/basic_descriptor.hpp
@@ -1,8 +1,8 @@
 //
-// basic_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// posix/basic_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/posix/descriptor_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace posix {
@@ -291,4 +292,7 @@ protected:
 
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
 #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/basic_stream_descriptor.hpp b/ext/asio/asio/posix/basic_stream_descriptor.hpp
index 21e2287..8211c58 100644
--- a/ext/asio/asio/posix/basic_stream_descriptor.hpp
+++ b/ext/asio/asio/posix/basic_stream_descriptor.hpp
@@ -1,8 +1,8 @@
 //
-// basic_stream_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// posix/basic_stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
 
+#include <cstddef>
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/posix/basic_descriptor.hpp"
 #include "asio/posix/stream_descriptor_service.hpp"
-#include "asio/detail/throw_error.hpp"
 
-#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace posix {
@@ -296,9 +294,9 @@ public:
 } // namespace posix
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/descriptor_base.hpp b/ext/asio/asio/posix/descriptor_base.hpp
index 29e1746..2222915 100644
--- a/ext/asio/asio/posix/descriptor_base.hpp
+++ b/ext/asio/asio/posix/descriptor_base.hpp
@@ -1,8 +1,8 @@
 //
-// descriptor_base.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// posix/descriptor_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/detail/io_control.hpp"
 #include "asio/detail/socket_option.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace posix {
 
@@ -90,4 +90,7 @@ protected:
 
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
 #endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP
diff --git a/ext/asio/asio/posix/stream_descriptor.hpp b/ext/asio/asio/posix/stream_descriptor.hpp
index 72fbbed..48c20a3 100644
--- a/ext/asio/asio/posix/stream_descriptor.hpp
+++ b/ext/asio/asio/posix/stream_descriptor.hpp
@@ -1,8 +1,8 @@
 //
-// stream_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// posix/stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/posix/basic_stream_descriptor.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include "asio/posix/basic_stream_descriptor.hpp"
+
 namespace asio {
 namespace posix {
 
@@ -34,6 +34,4 @@ typedef basic_stream_descriptor<> stream_descriptor;
 #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/stream_descriptor_service.hpp b/ext/asio/asio/posix/stream_descriptor_service.hpp
index 61cee1b..4660e79 100644
--- a/ext/asio/asio/posix/stream_descriptor_service.hpp
+++ b/ext/asio/asio/posix/stream_descriptor_service.hpp
@@ -1,8 +1,8 @@
 //
-// stream_descriptor_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// posix/stream_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-
-#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
-# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#  define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
-# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
 #include "asio/detail/reactive_descriptor_service.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace posix {
 
@@ -179,9 +169,9 @@ private:
 } // namespace posix
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP
diff --git a/ext/asio/asio/raw_socket_service.hpp b/ext/asio/asio/raw_socket_service.hpp
index a8973d3..3d0016d 100644
--- a/ext/asio/asio/raw_socket_service.hpp
+++ b/ext/asio/asio/raw_socket_service.hpp
@@ -2,7 +2,7 @@
 // raw_socket_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 # include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
 # include "asio/detail/reactive_socket_service.hpp"
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Default service implementation for a raw socket.
diff --git a/ext/asio/asio/read.hpp b/ext/asio/asio/read.hpp
index 859c05a..7f04b07 100644
--- a/ext/asio/asio/read.hpp
+++ b/ext/asio/asio/read.hpp
@@ -2,7 +2,7 @@
 // read.hpp
 // ~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
 #include "asio/error.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /**
@@ -536,8 +533,8 @@ void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
 
 } // namespace asio
 
-#include "asio/impl/read.ipp"
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/impl/read.hpp"
+
 #endif // ASIO_READ_HPP
diff --git a/ext/asio/asio/read_at.hpp b/ext/asio/asio/read_at.hpp
index 6bb3fe1..4be1f96 100644
--- a/ext/asio/asio/read_at.hpp
+++ b/ext/asio/asio/read_at.hpp
@@ -2,7 +2,7 @@
 // read_at.hpp
 // ~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
 #include "asio/error.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /**
@@ -569,8 +566,8 @@ void async_read_at(AsyncRandomAccessReadDevice& d,
 
 } // namespace asio
 
-#include "asio/impl/read_at.ipp"
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/impl/read_at.hpp"
+
 #endif // ASIO_READ_AT_HPP
diff --git a/ext/asio/asio/read_until.hpp b/ext/asio/asio/read_until.hpp
index 5df71ce..67fa066 100644
--- a/ext/asio/asio/read_until.hpp
+++ b/ext/asio/asio/read_until.hpp
@@ -2,7 +2,7 @@
 // read_until.hpp
 // ~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,22 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
-#include <boost/regex.hpp>
 #include <boost/type_traits/is_function.hpp>
 #include <boost/type_traits/remove_pointer.hpp>
 #include <boost/utility/enable_if.hpp>
 #include <boost/detail/workaround.hpp>
 #include <string>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/basic_streambuf.hpp"
+#include "asio/detail/regex_fwd.hpp"
 #include "asio/error.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 namespace detail
@@ -914,10 +909,10 @@ void async_read_until(AsyncReadStream& s,
 
 } // namespace asio
 
-#include "asio/impl/read_until.ipp"
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/read_until.hpp"
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_READ_UNTIL_HPP
diff --git a/ext/asio/asio/serial_port.hpp b/ext/asio/asio/serial_port.hpp
index a55a03a..4cc6fd4 100644
--- a/ext/asio/asio/serial_port.hpp
+++ b/ext/asio/asio/serial_port.hpp
@@ -2,7 +2,7 @@
 // serial_port.hpp
 // ~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,13 +16,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/basic_serial_port.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_SERIAL_PORT) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include "asio/basic_serial_port.hpp"
+
 namespace asio {
 
 /// Typedef for the typical usage of a serial port.
@@ -33,6 +33,4 @@ typedef basic_serial_port<> serial_port;
 #endif // defined(ASIO_HAS_SERIAL_PORT)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_SERIAL_PORT_HPP
diff --git a/ext/asio/asio/serial_port_base.hpp b/ext/asio/asio/serial_port_base.hpp
index 28e51a0..9c7a773 100644
--- a/ext/asio/asio/serial_port_base.hpp
+++ b/ext/asio/asio/serial_port_base.hpp
@@ -2,7 +2,7 @@
 // serial_port_base.hpp
 // ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,32 +16,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <stdexcept>
-#include <boost/config.hpp>
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(ASIO_DISABLE_SERIAL_PORT)
-# if defined(ASIO_HAS_IOCP) \
-    || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#  define ASIO_HAS_SERIAL_PORT 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_STREAM_HANDLE)
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_SERIAL_PORT) \
   || defined(GENERATING_DOCUMENTATION)
 
 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-# include "asio/detail/push_options.hpp"
 # include <termios.h>
-# include "asio/detail/pop_options.hpp"
 #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
-#include "asio/error_code.hpp"
+#include <boost/detail/workaround.hpp>
 #include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
 
 #if defined(GENERATING_DOCUMENTATION)
 # define ASIO_OPTION_STORAGE implementation_defined
@@ -51,6 +37,8 @@
 # define ASIO_OPTION_STORAGE termios
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// The serial_port_base class is used as a base for the basic_serial_port class
@@ -67,9 +55,11 @@ public:
   public:
     explicit baud_rate(unsigned int rate = 0);
     unsigned int value() const;
-    asio::error_code store(ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code store(
+        ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec) const;
-    asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code load(
+        const ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec);
   private:
     unsigned int value_;
@@ -83,11 +73,13 @@ public:
   {
   public:
     enum type { none, software, hardware };
-    explicit flow_control(type t = none);
+    ASIO_DECL explicit flow_control(type t = none);
     type value() const;
-    asio::error_code store(ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code store(
+        ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec) const;
-    asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code load(
+        const ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec);
   private:
     type value_;
@@ -101,11 +93,13 @@ public:
   {
   public:
     enum type { none, odd, even };
-    explicit parity(type t = none);
+    ASIO_DECL explicit parity(type t = none);
     type value() const;
-    asio::error_code store(ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code store(
+        ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec) const;
-    asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code load(
+        const ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec);
   private:
     type value_;
@@ -119,11 +113,13 @@ public:
   {
   public:
     enum type { one, onepointfive, two };
-    explicit stop_bits(type t = one);
+    ASIO_DECL explicit stop_bits(type t = one);
     type value() const;
-    asio::error_code store(ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code store(
+        ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec) const;
-    asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code load(
+        const ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec);
   private:
     type value_;
@@ -136,11 +132,13 @@ public:
   class character_size
   {
   public:
-    explicit character_size(unsigned int t = 8);
+    ASIO_DECL explicit character_size(unsigned int t = 8);
     unsigned int value() const;
-    asio::error_code store(ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code store(
+        ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec) const;
-    asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+    ASIO_DECL asio::error_code load(
+        const ASIO_OPTION_STORAGE& storage,
         asio::error_code& ec);
   private:
     unsigned int value_;
@@ -161,13 +159,16 @@ private:
 
 } // namespace asio
 
-#include "asio/impl/serial_port_base.ipp"
+#include "asio/detail/pop_options.hpp"
 
 #undef ASIO_OPTION_STORAGE
 
+#include "asio/impl/serial_port_base.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/serial_port_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
 #endif // defined(ASIO_HAS_SERIAL_PORT)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_SERIAL_PORT_BASE_HPP
diff --git a/ext/asio/asio/serial_port_service.hpp b/ext/asio/asio/serial_port_service.hpp
index 5847c29..37142d5 100644
--- a/ext/asio/asio/serial_port_service.hpp
+++ b/ext/asio/asio/serial_port_service.hpp
@@ -2,7 +2,7 @@
 // serial_port_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT) \
+  || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <string>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/reactive_serial_port_service.hpp"
+#include "asio/detail/win_iocp_serial_port_service.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/serial_port_base.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/reactive_serial_port_service.hpp"
-#include "asio/detail/win_iocp_serial_port_service.hpp"
 
-#if defined(ASIO_HAS_SERIAL_PORT) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
@@ -199,9 +196,9 @@ private:
 
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_SERIAL_PORT)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/socket_acceptor_service.hpp b/ext/asio/asio/socket_acceptor_service.hpp
index b2e2c6d..a1e4874 100644
--- a/ext/asio/asio/socket_acceptor_service.hpp
+++ b/ext/asio/asio/socket_acceptor_service.hpp
@@ -2,7 +2,7 @@
 // socket_acceptor_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/basic_socket.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 # include "asio/detail/win_iocp_socket_service.hpp"
@@ -28,6 +26,8 @@
 # include "asio/detail/reactive_socket_service.hpp"
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Default service implementation for a socket acceptor.
diff --git a/ext/asio/asio/socket_base.hpp b/ext/asio/asio/socket_base.hpp
index d82cd22..56585e1 100644
--- a/ext/asio/asio/socket_base.hpp
+++ b/ext/asio/asio/socket_base.hpp
@@ -2,7 +2,7 @@
 // socket_base.hpp
 // ~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/io_control.hpp"
 #include "asio/detail/socket_option.hpp"
 #include "asio/detail/socket_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// The socket_base class is used as a base for the basic_stream_socket and
diff --git a/ext/asio/asio/ssl.hpp b/ext/asio/asio/ssl.hpp
index a9fff5e..48aff5a 100644
--- a/ext/asio/asio/ssl.hpp
+++ b/ext/asio/asio/ssl.hpp
@@ -2,7 +2,7 @@
 // ssl.hpp
 // ~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/ssl/basic_context.hpp b/ext/asio/asio/ssl/basic_context.hpp
index ea3893e..20ed57d 100755
--- a/ext/asio/asio/ssl/basic_context.hpp
+++ b/ext/asio/asio/ssl/basic_context.hpp
@@ -1,9 +1,9 @@
 //
-// basic_context.hpp
-// ~~~~~~~~~~~~~~~~~
+// ssl/basic_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,17 +16,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <string>
 #include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
 #include "asio/ssl/context_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ssl {
diff --git a/ext/asio/asio/ssl/context.hpp b/ext/asio/asio/ssl/context.hpp
index d53882a..7aedc4d 100644
--- a/ext/asio/asio/ssl/context.hpp
+++ b/ext/asio/asio/ssl/context.hpp
@@ -1,9 +1,9 @@
 //
-// context.hpp
-// ~~~~~~~~~~~
+// ssl/context.hpp
+// ~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,8 +16,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/ssl/basic_context.hpp"
 #include "asio/ssl/context_service.hpp"
 
@@ -30,6 +29,4 @@ typedef basic_context<context_service> context;
 } // namespace ssl
 } // namespace asio
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_SSL_CONTEXT_HPP
diff --git a/ext/asio/asio/ssl/context_base.hpp b/ext/asio/asio/ssl/context_base.hpp
index a0700ca..7636bed 100755
--- a/ext/asio/asio/ssl/context_base.hpp
+++ b/ext/asio/asio/ssl/context_base.hpp
@@ -1,8 +1,8 @@
 //
-// context_base.hpp
-// ~~~~~~~~~~~~~~~~
+// ssl/context_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/ssl/detail/openssl_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ssl {
 
diff --git a/ext/asio/asio/ssl/context_service.hpp b/ext/asio/asio/ssl/context_service.hpp
index e9cfef7..766bbde 100755
--- a/ext/asio/asio/ssl/context_service.hpp
+++ b/ext/asio/asio/ssl/context_service.hpp
@@ -1,9 +1,9 @@
 //
-// context_service.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// ssl/context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,19 +16,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <string>
 #include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/ssl/context_base.hpp"
 #include "asio/ssl/detail/openssl_context_service.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ssl {
 
diff --git a/ext/asio/asio/ssl/detail/openssl_context_service.hpp b/ext/asio/asio/ssl/detail/openssl_context_service.hpp
index a3d4fdb..7019542 100755
--- a/ext/asio/asio/ssl/detail/openssl_context_service.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_context_service.hpp
@@ -1,9 +1,9 @@
 //
-// openssl_context_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,21 +16,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstring>
 #include <string>
 #include <boost/function.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/ssl/context_base.hpp"
 #include "asio/ssl/detail/openssl_init.hpp"
 #include "asio/ssl/detail/openssl_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ssl {
 namespace detail {
diff --git a/ext/asio/asio/ssl/detail/openssl_init.hpp b/ext/asio/asio/ssl/detail/openssl_init.hpp
index 9ecbb78..dcda50f 100755
--- a/ext/asio/asio/ssl/detail/openssl_init.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_init.hpp
@@ -1,9 +1,9 @@
 //
-// openssl_init.hpp
-// ~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,20 +16,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstring>
 #include <vector>
 #include <boost/assert.hpp>
-#include <boost/config.hpp>
 #include <boost/shared_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/tss_ptr.hpp"
 #include "asio/ssl/detail/openssl_types.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 namespace ssl {
 namespace detail {
diff --git a/ext/asio/asio/ssl/detail/openssl_operation.hpp b/ext/asio/asio/ssl/detail/openssl_operation.hpp
index 8d237e3..c5119a5 100755
--- a/ext/asio/asio/ssl/detail/openssl_operation.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_operation.hpp
@@ -1,6 +1,6 @@
 //
-// openssl_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
 //
@@ -15,19 +15,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <boost/function.hpp>
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/buffer.hpp"
-#include "asio/placeholders.hpp"
-#include "asio/write.hpp"
 #include "asio/detail/socket_ops.hpp"
+#include "asio/placeholders.hpp"
 #include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/strand.hpp"
+#include "asio/system_error.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ssl {
@@ -160,7 +160,7 @@ public:
 
     if (error_code == SSL_ERROR_SSL)
       return handler_(asio::error_code(
-            error_code, asio::error::get_ssl_category()), rc);
+            sys_error_code, asio::error::get_ssl_category()), rc);
 
     bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
     bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
@@ -195,7 +195,7 @@ public:
       else
       {
         return handler_(asio::error_code(
-              error_code, asio::error::get_ssl_category()), rc); 
+              sys_error_code, asio::error::get_ssl_category()), rc); 
       }
     }
 
diff --git a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
index d7bb457..aef9e7e 100644
--- a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
@@ -1,9 +1,9 @@
 //
-// stream_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ssl/detail/stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,9 +16,7 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
 #include <climits>
 #include <memory>
@@ -26,17 +24,17 @@
 #include <boost/noncopyable.hpp>
 #include <boost/function.hpp>
 #include <boost/bind.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/buffer_sequence_adapter.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/strand.hpp"
-#include "asio/detail/buffer_sequence_adapter.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/ssl/basic_context.hpp"
 #include "asio/ssl/stream_base.hpp"
 #include "asio/ssl/detail/openssl_operation.hpp"
 #include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/strand.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ssl {
@@ -92,7 +90,7 @@ private:
       : base_handler<Stream>(io_service)
       , handler_(handler)
     {
-      set_func(boost::bind(
+      this->set_func(boost::bind(
         &io_handler<Stream, Handler>::handler_impl, 
         this, boost::arg<1>(), boost::arg<2>() ));
     }
@@ -116,7 +114,7 @@ private:
       : base_handler<Stream>(io_service)
       , handler_(handler)
     {
-      set_func(boost::bind(
+      this->set_func(boost::bind(
         &handshake_handler<Stream, Handler>::handler_impl, 
         this, boost::arg<1>(), boost::arg<2>() ));
     }
@@ -141,7 +139,7 @@ private:
       : base_handler<Stream>(io_service),
         handler_(handler)
     { 
-      set_func(boost::bind(
+      this->set_func(boost::bind(
         &shutdown_handler<Stream, Handler>::handler_impl, 
         this, boost::arg<1>(), boost::arg<2>() ));
     }
diff --git a/ext/asio/asio/ssl/detail/openssl_types.hpp b/ext/asio/asio/ssl/detail/openssl_types.hpp
index c697d74..fbe1b74 100755
--- a/ext/asio/asio/ssl/detail/openssl_types.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_types.hpp
@@ -1,8 +1,8 @@
 //
-// openssl_types.hpp
-// ~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,11 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/socket_types.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <openssl/conf.h>
 #include <openssl/ssl.h>
 #include <openssl/engine.h>
 #include <openssl/err.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/socket_types.hpp"
 
 #endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
diff --git a/ext/asio/asio/ssl/stream.hpp b/ext/asio/asio/ssl/stream.hpp
index e800e62..e16cd9a 100644
--- a/ext/asio/asio/ssl/stream.hpp
+++ b/ext/asio/asio/ssl/stream.hpp
@@ -1,9 +1,9 @@
 //
-// stream.hpp
-// ~~~~~~~~~~
+// ssl/stream.hpp
+// ~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,20 +16,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/ssl/basic_context.hpp"
 #include "asio/ssl/stream_base.hpp"
 #include "asio/ssl/stream_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ssl {
diff --git a/ext/asio/asio/ssl/stream_base.hpp b/ext/asio/asio/ssl/stream_base.hpp
index d62d386..e1cc0d7 100755
--- a/ext/asio/asio/ssl/stream_base.hpp
+++ b/ext/asio/asio/ssl/stream_base.hpp
@@ -1,8 +1,8 @@
 //
-// stream_base.hpp
-// ~~~~~~~~~~~~~~~
+// ssl/stream_base.hpp
+// ~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <boost/detail/workaround.hpp>
 
 #include "asio/detail/push_options.hpp"
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
 
 namespace asio {
 namespace ssl {
diff --git a/ext/asio/asio/ssl/stream_service.hpp b/ext/asio/asio/ssl/stream_service.hpp
index 1f1e6ad..d99548e 100644
--- a/ext/asio/asio/ssl/stream_service.hpp
+++ b/ext/asio/asio/ssl/stream_service.hpp
@@ -1,9 +1,9 @@
 //
-// stream_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ssl/stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
 //
 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,19 +16,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 #include "asio/ssl/basic_context.hpp"
-#include "asio/ssl/stream_base.hpp"
 #include "asio/ssl/detail/openssl_stream_service.hpp"
+#include "asio/ssl/stream_base.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace ssl {
diff --git a/ext/asio/asio/strand.hpp b/ext/asio/asio/strand.hpp
index 6b32151..5a526f2 100644
--- a/ext/asio/asio/strand.hpp
+++ b/ext/asio/asio/strand.hpp
@@ -2,7 +2,7 @@
 // strand.hpp
 // ~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
 #include "asio/detail/strand_service.hpp"
 #include "asio/detail/wrapped_handler.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 
diff --git a/ext/asio/asio/stream_socket_service.hpp b/ext/asio/asio/stream_socket_service.hpp
index 1c4935c..553719e 100644
--- a/ext/asio/asio/stream_socket_service.hpp
+++ b/ext/asio/asio/stream_socket_service.hpp
@@ -2,7 +2,7 @@
 // stream_socket_service.hpp
 // ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
 
 #if defined(ASIO_HAS_IOCP)
 # include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
 # include "asio/detail/reactive_socket_service.hpp"
 #endif
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Default service implementation for a stream socket.
diff --git a/ext/asio/asio/streambuf.hpp b/ext/asio/asio/streambuf.hpp
index 665155b..553da3e 100644
--- a/ext/asio/asio/streambuf.hpp
+++ b/ext/asio/asio/streambuf.hpp
@@ -2,7 +2,7 @@
 // streambuf.hpp
 // ~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/detail/config.hpp"
 
 #if !defined(BOOST_NO_IOSTREAM)
 
+#include "asio/basic_streambuf.hpp"
+
 namespace asio {
 
 /// Typedef for the typical usage of basic_streambuf.
@@ -30,6 +30,4 @@ typedef basic_streambuf<> streambuf;
 
 #endif // !defined(BOOST_NO_IOSTREAM)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_STREAMBUF_HPP
diff --git a/ext/asio/asio/system_error.hpp b/ext/asio/asio/system_error.hpp
index e704b3f..60580a1 100644
--- a/ext/asio/asio/system_error.hpp
+++ b/ext/asio/asio/system_error.hpp
@@ -2,7 +2,7 @@
 // system_error.hpp
 // ~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,15 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
 #include <boost/scoped_ptr.hpp>
 #include <cerrno>
 #include <exception>
 #include <string>
-#include "asio/detail/pop_options.hpp"
-
 #include "asio/error_code.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// The system_error class is used to represent system conditions that
diff --git a/ext/asio/asio/thread.hpp b/ext/asio/asio/thread.hpp
index 9e578bc..070483e 100644
--- a/ext/asio/asio/thread.hpp
+++ b/ext/asio/asio/thread.hpp
@@ -2,7 +2,7 @@
 // thread.hpp
 // ~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/thread.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// A simple abstraction for starting threads.
diff --git a/ext/asio/asio/time_traits.hpp b/ext/asio/asio/time_traits.hpp
index 0371373..3b2899b 100644
--- a/ext/asio/asio/time_traits.hpp
+++ b/ext/asio/asio/time_traits.hpp
@@ -2,7 +2,7 @@
 // time_traits.hpp
 // ~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
 #include "asio/detail/socket_types.hpp" // Must come before posix_time.
 
 #include "asio/detail/push_options.hpp"
 #include <boost/date_time/posix_time/posix_time_types.hpp>
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /// Time traits suitable for use with the deadline timer.
diff --git a/ext/asio/asio/version.hpp b/ext/asio/asio/version.hpp
index 198f508..0402d0e 100644
--- a/ext/asio/asio/version.hpp
+++ b/ext/asio/asio/version.hpp
@@ -2,7 +2,7 @@
 // version.hpp
 // ~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -18,6 +18,6 @@
 // ASIO_VERSION % 100 is the sub-minor version
 // ASIO_VERSION / 100 % 1000 is the minor version
 // ASIO_VERSION / 100000 is the major version
-#define ASIO_VERSION 100405 // 1.4.5
+#define ASIO_VERSION 100408 // 1.4.8
 
 #endif // ASIO_VERSION_HPP
diff --git a/ext/asio/asio/windows/basic_handle.hpp b/ext/asio/asio/windows/basic_handle.hpp
index 8c2ee60..f87b3db 100644
--- a/ext/asio/asio/windows/basic_handle.hpp
+++ b/ext/asio/asio/windows/basic_handle.hpp
@@ -1,8 +1,8 @@
 //
-// basic_handle.hpp
-// ~~~~~~~~~~~~~~~~
+// windows/basic_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
 
 #include "asio/basic_io_object.hpp"
-#include "asio/error.hpp"
 #include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -222,4 +224,8 @@ protected:
 
 #include "asio/detail/pop_options.hpp"
 
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+       //   || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
 #endif // ASIO_WINDOWS_BASIC_HANDLE_HPP
diff --git a/ext/asio/asio/windows/basic_random_access_handle.hpp b/ext/asio/asio/windows/basic_random_access_handle.hpp
index 2e6b994..056b175 100644
--- a/ext/asio/asio/windows/basic_random_access_handle.hpp
+++ b/ext/asio/asio/windows/basic_random_access_handle.hpp
@@ -1,8 +1,8 @@
 //
-// basic_random_access_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/basic_random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
 
+#include <cstddef>
+#include "asio/detail/throw_error.hpp"
 #include "asio/error.hpp"
 #include "asio/windows/basic_handle.hpp"
 #include "asio/windows/random_access_handle_service.hpp"
-#include "asio/detail/throw_error.hpp"
 
-#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -312,9 +310,9 @@ public:
 } // namespace windows
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
diff --git a/ext/asio/asio/windows/basic_stream_handle.hpp b/ext/asio/asio/windows/basic_stream_handle.hpp
index 48e7153..28149f4 100644
--- a/ext/asio/asio/windows/basic_stream_handle.hpp
+++ b/ext/asio/asio/windows/basic_stream_handle.hpp
@@ -1,8 +1,8 @@
 //
-// basic_stream_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// windows/basic_stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
 
+#include <cstddef>
 #include "asio/error.hpp"
 #include "asio/windows/basic_handle.hpp"
 #include "asio/windows/stream_handle_service.hpp"
 #include "asio/detail/throw_error.hpp"
 
-#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -294,9 +292,9 @@ public:
 } // namespace windows
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
diff --git a/ext/asio/asio/windows/overlapped_ptr.hpp b/ext/asio/asio/windows/overlapped_ptr.hpp
index 087170b..8f4d628 100644
--- a/ext/asio/asio/windows/overlapped_ptr.hpp
+++ b/ext/asio/asio/windows/overlapped_ptr.hpp
@@ -1,8 +1,8 @@
 //
-// overlapped_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~
+// windows/overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,16 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \
+  || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/io_service.hpp"
 #include "asio/detail/noncopyable.hpp"
 #include "asio/detail/win_iocp_overlapped_ptr.hpp"
+#include "asio/io_service.hpp"
 
-#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
-# if defined(ASIO_HAS_IOCP)
-#  define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
-
-#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -110,9 +106,9 @@ private:
 } // namespace windows
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP
diff --git a/ext/asio/asio/windows/random_access_handle.hpp b/ext/asio/asio/windows/random_access_handle.hpp
index 6e5dd7b..727b084 100644
--- a/ext/asio/asio/windows/random_access_handle.hpp
+++ b/ext/asio/asio/windows/random_access_handle.hpp
@@ -1,8 +1,8 @@
 //
-// random_access_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/windows/basic_random_access_handle.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include "asio/windows/basic_random_access_handle.hpp"
+
 namespace asio {
 namespace windows {
 
@@ -34,6 +34,4 @@ typedef basic_random_access_handle<> random_access_handle;
 #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
diff --git a/ext/asio/asio/windows/random_access_handle_service.hpp b/ext/asio/asio/windows/random_access_handle_service.hpp
index 2e579f8..b2c05ef 100644
--- a/ext/asio/asio/windows/random_access_handle_service.hpp
+++ b/ext/asio/asio/windows/random_access_handle_service.hpp
@@ -1,8 +1,8 @@
 //
-// random_access_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/random_access_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,19 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/push_options.hpp"
 #include <cstddef>
 #include <boost/config.hpp>
 #include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/win_iocp_handle_service.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/win_iocp_handle_service.hpp"
 
-#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
-# if defined(ASIO_HAS_IOCP)
-#  define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
-
-#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -172,9 +164,9 @@ private:
 } // namespace windows
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/windows/stream_handle.hpp b/ext/asio/asio/windows/stream_handle.hpp
index d55dc31..802d157 100644
--- a/ext/asio/asio/windows/stream_handle.hpp
+++ b/ext/asio/asio/windows/stream_handle.hpp
@@ -1,8 +1,8 @@
 //
-// stream_handle.hpp
-// ~~~~~~~~~~~~~~~~~~
+// windows/stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/windows/basic_stream_handle.hpp"
+#include "asio/detail/config.hpp"
 
 #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
   || defined(GENERATING_DOCUMENTATION)
 
+#include "asio/windows/basic_stream_handle.hpp"
+
 namespace asio {
 namespace windows {
 
@@ -34,6 +34,4 @@ typedef basic_stream_handle<> stream_handle;
 #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_STREAM_HANDLE_HPP
diff --git a/ext/asio/asio/windows/stream_handle_service.hpp b/ext/asio/asio/windows/stream_handle_service.hpp
index 75eff60..816cfe5 100644
--- a/ext/asio/asio/windows/stream_handle_service.hpp
+++ b/ext/asio/asio/windows/stream_handle_service.hpp
@@ -1,8 +1,8 @@
 //
-// stream_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/stream_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,17 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
 
+#include <cstddef>
+#include "asio/detail/win_iocp_handle_service.hpp"
 #include "asio/error.hpp"
 #include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/win_iocp_handle_service.hpp"
 
-#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
-# if defined(ASIO_HAS_IOCP)
-#  define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
-
-#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
-  || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
 
 namespace asio {
 namespace windows {
@@ -170,9 +161,9 @@ private:
 } // namespace windows
 } // namespace asio
 
+#include "asio/detail/pop_options.hpp"
+
 #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
        //   || defined(GENERATING_DOCUMENTATION)
 
-#include "asio/detail/pop_options.hpp"
-
 #endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/write.hpp b/ext/asio/asio/write.hpp
index 2b188cd..bd90ecb 100644
--- a/ext/asio/asio/write.hpp
+++ b/ext/asio/asio/write.hpp
@@ -2,7 +2,7 @@
 // write.hpp
 // ~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
 #include "asio/error.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /**
@@ -533,8 +530,8 @@ void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
 
 } // namespace asio
 
-#include "asio/impl/write.ipp"
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/impl/write.hpp"
+
 #endif // ASIO_WRITE_HPP
diff --git a/ext/asio/asio/write_at.hpp b/ext/asio/asio/write_at.hpp
index 5690bcf..37d0cbb 100644
--- a/ext/asio/asio/write_at.hpp
+++ b/ext/asio/asio/write_at.hpp
@@ -2,7 +2,7 @@
 // write_at.hpp
 // ~~~~~~~~~~~~
 //
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
 #include <cstddef>
-#include <boost/config.hpp>
 #include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
 #include "asio/error.hpp"
 
+#include "asio/detail/push_options.hpp"
+
 namespace asio {
 
 /**
@@ -556,8 +553,8 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
 
 } // namespace asio
 
-#include "asio/impl/write_at.ipp"
-
 #include "asio/detail/pop_options.hpp"
 
+#include "asio/impl/write_at.hpp"
+
 #endif // ASIO_WRITE_AT_HPP
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 1768ce7..23d660c 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -1,4 +1,4 @@
 SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout \
-	usermgr zonemgr stats tests resolver
+	usermgr zonemgr stats tests resolver sockcreator
 
 check-recursive: all-recursive
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index cdfc55e..56dc348 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -39,9 +39,9 @@ pkglibexec_PROGRAMS = b10-auth
 b10_auth_SOURCES = query.cc query.h
 b10_auth_SOURCES += auth_srv.cc auth_srv.h
 b10_auth_SOURCES += change_user.cc change_user.h
-b10_auth_SOURCES += config.cc config.h
+b10_auth_SOURCES += auth_config.cc auth_config.h
 b10_auth_SOURCES += command.cc command.h
-b10_auth_SOURCES += common.h
+b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
 b10_auth_SOURCES += main.cc
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
@@ -49,6 +49,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
 b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_auth_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
new file mode 100644
index 0000000..7929d80
--- /dev/null
+++ b/src/bin/auth/auth_config.cc
@@ -0,0 +1,347 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/memory_datasrc.h>
+#include <datasrc/zonetable.h>
+
+#include <auth/auth_srv.h>
+#include <auth/auth_config.h>
+#include <auth/common.h>
+
+#include <server_common/portconfig.h>
+
+using namespace std;
+using boost::shared_ptr;
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::datasrc;
+using namespace isc::server_common::portconfig;
+
+namespace {
+// Forward declaration
+AuthConfigParser*
+createAuthConfigParser(AuthSrv& server, const std::string& config_id,
+                       bool internal);
+
+/// A derived \c AuthConfigParser class for the "datasources" configuration
+/// identifier.
+class DatasourcesConfig : public AuthConfigParser {
+public:
+    DatasourcesConfig(AuthSrv& server) : server_(server) {}
+    virtual void build(ConstElementPtr config_value);
+    virtual void commit();
+private:
+    AuthSrv& server_;
+    vector<shared_ptr<AuthConfigParser> > datasources_;
+    set<string> configured_sources_;
+};
+
+void
+DatasourcesConfig::build(ConstElementPtr config_value) {
+    BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
+        // The caller is supposed to perform syntax-level checks, but we'll
+        // do minimum level of validation ourselves so that we won't crash due
+        // to a buggy application.
+        ConstElementPtr datasrc_type = datasrc_elem->get("type");
+        if (!datasrc_type) {
+            isc_throw(AuthConfigError, "Missing data source type");
+        }
+
+        if (configured_sources_.find(datasrc_type->stringValue()) !=
+            configured_sources_.end()) {
+            isc_throw(AuthConfigError, "Data source type '" <<
+                      datasrc_type->stringValue() << "' already configured");
+        }
+        
+        shared_ptr<AuthConfigParser> datasrc_config =
+            shared_ptr<AuthConfigParser>(
+                createAuthConfigParser(server_, string("datasources/") +
+                                       datasrc_type->stringValue(),
+                                       true));
+        datasrc_config->build(datasrc_elem);
+        datasources_.push_back(datasrc_config);
+
+        configured_sources_.insert(datasrc_type->stringValue());
+    }
+}
+
+void
+DatasourcesConfig::commit() {
+    // XXX a short term workaround: clear all data sources and then reset
+    // to new ones so that we can remove data sources that don't exist in
+    // the new configuration and have been used in the server.
+    // This could be inefficient and requires knowledge about
+    // server implementation details, and isn't scalable wrt the number of
+    // data source types, and should eventually be improved.
+    // Currently memory data source for class IN is the only possibility.
+    server_.setMemoryDataSrc(RRClass::IN(), AuthSrv::MemoryDataSrcPtr());
+
+    BOOST_FOREACH(shared_ptr<AuthConfigParser> datasrc_config, datasources_) {
+        datasrc_config->commit();
+    }
+}
+
+/// A derived \c AuthConfigParser class for the memory type datasource
+/// configuration.  It does not correspond to the configuration syntax;
+/// it's instantiated for internal use.
+class MemoryDatasourceConfig : public AuthConfigParser {
+public:
+    MemoryDatasourceConfig(AuthSrv& server) :
+        server_(server),
+        rrclass_(0)              // XXX: dummy initial value
+    {}
+    virtual void build(ConstElementPtr config_value);
+    virtual void commit() {
+        server_.setMemoryDataSrc(rrclass_, memory_datasrc_);
+    }
+private:
+    AuthSrv& server_;
+    RRClass rrclass_;
+    AuthSrv::MemoryDataSrcPtr memory_datasrc_;
+};
+
+void
+MemoryDatasourceConfig::build(ConstElementPtr config_value) {
+    // XXX: apparently we cannot retrieve the default RR class from the
+    // module spec.  As a temporary workaround we hardcode the default value.
+    ConstElementPtr rrclass_elem = config_value->get("class");
+    rrclass_ = RRClass(rrclass_elem ? rrclass_elem->stringValue() : "IN");
+
+    // We'd eventually optimize building zones (in case of reloading) by
+    // selectively loading fresh zones.  Right now we simply check the
+    // RR class is supported by the server implementation.
+    server_.getMemoryDataSrc(rrclass_);
+    memory_datasrc_ = AuthSrv::MemoryDataSrcPtr(new MemoryDataSrc());
+
+    ConstElementPtr zones_config = config_value->get("zones");
+    if (!zones_config) {
+        // XXX: Like the RR class, we cannot retrieve the default value here,
+        // so we assume an empty zone list in this case.
+        return;
+    }
+
+    BOOST_FOREACH(ConstElementPtr zone_config, zones_config->listValue()) {
+        ConstElementPtr origin = zone_config->get("origin");
+        if (!origin) {
+            isc_throw(AuthConfigError, "Missing zone origin");
+        }
+        ConstElementPtr file = zone_config->get("file");
+        if (!file) {
+            isc_throw(AuthConfigError, "Missing zone file for zone: "
+                      << origin->str());
+        }
+        shared_ptr<MemoryZone> new_zone(new MemoryZone(rrclass_,
+            Name(origin->stringValue())));
+        const result::Result result = memory_datasrc_->addZone(new_zone);
+        if (result == result::EXIST) {
+            isc_throw(AuthConfigError, "zone "<< origin->str()
+                      << " already exists");
+        }
+
+        /*
+         * TODO: Once we have better reloading of configuration (something
+         * else than throwing everything away and loading it again), we will
+         * need the load method to be split into some kind of build and
+         * commit/abort parts.
+         */
+        new_zone->load(file->stringValue());
+    }
+}
+
+/// A derived \c AuthConfigParser class for the "statistics-internal"
+/// configuration identifier.
+class StatisticsIntervalConfig : public AuthConfigParser {
+public:
+    StatisticsIntervalConfig(AuthSrv& server) :
+        server_(server), interval_(0)
+    {}
+    virtual void build(ConstElementPtr config_value) {
+        const int32_t config_interval = config_value->intValue();
+        if (config_interval < 0) {
+            isc_throw(AuthConfigError, "Negative statistics interval value: "
+                      << config_interval);
+        }
+        if (config_interval > 86400) {
+            isc_throw(AuthConfigError, "Statistics interval value "
+                      << config_interval
+                      << " must be equal to or shorter than 86400");
+        }
+        interval_ = config_interval;
+    }
+    virtual void commit() {
+        // setStatisticsTimerInterval() is not 100% exception free.  But
+        // exceptions should happen only in a very rare situation, so we
+        // let them be thrown and subsequently regard them as a fatal error.
+        server_.setStatisticsTimerInterval(interval_);
+    }
+private:
+    AuthSrv& server_;
+    uint32_t interval_;
+};
+
+/// A special parser for testing: it throws from commit() despite the
+/// suggested convention of the class interface.
+class ThrowerCommitConfig : public AuthConfigParser {
+public:
+    virtual void build(ConstElementPtr) {} // ignore param, do nothing
+    virtual void commit() {
+        throw 10;
+    }
+};
+
+/**
+ * \brief Configuration parser for listen_on.
+ *
+ * It parses and sets the listening addresses of the server.
+ *
+ * It acts in unusual way. Since actually binding (changing) the sockets
+ * is an operation that is expected to throw often, it shouldn't happen
+ * in commit. Thefere we do it in build. But if the config is not committed
+ * then, we would have it wrong. So we store the old addresses and if
+ * commit is not called before destruction of the object, we return the
+ * old addresses (which is the same kind of dangerous operation, but it is
+ * expected that if we just managed to bind some and had the old ones binded
+ * before, it should work).
+ *
+ * We might do something better in future (like open only the ports that are
+ * extra, put them in in commit and close the old ones), but that's left out
+ * for now.
+ */
+class ListenAddressConfig : public AuthConfigParser {
+public:
+    ListenAddressConfig(AuthSrv& server) :
+        server_(server)
+    { }
+    ~ ListenAddressConfig() {
+        if (rollbackAddresses_.get() != NULL) {
+            server_.setListenAddresses(*rollbackAddresses_);
+        }
+    }
+private:
+    typedef auto_ptr<AddressList> AddrListPtr;
+public:
+    virtual void build(ConstElementPtr config) {
+        AddressList newAddresses = parseAddresses(config, "listen_on");
+        AddrListPtr old(new AddressList(server_.getListenAddresses()));
+        server_.setListenAddresses(newAddresses);
+        /*
+         * Set the rollback addresses only after successful setting of the
+         * new addresses, so we don't try to rollback if the setup is
+         * unsuccessful (the above can easily throw).
+         */
+        rollbackAddresses_ = old;
+    }
+    virtual void commit() {
+        rollbackAddresses_.release();
+    }
+private:
+    AuthSrv& server_;
+    /**
+     * This is the old address list, if we expect to roll back. When we commit,
+     * this is set to NULL.
+     */
+    AddrListPtr rollbackAddresses_;
+};
+
+// This is a generalized version of create function that can create
+// an AuthConfigParser object for "internal" use.
+AuthConfigParser*
+createAuthConfigParser(AuthSrv& server, const std::string& config_id,
+                       bool internal)
+{
+    // For the initial implementation we use a naive if-else blocks for
+    // simplicity.  In future we'll probably generalize it using map-like
+    // data structure, and may even provide external register interface so
+    // that it can be dynamically customized.
+    if (config_id == "datasources") {
+        return (new DatasourcesConfig(server));
+    } else if (config_id == "statistics-interval") {
+        return (new StatisticsIntervalConfig(server));
+    } else if (internal && config_id == "datasources/memory") {
+        return (new MemoryDatasourceConfig(server));
+    } else if (config_id == "listen_on") {
+        return (new ListenAddressConfig(server));
+    } else if (config_id == "_commit_throw") {
+        // This is for testing purpose only and should not appear in the
+        // actual configuration syntax.  While this could crash the caller
+        // as a result, the server implementation is expected to perform
+        // syntax level validation and should be safe in practice.  In future,
+        // we may introduce dynamic registration of configuration parsers,
+        // and then this test can be done in a cleaner and safer way.
+        return (new ThrowerCommitConfig());
+    } else {
+        isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
+                  config_id);
+    }
+}
+} // end of unnamed namespace
+
+AuthConfigParser*
+createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
+    return (createAuthConfigParser(server, config_id, false));
+}
+
+void
+configureAuthServer(AuthSrv& server, ConstElementPtr config_set) {
+    if (!config_set) {
+        isc_throw(AuthConfigError,
+                  "Null pointer is passed to configuration parser");
+    }
+
+    typedef shared_ptr<AuthConfigParser> ParserPtr;
+    vector<ParserPtr> parsers;
+    typedef pair<string, ConstElementPtr> ConfigPair;
+    try {
+        BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
+            // We should eventually integrate the sqlite3 DB configuration to
+            // this framework, but to minimize diff we begin with skipping that
+            // part.
+            if (config_pair.first == "database_file") {
+                continue;
+            }
+
+            ParserPtr parser(createAuthConfigParser(server,
+                                                    config_pair.first));
+            parser->build(config_pair.second);
+            parsers.push_back(parser);
+        }
+    } catch (const AuthConfigError& ex) {
+        throw;                  // simply rethrowing it
+    } catch (const isc::Exception& ex) {
+        isc_throw(AuthConfigError, "Server configuration failed: " <<
+                  ex.what());
+    }
+
+    try {
+        BOOST_FOREACH(ParserPtr parser, parsers) {
+            parser->commit();
+        }
+    } catch (...) {
+        throw FatalError("Unrecoverable error: "
+                         "a configuration parser threw in commit");
+    }
+}
diff --git a/src/bin/auth/auth_config.h b/src/bin/auth/auth_config.h
new file mode 100644
index 0000000..6f18810
--- /dev/null
+++ b/src/bin/auth/auth_config.h
@@ -0,0 +1,202 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+#include <cc/data.h>
+
+#ifndef __CONFIG_H
+#define __CONFIG_H 1
+
+class AuthSrv;
+
+/// An exception that is thrown if an error occurs while configuring an
+/// \c AuthSrv object.
+class AuthConfigError : public isc::Exception {
+public:
+    AuthConfigError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// The abstract base class that represents a single configuration identifier
+/// for an \c AuthSrv object.
+///
+/// In general, each top level configuration identifier for \c AuthSrv is
+/// expected to have its own derived class of this base class.
+/// For example, for the following configuration:
+/// \code { "param1": 10, "param2": { "subparam1": "foo", "subparam2": [] } }
+/// \endcode
+/// "param1" and "param2" are top level identifiers, and would correspond to
+/// derived \c AuthConfigParser classes.
+/// "subparam1" and/or "subparam2" may also have dedicated derived classes.
+///
+/// These derived classes are hidden inside the implementation; applications
+/// are not expected to (and in fact cannot) instantiate them directly.
+///
+/// Each derived class is generally expected to be constructed with an
+/// \c AuthSrv object to be configured and hold a reference to the server
+/// throughout the configuration process.
+/// For each derived class, the \c build() method parses the configuration
+/// value for the corresponding identifier and prepares new configuration
+/// value(s) to be applied to the server.  This method may throw an exception
+/// when it encounters an error.
+/// The \c commit() method actually applies the new configuration value
+/// to the server.  It's basically not expected to throw an exception;
+/// any configuration operations that can fail (such as ones involving
+/// resource allocation) should be done in \c build().
+///
+/// When the destructor is called before \c commit(), the destructor is
+/// supposed to make sure the state of the \c AuthSrv object is the same
+/// as that before it starts building the configuration value.
+/// If \c build() doesn't change the server state (which is recommended)
+/// the destructor doesn't have to do anything special in this regard.
+/// This is a key to ensure the strong exception guarantee (see also
+/// the description of \c configureAuthServer()).
+class AuthConfigParser {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private to make it explicit that this is a
+    /// pure base class.
+    //@{
+private:
+    AuthConfigParser(const AuthConfigParser& source);
+    AuthConfigParser& operator=(const AuthConfigParser& source);
+protected:
+    /// \brief The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).
+    AuthConfigParser() {}
+public:
+    /// The destructor.
+    virtual ~AuthConfigParser() {}
+    //@}
+
+    /// Prepare configuration value.
+    ///
+    /// This method parses the "value part" of the configuration identifier
+    /// that corresponds to this derived class and prepares a new value to
+    /// apply to the server.
+    /// In the above example, the derived class for the identifier "param1"
+    /// would be passed an data \c Element storing an integer whose value
+    /// is 10, and would record that value internally;
+    /// the derived class for the identifier "param2" would be passed a
+    /// map element and (after parsing) convert it into some internal
+    /// data structure.
+    ///
+    /// This method must validate the given value both in terms of syntax
+    /// and semantics of the configuration, so that the server will be
+    /// validly configured at the time of \c commit().  Note: the given
+    /// configuration value is normally syntactically validated, but the
+    /// \c build() implementation must also expect invalid input.  If it
+    /// detects an error it may throw an exception of a derived class
+    /// of \c isc::Exception.
+    ///
+    /// Preparing a configuration value will often require resource
+    /// allocation.  If it fails, it may throw a corresponding standard
+    /// exception.
+    ///
+    /// This method is not expected to be called more than once.  Although
+    /// multiple calls are not prohibited by the interface, the behavior
+    /// is undefined.
+    ///
+    /// \param config_value The configuration value for the identifier
+    /// corresponding to the derived class.
+    virtual void build(isc::data::ConstElementPtr config_value) = 0;
+
+    /// Apply the prepared configuration value to the server.
+    ///
+    /// This method is expected to be exception free, and, as a consequence,
+    /// it should normally not involve resource allocation.
+    /// Typically it would simply perform exception free assignment or swap
+    /// operation on the value prepared in \c build().
+    /// In some cases, however, it may be very difficult to meet this
+    /// condition in a realistic way, while the failure case should really
+    /// be very rare.  In such a case it may throw, and, if the parser is
+    /// called via \c configureAuthServer(), the caller will convert the
+    /// exception as a fatal error.
+    ///
+    /// This method is expected to be called after \c build(), and only once.
+    /// The result is undefined otherwise.
+    virtual void commit() = 0;
+};
+
+/// Configure an \c AuthSrv object with a set of configuration values.
+///
+/// This function parses configuration information stored in \c config_set
+/// and configures the \c server by applying the configuration to it.
+/// It provides the strong exception guarantee as long as the underlying
+/// derived class implementations of \c AuthConfigParser meet the assumption,
+/// that is, it ensures that either configuration is fully applied or the
+/// state of the server is intact.
+///
+/// If a syntax or semantics level error happens during the configuration
+/// (such as malformed configuration or invalid configuration parameter),
+/// this function throws an exception of class \c AuthConfigError.
+/// If the given configuration requires resource allocation and it fails,
+/// a corresponding standard exception will be thrown.
+/// Other exceptions may also be thrown, depending on the implementation of
+/// the underlying derived class of \c AuthConfigError.
+/// In any case the strong guarantee is provided as described above except
+/// in the very rare cases where the \c commit() method of a parser throws
+/// an exception.  If that happens this function converts the exception
+/// into a \c FatalError exception and rethrows it.  This exception is
+/// expected to be caught at the highest level of the application to terminate
+/// the program gracefully.
+///
+/// \param server The \c AuthSrv object to be configured.
+/// \param config_set A JSON style configuration to apply to \c server.
+void configureAuthServer(AuthSrv& server,
+                         isc::data::ConstElementPtr config_set);
+
+/// Create a new \c AuthConfigParser object for a given configuration
+/// identifier.
+///
+/// It internally identifies an appropriate derived class for the given
+/// identifier and creates a new instance of that class.  The caller can
+/// then configure the \c server regarding the identifier by calling
+/// the \c build() and \c commit() methods of the returned object.
+///
+/// In practice, this function is only expected to be used as a backend of
+/// \c configureAuthServer() and is not supposed to be called directly
+/// by applications.  It is publicly available mainly for testing purposes.
+/// When called directly, the created object must be deleted by the caller.
+/// Note: this means if this module and the caller use incompatible sets of
+/// new/delete, it may cause unexpected strange failure.  We could avoid that
+/// by providing a separate deallocation function or by using a smart pointer,
+/// but since the expected usage of this function is very limited (i.e. for
+/// our own testing purposes) it would be an overkilling.  We therefore prefer
+/// simplicity and keeping the interface intuitive.
+///
+/// If the resource allocation for the new object fails, a corresponding
+/// standard exception will be thrown.  Otherwise this function is not
+/// expected to throw an exception, unless the constructor of the underlying
+/// derived class implementation (unexpectedly) throws.
+///
+/// \param server The \c AuthSrv object to be configured.
+/// \param config_id The configuration identifier for which a parser object
+/// is to be created.
+/// \return A pointer to an \c AuthConfigParser object.
+AuthConfigParser* createAuthConfigParser(AuthSrv& server,
+                                         const std::string& config_id);
+
+#endif // __CONFIG_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index f46752a..a863ef3 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -31,7 +31,8 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
@@ -52,7 +53,7 @@
 #include <xfr/xfrout_client.h>
 
 #include <auth/common.h>
-#include <auth/config.h>
+#include <auth/auth_config.h>
 #include <auth/auth_srv.h>
 #include <auth/query.h>
 #include <auth/statistics.h>
@@ -63,12 +64,14 @@ using namespace isc;
 using namespace isc::cc;
 using namespace isc::datasrc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::auth;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::config;
 using namespace isc::xfr;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
 using namespace isc::server_common::portconfig;
 
 class AuthSrvImpl {
@@ -766,6 +769,6 @@ AuthSrv::setListenAddresses(const AddressList& addresses) {
 }
 
 void
-AuthSrv::setDNSService(asiolink::DNSService& dnss) {
+AuthSrv::setDNSService(isc::asiodns::DNSService& dnss) {
     dnss_ = &dnss;
 }
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index 8253c85..88f00c1 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -23,6 +23,15 @@
 
 #include <cc/data.h>
 #include <config/ccsession.h>
+#include <dns/message.h>
+#include <util/buffer.h>
+
+#include <asiodns/dns_server.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_answer.h>
+#include <asiolink/io_message.h>
+#include <asiolink/io_service.h>
+#include <asiolink/simple_callback.h>
 
 #include <asiolink/asiolink.h>
 #include <server_common/portconfig.h>
@@ -107,10 +116,10 @@ public:
     /// \param server Pointer to the \c DNSServer
     ///
     /// \throw isc::Unexpected Protocol type of \a message is unexpected
-    void processMessage(const asiolink::IOMessage& io_message,
+    void processMessage(const isc::asiolink::IOMessage& io_message,
                         isc::dns::MessagePtr message,
-                        isc::dns::OutputBufferPtr buffer,
-                        asiolink::DNSServer* server);
+                        isc::util::OutputBufferPtr buffer,
+                        isc::asiodns::DNSServer* server);
 
     /// \brief Set verbose flag
     ///
@@ -193,16 +202,16 @@ public:
     void setConfigSession(isc::config::ModuleCCSession* config_session);
 
     /// \brief Return this object's ASIO IO Service queue
-    asiolink::IOService& getIOService();
+    isc::asiolink::IOService& getIOService();
 
     /// \brief Return pointer to the DNS Lookup callback function
-    asiolink::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); }
+    isc::asiodns::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); }
 
     /// \brief Return pointer to the DNS Answer callback function
-    asiolink::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); }
+    isc::asiodns::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); }
 
     /// \brief Return pointer to the Checkin callback function
-    asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
+    isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
 
     /// \brief Set or update the size (number of slots) of hot spot cache.
     ///
@@ -363,15 +372,15 @@ public:
         const;
 
     /// \brief Assign an ASIO DNS Service queue to this Auth object
-    void setDNSService(asiolink::DNSService& dnss);
+    void setDNSService(isc::asiodns::DNSService& dnss);
 
 
 private:
     AuthSrvImpl* impl_;
-    asiolink::SimpleCallback* checkin_;
-    asiolink::DNSLookup* dns_lookup_;
-    asiolink::DNSAnswer* dns_answer_;
-    asiolink::DNSService* dnss_;
+    isc::asiolink::SimpleCallback* checkin_;
+    isc::asiodns::DNSLookup* dns_lookup_;
+    isc::asiodns::DNSAnswer* dns_answer_;
+    isc::asiodns::DNSService* dnss_;
 };
 
 #endif // __AUTH_SRV_H
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index 3078dd5..a569147 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -10,7 +10,7 @@ noinst_PROGRAMS = query_bench
 query_bench_SOURCES = query_bench.cc
 query_bench_SOURCES += ../query.h  ../query.cc
 query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
-query_bench_SOURCES += ../config.h ../config.cc
+query_bench_SOURCES += ../auth_config.h ../auth_config.cc
 query_bench_SOURCES += ../statistics.h ../statistics.cc
 
 query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
@@ -22,6 +22,7 @@ query_bench_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la
 query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
 query_bench_LDADD += $(SQLITE_LIBS)
diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc
index 5e69134..ba2e7b2 100644
--- a/src/bin/auth/benchmarks/query_bench.cc
+++ b/src/bin/auth/benchmarks/query_bench.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <stdlib.h>
 
 #include <iostream>
@@ -22,7 +24,7 @@
 #include <bench/benchmark.h>
 #include <bench/benchmark_util.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/question.h>
@@ -31,9 +33,10 @@
 #include <xfr/xfrout_client.h>
 
 #include <auth/auth_srv.h>
-#include <auth/config.h>
+#include <auth/auth_config.h>
 #include <auth/query.h>
 
+#include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 
 using namespace std;
@@ -41,9 +44,11 @@ using namespace isc;
 using namespace isc::data;
 using namespace isc::auth;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::xfr;
 using namespace isc::bench;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 
 namespace {
 // Commonly used constant:
diff --git a/src/bin/auth/common.cc b/src/bin/auth/common.cc
new file mode 100644
index 0000000..35381a1
--- /dev/null
+++ b/src/bin/auth/common.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <auth/common.h>
+#include <auth/spec_config.h>
+#include <stdlib.h>
+
+using std::string;
+
+string getXfroutSocketPath() {
+    if (getenv("B10_FROM_BUILD") != NULL) {
+        if (getenv("B10_FROM_SOURCE_LOCALSTATEDIR")) {
+            return (string(getenv("B10_FROM_SOURCE_LOCALSTATEDIR")) +
+                    "/auth_xfrout_conn");
+        } else {
+            return (string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn");
+        }
+    } else {
+        if (getenv("BIND10_XFROUT_SOCKET_FILE")) {
+            return (getenv("BIND10_XFROUT_SOCKET_FILE"));
+        } else {
+            return (UNIX_SOCKET_FILE);
+        }
+    }
+}
diff --git a/src/bin/auth/common.h b/src/bin/auth/common.h
index 6af09fb..b913593 100644
--- a/src/bin/auth/common.h
+++ b/src/bin/auth/common.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +29,15 @@ public:
     {}
 };
 
+/// \short Get the path of socket to talk to xfrout
+///
+/// It takes some environment variables into account (B10_FROM_BUILD,
+/// B10_FROM_SOURCE_LOCALSTATEDIR and BIND10_XFROUT_SOCKET_FILE). It
+/// also considers the installation prefix.
+///
+/// The logic should be the same as in b10-xfrout, so they find each other.
+std::string getXfroutSocketPath();
+
 #endif // __COMMON_H
 
 // Local Variables:
diff --git a/src/bin/auth/config.cc b/src/bin/auth/config.cc
deleted file mode 100644
index f289ca0..0000000
--- a/src/bin/auth/config.cc
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-
-#include <cc/data.h>
-
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/zonetable.h>
-
-#include <auth/auth_srv.h>
-#include <auth/config.h>
-#include <auth/common.h>
-
-#include <server_common/portconfig.h>
-
-using namespace std;
-using boost::shared_ptr;
-using namespace isc::dns;
-using namespace isc::data;
-using namespace isc::datasrc;
-using namespace isc::server_common::portconfig;
-
-namespace {
-// Forward declaration
-AuthConfigParser*
-createAuthConfigParser(AuthSrv& server, const std::string& config_id,
-                       bool internal);
-
-/// A derived \c AuthConfigParser class for the "datasources" configuration
-/// identifier.
-class DatasourcesConfig : public AuthConfigParser {
-public:
-    DatasourcesConfig(AuthSrv& server) : server_(server) {}
-    virtual void build(ConstElementPtr config_value);
-    virtual void commit();
-private:
-    AuthSrv& server_;
-    vector<shared_ptr<AuthConfigParser> > datasources_;
-    set<string> configured_sources_;
-};
-
-void
-DatasourcesConfig::build(ConstElementPtr config_value) {
-    BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
-        // The caller is supposed to perform syntax-level checks, but we'll
-        // do minimum level of validation ourselves so that we won't crash due
-        // to a buggy application.
-        ConstElementPtr datasrc_type = datasrc_elem->get("type");
-        if (!datasrc_type) {
-            isc_throw(AuthConfigError, "Missing data source type");
-        }
-
-        if (configured_sources_.find(datasrc_type->stringValue()) !=
-            configured_sources_.end()) {
-            isc_throw(AuthConfigError, "Data source type '" <<
-                      datasrc_type->stringValue() << "' already configured");
-        }
-        
-        shared_ptr<AuthConfigParser> datasrc_config =
-            shared_ptr<AuthConfigParser>(
-                createAuthConfigParser(server_, string("datasources/") +
-                                       datasrc_type->stringValue(),
-                                       true));
-        datasrc_config->build(datasrc_elem);
-        datasources_.push_back(datasrc_config);
-
-        configured_sources_.insert(datasrc_type->stringValue());
-    }
-}
-
-void
-DatasourcesConfig::commit() {
-    // XXX a short term workaround: clear all data sources and then reset
-    // to new ones so that we can remove data sources that don't exist in
-    // the new configuration and have been used in the server.
-    // This could be inefficient and requires knowledge about
-    // server implementation details, and isn't scalable wrt the number of
-    // data source types, and should eventually be improved.
-    // Currently memory data source for class IN is the only possibility.
-    server_.setMemoryDataSrc(RRClass::IN(), AuthSrv::MemoryDataSrcPtr());
-
-    BOOST_FOREACH(shared_ptr<AuthConfigParser> datasrc_config, datasources_) {
-        datasrc_config->commit();
-    }
-}
-
-/// A derived \c AuthConfigParser class for the memory type datasource
-/// configuration.  It does not correspond to the configuration syntax;
-/// it's instantiated for internal use.
-class MemoryDatasourceConfig : public AuthConfigParser {
-public:
-    MemoryDatasourceConfig(AuthSrv& server) :
-        server_(server),
-        rrclass_(0)              // XXX: dummy initial value
-    {}
-    virtual void build(ConstElementPtr config_value);
-    virtual void commit() {
-        server_.setMemoryDataSrc(rrclass_, memory_datasrc_);
-    }
-private:
-    AuthSrv& server_;
-    RRClass rrclass_;
-    AuthSrv::MemoryDataSrcPtr memory_datasrc_;
-};
-
-void
-MemoryDatasourceConfig::build(ConstElementPtr config_value) {
-    // XXX: apparently we cannot retrieve the default RR class from the
-    // module spec.  As a temporary workaround we hardcode the default value.
-    ConstElementPtr rrclass_elem = config_value->get("class");
-    rrclass_ = RRClass(rrclass_elem ? rrclass_elem->stringValue() : "IN");
-
-    // We'd eventually optimize building zones (in case of reloading) by
-    // selectively loading fresh zones.  Right now we simply check the
-    // RR class is supported by the server implementation.
-    server_.getMemoryDataSrc(rrclass_);
-    memory_datasrc_ = AuthSrv::MemoryDataSrcPtr(new MemoryDataSrc());
-
-    ConstElementPtr zones_config = config_value->get("zones");
-    if (!zones_config) {
-        // XXX: Like the RR class, we cannot retrieve the default value here,
-        // so we assume an empty zone list in this case.
-        return;
-    }
-
-    BOOST_FOREACH(ConstElementPtr zone_config, zones_config->listValue()) {
-        ConstElementPtr origin = zone_config->get("origin");
-        if (!origin) {
-            isc_throw(AuthConfigError, "Missing zone origin");
-        }
-        ConstElementPtr file = zone_config->get("file");
-        if (!file) {
-            isc_throw(AuthConfigError, "Missing zone file for zone: "
-                      << origin->str());
-        }
-        shared_ptr<MemoryZone> new_zone(new MemoryZone(rrclass_,
-            Name(origin->stringValue())));
-        const result::Result result = memory_datasrc_->addZone(new_zone);
-        if (result == result::EXIST) {
-            isc_throw(AuthConfigError, "zone "<< origin->str()
-                      << " already exists");
-        }
-
-        /*
-         * TODO: Once we have better reloading of configuration (something
-         * else than throwing everything away and loading it again), we will
-         * need the load method to be split into some kind of build and
-         * commit/abort parts.
-         */
-        new_zone->load(file->stringValue());
-    }
-}
-
-/// A derived \c AuthConfigParser class for the "statistics-internal"
-/// configuration identifier.
-class StatisticsIntervalConfig : public AuthConfigParser {
-public:
-    StatisticsIntervalConfig(AuthSrv& server) :
-        server_(server), interval_(0)
-    {}
-    virtual void build(ConstElementPtr config_value) {
-        const int32_t config_interval = config_value->intValue();
-        if (config_interval < 0) {
-            isc_throw(AuthConfigError, "Negative statistics interval value: "
-                      << config_interval);
-        }
-        if (config_interval > 86400) {
-            isc_throw(AuthConfigError, "Statistics interval value "
-                      << config_interval
-                      << " must be equal to or shorter than 86400");
-        }
-        interval_ = config_interval;
-    }
-    virtual void commit() {
-        // setStatisticsTimerInterval() is not 100% exception free.  But
-        // exceptions should happen only in a very rare situation, so we
-        // let them be thrown and subsequently regard them as a fatal error.
-        server_.setStatisticsTimerInterval(interval_);
-    }
-private:
-    AuthSrv& server_;
-    uint32_t interval_;
-};
-
-/// A special parser for testing: it throws from commit() despite the
-/// suggested convention of the class interface.
-class ThrowerCommitConfig : public AuthConfigParser {
-public:
-    virtual void build(ConstElementPtr) {} // ignore param, do nothing
-    virtual void commit() {
-        throw 10;
-    }
-};
-
-/**
- * \brief Configuration parser for listen_on.
- *
- * It parses and sets the listening addresses of the server.
- *
- * It acts in unusual way. Since actually binding (changing) the sockets
- * is an operation that is expected to throw often, it shouldn't happen
- * in commit. Thefere we do it in build. But if the config is not committed
- * then, we would have it wrong. So we store the old addresses and if
- * commit is not called before destruction of the object, we return the
- * old addresses (which is the same kind of dangerous operation, but it is
- * expected that if we just managed to bind some and had the old ones binded
- * before, it should work).
- *
- * We might do something better in future (like open only the ports that are
- * extra, put them in in commit and close the old ones), but that's left out
- * for now.
- */
-class ListenAddressConfig : public AuthConfigParser {
-public:
-    ListenAddressConfig(AuthSrv& server) :
-        server_(server)
-    { }
-    ~ ListenAddressConfig() {
-        if (rollbackAddresses_.get() != NULL) {
-            server_.setListenAddresses(*rollbackAddresses_);
-        }
-    }
-private:
-    typedef auto_ptr<AddressList> AddrListPtr;
-public:
-    virtual void build(ConstElementPtr config) {
-        AddressList newAddresses = parseAddresses(config, "listen_on");
-        AddrListPtr old(new AddressList(server_.getListenAddresses()));
-        server_.setListenAddresses(newAddresses);
-        /*
-         * Set the rollback addresses only after successful setting of the
-         * new addresses, so we don't try to rollback if the setup is
-         * unsuccessful (the above can easily throw).
-         */
-        rollbackAddresses_ = old;
-    }
-    virtual void commit() {
-        rollbackAddresses_.release();
-    }
-private:
-    AuthSrv& server_;
-    /**
-     * This is the old address list, if we expect to roll back. When we commit,
-     * this is set to NULL.
-     */
-    AddrListPtr rollbackAddresses_;
-};
-
-// This is a generalized version of create function that can create
-// an AuthConfigParser object for "internal" use.
-AuthConfigParser*
-createAuthConfigParser(AuthSrv& server, const std::string& config_id,
-                       bool internal)
-{
-    // For the initial implementation we use a naive if-else blocks for
-    // simplicity.  In future we'll probably generalize it using map-like
-    // data structure, and may even provide external register interface so
-    // that it can be dynamically customized.
-    if (config_id == "datasources") {
-        return (new DatasourcesConfig(server));
-    } else if (config_id == "statistics-interval") {
-        return (new StatisticsIntervalConfig(server));
-    } else if (internal && config_id == "datasources/memory") {
-        return (new MemoryDatasourceConfig(server));
-    } else if (config_id == "listen_on") {
-        return (new ListenAddressConfig(server));
-    } else if (config_id == "_commit_throw") {
-        // This is for testing purpose only and should not appear in the
-        // actual configuration syntax.  While this could crash the caller
-        // as a result, the server implementation is expected to perform
-        // syntax level validation and should be safe in practice.  In future,
-        // we may introduce dynamic registration of configuration parsers,
-        // and then this test can be done in a cleaner and safer way.
-        return (new ThrowerCommitConfig());
-    } else {
-        isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
-                  config_id);
-    }
-}
-} // end of unnamed namespace
-
-AuthConfigParser*
-createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
-    return (createAuthConfigParser(server, config_id, false));
-}
-
-void
-configureAuthServer(AuthSrv& server, ConstElementPtr config_set) {
-    if (!config_set) {
-        isc_throw(AuthConfigError,
-                  "Null pointer is passed to configuration parser");
-    }
-
-    typedef shared_ptr<AuthConfigParser> ParserPtr;
-    vector<ParserPtr> parsers;
-    typedef pair<string, ConstElementPtr> ConfigPair;
-    try {
-        BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
-            // We should eventually integrate the sqlite3 DB configuration to
-            // this framework, but to minimize diff we begin with skipping that
-            // part.
-            if (config_pair.first == "database_file") {
-                continue;
-            }
-
-            ParserPtr parser(createAuthConfigParser(server,
-                                                    config_pair.first));
-            parser->build(config_pair.second);
-            parsers.push_back(parser);
-        }
-    } catch (const AuthConfigError& ex) {
-        throw;                  // simply rethrowing it
-    } catch (const isc::Exception& ex) {
-        isc_throw(AuthConfigError, "Server configuration failed: " <<
-                  ex.what());
-    }
-
-    try {
-        BOOST_FOREACH(ParserPtr parser, parsers) {
-            parser->commit();
-        }
-    } catch (...) {
-        throw FatalError("Unrecoverable error: "
-                         "a configuration parser threw in commit");
-    }
-}
diff --git a/src/bin/auth/config.h b/src/bin/auth/config.h
deleted file mode 100644
index 6f18810..0000000
--- a/src/bin/auth/config.h
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-
-#include <exceptions/exceptions.h>
-
-#include <cc/data.h>
-
-#ifndef __CONFIG_H
-#define __CONFIG_H 1
-
-class AuthSrv;
-
-/// An exception that is thrown if an error occurs while configuring an
-/// \c AuthSrv object.
-class AuthConfigError : public isc::Exception {
-public:
-    AuthConfigError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-/// The abstract base class that represents a single configuration identifier
-/// for an \c AuthSrv object.
-///
-/// In general, each top level configuration identifier for \c AuthSrv is
-/// expected to have its own derived class of this base class.
-/// For example, for the following configuration:
-/// \code { "param1": 10, "param2": { "subparam1": "foo", "subparam2": [] } }
-/// \endcode
-/// "param1" and "param2" are top level identifiers, and would correspond to
-/// derived \c AuthConfigParser classes.
-/// "subparam1" and/or "subparam2" may also have dedicated derived classes.
-///
-/// These derived classes are hidden inside the implementation; applications
-/// are not expected to (and in fact cannot) instantiate them directly.
-///
-/// Each derived class is generally expected to be constructed with an
-/// \c AuthSrv object to be configured and hold a reference to the server
-/// throughout the configuration process.
-/// For each derived class, the \c build() method parses the configuration
-/// value for the corresponding identifier and prepares new configuration
-/// value(s) to be applied to the server.  This method may throw an exception
-/// when it encounters an error.
-/// The \c commit() method actually applies the new configuration value
-/// to the server.  It's basically not expected to throw an exception;
-/// any configuration operations that can fail (such as ones involving
-/// resource allocation) should be done in \c build().
-///
-/// When the destructor is called before \c commit(), the destructor is
-/// supposed to make sure the state of the \c AuthSrv object is the same
-/// as that before it starts building the configuration value.
-/// If \c build() doesn't change the server state (which is recommended)
-/// the destructor doesn't have to do anything special in this regard.
-/// This is a key to ensure the strong exception guarantee (see also
-/// the description of \c configureAuthServer()).
-class AuthConfigParser {
-    ///
-    /// \name Constructors and Destructor
-    ///
-    /// Note: The copy constructor and the assignment operator are
-    /// intentionally defined as private to make it explicit that this is a
-    /// pure base class.
-    //@{
-private:
-    AuthConfigParser(const AuthConfigParser& source);
-    AuthConfigParser& operator=(const AuthConfigParser& source);
-protected:
-    /// \brief The default constructor.
-    ///
-    /// This is intentionally defined as \c protected as this base class should
-    /// never be instantiated (except as part of a derived class).
-    AuthConfigParser() {}
-public:
-    /// The destructor.
-    virtual ~AuthConfigParser() {}
-    //@}
-
-    /// Prepare configuration value.
-    ///
-    /// This method parses the "value part" of the configuration identifier
-    /// that corresponds to this derived class and prepares a new value to
-    /// apply to the server.
-    /// In the above example, the derived class for the identifier "param1"
-    /// would be passed an data \c Element storing an integer whose value
-    /// is 10, and would record that value internally;
-    /// the derived class for the identifier "param2" would be passed a
-    /// map element and (after parsing) convert it into some internal
-    /// data structure.
-    ///
-    /// This method must validate the given value both in terms of syntax
-    /// and semantics of the configuration, so that the server will be
-    /// validly configured at the time of \c commit().  Note: the given
-    /// configuration value is normally syntactically validated, but the
-    /// \c build() implementation must also expect invalid input.  If it
-    /// detects an error it may throw an exception of a derived class
-    /// of \c isc::Exception.
-    ///
-    /// Preparing a configuration value will often require resource
-    /// allocation.  If it fails, it may throw a corresponding standard
-    /// exception.
-    ///
-    /// This method is not expected to be called more than once.  Although
-    /// multiple calls are not prohibited by the interface, the behavior
-    /// is undefined.
-    ///
-    /// \param config_value The configuration value for the identifier
-    /// corresponding to the derived class.
-    virtual void build(isc::data::ConstElementPtr config_value) = 0;
-
-    /// Apply the prepared configuration value to the server.
-    ///
-    /// This method is expected to be exception free, and, as a consequence,
-    /// it should normally not involve resource allocation.
-    /// Typically it would simply perform exception free assignment or swap
-    /// operation on the value prepared in \c build().
-    /// In some cases, however, it may be very difficult to meet this
-    /// condition in a realistic way, while the failure case should really
-    /// be very rare.  In such a case it may throw, and, if the parser is
-    /// called via \c configureAuthServer(), the caller will convert the
-    /// exception as a fatal error.
-    ///
-    /// This method is expected to be called after \c build(), and only once.
-    /// The result is undefined otherwise.
-    virtual void commit() = 0;
-};
-
-/// Configure an \c AuthSrv object with a set of configuration values.
-///
-/// This function parses configuration information stored in \c config_set
-/// and configures the \c server by applying the configuration to it.
-/// It provides the strong exception guarantee as long as the underlying
-/// derived class implementations of \c AuthConfigParser meet the assumption,
-/// that is, it ensures that either configuration is fully applied or the
-/// state of the server is intact.
-///
-/// If a syntax or semantics level error happens during the configuration
-/// (such as malformed configuration or invalid configuration parameter),
-/// this function throws an exception of class \c AuthConfigError.
-/// If the given configuration requires resource allocation and it fails,
-/// a corresponding standard exception will be thrown.
-/// Other exceptions may also be thrown, depending on the implementation of
-/// the underlying derived class of \c AuthConfigError.
-/// In any case the strong guarantee is provided as described above except
-/// in the very rare cases where the \c commit() method of a parser throws
-/// an exception.  If that happens this function converts the exception
-/// into a \c FatalError exception and rethrows it.  This exception is
-/// expected to be caught at the highest level of the application to terminate
-/// the program gracefully.
-///
-/// \param server The \c AuthSrv object to be configured.
-/// \param config_set A JSON style configuration to apply to \c server.
-void configureAuthServer(AuthSrv& server,
-                         isc::data::ConstElementPtr config_set);
-
-/// Create a new \c AuthConfigParser object for a given configuration
-/// identifier.
-///
-/// It internally identifies an appropriate derived class for the given
-/// identifier and creates a new instance of that class.  The caller can
-/// then configure the \c server regarding the identifier by calling
-/// the \c build() and \c commit() methods of the returned object.
-///
-/// In practice, this function is only expected to be used as a backend of
-/// \c configureAuthServer() and is not supposed to be called directly
-/// by applications.  It is publicly available mainly for testing purposes.
-/// When called directly, the created object must be deleted by the caller.
-/// Note: this means if this module and the caller use incompatible sets of
-/// new/delete, it may cause unexpected strange failure.  We could avoid that
-/// by providing a separate deallocation function or by using a smart pointer,
-/// but since the expected usage of this function is very limited (i.e. for
-/// our own testing purposes) it would be an overkilling.  We therefore prefer
-/// simplicity and keeping the interface intuitive.
-///
-/// If the resource allocation for the new object fails, a corresponding
-/// standard exception will be thrown.  Otherwise this function is not
-/// expected to throw an exception, unless the constructor of the underlying
-/// derived class implementation (unexpectedly) throws.
-///
-/// \param server The \c AuthSrv object to be configured.
-/// \param config_id The configuration identifier for which a parser object
-/// is to be created.
-/// \return A pointer to an \c AuthConfigParser object.
-AuthConfigParser* createAuthConfigParser(AuthSrv& server,
-                                         const std::string& config_id);
-
-#endif // __CONFIG_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index fad4a72..480c2f7 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/select.h>
@@ -25,7 +27,8 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
 
@@ -37,10 +40,11 @@
 
 #include <auth/spec_config.h>
 #include <auth/common.h>
-#include <auth/config.h>
+#include <auth/auth_config.h>
 #include <auth/command.h>
 #include <auth/change_user.h>
 #include <auth/auth_srv.h>
+#include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 #include <log/dummylog.h>
 
@@ -49,8 +53,10 @@ using namespace isc::data;
 using namespace isc::cc;
 using namespace isc::config;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::xfr;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
 
 namespace {
 
@@ -120,19 +126,7 @@ main(int argc, char* argv[]) {
     bool xfrin_session_established = false; // XXX (see Trac #287)
     bool statistics_session_established = false; // XXX (see Trac #287)
     ModuleCCSession* config_session = NULL;
-    string xfrout_socket_path;
-    if (getenv("B10_FROM_BUILD") != NULL) {
-        if (getenv("B10_FROM_SOURCE_LOCALSTATEDIR")) {
-            xfrout_socket_path = string("B10_FROM_SOURCE_LOCALSTATEDIR") +
-                "/auth_xfrout_conn";
-        } else {
-            xfrout_socket_path = string(getenv("B10_FROM_BUILD")) +
-                "/auth_xfrout_conn";
-        }
-    } else {
-        xfrout_socket_path = UNIX_SOCKET_FILE;
-    }
-    XfroutClient xfrout_client(xfrout_socket_path);
+    XfroutClient xfrout_client(getXfroutSocketPath());
     try {
         string specfile;
         if (getenv("B10_FROM_BUILD")) {
@@ -182,9 +176,15 @@ main(int argc, char* argv[]) {
         // all initial configurations, but as a short term workaround we
         // handle the traditional "database_file" setup by directly calling
         // updateConfig().
+        // if server load configure failed, we won't exit, give user second chance
+        // to correct the configure.
         auth_server->setConfigSession(config_session);
-        configureAuthServer(*auth_server, config_session->getFullConfig());
-        auth_server->updateConfig(ElementPtr());
+        try {
+            configureAuthServer(*auth_server, config_session->getFullConfig());
+            auth_server->updateConfig(ElementPtr());
+        } catch (const AuthConfigError& ex) {
+            cout << "[bin10-auth] Server load config failed:" << ex.what() << endl;
+        }
 
         if (uid != NULL) {
             changeUser(uid);
diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc
index e68793c..415aa14 100644
--- a/src/bin/auth/statistics.cc
+++ b/src/bin/auth/statistics.cc
@@ -91,10 +91,6 @@ AuthCountersImpl::submitStatistics() const {
         const int seq =
             statistics_session_->group_sendmsg(statistics_element, "Stats");
         isc::data::ConstElementPtr env, answer;
-        if (verbose_mode_) {
-            std::cerr << "[b10-auth] "
-                      << "send statistics data" << std::endl;
-        }
         // TODO: parse and check response from statistics module
         // currently it just returns empty message
         statistics_session_->group_recvmsg(env, answer, false, seq);
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 7d489a1..050373a 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -1,4 +1,5 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += $(BOOST_INCLUDES)
@@ -16,18 +17,21 @@ CLEANFILES = *.gcno *.gcda
 
 TESTS =
 if HAVE_GTEST
+
 TESTS += run_unittests
 run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
 run_unittests_SOURCES += ../auth_srv.h ../auth_srv.cc
 run_unittests_SOURCES += ../query.h ../query.cc
 run_unittests_SOURCES += ../change_user.h ../change_user.cc
-run_unittests_SOURCES += ../config.h ../config.cc
+run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
 run_unittests_SOURCES += ../command.h ../command.cc
+run_unittests_SOURCES += ../common.h ../common.cc
 run_unittests_SOURCES += ../statistics.h ../statistics.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
 run_unittests_SOURCES += config_unittest.cc
 run_unittests_SOURCES += command_unittest.cc
+run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += change_user_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
@@ -39,6 +43,7 @@ run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 379342e..a77f7e6 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -41,10 +41,12 @@
 using namespace std;
 using namespace isc::cc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::xfr;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 using namespace isc::testutils;
 using namespace isc::server_common::portconfig;
 using isc::UnitTestUtil;
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index f788d9e..3fdd086 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <cassert>
 #include <cstdlib>
 #include <string>
@@ -32,7 +34,7 @@
 #include <datasrc/memory_datasrc.h>
 
 #include <auth/auth_srv.h>
-#include <auth/config.h>
+#include <auth/auth_config.h>
 #include <auth/command.h>
 
 #include <asiolink/asiolink.h>
@@ -97,7 +99,7 @@ AuthConmmandTest::stopServer() {
 }
 
 TEST_F(AuthConmmandTest, shutdown) {
-    asiolink::IntervalTimer itimer(server.getIOService());
+    isc::asiolink::IntervalTimer itimer(server.getIOService());
     itimer.setup(boost::bind(&AuthConmmandTest::stopServer, this), 1);
     server.getIOService().run();
     EXPECT_EQ(0, rcode);
diff --git a/src/bin/auth/tests/common_unittest.cc b/src/bin/auth/tests/common_unittest.cc
new file mode 100644
index 0000000..9b18142
--- /dev/null
+++ b/src/bin/auth/tests/common_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <auth/common.h>
+#include <auth/spec_config.h>
+#include <vector>
+#include <string>
+#include <cstdio>
+#include <boost/foreach.hpp>
+
+using std::pair;
+using std::vector;
+using std::string;
+
+namespace {
+
+class Paths : public ::testing::Test {
+private:
+    typedef pair<string, string*> Environ;
+    vector<Environ> restoreEnviron;
+public:
+    void TearDown() {
+        // Restore the original environment
+        BOOST_FOREACH(const Environ &env, restoreEnviron) {
+            if (env.second == NULL) {
+                EXPECT_EQ(0, unsetenv(env.first.c_str())) <<
+                    "Couldn't restore environment, results of other tests"
+                    "are uncertain";
+            } else {
+                EXPECT_EQ(0, setenv(env.first.c_str(), env.second->c_str(),
+                                    1)) << "Couldn't restore environment, "
+                    "results of other tests are uncertain";
+            }
+        }
+    }
+protected:
+    // Sets a temporary value into environment. If value is empty, it deletes
+    // the variable from environment (just for simplicity).
+    void setEnv(const string& name, const string& value) {
+        // Backup the original environment
+        char* env(getenv(name.c_str()));
+        restoreEnviron.push_back(Environ(name, env == NULL ? NULL :
+                                         new string(env)));
+        // Set the new value
+        if (value.empty()) {
+            EXPECT_EQ(0, unsetenv(name.c_str()));
+        } else {
+            EXPECT_EQ(0, setenv(name.c_str(), value.c_str(), 1));
+        }
+    }
+    // Test getXfroutSocketPath under given environment
+    void testXfrout(const string& fromBuild, const string& localStateDir,
+                    const string& socketFile, const string& expected)
+    {
+        setEnv("B10_FROM_BUILD", fromBuild);
+        setEnv("B10_FROM_SOURCE_LOCALSTATEDIR", localStateDir);
+        setEnv("BIND10_XFROUT_SOCKET_FILE", socketFile);
+        EXPECT_EQ(expected, getXfroutSocketPath());
+    }
+};
+
+// Test that when we have no special environment, we get the default from prefix
+TEST_F(Paths, xfroutNoEnv) {
+    testXfrout("", "", "", UNIX_SOCKET_FILE);
+}
+
+// Override by B10_FROM_BUILD
+TEST_F(Paths, xfroutFromBuild) {
+    testXfrout("/from/build", "", "/wrong/path",
+               "/from/build/auth_xfrout_conn");
+}
+
+// Override by B10_FROM_SOURCE_LOCALSTATEDIR
+TEST_F(Paths, xfroutLocalStatedir) {
+    testXfrout("/wrong/path", "/state/dir", "/wrong/path",
+               "/state/dir/auth_xfrout_conn");
+}
+
+// Override by BIND10_XFROUT_SOCKET_FILE explicitly
+TEST_F(Paths, xfroutFromEnv) {
+    testXfrout("", "", "/the/path/to/file", "/the/path/to/file");
+}
+
+}
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 8cce0af..7658b84 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -26,7 +26,7 @@
 #include <xfr/xfrout_client.h>
 
 #include <auth/auth_srv.h>
-#include <auth/config.h>
+#include <auth/auth_config.h>
 #include <auth/common.h>
 
 #include <testutils/mockups.h>
@@ -35,7 +35,8 @@
 using namespace isc::dns;
 using namespace isc::data;
 using namespace isc::datasrc;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 
 namespace {
 class AuthConfigTest : public ::testing::Test {
diff --git a/src/bin/bind10/bind10.8 b/src/bin/bind10/bind10.8
index b275f2d..d5ab905 100644
--- a/src/bin/bind10/bind10.8
+++ b/src/bin/bind10/bind10.8
@@ -2,12 +2,12 @@
 .\"     Title: bind10
 .\"    Author: [see the "AUTHORS" section]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: February 22, 2011
+.\"      Date: March 31, 2011
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "BIND10" "8" "February 22, 2011" "BIND10" "BIND10"
+.TH "BIND10" "8" "March 31, 2011" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -22,7 +22,7 @@
 bind10 \- BIND 10 boss process
 .SH "SYNOPSIS"
 .HP \w'\fBbind10\fR\ 'u
-\fBbind10\fR [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-brittle\fR] [\fB\-\-verbose\fR]
+\fBbind10\fR [\fB\-c\ \fR\fB\fIconfig\-filename\fR\fR] [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-p\ \fR\fB\fIdata_path\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-brittle\fR] [\fB\-\-cmdctl\-port\fR\ \fIport\fR] [\fB\-\-config\-file\fR\ \fIconfig\-filename\fR] [\fB\-\-data\-path\fR\ \fIdirectory\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-pid\-file\fR\ \fIfilename\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-verbose\fR]
 .SH "DESCRIPTION"
 .PP
 The
@@ -32,6 +32,34 @@ daemon starts up other BIND 10 required daemons\&. It handles restarting of exit
 .PP
 The arguments are as follows:
 .PP
+\fB\-\-brittle\fR
+.RS 4
+Shutdown if any of the child processes of
+\fBbind10\fR
+exit\&. This is intended to help developers debug the server, and should not be used in production\&.
+.RE
+.PP
+\fB\-c\fR \fIconfig\-filename\fR, \fB\-\-config\-file\fR \fIconfig\-filename\fR
+.RS 4
+The configuration filename to use\&. Can be either absolute or relative to data path\&. In case it is absolute, value of data path is not considered\&.
+.sp
+Defaults to b10\-config\&.db\&.
+.RE
+.PP
+\fB\-\-cmdctl\-port\fR \fIport\fR
+.RS 4
+The
+\fBb10\-cmdctl\fR
+daemon will listen on this port\&. (See
+b10\-cmdctl(8)
+for the default\&.)
+.RE
+.PP
+\fB\-p\fR \fIdirectory\fR, \fB\-\-data\-path\fR \fIdirectory\fR
+.RS 4
+The path where BIND 10 programs look for various data files\&. Currently only b10\-cfgmgr uses it to locate the configuration file, but the usage might be extended for other programs and other types of files\&.
+.RE
+.PP
 \fB\-m\fR \fIfile\fR, \fB\-\-msgq\-socket\-file\fR \fIfile\fR
 .RS 4
 The UNIX domain socket file for the
@@ -57,6 +85,13 @@ to run as\&.
 must be initially ran as the root user to use this option\&. The default is to run as the current user\&.
 .RE
 .PP
+\fB\-\-pid\-file\fR \fIfilename\fR
+.RS 4
+If defined, the PID of the
+\fBbind10\fR
+is stored in this file\&. This is used for testing purposes\&.
+.RE
+.PP
 \fB\-\-pretty\-name \fR\fB\fIname\fR\fR
 .RS 4
 The name this process should have in tools like
@@ -66,14 +101,6 @@ or
 \fBbind10\fR\&.
 .RE
 .PP
-\fB\-\-brittle\fR
-.RS 4
-Shutdown if any of the child processes of 
-\fBbind10\fR
-exit\&. This is intended to help developers debug the server, and should
-not be used in production.
-.RE
-.PP
 \fB\-v\fR, \fB\-\-verbose\fR
 .RS 4
 Display more about what is going on for
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 9224ffa..648d085 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -297,7 +297,7 @@ class BoB:
 
     def command_handler(self, command, args):
         if self.verbose:
-            sys.stdout.write("[bind10] Boss got command: " + command + "\n")
+            sys.stdout.write("[bind10] Boss got command: " + str(command) + "\n")
         answer = isc.config.ccsession.create_answer(1, "command not implemented")
         if type(command) != str:
             answer = isc.config.ccsession.create_answer(1, "bad command")
@@ -305,6 +305,15 @@ class BoB:
             if command == "shutdown":
                 self.runnable = False
                 answer = isc.config.ccsession.create_answer(0)
+            elif command == "sendstats":
+                # send statistics data to the stats daemon immediately
+                cmd = isc.config.ccsession.create_command(
+                    'set', { "stats_data": {
+                            'bind10.boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
+                            }})
+                seq = self.cc_session.group_sendmsg(cmd, 'Stats')
+                self.cc_session.group_recvmsg(True, seq)
+                answer = isc.config.ccsession.create_answer(0)
             elif command == "ping":
                 answer = isc.config.ccsession.create_answer(0, "pong")
             elif command == "show_processes":
@@ -537,6 +546,9 @@ class BoB:
     def start_stats(self, c_channel_env):
         self.start_simple("b10-stats", c_channel_env)
 
+    def start_stats_httpd(self, c_channel_env):
+        self.start_simple("b10-stats-httpd", c_channel_env)
+
     def start_cmdctl(self, c_channel_env):
         """
             Starts the command control process
@@ -586,6 +598,7 @@ class BoB:
 
         # ... and finally start the remaining processes
         self.start_stats(c_channel_env)
+        self.start_stats_httpd(c_channel_env)
         self.start_cmdctl(c_channel_env)
     
     def startup(self):
@@ -635,6 +648,7 @@ class BoB:
         self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
         self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
         self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
+        self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
 
     def stop_process(self, process, recipient):
         """
@@ -977,17 +991,6 @@ def main():
     sys.stdout.write("[bind10] BIND 10 started\n")
     dump_pid(options.pid_file)
 
-    # send "bind10.boot_time" to b10-stats
-    time.sleep(1) # wait a second
-    if options.verbose:
-        sys.stdout.write("[bind10] send \"bind10.boot_time\" to b10-stats\n")
-    cmd = isc.config.ccsession.create_command('set', 
-            { "stats_data": {
-              'bind10.boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
-              }
-            })
-    boss_of_bind.cc_session.group_sendmsg(cmd, 'Stats')
-
     # In our main loop, we check for dead processes or messages 
     # on the c-channel.
     wakeup_fd = wakeup_pipe[0]
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index 6331503..1128264 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>February 22, 2011</date>
+    <date>March 31, 2011</date>
   </refentryinfo>
 
   <refmeta>
@@ -44,16 +44,21 @@
   <refsynopsisdiv>
     <cmdsynopsis>
       <command>bind10</command>
+      <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
       <arg><option>-m <replaceable>file</replaceable></option></arg>
       <arg><option>-n</option></arg>
+      <arg><option>-p <replaceable>data_path</replaceable></option></arg>
       <arg><option>-u <replaceable>user</replaceable></option></arg>
       <arg><option>-v</option></arg>
-      <arg><option>-c<replaceable>config-filename</replaceable></option></arg>
-      <arg><option>-p<replaceable>data_path</replaceable></option></arg>
+      <arg><option>--brittle</option></arg>
+      <arg><option>--cmdctl-port</option> <replaceable>port</replaceable></arg>
+      <arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
+      <arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
       <arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
       <arg><option>--no-cache</option></arg>
-      <arg><option>--user <replaceable>user</replaceable></option></arg>
+      <arg><option>--pid-file</option> <replaceable>filename</replaceable></arg>
       <arg><option>--pretty-name <replaceable>name</replaceable></option></arg>
+      <arg><option>--user <replaceable>user</replaceable></option></arg>
       <arg><option>--verbose</option></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -82,9 +87,24 @@
     <para>The arguments are as follows:</para>
 
     <variablelist>
+
+      <varlistentry>
+        <term>
+          <option>--brittle</option>
+        </term>
+        <listitem>
+          <para>
+	    Shutdown if any of the child processes of
+	    <command>bind10</command> exit.  This is intended to
+	    help developers debug the server, and should not be
+	    used in production.
+          </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>
-          <option>-c</option><replaceable>config-filename</replaceable>,
+          <option>-c</option> <replaceable>config-filename</replaceable>,
           <option>--config-file</option> <replaceable>config-filename</replaceable>
         </term>
         <listitem>
@@ -97,8 +117,22 @@
 
       <varlistentry>
         <term>
-          <option>-p</option><replaceable>data-path</replaceable>,
-          <option>--data-path</option> <replaceable>data-path</replaceable>
+          <option>--cmdctl-port</option> <replaceable>port</replaceable>
+        </term>
+        <listitem>
+	  <para>The <command>b10-cmdctl</command> daemon will listen
+	    on this port.
+	    (See
+	    <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
+            for the default.)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-p</option> <replaceable>directory</replaceable>,
+          <option>--data-path</option> <replaceable>directory</replaceable>
         </term>
         <listitem>
           <para>The path where BIND 10 programs look for various data files.
@@ -134,7 +168,6 @@
 
       <varlistentry>
         <term><option>-u</option> <replaceable>user</replaceable>, <option>--user</option> <replaceable>name</replaceable></term>
-
         <listitem>
           <para>The username for <command>bind10</command> to run as.
 <!-- TODO: example more detail. -->
@@ -145,6 +178,16 @@
       </varlistentry>
 
       <varlistentry>
+        <term><option>--pid-file</option> <replaceable>filename</replaceable></term>
+        <listitem>
+          <para>If defined, the PID of the <command>bind10</command> is stored
+             in this file.
+             This is used for testing purposes.
+          </para>
+         </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--pretty-name <replaceable>name</replaceable></option></term>
 
         <listitem>
diff --git a/src/bin/bind10/bob.spec b/src/bin/bind10/bob.spec
index c206b34..1184fd1 100644
--- a/src/bin/bind10/bob.spec
+++ b/src/bin/bind10/bob.spec
@@ -23,6 +23,11 @@
         "command_args": []
       },
       {
+        "command_name": "sendstats",
+        "command_description": "Send data to a statistics module at once",
+        "command_args": []
+      },
+      {
         "command_name": "ping",
         "command_description": "Ping the boss process",
         "command_args": []
diff --git a/src/bin/bind10/run_bind10.sh.in b/src/bin/bind10/run_bind10.sh.in
old mode 100644
new mode 100755
index edc01fe..89301bd
--- a/src/bin/bind10/run_bind10.sh.in
+++ b/src/bin/bind10/run_bind10.sh.in
@@ -23,14 +23,14 @@ BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
 export PATH
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
 # required by loadable python modules.
 SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
 if test $SET_ENV_LIBRARY_PATH = yes; then
-	@ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
+	@ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/cryptolink/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
 	export @ENV_LIBRARY_PATH@
 fi
 
diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am
index d05d977..34d809a 100644
--- a/src/bin/bind10/tests/Makefile.am
+++ b/src/bin/bind10/tests/Makefile.am
@@ -1,5 +1,6 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 #PYTESTS = args_test.py bind10_test.py
+# NOTE: this has a generated test found in the builddir
 PYTESTS = bind10_test.py
 EXTRA_DIST = $(PYTESTS)
 
@@ -14,5 +15,5 @@ endif
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
 	BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
-		$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+		$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
 	done
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 2d58b61..2ffe2b4 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -13,7 +13,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-from bind10 import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file
+from bind10 import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file, _BASETIME
 
 # XXX: environment tests are currently disabled, due to the preprocessor
 #      setup that we have now complicating the environment
@@ -24,6 +24,9 @@ import os
 import signal
 import socket
 from isc.net.addr import IPAddr
+import time
+import isc
+
 from isc.testutils.parse_args import TestOptParser, OptsError
 
 class TestProcessInfo(unittest.TestCase):
@@ -123,6 +126,41 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.cfg_start_auth, True)
         self.assertEqual(bob.cfg_start_resolver, False)
 
+    def test_command_handler(self):
+        class DummySession():
+            def group_sendmsg(self, msg, group):
+                (self.msg, self.group) = (msg, group)
+            def group_recvmsg(self, nonblock, seq): pass
+        bob = BoB()
+        bob.verbose = True
+        bob.cc_session = DummySession()
+        # a bad command
+        self.assertEqual(bob.command_handler(-1, None),
+                         isc.config.ccsession.create_answer(1, "bad command"))
+        # "shutdown" command
+        self.assertEqual(bob.command_handler("shutdown", None),
+                         isc.config.ccsession.create_answer(0))
+        self.assertFalse(bob.runnable)
+        # "sendstats" command
+        self.assertEqual(bob.command_handler("sendstats", None),
+                         isc.config.ccsession.create_answer(0))
+        self.assertEqual(bob.cc_session.group, "Stats")
+        self.assertEqual(bob.cc_session.msg,
+                         isc.config.ccsession.create_command(
+                'set', { "stats_data": {
+                        'bind10.boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
+                        }}))
+        # "ping" command
+        self.assertEqual(bob.command_handler("ping", None),
+                         isc.config.ccsession.create_answer(0, "pong"))
+        # "show_processes" command
+        self.assertEqual(bob.command_handler("show_processes", None),
+                         isc.config.ccsession.create_answer(0,
+                                                            bob.get_processes()))
+        # an unknown command
+        self.assertEqual(bob.command_handler("__UNKNOWN__", None),
+                         isc.config.ccsession.create_answer(1, "Unknown command"))
+
 # Class for testing the BoB without actually starting processes.
 # This is used for testing the start/stop components routines and
 # the BoB commands.
@@ -145,6 +183,7 @@ class MockBob(BoB):
         self.xfrin = False
         self.zonemgr = False
         self.stats = False
+        self.stats_httpd = False
         self.cmdctl = False
         self.c_channel_env = {}
         self.processes = { }
@@ -198,10 +237,15 @@ class MockBob(BoB):
         self.processes[10] = ProcessInfo('b10-stats', ['/bin/false'])
         self.processes[10].pid = 10
 
+    def start_stats_httpd(self, c_channel_env):
+        self.stats_httpd = True
+        self.processes[11] = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+        self.processes[11].pid = 11
+
     def start_cmdctl(self, c_channel_env):
         self.cmdctl = True
-        self.processes[11] = ProcessInfo('b10-cmdctl', ['/bin/false'])
-        self.processes[11].pid = 11
+        self.processes[12] = ProcessInfo('b10-cmdctl', ['/bin/false'])
+        self.processes[12].pid = 12
 
     # We don't really use all of these stop_ methods. But it might turn out
     # someone would add some stop_ method to BoB and we want that one overriden
@@ -251,9 +295,14 @@ class MockBob(BoB):
             del self.processes[10]
         self.stats = False
 
+    def stop_stats_httpd(self):
+        if self.stats_httpd:
+            del self.processes[11]
+        self.stats_httpd = False
+
     def stop_cmdctl(self):
         if self.cmdctl:
-            del self.processes[11]
+            del self.processes[12]
         self.cmdctl = False
 
 class TestStartStopProcessesBob(unittest.TestCase):
@@ -278,6 +327,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
         self.assertEqual(bob.xfrin, auth)
         self.assertEqual(bob.zonemgr, auth)
         self.assertEqual(bob.stats, core)
+        self.assertEqual(bob.stats_httpd, core)
         self.assertEqual(bob.cmdctl, core)
 
     def check_preconditions(self, bob):
@@ -506,7 +556,8 @@ class TestBossCmd(unittest.TestCase):
                      [8, 'b10-xfrin'], 
                      [9, 'b10-zonemgr'],
                      [10, 'b10-stats'], 
-                     [11, 'b10-cmdctl']]
+                     [11, 'b10-stats-httpd'], 
+                     [12, 'b10-cmdctl']]
         self.assertEqual(answer, {'result': [0, processes]})
 
 class TestParseArgs(unittest.TestCase):
diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am
index a41448b..fc0ed4a 100644
--- a/src/bin/cfgmgr/Makefile.am
+++ b/src/bin/cfgmgr/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . plugins tests
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 5355582..d91dfca 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -18,30 +18,21 @@
 import sys; sys.path.append ('@@PYTHONPATH@@')
 
 from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
+import bind10_config
 from isc.cc import SessionError
 import isc.util.process
 import signal
 import os
 from optparse import OptionParser
+import glob
+import os.path
 
 isc.util.process.rename()
 
-# If B10_FROM_SOURCE is set in the environment, we use data files
-# from a directory relative to the value of that variable, or, if defined,
-# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR.  Otherwise
-# we use the ones installed on the system.
-# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
-# tests where we want to use variuos types of configuration within the test
-# environment.  (We may want to make it even more generic so that the path is
-# passed from the boss process)
-if "B10_FROM_SOURCE" in os.environ:
-    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
-        DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
-    else:
-        DATA_PATH = os.environ["B10_FROM_SOURCE"]
-else:
-    PREFIX = "@prefix@"
-    DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
+# Import some paths from our configuration
+DATA_PATH = bind10_config.DATA_PATH
+PLUGIN_PATHS = bind10_config.PLUGIN_PATHS
+PREFIX = bind10_config.PREFIX
 DEFAULT_CONFIG_FILE = "b10-config.db"
 
 cm = None
@@ -65,6 +56,28 @@ def signal_handler(signal, frame):
     if cm:
         cm.running = False
 
+def load_plugins(path, cm):
+    """Load all python files in the given path and treat them as plugins."""
+    # Find the python files
+    plugins = glob.glob(path + os.sep + '*.py')
+    # Search this directory first, but leave the others there for the imports
+    # of the modules
+    sys.path.insert(0, path)
+    try:
+        for plugin in plugins:
+            # Generate the name of the plugin
+            filename = os.path.basename(plugin)
+            name = filename[:-3]
+            # Load it
+            module = __import__(name)
+            # Ask it to provide the spec and checking function
+            (spec, check_func) = module.load()
+            # And insert it into the manager
+            cm.set_virtual_module(spec, check_func)
+    finally:
+        # Restore the search path
+        sys.path = sys.path[1:]
+
 def main():
     options = parse_options()
     global cm
@@ -73,6 +86,8 @@ def main():
         signal.signal(signal.SIGINT, signal_handler)
         signal.signal(signal.SIGTERM, signal_handler)
         cm.read_config()
+        for ppath in PLUGIN_PATHS:
+            load_plugins(ppath, cm)
         cm.notify_boss()
         cm.run()
     except SessionError as se:
diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am
new file mode 100644
index 0000000..d83c2bb
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = tests
+EXTRA_DIST = README tsig_keys.py tsig_keys.spec
+
+config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
+config_plugin_DATA = tsig_keys.py tsig_keys.spec
diff --git a/src/bin/cfgmgr/plugins/README b/src/bin/cfgmgr/plugins/README
new file mode 100644
index 0000000..27fb0c0
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/README
@@ -0,0 +1,34 @@
+How to write a configuration plugin
+===================================
+
+The plugins are used to describe configuration modules that have no hosting
+process. Therefore there's no process to provide their specification and to
+check them for correctness. So the plugin takes this responsibility.
+
+Each plugin is a python file installed into the
+`@prefix@/share/@PACKAGE@/config_plugins` directory (usually
+`/usr/share/bind10/config_plugins`). It is loaded automatically at startup.
+
+The entrypoint of a plugin is function called `load()`. It should return a
+tuple, first value should be the module specification (usually instance of
+`isc.config.module_spec.ModuleSpec`, loaded by `module_spec_from_file()`).
+
+The second value is a callable object. It will be called whenever the
+configuration of module needs to be checked. The only parameter will be the new
+config (as python dictionary). To accept the new configuration, return None. If
+you return a string, it is taken as an error message. If you raise an
+exception, the config is rejected as well, however it is not considered a
+graceful rejection, but a failure of the module.
+
+So, this is how a plugin could look like:
+
+  from isc.config.module_spec import module_spec_from_file
+
+  def check(config):
+      if config['bogosity'] > 1:
+          return "Too bogus to live with"
+      else:
+          return None
+
+  def load():
+      return (module_spec_from_file('module_spec.spec'), check)
diff --git a/src/bin/cfgmgr/plugins/tests/Makefile.am b/src/bin/cfgmgr/plugins/tests/Makefile.am
new file mode 100644
index 0000000..896dab7
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tests/Makefile.am
@@ -0,0 +1,27 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+PYTESTS = tsig_keys_test.py
+
+EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs
+endif
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	env B10_TEST_PLUGIN_DIR=$(abs_srcdir)/..:$(abs_builddir)/.. \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr:$(abs_top_builddir)/src/lib/dns/python/.libs \
+	$(LIBRARY_PATH_PLACEHOLDER) \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+	done
+
diff --git a/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py b/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
new file mode 100644
index 0000000..be2921c
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
@@ -0,0 +1,103 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Make sure we can load the module, put it into path
+import sys
+import os
+sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
+
+import tsig_keys
+import unittest
+import isc.config.module_spec
+
+class TSigKeysTest(unittest.TestCase):
+    def test_load(self):
+        """
+        Checks the entry point returns the correct values.
+        """
+        (spec, check) = tsig_keys.load()
+        # It returns the checking function
+        self.assertEqual(check, tsig_keys.check)
+        # The plugin stores it's spec
+        self.assertEqual(spec, tsig_keys.spec)
+
+    def test_spec(self):
+        """
+        Checks the spec is looking sane (doesn't do really deep check here).
+        """
+        spec = tsig_keys.spec
+        # In python, we don't generally check the type of something, because
+        # of the duck typing.
+        # But this is unittest, so we check it does what we intend and
+        # supplying that's behaving the same but is different is not our
+        # intention
+        self.assertTrue(isinstance(spec, isc.config.module_spec.ModuleSpec))
+        # Correct name
+        self.assertEqual("tsig_keys", spec.get_module_name())
+        # There are no commands, nobody would handle them anyway
+        self.assertEqual([], spec.get_commands_spec())
+        # There's some nonempty configuration
+        self.assertNotEqual({}, spec.get_config_spec())
+
+    def test_missing_keys(self):
+        """
+        Test that missing keys doesn't kill us. There are just no keys there.
+        """
+        self.assertEqual(None, tsig_keys.check({}))
+
+    def test_data_empty(self):
+        """Check we accept valid config with empty set of tsig keys."""
+        self.assertEqual(None, tsig_keys.check({'keys': []}))
+
+    def test_keys_valid(self):
+        """
+        Check we accept some valid keys (we don't check all the algorithms,
+        that's the job of isc.dns.TSIGKey).
+        """
+        self.assertEqual(None, tsig_keys.check({'keys':
+            ['testkey:QklORCAxMCBpcyBjb29sCg==',
+             'test.key:QklORCAxMCBpcyBjb29sCg==:hmac-sha1']}))
+
+    def test_keys_same_name(self):
+        """
+        Test we reject when we have multiple keys with the same name.
+        """
+        self.assertEqual("Multiple TSIG keys with name 'test.key.'",
+                         tsig_keys.check({'keys':
+                                         ['test.key:QklORCAxMCBpcyBjb29sCg==',
+                                          'test.key:b3RoZXIK']}))
+
+    def test_invalid_key(self):
+        """
+        Test we reject invalid key.
+        """
+        self.assertEqual("TSIG: Invalid TSIG key string: invalid.key",
+                         tsig_keys.check({'keys': ['invalid.key']}))
+        self.assertEqual(
+            "TSIG: attempt to decode a value not in base64 char set",
+            tsig_keys.check({'keys': ['invalid.key:123']}))
+
+    def test_bad_format(self):
+        """
+        Test we fail on bad format. We don't really care much how here, though,
+        as this should not get in trough config manager anyway.
+        """
+        self.assertNotEqual(None, tsig_keys.check({'bad_name': {}}))
+        self.assertNotEqual(None, tsig_keys.check({'keys': 'not_list'}))
+        self.assertNotEqual(None, tsig_keys.check({'keys': 42}))
+        self.assertNotEqual(None, tsig_keys.check({'keys': {}}))
+
+if __name__ == '__main__':
+        unittest.main()
diff --git a/src/bin/cfgmgr/plugins/tsig_keys.py b/src/bin/cfgmgr/plugins/tsig_keys.py
new file mode 100644
index 0000000..d57e645
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tsig_keys.py
@@ -0,0 +1,50 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# This is the plugin for tsig_keys configuration section. The TSIG keyring
+# lives there (eg. all the shared secrets, with some exceptions where there
+# are some TSIG keys elsewhere, but these should be removed soon). We do
+# sanity checking of user configuration here, simply by trying to construct
+# all the keys here.
+
+from isc.config.module_spec import module_spec_from_file
+from isc.util.file import path_search
+from pydnspp import TSIGKey, InvalidParameter
+from bind10_config import PLUGIN_PATHS
+spec = module_spec_from_file(path_search('tsig_keys.spec', PLUGIN_PATHS))
+
+def check(config):
+    # Check the data layout first
+    errors=[]
+    if not spec.validate_config(False, config, errors):
+        return ' '.join(errors)
+    # Get the list of keys, if any
+    keys = config.get('keys', [])
+    # Run through them, check they can be constructed and there are no
+    # duplicates
+    keyNames = set()
+    for key in keys:
+        try:
+            name = str(TSIGKey(key).get_key_name())
+        except InvalidParameter as e:
+            return "TSIG: " + str(e)
+        if name in keyNames:
+            return "Multiple TSIG keys with name '" + name + "'"
+        keyNames.add(name)
+    # No error found, so let's assume it's OK
+    return None
+
+def load():
+    return (spec, check)
diff --git a/src/bin/cfgmgr/plugins/tsig_keys.spec b/src/bin/cfgmgr/plugins/tsig_keys.spec
new file mode 100644
index 0000000..e558dd2
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tsig_keys.spec
@@ -0,0 +1,21 @@
+{
+    "module_spec": {
+        "module_name": "tsig_keys",
+        "module_description": "The TSIG keyring is stored here",
+        "config_data": [
+            {
+                "item_name": "keys",
+                "item_type": "list",
+                "item_optional": false,
+                "item_default": [],
+                "list_item_spec": {
+                    "item_name": "key",
+                    "item_type": "string",
+                    "item_optional": false,
+                    "item_default": ""
+                }
+            }
+        ],
+        "commands": []
+    }
+}
diff --git a/src/bin/cfgmgr/tests/Makefile.am b/src/bin/cfgmgr/tests/Makefile.am
index 16e6223..68666e6 100644
--- a/src/bin/cfgmgr/tests/Makefile.am
+++ b/src/bin/cfgmgr/tests/Makefile.am
@@ -1,7 +1,7 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = b10-cfgmgr_test.py
 
-EXTRA_DIST = $(PYTESTS)
+EXTRA_DIST = $(PYTESTS) testdata/plugins/testplugin.py
 
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
@@ -12,6 +12,7 @@ if ENABLE_PYTHON_COVERAGE
 endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
+	env TESTDATA_PATH=$(abs_srcdir)/testdata \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
 	$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
 	done
diff --git a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
index 037a106..ea5fc8b 100644
--- a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
+++ b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
@@ -20,6 +20,7 @@
 import unittest
 import os
 import sys
+import bind10_config
 from isc.testutils.parse_args import OptsError, TestOptParser
 
 class MyConfigManager:
@@ -30,6 +31,7 @@ class MyConfigManager:
         self.run_called = False
         self.write_config_called = False
         self.running = True
+        self.virtual_modules = []
 
     def read_config(self):
         self.read_config_called = True
@@ -43,6 +45,24 @@ class MyConfigManager:
     def write_config(self):
         self.write_config_called = True
 
+    def set_virtual_module(self, spec, function):
+        self.virtual_modules.append((spec, function))
+
+class TestPlugins(unittest.TestCase):
+    def test_load_plugins(self):
+        """Test we can successfully find and load the mock plugin."""
+        # Let it load the plugin
+        b = __import__("b10-cfgmgr")
+        # The parameters aren't important for this test
+        cm = MyConfigManager(None, None)
+        b.load_plugins(os.environ['TESTDATA_PATH'] + os.sep + 'plugins', cm)
+        # Check exactly one plugin was loaded and the right data were fed into
+        # the cm
+        self.assertEqual(len(cm.virtual_modules), 1)
+        (spec, check) = cm.virtual_modules[0]
+        self.assertEqual(spec.get_module_name(), "mock_config_plugin")
+        self.assertEqual(check(None), "Mock config plugin")
+
 class TestConfigManagerStartup(unittest.TestCase):
     def test_cfgmgr(self):
         # some creative module use;
@@ -50,13 +70,24 @@ class TestConfigManagerStartup(unittest.TestCase):
         # this also gives us the chance to override the imported
         # module ConfigManager in it.
         b = __import__("b10-cfgmgr")
+        orig_load = b.load_plugins
+        b.PLUGIN_PATHS = ["/plugin/path"]
+        self.loaded_plugins = False
+        def load_plugins(path, cm):
+            # Check it's called with proper arguments
+            self.assertEqual(path, "/plugin/path")
+            self.assertTrue(isinstance(cm, MyConfigManager))
+            self.loaded_plugins = True
+        b.load_plugins = load_plugins
         b.ConfigManager = MyConfigManager
 
         b.main()
+        b.load_plugins = orig_load
 
         self.assertTrue(b.cm.read_config_called)
         self.assertTrue(b.cm.notify_boss_called)
         self.assertTrue(b.cm.run_called)
+        self.assertTrue(self.loaded_plugins)
         # if there are no changes, config is not written
         self.assertFalse(b.cm.write_config_called)
 
@@ -80,12 +111,15 @@ class TestConfigManagerStartup(unittest.TestCase):
             env_var = os.environ["B10_FROM_SOURCE"]
 
         os.environ["B10_FROM_SOURCE"] = tmp_env_var
+        bind10_config.reload()
         b = __import__("b10-cfgmgr", globals(), locals())
+        b.PLUGIN_PATH = [] # It's enough to test plugins in one test
         b.ConfigManager = MyConfigManager
         self.assertEqual(tmp_env_var, b.DATA_PATH)
 
         if env_var != None:
             os.environ["B10_FROM_SOURCE"] = env_var
+        bind10_config.reload()
 
         sys.modules.pop("b10-cfgmgr")
 
diff --git a/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py b/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py
new file mode 100644
index 0000000..a50eefe
--- /dev/null
+++ b/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py
@@ -0,0 +1,34 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# A test plugin. It does mostly nothing, just provides a function we can
+# recognize from the test. However, it looks like a real plugin, with the
+# (almost) correct interface, even when it's not used.
+
+class MockSpec:
+    """Mock spec, contains no data, it can only provide it's name.
+       It'll not really be used for anything."""
+    def get_module_name(self):
+        return "mock_config_plugin"
+
+def mock_check_config(config):
+    """Mock function to check config. Does nothing, only returns
+       an "error" string to indicate it's this one."""
+    return "Mock config plugin"
+
+def load():
+    """When a plugin is loaded, this is called to provide the spec and
+       checking function."""
+    return (MockSpec(), mock_check_config)
diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am
index 0758cb9..ec34ce7 100644
--- a/src/bin/host/Makefile.am
+++ b/src/bin/host/Makefile.am
@@ -10,17 +10,20 @@ endif
 
 CLEANFILES = *.gcno *.gcda
 
-bin_PROGRAMS = host
-host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-
-#man_MANS = host.1
-#EXTRA_DIST = $(man_MANS) host.xml
-#
-#if ENABLE_MAN
-#
-#host.1: host.xml
-#	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/host.xml
-#
-#endif
+bin_PROGRAMS = b10-host
+b10_host_SOURCES = host.cc
+b10_host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
+b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
+man_MANS = b10-host.1
+EXTRA_DIST = $(man_MANS) b10-host.xml
+
+.PHONY: man
+if ENABLE_MAN
+
+man: b10-host.1
+
+b10-host.1: b10-host.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-host.xml
+
+endif
diff --git a/src/bin/host/README b/src/bin/host/README
index d493a95..5cc4068 100644
--- a/src/bin/host/README
+++ b/src/bin/host/README
@@ -1,14 +1,4 @@
-Rewriting host(1) in C++ from scratch using BIND 10's libdns.
+Rewriting host(1) in C++ from scratch using BIND 10's libdns++.
 
-Initial functionality:
-
-  host _hostname_ [server]
-
-By default, it looks up the A, AAAA, and MX record sets.
-
-Note it doesn't use /etc/resolv.conf at this time.
-The default name server used is 127.0.0.1.
-
-  -r	 	disable recursive processing
-  -t _type_	specific query type 
-  -v		enable verbose output mode, including elapsed time
+The bugs and incompatibilities are listed in the manual page
+and in the source code.
diff --git a/src/bin/host/b10-host.1 b/src/bin/host/b10-host.1
new file mode 100644
index 0000000..ed0068b
--- /dev/null
+++ b/src/bin/host/b10-host.1
@@ -0,0 +1,122 @@
+'\" t
+.\"     Title: b10-host
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: May 4, 2011
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-HOST" "1" "May 4, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-host \- DNS lookup utility
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-host\fR\ 'u
+\fBb10\-host\fR [\fB\-a\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-d\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-r\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-v\fR] [\fIname\fR] [\fB\fIserver\fR\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-host\fR
+utility does DNS lookups\&. Its initial goal is to be a
+\fBhost\fR(1)
+clone, but also add a few features useful for BIND 10 development testing\&.
+.PP
+By default, it looks up the A, AAAA, and MX record sets for the
+\fIname\fR\&. Optionally, you may select a name server to query against by adding the
+\fIserver\fR
+argument\&.
+.SH "OPTIONS"
+.PP
+The arguments are as follows:
+.PP
+\fB\-a\fR
+.RS 4
+Enable verbose mode and do a query for type ANY\&. (If the
+\fB\-t\fR
+option is also set, then the ANY query is not done, but it still uses verbose mode\&.)
+.RE
+.PP
+\fB\-c \fR\fB\fIclass\fR\fR
+.RS 4
+Define the class for the query\&. The default is IN (Internet)\&.
+.RE
+.PP
+\fB\-d\fR
+.RS 4
+Enable verbose output mode, including elapsed time in milliseconds\&. Verbose mode shows the header, question, answer, authority, and additional sections (if provided)\&. (Same as
+\fB\-v\fR\&.)
+.RE
+.PP
+\fB\-p \fR\fB\fIport\fR\fR
+.RS 4
+Select an alternative port for the query\&. This may be a number or a service name\&. The default is 53 (domain)\&. This is not a standard feature of
+\fBhost\fR(1)\&.
+.RE
+.PP
+\fB\-r\fR
+.RS 4
+Disable recursive processing by not setting the Recursion Desired flag in the query\&.
+.RE
+.PP
+\fB\-t \fR\fB\fItype\fR\fR
+.RS 4
+Select a specific resource record type for the query\&. By default, it looks up the A, AAAA, and MX record sets\&.
+(This overrides the
+\fB\-a\fR
+option\&.)
+.RE
+.PP
+\fB\-v\fR
+.RS 4
+Same as
+\fB\-d\fR
+option\&.
+.RE
+.SH "COMPATIBILITY / BUGS"
+.PP
+
+\fBb10\-host\fR
+does not do reverse lookups by default yet (by detecting if name is a IPv4 or IPv6 address)\&.
+.PP
+Unknown
+\fB\-c\fR
+class or
+\fB\-t\fR
+type causes
+\fBb10\-host\fR
+to Abort\&.
+.PP
+Not all types are supported yet for formatting\&. Not all switches are supported yet\&.
+.PP
+It doesn\'t use
+/etc/resolv\&.conf
+at this time\&. The default name server used is 127\&.0\&.0\&.1\&.
+.PP
+
+\fBb10\-host\fR
+does not do reverse lookups by default yet (by detecting if name is a IPv4 or IPv6 address)\&.
+.PP
+
+\fB\-p\fR
+is not a standard feature\&.
+.SH "HISTORY"
+.PP
+The C++ version of
+\fBb10\-host\fR
+was started in October 2009 by Jeremy C\&. Reed of ISC\&. Its usage and output were based on the standard
+\fBhost\fR
+command\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/host/b10-host.xml b/src/bin/host/b10-host.xml
new file mode 100644
index 0000000..7da07dd
--- /dev/null
+++ b/src/bin/host/b10-host.xml
@@ -0,0 +1,201 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id$ -->
+<refentry>
+
+  <refentryinfo>
+    <date>May 4, 2011</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-host</refentrytitle>
+    <manvolnum>1</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-host</refname>
+    <refpurpose>DNS lookup utility</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2011</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-host</command>
+      <arg><option>-a</option></arg>
+      <arg><option>-c <replaceable>class</replaceable></option></arg>
+      <arg><option>-d</option></arg>
+      <arg><option>-p <replaceable>port</replaceable></option></arg>
+      <arg><option>-r</option></arg>
+      <arg><option>-t <replaceable>type</replaceable></option></arg>
+      <arg><option>-v</option></arg>
+      <arg><replaceable>name</replaceable></arg>
+      <arg><option><replaceable>server</replaceable></option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-host</command> utility does DNS lookups.
+      Its initial goal is to be a
+      <citerefentry><refentrytitle>host</refentrytitle>
+        <manvolnum>1</manvolnum></citerefentry>
+      clone, but also add a few features useful for BIND 10 development
+      testing.
+    </para>
+
+    <para>
+      By default, it looks up the A, AAAA, and MX record sets for the
+      <replaceable>name</replaceable>.
+      Optionally, you may select a name server to query against by adding
+      the <replaceable>server</replaceable> argument.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><option>-a</option></term>
+        <listitem><para>
+          Enable verbose mode and do a query for type ANY.
+          (If the <option>-t</option> option is also set, then the
+          ANY query is not done, but it still uses verbose mode.)
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-c <replaceable>class</replaceable></option></term>
+        <listitem><para>
+          Define the class for the query.
+          The default is IN (Internet).
+<!-- TODO: bug if class is unknown causes seg fault and possible core dump -->
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-d</option></term>
+        <listitem><para>
+	  Enable verbose output mode, including elapsed time in
+	  milliseconds.
+          Verbose mode shows the header, question, answer, authority,
+          and additional sections (if provided).
+          (Same as <option>-v</option>.)
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-p <replaceable>port</replaceable></option></term>
+        <listitem><para>
+          Select an alternative port for the query.
+          This may be a number or a service name.
+          The default is 53 (domain).
+          This is not a standard feature of
+          <citerefentry><refentrytitle>host</refentrytitle>
+            <manvolnum>1</manvolnum></citerefentry>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-r</option></term>
+        <listitem><para>
+          Disable recursive processing by not setting the
+          Recursion Desired flag in the query.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-t <replaceable>type</replaceable></option></term>
+        <listitem><para>
+          Select a specific resource record type for the query.
+          By default, it looks up the A, AAAA, and MX record sets.
+<!-- TODO: bug if class is unknown causes seg fault and possible core dump -->
+          (This overrides the <option>-a</option> option.)
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v</option></term>
+        <listitem><para>
+	  Same as <option>-d</option> option.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>COMPATIBILITY / BUGS</title>
+    <para>
+      <command>b10-host</command> does not do reverse lookups by
+      default yet (by detecting if name is a IPv4 or IPv6 address).
+    </para>
+
+    <para>
+      Unknown <option>-c</option> class or <option>-t</option> type
+      causes <command>b10-host</command> to Abort.
+    </para>
+
+    <para>
+      Not all types are supported yet for formatting.
+      Not all switches are supported yet.
+    </para>
+
+    <para>
+      It doesn't use <filename>/etc/resolv.conf</filename> at this time.
+      The default name server used is 127.0.0.1.
+    </para>
+
+    <para>
+      <command>b10-host</command> does not do reverse lookups by
+      default yet (by detecting if name is a IPv4 or IPv6 address).
+    </para>
+
+    <para>
+      <option>-p</option> is not a standard feature.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The C++ version of <command>b10-host</command> was started in
+      October 2009 by Jeremy C. Reed of ISC.
+      Its usage and output were based on the standard <command>host</command>
+      command.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/host/host.cc b/src/bin/host/host.cc
index c513b5a..f0df0c8 100644
--- a/src/bin/host/host.cc
+++ b/src/bin/host/host.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -24,7 +24,8 @@
 #include <string>
 #include <iostream>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/name.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -37,18 +38,22 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 char* dns_type = NULL;    // not set, so A, AAAA, MX
 const char* server = "127.0.0.1";
 const char* server_port = "53";
-int   verbose = 0;
-int   first_time = 1;
-bool  recursive_bit = true;
+const char* dns_class  = "IN";
+bool verbose = false;
+bool dns_any = false;
+int first_time = 1;
+bool recursive_bit = true;
 struct timeval before_time, after_time;
 
 int
-host_lookup(const char* const name, const char* const type) {
+host_lookup(const char* const name, const char* const dns_class,
+            const char* const type, bool any) {
 
     Message msg(Message::RENDER);
 
@@ -62,8 +67,8 @@ host_lookup(const char* const name, const char* const type) {
     }
 
     msg.addQuestion(Question(Name(name),
-                             RRClass::IN(),    // IN class only for now
-                             RRType(type)));  // if NULL then:
+                             RRClass(dns_class),
+                             any ? RRType::ANY() : RRType(type)));  // if NULL then:
 
     OutputBuffer obuffer(512);
     MessageRenderer renderer(obuffer);
@@ -125,18 +130,29 @@ host_lookup(const char* const name, const char* const type) {
 
             rmsg.fromWire(ibuffer);
             if (!verbose) {
+                string description = "";
                 for (RRsetIterator it =
                          rmsg.beginSection(Message::SECTION_ANSWER);
                      it != rmsg.endSection(Message::SECTION_ANSWER);
                      ++it) {
-                      if ((*it)->getType() != RRType::A()) {
-                          continue;
+
+                      if ((*it)->getType() == RRType::A()) {
+                          description = "has address";
+                      }
+                      else if ((*it)->getType() == RRType::AAAA()) {
+                          description = "has IPv6 address";
+                      }
+                      else if ((*it)->getType() == RRType::MX()) {
+                          description = "mail is handled by";
+                      }
+                      else if ((*it)->getType() == RRType::TXT()) {
+                          description = "descriptive text";
                       }
 
                       RdataIteratorPtr rit = (*it)->getRdataIterator();
                       for (; !rit->isLast(); rit->next()) {
                           // instead of using my name, maybe use returned label?
-                          cout << name << " has address " <<
+                          cout << name << " "  << description << " " <<
                               (*rit).getCurrent().toText() << endl;
                       }
                   }
@@ -157,13 +173,19 @@ host_lookup(const char* const name, const char* const type) {
 
                 // TODO: if NXDOMAIN, host(1) doesn't show HEADER
                 // Host hsdjkfhksjhdfkj not found: 3(NXDOMAIN)
-                // TODO: figure out the new libdns way to test if NXDOMAIN
+                // TODO: test if NXDOMAIN
 
                 std::cout << "Received " << cc <<
                     " bytes in " << elapsed_time << " ms\n";
                 // TODO: " bytes from 127.0.0.1#53 in 0 ms
 
             } //verbose
+/*
+TODO: handle InvalidRRClass
+TODO: handle invalid type exception
+        } catch (InvalidType ivt) {
+            std::cerr << "invalid type:" << ivt.what();
+*/
         } catch (const exception& ex) {
             std::cerr << "parse failed for " <<
                 string(name) << "/" << type << ": " << ex.what() << std::endl;
@@ -182,26 +204,36 @@ int
 main(int argc, char* argv[]) {
     int c;
 
-    while ((c = getopt(argc, argv, "p:rt:v")) != -1)
+    while ((c = getopt(argc, argv, "ac:dp:rt:v")) != -1)
         switch (c) {
+        case 'a':
+            dns_any = true;
+            verbose = true;
+            break;
+        case 'c':
+            dns_class = optarg;
+            break;
+	// p for port is a non-standard switch
+        case 'p':
+            server_port = optarg;
+            break;
         case 'r':
             recursive_bit = false;
             break;
         case 't':
             dns_type = optarg;
             break;
-        case 'p':
-            server_port = optarg;
-            break;
+        case 'd':
+            // drop through to v, because debug and verbose are equivalent
         case 'v':
-            verbose = 1;
+            verbose = true;
             break;
     }
     argc -= optind;
     argv += optind;
 
     if (argc < 1) {
-        cout << "Usage: host [-vr] [-t type] hostname [server]\n";
+        cout << "Usage: host [-adprv] [-c class] [-t type] hostname [server]\n";
         exit(1);
     }
 
@@ -210,12 +242,13 @@ main(int argc, char* argv[]) {
     }
 
     if (dns_type == NULL) {
-        host_lookup(argv[0], "A");
+        host_lookup(argv[0], dns_class, "A", dns_any);
         // TODO: don't do next if A doesn't exist
-        host_lookup(argv[0], "AAAA");
-        host_lookup(argv[0], "MX");
+        host_lookup(argv[0], dns_class, "AAAA", dns_any);
+        host_lookup(argv[0], dns_class, "MX", dns_any);
     } else {
-        host_lookup(argv[0], dns_type); 
+        // -t overrides -a, regardless of order
+        host_lookup(argv[0], dns_class, dns_type, false);
     }
     return (0);
 }
diff --git a/src/bin/msgq/tests/msgq_test.py b/src/bin/msgq/tests/msgq_test.py
index f926845..fe4f7d4 100644
--- a/src/bin/msgq/tests/msgq_test.py
+++ b/src/bin/msgq/tests/msgq_test.py
@@ -132,7 +132,7 @@ class SendNonblock(unittest.TestCase):
             task()
             # If we got here, then everything worked well and in time
             # In that case, we terminate successfully
-            sys.exit(0)	# needs exit code
+            os._exit(0)	# needs exit code
         else:
             (pid, status) = os.waitpid(task_pid, 0)
             self.assertEqual(0, status,
@@ -202,7 +202,7 @@ class SendNonblock(unittest.TestCase):
                 try:
                     def killall(signum, frame):
                         os.kill(queue_pid, signal.SIGTERM)
-                        sys.exit(1)
+                        os._exit(1)
                     signal.signal(signal.SIGALRM, killall)
                     msg = msgq.preparemsg({"type" : "ping"}, data)
                     now = time.clock()
diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am
index 54e15bd..094e3ad 100644
--- a/src/bin/resolver/Makefile.am
+++ b/src/bin/resolver/Makefile.am
@@ -4,6 +4,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiodns
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiodns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
 AM_CPPFLAGS += $(BOOST_INCLUDES)
@@ -45,6 +47,7 @@ b10_resolver_LDADD =  $(top_builddir)/src/lib/dns/libdns++.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/bin/resolver/main.cc b/src/bin/resolver/main.cc
index 1d76e0b..5103bf9 100644
--- a/src/bin/resolver/main.cc
+++ b/src/bin/resolver/main.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/select.h>
@@ -25,11 +27,12 @@
 
 #include <boost/foreach.hpp>
 
+#include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/rcode.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -56,7 +59,8 @@ using namespace isc::cc;
 using namespace isc::config;
 using namespace isc::data;
 using isc::log::dlog;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 
 namespace {
 
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 2322076..e43b48e 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -20,6 +20,7 @@
 #include <vector>
 #include <cassert>
 
+#include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 
 #include <boost/foreach.hpp>
@@ -29,9 +30,10 @@
 
 #include <exceptions/exceptions.h>
 
+#include <util/buffer.h>
+
 #include <dns/opcode.h>
 #include <dns/rcode.h>
-#include <dns/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/name.h>
 #include <dns/question.h>
@@ -50,11 +52,13 @@
 using namespace std;
 
 using namespace isc;
+using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::data;
 using namespace isc::config;
 using isc::log::dlog;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 using namespace isc::server_common::portconfig;
 
 class ResolverImpl {
@@ -140,7 +144,7 @@ public:
     void resolve(const isc::dns::QuestionPtr& question,
         const isc::resolve::ResolverInterface::CallbackPtr& callback);
 
-    void processNormalQuery(const Question& question,
+    void processNormalQuery(ConstMessagePtr query_message,
                             MessagePtr answer_message,
                             OutputBufferPtr buffer,
                             DNSServer* server);
@@ -295,7 +299,7 @@ public:
             edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
             answer_message->setEDNS(edns_response);
         }
-        
+
         if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
             if (edns) {
                 renderer.setLengthLimit(edns->getUDPSize());
@@ -345,7 +349,7 @@ Resolver::~Resolver() {
 }
 
 void
-Resolver::setDNSService(asiolink::DNSService& dnss) {
+Resolver::setDNSService(isc::asiodns::DNSService& dnss) {
     dnss_ = &dnss;
 }
 
@@ -464,7 +468,7 @@ Resolver::processMessage(const IOMessage& io_message,
             // The RecursiveQuery object will post the "resume" event to the
             // DNSServer when an answer arrives, so we don't have to do it now.
             sendAnswer = false;
-            impl_->processNormalQuery(*question, answer_message,
+            impl_->processNormalQuery(query_message, answer_message,
                                       buffer, server);
         }
     }
@@ -482,13 +486,19 @@ ResolverImpl::resolve(const QuestionPtr& question,
 }
 
 void
-ResolverImpl::processNormalQuery(const Question& question,
+ResolverImpl::processNormalQuery(ConstMessagePtr query_message,
                                  MessagePtr answer_message,
                                  OutputBufferPtr buffer,
                                  DNSServer* server)
 {
-    dlog("Processing normal query");
-    rec_query_->resolve(question, answer_message, buffer, server);
+    if (upstream_.empty()) {
+        dlog("Processing normal query");
+        ConstQuestionPtr question = *query_message->beginQuestion();
+        rec_query_->resolve(*question, answer_message, buffer, server);
+    } else {
+        dlog("Processing forward query");
+        rec_query_->forward(query_message, answer_message, buffer, server);
+    }
 }
 
 ConstElementPtr
diff --git a/src/bin/resolver/resolver.h b/src/bin/resolver/resolver.h
index 002e58b..2890dd3 100644
--- a/src/bin/resolver/resolver.h
+++ b/src/bin/resolver/resolver.h
@@ -21,8 +21,16 @@
 
 #include <cc/data.h>
 #include <config/ccsession.h>
+#include <dns/message.h>
+#include <util/buffer.h>
 
-#include <asiolink/asiolink.h>
+#include <asiodns/dns_server.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_answer.h>
+#include <asiolink/io_message.h>
+#include <asiolink/io_service.h>
+#include <asiolink/simple_callback.h>
 
 #include <nsas/nameserver_address_store.h>
 #include <cache/resolver_cache.h>
@@ -74,11 +82,11 @@ public:
     /// shall return to the client
     /// \param buffer Pointer to an \c OutputBuffer for the resposne
     /// \param server Pointer to the \c DNSServer
-    void processMessage(const asiolink::IOMessage& io_message,
+    void processMessage(const isc::asiolink::IOMessage& io_message,
                         isc::dns::MessagePtr query_message,
                         isc::dns::MessagePtr answer_message,
-                        isc::dns::OutputBufferPtr buffer,
-                        asiolink::DNSServer* server);
+                        isc::util::OutputBufferPtr buffer,
+                        isc::asiodns::DNSServer* server);
 
     /// \brief Set and get the config session
     isc::config::ModuleCCSession* getConfigSession() const;
@@ -88,16 +96,16 @@ public:
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
 
     /// \brief Assign an ASIO IO Service queue to this Resolver object
-    void setDNSService(asiolink::DNSService& dnss);
-    
+    void setDNSService(isc::asiodns::DNSService& dnss);
+
     /// \brief Assign a NameserverAddressStore to this Resolver object
     void setNameserverAddressStore(isc::nsas::NameserverAddressStore &nsas);
-    
+
     /// \brief Assign a cache to this Resolver object
     void setCache(isc::cache::ResolverCache& cache);
 
     /// \brief Return this object's ASIO IO Service queue
-    asiolink::DNSService& getDNSService() const { return (*dnss_); }
+    isc::asiodns::DNSService& getDNSService() const { return (*dnss_); }
 
     /// \brief Returns this object's NSAS
     isc::nsas::NameserverAddressStore& getNameserverAddressStore() const {
@@ -108,15 +116,15 @@ public:
     isc::cache::ResolverCache& getResolverCache() const {
         return *cache_;
     };
-    
+
     /// \brief Return pointer to the DNS Lookup callback function
-    asiolink::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
+    isc::asiodns::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
 
     /// \brief Return pointer to the DNS Answer callback function
-    asiolink::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); }
+    isc::asiodns::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); }
 
     /// \brief Return pointer to the Checkin callback function
-    asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); }
+    isc::asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); }
 
     /**
      * \brief Tell the Resolver that is has already been configured
@@ -230,10 +238,10 @@ public:
 
 private:
     ResolverImpl* impl_;
-    asiolink::DNSService* dnss_;
-    asiolink::SimpleCallback* checkin_;
-    asiolink::DNSLookup* dns_lookup_;
-    asiolink::DNSAnswer* dns_answer_;
+    isc::asiodns::DNSService* dnss_;
+    isc::asiolink::SimpleCallback* checkin_;
+    isc::asiodns::DNSLookup* dns_lookup_;
+    isc::asiodns::DNSAnswer* dns_answer_;
     isc::nsas::NameserverAddressStore* nsas_;
     isc::cache::ResolverCache* cache_;
     // This value is initally false, and will be set to true
@@ -244,6 +252,6 @@ private:
 
 #endif // __RESOLVER_H
 
-// Local Variables: 
+// Local Variables:
 // mode: c++
-// End: 
+// End:
diff --git a/src/bin/resolver/response_scrubber.cc b/src/bin/resolver/response_scrubber.cc
index 060a8b1..d35a96f 100644
--- a/src/bin/resolver/response_scrubber.cc
+++ b/src/bin/resolver/response_scrubber.cc
@@ -1,4 +1,3 @@
-
 // Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
@@ -26,7 +25,7 @@ using namespace std;
 // Compare addresses etc.
 
 ResponseScrubber::Category ResponseScrubber::addressCheck(
-    const asiolink::IOEndpoint& to, const asiolink::IOEndpoint& from)
+    const isc::asiolink::IOEndpoint& to, const isc::asiolink::IOEndpoint& from)
 {
     if (from.getProtocol() == to.getProtocol()) {
         if (from.getAddress() == to.getAddress()) {
@@ -50,7 +49,7 @@ ResponseScrubber::Category ResponseScrubber::addressCheck(
 unsigned int
 ResponseScrubber::scrubSection(Message& message,
     const vector<const Name*>& names,
-    const NameComparisonResult::NameRelation connection, 
+    const NameComparisonResult::NameRelation connection,
     const Message::Section section)
 {
     unsigned int count = 0;     // Count of RRsets removed
@@ -74,30 +73,32 @@ ResponseScrubber::scrubSection(Message& message,
 
         // Start looking at the remaining entries in the section.
         removed = false;
-        for (; (i != message.endSection(section)) && (!removed); ++i) {
+        for (; i != message.endSection(section); ++i) {
 
             // Loop through the list of names given and see if any are in the
             // given relationship with the QNAME of this RRset
-            bool nomatch = true;
+            bool match = false;
             for (vector<const Name*>::const_iterator n = names.begin();
-                ((n != names.end()) && nomatch); ++n) {
+                 n != names.end(); ++n) {
                 NameComparisonResult result = (*i)->getName().compare(**n);
                 NameComparisonResult::NameRelation relationship =
                     result.getRelation();
                 if ((relationship == NameComparisonResult::EQUAL) ||
                    (relationship == connection)) {
-                    
+
                     // RRset in the specified relationship, so a match has
                     // been found
-                    nomatch = false;
+                    match = true;
+                    break;
                 }
             }
 
             // Remove the RRset if there was no match to one of the given names.
-            if (nomatch) {
+            if (!match) {
                 message.removeRRset(section, i);
                 ++count;            // One more RRset removed
                 removed = true;     // Something was removed
+                break; // It invalidated the iterators, start again
              } else {
 
                 // There was a match so this is one more entry we can skip next
@@ -107,7 +108,7 @@ ResponseScrubber::scrubSection(Message& message,
         }
     }
 
-    return count;
+    return (count);
 }
 
 // Perform the scrubbing of all sections of the message.
@@ -126,7 +127,7 @@ ResponseScrubber::scrubAllSections(Message& message, const Name& bailiwick) {
     count += scrubSection(message, bailiwick_names,
             NameComparisonResult::SUBDOMAIN, Message::SECTION_ADDITIONAL);
 
-    return count;
+    return (count);
 }
 
 // Scrub across sections.
@@ -171,7 +172,6 @@ ResponseScrubber::scrubCrossSections(isc::dns::Message& message) {
     // superdomain of the names in the question/answer section.
     return (scrubSection(message, source,
         NameComparisonResult::SUPERDOMAIN, Message::SECTION_AUTHORITY));
-
 }
 
 // Scrub a message
@@ -183,7 +183,7 @@ ResponseScrubber::scrub(const isc::dns::MessagePtr& message,
     unsigned int sections_removed = scrubAllSections(*message, bailiwick);
     sections_removed += scrubCrossSections(*message);
 
-    return sections_removed;
+    return (sections_removed);
 }
 
 
diff --git a/src/bin/resolver/response_scrubber.h b/src/bin/resolver/response_scrubber.h
index 680aa5a..c59ac15 100644
--- a/src/bin/resolver/response_scrubber.h
+++ b/src/bin/resolver/response_scrubber.h
@@ -282,8 +282,8 @@ public:
     ///
     /// \return SUCCESS if the two endpoints match, otherwise an error status
     /// indicating what was incorrect.
-    static Category addressCheck(const asiolink::IOEndpoint& to,
-        const asiolink::IOEndpoint& from);
+    static Category addressCheck(const isc::asiolink::IOEndpoint& to,
+        const isc::asiolink::IOEndpoint& from);
 
     /// \brief Check QID
     ///
diff --git a/src/bin/resolver/tests/Makefile.am b/src/bin/resolver/tests/Makefile.am
index b85c223..444358b 100644
--- a/src/bin/resolver/tests/Makefile.am
+++ b/src/bin/resolver/tests/Makefile.am
@@ -31,6 +31,7 @@ run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
diff --git a/src/bin/resolver/tests/resolver_config_unittest.cc b/src/bin/resolver/tests/resolver_config_unittest.cc
index 2fa62e5..70e856d 100644
--- a/src/bin/resolver/tests/resolver_config_unittest.cc
+++ b/src/bin/resolver/tests/resolver_config_unittest.cc
@@ -12,12 +12,15 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <string>
 
 #include <gtest/gtest.h>
 
 #include <cc/data.h>
 
+#include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 
 #include <resolver/resolver.h>
@@ -29,7 +32,8 @@
 using namespace std;
 using namespace isc::data;
 using namespace isc::testutils;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 using isc::UnitTestUtil;
 
 namespace {
diff --git a/src/bin/resolver/tests/response_scrubber_unittest.cc b/src/bin/resolver/tests/response_scrubber_unittest.cc
index 1dc6639..eff5598 100644
--- a/src/bin/resolver/tests/response_scrubber_unittest.cc
+++ b/src/bin/resolver/tests/response_scrubber_unittest.cc
@@ -41,6 +41,7 @@
 // Class for endpoint checks.  The family of the endpoint is set in the
 // constructor; the address family by the string provided for the address.
 
+namespace isc {
 namespace asiolink {
 
 class GenericEndpoint : public IOEndpoint {
@@ -73,13 +74,14 @@ private:
     short       protocol_;      // Protocol of the endpoint
     };
 }
+}
 
 using namespace asio::ip;
 using namespace isc::dns;
 using namespace rdata;
 using namespace isc::dns::rdata::generic;
 using namespace isc::dns::rdata::in;
-using namespace asiolink;
+using namespace isc::asiolink;
 
 // Test class
 
diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am
new file mode 100644
index 0000000..1ac4640
--- /dev/null
+++ b/src/bin/sockcreator/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+CLEANFILES = *.gcno *.gcda
+
+pkglibexec_PROGRAMS = b10-sockcreator
+
+b10_sockcreator_SOURCES = sockcreator.cc sockcreator.h main.cc
+b10_sockcreator_LDADD = $(top_builddir)/src/lib/util/io/libutil_io.la
diff --git a/src/bin/sockcreator/README b/src/bin/sockcreator/README
new file mode 100644
index 0000000..4dbbee7
--- /dev/null
+++ b/src/bin/sockcreator/README
@@ -0,0 +1,49 @@
+The socket creator
+==================
+
+The only thing we need higher rights than standard user is binding sockets to
+ports lower than 1024. So we will have a separate process that keeps the
+rights, while the rests drop them for security reasons.
+
+This process is the socket creator. Its goal is to be as simple as possible
+and to contain as little code as possible to minimise the amount of code
+running with higher privileges (to minimize the number of bugs and make
+checking/auditing it easier). It uses low-level OS API instead of some
+fancy library for that reason. It has only fixed-length reads so there's no
+place for buffer overruns.
+
+Protocol
+--------
+
+It talks with whoever started it by its stdin/stdout. It reads simple
+binary protocol from stdin and does what the commands ask. Command is a single
+byte (usually from the printable range, so it is easier to debug and guess
+what it does), followed by parameters.
+
+Note that as send_fd and recv_fd works only with unix domain socket, it's stdio
+must be a socket, not pipe.
+
+* 'T': It has no parameters. It asks the socket creator to terminate.
+
+* 'S' 'U|T' '4|6' port address: Asks it to create a port. First parameter
+  tels the socket type (either UDP or TCP). The second one is address family
+  (either IPv4 or IPv6). Then there's 2 bytes of the port number, in the
+  network byte order. The last one is either 4 or 16 bytes of address, as
+  they would be passed to bind (note that both parameters are already prepared,
+  like hton called on them).
+
+  The answer to this is either 'S' directly followed by the socket (using
+  sendmsg) if it is successful. If it fails, 'E' is returned instead, followed
+  by either 'S' or 'B' (either socket() or bind() call failed). Then there is
+  one int (architecture-dependent length and endianess), which is the errno
+  value after the failure.
+
+The creator may also send these messages at any time (but not in the middle
+of another message):
+
+* 'F': A fatal error has been detected. It is followed by one byte of error
+  condition code and then the creator terminates with non-zero status.
+
+  The conditions are:
+  * 'I': Invalid input (eg. someone sent a wrong letter and it does not
+    understand it).
diff --git a/src/bin/sockcreator/main.cc b/src/bin/sockcreator/main.cc
new file mode 100644
index 0000000..37da303
--- /dev/null
+++ b/src/bin/sockcreator/main.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "sockcreator.h"
+
+using namespace isc::socket_creator;
+
+int
+main() {
+    /*
+     * TODO Maybe use some OS-specific caps interface and drop everything
+     * but ability to bind ports? It would be nice.
+     */
+    return run(0, 1); // Read commands from stdin, output to stdout
+}
diff --git a/src/bin/sockcreator/sockcreator.cc b/src/bin/sockcreator/sockcreator.cc
new file mode 100644
index 0000000..6b50813
--- /dev/null
+++ b/src/bin/sockcreator/sockcreator.cc
@@ -0,0 +1,151 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "sockcreator.h"
+
+#include <util/io/fd.h>
+
+#include <unistd.h>
+#include <cerrno>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+using namespace isc::util::io;
+
+namespace isc {
+namespace socket_creator {
+
+int
+get_sock(const int type, struct sockaddr *bind_addr, const socklen_t addr_len)
+{
+    int sock(socket(bind_addr->sa_family, type, 0));
+    if (sock == -1) {
+        return -1;
+    }
+    if (bind(sock, bind_addr, addr_len) == -1) {
+        return -2;
+    }
+    return sock;
+}
+
+// These are macros so they can exit the function
+#define READ(WHERE, HOW_MANY) do { \
+        size_t how_many = (HOW_MANY); \
+        if (read_data(input_fd, (WHERE), how_many) < how_many) { \
+            return 1; \
+        } \
+    } while (0)
+
+#define WRITE(WHAT, HOW_MANY) do { \
+        if (!write_data(output_fd, (WHAT), (HOW_MANY))) { \
+            return 2; \
+        } \
+    } while (0)
+
+#define DEFAULT \
+    default: /* Unrecognized part of protocol */ \
+        WRITE("FI", 2); \
+        return 3;
+
+int
+run(const int input_fd, const int output_fd, const get_sock_t get_sock,
+    const send_fd_t send_fd)
+{
+    for (;;) {
+        // Read the command
+        char command;
+        READ(&command, 1);
+        switch (command) {
+            case 'T': // The "terminate" command
+                return 0;
+            case 'S': { // Create a socket
+                // Read what type of socket they want
+                char type[2];
+                READ(type, 2);
+                // Read the address they ask for
+                struct sockaddr *addr(NULL);
+                size_t addr_len(0);
+                struct sockaddr_in addr_in;
+                struct sockaddr_in6 addr_in6;
+                switch (type[1]) { // The address family
+                    /*
+                     * Here are some casts. They are required by C++ and
+                     * the low-level interface (they are implicit in C).
+                     */
+                    case '4':
+                        addr = static_cast<struct sockaddr *>(
+                            static_cast<void *>(&addr_in));
+                        addr_len = sizeof addr_in;
+                        memset(&addr_in, 0, sizeof addr_in);
+                        addr_in.sin_family = AF_INET;
+                        READ(static_cast<char *>(static_cast<void *>(
+                            &addr_in.sin_port)), 2);
+                        READ(static_cast<char *>(static_cast<void *>(
+                            &addr_in.sin_addr.s_addr)), 4);
+                        break;
+                    case '6':
+                        addr = static_cast<struct sockaddr *>(
+                            static_cast<void *>(&addr_in6));
+                        addr_len = sizeof addr_in6;
+                        memset(&addr_in6, 0, sizeof addr_in6);
+                        addr_in6.sin6_family = AF_INET6;
+                        READ(static_cast<char *>(static_cast<void *>(
+                            &addr_in6.sin6_port)), 2);
+                        READ(static_cast<char *>(static_cast<void *>(
+                            &addr_in6.sin6_addr.s6_addr)), 16);
+                        break;
+                    DEFAULT
+                }
+                int sock_type;
+                switch (type[0]) { // Translate the type
+                    case 'T':
+                        sock_type = SOCK_STREAM;
+                        break;
+                    case 'U':
+                        sock_type = SOCK_DGRAM;
+                        break;
+                    DEFAULT
+                }
+                int result(get_sock(sock_type, addr, addr_len));
+                if (result >= 0) { // We got the socket
+                    WRITE("S", 1);
+                    // FIXME: Check the output and write a test for it
+                    send_fd(output_fd, result);
+                } else {
+                    WRITE("E", 1);
+                    switch (result) {
+                        case -1:
+                            WRITE("S", 1);
+                            break;
+                        case -2:
+                            WRITE("B", 1);
+                            break;
+                        default:
+                            return 4;
+                    }
+                    int error(errno);
+                    WRITE(static_cast<char *>(static_cast<void *>(&error)),
+                        sizeof error);
+                }
+                break;
+            }
+            DEFAULT
+        }
+    }
+}
+
+} // End of the namespaces
+}
diff --git a/src/bin/sockcreator/sockcreator.h b/src/bin/sockcreator/sockcreator.h
new file mode 100644
index 0000000..ddf9a09
--- /dev/null
+++ b/src/bin/sockcreator/sockcreator.h
@@ -0,0 +1,100 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/**
+ * \file sockcreator.h
+ * \short Socket creator functionality.
+ *
+ * This module holds the functionality of the socket creator. It is
+ * a separate module from main to ease up the tests.
+ */
+
+#ifndef __SOCKCREATOR_H
+#define __SOCKCREATOR_H 1
+
+#include <util/io/fd_share.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+namespace isc {
+namespace socket_creator {
+
+/**
+ * \short Create a socket and bind it.
+ *
+ * This is just a bundle of socket() and bind() calls. The sa_family of
+ * bind_addr is used to determine the domain of the socket.
+ *
+ * \return The file descriptor of the newly created socket, if everything
+ *     goes well. A negative number is returned if an error occurs -
+ *     -1 if the socket() call fails or -2 if bind() fails. In case of error,
+ *     errno is set (or better, left intact from socket() or bind()).
+ * \param type The type of socket to create (SOCK_STREAM, SOCK_DGRAM, etc).
+ * \param bind_addr The address to bind.
+ * \param addr_len The actual length of bind_addr.
+ */
+int
+get_sock(const int type, struct sockaddr *bind_addr, const socklen_t addr_len);
+
+/**
+ * Type of the get_sock function, to pass it as parameter.
+ */
+typedef
+int
+(*get_sock_t)(const int, struct sockaddr *, const socklen_t);
+
+/**
+ * Type of the send_fd() function, so it can be passed as a parameter.
+ */
+typedef
+int
+(*send_fd_t)(const int, const int);
+
+/**
+ * \short Infinite loop parsing commands and returning the sockets.
+ *
+ * This reads commands and socket descriptions from the input_fd
+ * file descriptor, creates sockets and writes the results (socket or
+ * error) to output_fd.
+ *
+ * Current errors are:
+ * - 1: Read error
+ * - 2: Write error
+ * - 3: Protocol error (unknown command, etc)
+ * - 4: Some internal inconsistency detected
+ *
+ * It terminates either if a command asks it to or when unrecoverable
+ * error happens.
+ *
+ * \return Like a return value of a main - 0 means everything OK, anything
+ *     else is error.
+ * \param input_fd Here is where it reads the commads.
+ * \param output_fd Here is where it writes the results.
+ * \param get_sock_fun The function that is used to create the sockets.
+ *     This should be left on the default value, the parameter is here
+ *     for testing purposes.
+ * \param send_fd_fun The function that is used to send the socket over
+ *     a file descriptor. This should be left on the default value, it is
+ *     here for testing purposes.
+ */
+int
+run(const int input_fd, const int output_fd,
+    const get_sock_t get_sock_fun = get_sock,
+    const send_fd_t send_fd_fun = isc::util::io::send_fd);
+
+} // End of the namespaces
+}
+
+#endif // __SOCKCREATOR_H
diff --git a/src/bin/sockcreator/tests/Makefile.am b/src/bin/sockcreator/tests/Makefile.am
new file mode 100644
index 0000000..2e1307a
--- /dev/null
+++ b/src/bin/sockcreator/tests/Makefile.am
@@ -0,0 +1,25 @@
+CLEANFILES = *.gcno *.gcda
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = ../sockcreator.cc ../sockcreator.h
+run_unittests_SOURCES += sockcreator_tests.cc
+run_unittests_SOURCES += run_unittests.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
+run_unittests_LDADD += \
+	$(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/bin/sockcreator/tests/run_unittests.cc b/src/bin/sockcreator/tests/run_unittests.cc
new file mode 100644
index 0000000..e787ab1
--- /dev/null
+++ b/src/bin/sockcreator/tests/run_unittests.cc
@@ -0,0 +1,22 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char *argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/src/bin/sockcreator/tests/sockcreator_tests.cc b/src/bin/sockcreator/tests/sockcreator_tests.cc
new file mode 100644
index 0000000..73cbf48
--- /dev/null
+++ b/src/bin/sockcreator/tests/sockcreator_tests.cc
@@ -0,0 +1,273 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "../sockcreator.h"
+
+#include <util/unittests/fork.h>
+#include <util/io/fd.h>
+
+#include <gtest/gtest.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <cstring>
+#include <cerrno>
+
+using namespace isc::socket_creator;
+using namespace isc::util::unittests;
+using namespace isc::util::io;
+
+namespace {
+
+/*
+ * Generic version of the creation of socket test. It just tries to
+ * create the socket and checks the result is not negative (eg.
+ * it is valid descriptor) and that it can listen.
+ *
+ * This is a macro so ASSERT_* does abort the TEST, not just the
+ * function inside.
+ */
+#define TEST_ANY_CREATE(SOCK_TYPE, ADDR_TYPE, ADDR_FAMILY, FAMILY_FIELD, \
+    ADDR_SET, CHECK_SOCK) \
+    do { \
+        /*
+         * This should create an address that binds on all interfaces
+         * and lets the OS choose a free port.
+         */ \
+        struct ADDR_TYPE addr; \
+        memset(&addr, 0, sizeof addr); \
+        ADDR_SET(addr); \
+        addr.FAMILY_FIELD = ADDR_FAMILY; \
+        struct sockaddr *addr_ptr = static_cast<struct sockaddr *>( \
+            static_cast<void *>(&addr)); \
+        \
+        int socket = get_sock(SOCK_TYPE, addr_ptr, sizeof addr); \
+        /* Provide even nice error message. */ \
+        ASSERT_GE(socket, 0) << "Couldn't create a socket of type " \
+            #SOCK_TYPE " and family " #ADDR_FAMILY ", failed with " \
+            << socket << " and error " << strerror(errno); \
+        CHECK_SOCK(ADDR_TYPE, socket); \
+        EXPECT_EQ(0, close(socket)); \
+    } while (0)
+
+// Just helper macros
+#define INADDR_SET(WHAT) do { WHAT.sin_addr.s_addr = INADDR_ANY; } while (0)
+#define IN6ADDR_SET(WHAT) do { WHAT.sin6_addr = in6addr_loopback; } while (0)
+// If the get_sock returned something useful, listen must work
+#define TCP_CHECK(UNUSED, SOCKET) do { \
+        EXPECT_EQ(0, listen(SOCKET, 1)); \
+    } while (0)
+// More complicated with UDP, so we send a packet to ourselfs and se if it
+// arrives
+#define UDP_CHECK(ADDR_TYPE, SOCKET) do { \
+        struct ADDR_TYPE addr; \
+        memset(&addr, 0, sizeof addr); \
+        struct sockaddr *addr_ptr = static_cast<struct sockaddr *>( \
+            static_cast<void *>(&addr)); \
+        \
+        socklen_t len = sizeof addr; \
+        ASSERT_EQ(0, getsockname(SOCKET, addr_ptr, &len)); \
+        ASSERT_EQ(5, sendto(SOCKET, "test", 5, 0, addr_ptr, sizeof addr)) << \
+            "Send failed with error " << strerror(errno) << " on socket " << \
+            SOCKET; \
+        char buffer[5]; \
+        ASSERT_EQ(5, recv(SOCKET, buffer, 5, 0)) << \
+            "Recv failed with error " << strerror(errno) << " on socket " << \
+            SOCKET; \
+        EXPECT_STREQ("test", buffer); \
+    } while (0)
+
+/*
+ * Several tests to ensure we can create the sockets.
+ */
+TEST(get_sock, udp4_create) {
+    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
+        UDP_CHECK);
+}
+
+TEST(get_sock, tcp4_create) {
+    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
+        TCP_CHECK);
+}
+
+TEST(get_sock, udp6_create) {
+    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in6, AF_INET6, sin6_family,
+        IN6ADDR_SET, UDP_CHECK);
+}
+
+TEST(get_sock, tcp6_create) {
+    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in6, AF_INET6, sin6_family,
+        IN6ADDR_SET, TCP_CHECK);
+}
+
+/*
+ * Try to ask the get_sock function some nonsense and test if it
+ * is able to report error.
+ */
+TEST(get_sock, fail_with_nonsense) {
+    struct sockaddr addr;
+    memset(&addr, 0, sizeof addr);
+    ASSERT_LT(get_sock(0, &addr, sizeof addr), 0);
+}
+
+/*
+ * Helper functions to pass to run during testing.
+ */
+int
+get_sock_dummy(const int type, struct sockaddr *addr, const socklen_t)
+{
+    int result(0);
+    int port(0);
+    /*
+     * We encode the type and address family into the int and return it.
+     * Lets ignore the port and address for now
+     * First bit is 1 if it is known type. Second tells if TCP or UDP.
+     * The familly is similar - third bit is known address family,
+     * the fourth is the family.
+     */
+    switch (type) {
+        case SOCK_STREAM:
+            result += 1;
+            break;
+        case SOCK_DGRAM:
+            result += 3;
+            break;
+    }
+    switch (addr->sa_family) {
+        case AF_INET:
+            result += 4;
+            port = static_cast<struct sockaddr_in *>(
+                static_cast<void *>(addr))->sin_port;
+            break;
+        case AF_INET6:
+            result += 12;
+            port = static_cast<struct sockaddr_in6 *>(
+                static_cast<void *>(addr))->sin6_port;
+            break;
+    }
+    /*
+     * The port should be 0xffff. If it's not, we change the result.
+     * The port of 0xbbbb means bind should fail and 0xcccc means
+     * socket should fail.
+     */
+    if (port != 0xffff) {
+        errno = 0;
+        if (port == 0xbbbb) {
+            return -2;
+        } else if (port == 0xcccc) {
+            return -1;
+        } else {
+            result += 16;
+        }
+    }
+    return result;
+}
+
+int
+send_fd_dummy(const int destination, const int what)
+{
+    /*
+     * Make sure it is 1 byte so we know the length. We do not use more during
+     * the test anyway.
+     */
+    char fd_data(what);
+    if (!write_data(destination, &fd_data, 1)) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/*
+ * Generic test that it works, with various inputs and outputs.
+ * It uses different functions to create the socket and send it and pass
+ * data to it and check it returns correct data back, to see if the run()
+ * parses the commands correctly.
+ */
+void run_test(const char *input_data, const size_t input_size,
+    const char *output_data, const size_t output_size,
+    bool should_succeed = true)
+{
+    // Prepare the input feeder and output checker processes
+    int input_fd(0), output_fd(0);
+    pid_t input(provide_input(&input_fd, input_data, input_size)),
+        output(check_output(&output_fd, output_data, output_size));
+    ASSERT_NE(-1, input) << "Couldn't start input feeder";
+    ASSERT_NE(-1, output) << "Couldn't start output checker";
+    // Run the body
+    int result(run(input_fd, output_fd, get_sock_dummy, send_fd_dummy));
+    // Close the pipes
+    close(input_fd);
+    close(output_fd);
+    // Did it run well?
+    if (should_succeed) {
+        EXPECT_EQ(0, result);
+    } else {
+        EXPECT_NE(0, result);
+    }
+    // Check the subprocesses say everything is OK too
+    EXPECT_TRUE(process_ok(input));
+    EXPECT_TRUE(process_ok(output));
+}
+
+/*
+ * Check it terminates successfully when asked to.
+ */
+TEST(run, terminate) {
+    run_test("T", 1, NULL, 0);
+}
+
+/*
+ * Check it rejects incorrect input.
+ */
+TEST(run, bad_input) {
+    run_test("XXX", 3, "FI", 2, false);
+}
+
+/*
+ * Check it correctly parses queries to create sockets.
+ */
+TEST(run, sockets) {
+    run_test(
+        "SU4\xff\xff\0\0\0\0" // This has 9 bytes
+        "ST4\xff\xff\0\0\0\0" // This has 9 bytes
+        "ST6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // This has 21 bytes
+        "SU6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // This has 21 bytes
+        "T", 61,
+        "S\x07S\x05S\x0dS\x0f", 8);
+}
+
+/*
+ * Check if failures of get_socket are handled correctly.
+ */
+TEST(run, bad_sockets) {
+    // We need to construct the answer, but it depends on int length.
+    size_t int_len(sizeof(int));
+    size_t result_len(4 + 2 * int_len);
+    char result[4 + sizeof(int) * 2];
+    // Both errno parts should be 0
+    memset(result, 0, result_len);
+    // Fill the 2 control parts
+    strcpy(result, "EB");
+    strcpy(result + 2 + int_len, "ES");
+    // Run the test
+    run_test(
+        "SU4\xbb\xbb\0\0\0\0"
+        "SU4\xcc\xcc\0\0\0\0"
+        "T", 19,
+        result, result_len);
+}
+
+}
diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am
index b173813..e4a4f92 100644
--- a/src/bin/stats/Makefile.am
+++ b/src/bin/stats/Makefile.am
@@ -2,35 +2,35 @@ SUBDIRS = tests
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
-pkglibexec_SCRIPTS = b10-stats
-noinst_SCRIPTS = b10-stats_stub
+pkglibexec_SCRIPTS = b10-stats b10-stats-httpd
 
 b10_statsdir = $(pkgdatadir)
-b10_stats_DATA = stats.spec
+b10_stats_DATA = stats.spec stats-httpd.spec stats-schema.spec
+b10_stats_DATA += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl
 
-CLEANFILES = stats.spec b10-stats stats.pyc stats.pyo b10-stats_stub stats_stub.pyc stats_stub.pyo
+CLEANFILES = b10-stats stats.pyc
+CLEANFILES += b10-stats-httpd stats_httpd.pyc
 
-man_MANS = b10-stats.8
-EXTRA_DIST = $(man_MANS) b10-stats.xml
+man_MANS = b10-stats.8 b10-stats-httpd.8
+EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml
+EXTRA_DIST += stats.spec stats-httpd.spec stats-schema.spec
+EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl
 
 if ENABLE_MAN
 
 b10-stats.8: b10-stats.xml
 	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml
 
-endif
+b10-stats-httpd.8: b10-stats-httpd.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats-httpd.xml
 
-stats.spec: stats.spec.pre
-	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats.spec.pre >$@
+endif
 
 # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
 b10-stats: stats.py
-	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
-	       -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" \
-	       -e "s|.*#@@REMOVED@@$$||"  stats.py >$@
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|"  stats.py >$@
 	chmod a+x $@
 
-b10-stats_stub: stats_stub.py stats.py
-	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
-	       -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats_stub.py >$@
+b10-stats-httpd: stats_httpd.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" stats_httpd.py >$@
 	chmod a+x $@
diff --git a/src/bin/stats/b10-stats-httpd.8 b/src/bin/stats/b10-stats-httpd.8
new file mode 100644
index 0000000..ed4aafa
--- /dev/null
+++ b/src/bin/stats/b10-stats-httpd.8
@@ -0,0 +1,136 @@
+'\" t
+.\"     Title: b10-stats-httpd
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\"      Date: Mar 8, 2011
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-STATS\-HTTPD" "8" "Mar 8, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-stats-httpd \- BIND 10 HTTP server for HTTP/XML interface of statistics
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-stats\-httpd\fR\ 'u
+\fBb10\-stats\-httpd\fR [\fB\-v\fR]| [\fB\-\-verbose\fR]
+.SH "DESCRIPTION"
+.PP
+
+\fBb10\-stats\-httpd\fR
+is a standalone HTTP server\&. It is intended for HTTP/XML interface for statistics module\&. This server process runs as a process separated from the process of the BIND 10 Stats daemon (\fBb10\-stats\fR)\&. The server is initially executed by the BIND 10 boss process (\fBbind10\fR) and eventually exited by it\&. The server is intended to be server requests by HTTP clients like web browsers and third\-party modules\&. When the server is asked, it requests BIND 10 statistics data from
+\fBb10\-stats\fR, and it sends the data back in Python dictionary format and the server converts it into XML format\&. The server sends it to the HTTP client\&. The server can send three types of document, which are XML (Extensible Markup Language), XSD (XML Schema definition) and XSL (Extensible Stylesheet Language)\&. The XML document is the statistics data of BIND 10, The XSD document is the data schema of it, and The XSL document is the style sheet to be showed for the web browsers\&. There is different URL for each document\&. But please note that you would be redirected to the URL of XML document if you request the URL of the root document\&. For example, you would be redirected to http://127\&.0\&.0\&.1:8000/bind10/statistics/xml if you request http://127\&.0\&.0\&.1:8000/\&. Please see the manual and the spec file of
+\fBb10\-stats\fR
+for more details about the items of BIND 10 statistics\&. The server uses CC session in communication with
+\fBb10\-stats\fR\&. CC session is provided by
+\fBb10\-msgq\fR
+which is started by
+\fBbind10\fR
+in advance\&. The server is implemented by HTTP\-server libraries included in Python 3\&. The server obtains the configuration from the config manager (\fBb10\-cfgmgr\fR) in runtime\&. Please see below for more details about this spec file and configuration of the server\&.
+.SH "OPTIONS"
+.PP
+The argument is as follow:
+.PP
+\fB\-v\fR, \fB\-\-verbose\fR
+.RS 4
+
+\fBb10\-stats\-httpd\fR
+switches to verbose mode and sends verbose messages to STDOUT\&.
+.RE
+.SH "FILES"
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\&.spec
+\(em the spec file of
+\fBb10\-stats\-httpd\fR\&. This file contains configurable settings of
+\fBb10\-stats\-httpd\fR\&. This setting can be configured in runtime via
+bindctl(1)\&. Please see the manual of
+bindctl(1)
+about how to configure the settings\&.
+.PP
+/usr/local/share/bind10\-devel/stats\-schema\&.spec
+\(em This is a spec file for data schema of of BIND 10 statistics\&. This schema cannot be configured via
+bindctl(1)\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xml\&.tpl
+\(em the template file of XML document\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xsd\&.tpl
+\(em the template file of XSD document\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xsl\&.tpl
+\(em the template file of XSL document\&.
+.SH "CONFIGURATION AND COMMANDS"
+.PP
+The configurable setting in
+stats\-httpd\&.spec
+is:
+.PP
+\fIlisten_on\fR
+.RS 4
+a list of pairs of address and port for
+\fBb10\-stats\-httpd\fR
+to listen HTTP requests on\&. The pair consists of the
+\fIaddress\fR
+string and
+\fIport\fR
+number\&. The default setting is the list of address 127\&.0\&.0\&.1 port 8000\&. If the server is started by the default setting being left, for example, the URL for XML document is http://127\&.0\&.0\&.1:8000/bind10/statistics/xml\&. And also IPv6 addresses can be configured and they works in the runtime environment for dual stack\&. You can change the settings through
+bindctl(8)\&.
+.RE
+.PP
+The commands in
+stats\-httpd\&.spec
+are:
+.PP
+\fBstatus\fR
+.RS 4
+shows the status of
+\fBb10\-stats\-httpd\fR
+with its PID\&.
+.RE
+.PP
+\fBshutdown\fR
+.RS 4
+exits the
+\fBb10\-stats\-httpd\fR
+process\&. (Note that the BIND 10 boss process will restart this service\&.)
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBb10-stats\fR(8),
+\fBb10-msgq\fR(8),
+\fBb10-cfgmgr\fR(8),
+\fBbind10\fR(8),
+\fBbindctl\fR(1),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+
+\fBb10\-stats\-httpd\fR
+was designed and implemented by Naoki Kambe of JPRS in Mar 2011\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/stats/b10-stats-httpd.xml b/src/bin/stats/b10-stats-httpd.xml
new file mode 100644
index 0000000..34c704f
--- /dev/null
+++ b/src/bin/stats/b10-stats-httpd.xml
@@ -0,0 +1,221 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<refentry>
+
+  <refentryinfo>
+    <date>Mar 8, 2011</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-stats-httpd</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-stats-httpd</refname>
+    <refpurpose>BIND 10 HTTP server for HTTP/XML interface of statistics</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2011</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>      <command>b10-stats-httpd</command>
+      <arg><option>-v</option></arg>|<arg><option>--verbose</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      <command>b10-stats-httpd</command> is a standalone HTTP server. It is
+      intended for HTTP/XML interface for statistics module. This server
+      process runs as a process separated from the process of the BIND 10 Stats
+      daemon (<command>b10-stats</command>). The server is initially executed
+      by the BIND 10 boss process (<command>bind10</command>) and eventually
+      exited by it.  The server is intended to be server requests by HTTP
+      clients like web browsers and third-party modules. When the server is
+      asked, it requests BIND 10 statistics data from
+      <command>b10-stats</command>, and it sends the data back in Python
+      dictionary format and the server converts it into XML format. The server
+      sends it to the HTTP client. The server can send three types of document,
+      which are XML (Extensible Markup Language), XSD (XML Schema definition)
+      and XSL (Extensible Stylesheet Language). The XML document is the
+      statistics data of BIND 10, The XSD document is the data schema of it,
+      and The XSL document is the style sheet to be showed for the web
+      browsers. There is different URL for each document. But please note that
+      you would be redirected to the URL of XML document if you request the URL
+      of the root document. For example, you would be redirected to
+      http://127.0.0.1:8000/bind10/statistics/xml if you request
+      http://127.0.0.1:8000/. Please see the manual and the spec file
+      of <command>b10-stats</command> for more details about the items of BIND
+      10 statistics. The server uses CC session in communication
+      with <command>b10-stats</command>. CC session is provided
+      by <command>b10-msgq</command> which is started
+      by <command>bind10</command> in advance. The server is implemented by
+      HTTP-server libraries included in Python 3. The server obtains the
+      configuration from the config manager (<command>b10-cfgmgr</command>) in
+      runtime. Please see below for more details about this spec file and
+      configuration of the server.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+    <para>The argument is as follow:</para>
+    <variablelist>
+      <varlistentry>
+        <term><option>-v</option>, <option>--verbose</option></term>
+        <listitem>
+	  <para>
+          <command>b10-stats-httpd</command> switches to verbose mode and sends
+          verbose messages to STDOUT.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+    <para>
+      <filename>/usr/local/share/bind10-devel/stats-httpd.spec</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — the spec file of <command>b10-stats-httpd</command>. This file
+      contains configurable settings
+      of <command>b10-stats-httpd</command>. This setting can be configured in
+      runtime via
+      <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>. Please
+      see the manual
+      of <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum> about
+      how to configure the settings.
+    </para>
+    <para><filename>/usr/local/share/bind10-devel/stats-schema.spec</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — This is a spec file for data schema of
+      of BIND 10 statistics. This schema cannot be configured 
+      via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+    </para>
+    <para>
+      <filename>/usr/local/share/bind10-devel/stats-httpd-xml.tpl</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — the template file of XML document.
+    </para>
+    <para>
+      <filename>/usr/local/share/bind10-devel/stats-httpd-xsd.tpl</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — the template file of XSD document.
+    </para>
+    <para>
+      <filename>/usr/local/share/bind10-devel/stats-httpd-xsl.tpl</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — the template file of XSL document.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>CONFIGURATION AND COMMANDS</title>
+    <para>
+      The configurable setting in 
+      <filename>stats-httpd.spec</filename> is:
+    </para>
+    <variablelist>
+      <varlistentry>
+        <term><varname>listen_on</varname></term>
+        <listitem>
+	  <para>
+      	    a list of pairs of address and port for
+	    <command>b10-stats-httpd</command> to listen HTTP requests on. The
+	    pair consists of the <varname>address</varname> string
+	    and <varname>port</varname> number. The default setting is the list
+	    of address 127.0.0.1 port 8000. If the server is started by the
+	    default setting being left, for example, the URL for XML document
+	    is http://127.0.0.1:8000/bind10/statistics/xml. And also IPv6
+	    addresses can be configured and they works in the runtime
+	    environment for dual stack. You can change the settings
+	    through <refentrytitle>bindctl</refentrytitle><manvolnum>8</manvolnum>.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+    <para>
+      The commands in <filename>stats-httpd.spec</filename> are:
+    </para>
+    <variablelist>
+      <varlistentry>
+        <term><command>status</command></term>
+        <listitem>
+	  <para>
+	    shows the status of <command>b10-stats-httpd</command> with its
+	    PID.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><command>shutdown</command></term>
+        <listitem>
+	  <para>
+	    exits the <command>b10-stats-httpd</command> process. (Note that
+	    the BIND 10 boss process will restart this service.)
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+	<refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      <command>b10-stats-httpd</command> was designed and implemented by Naoki
+      Kambe of JPRS in Mar 2011.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/stats/b10-stats.8 b/src/bin/stats/b10-stats.8
index 062ff35..f69e4d3 100644
--- a/src/bin/stats/b10-stats.8
+++ b/src/bin/stats/b10-stats.8
@@ -1,7 +1,7 @@
 '\" t
 .\"     Title: b10-stats
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
 .\"      Date: Oct 15, 2010
 .\"    Manual: BIND10
 .\"    Source: BIND10
@@ -9,6 +9,15 @@
 .\"
 .TH "B10\-STATS" "8" "Oct 15, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" disable hyphenation
@@ -35,6 +44,11 @@ with other modules like
 \fBbind10\fR,
 \fBb10\-auth\fR
 and so on\&. It waits for coming data from other modules, then other modules send data to stats module periodically\&. Other modules send stats data to stats module independently from implementation of stats module, so the frequency of sending data may not be constant\&. Stats module collects data and aggregates it\&.
+\fBb10\-stats\fR
+invokes "sendstats" command for
+\fBbind10\fR
+after its initial starting because it\*(Aqs sure to collect statistics data from
+\fBbind10\fR\&.
 .SH "OPTIONS"
 .PP
 The arguments are as follows:
@@ -49,10 +63,17 @@ switches to verbose mode\&. It sends verbose messages to STDOUT\&.
 .PP
 /usr/local/share/bind10\-devel/stats\&.spec
 \(em This is a spec file for
-\fBb10\-stats\fR\&. It contains definitions of statistics items of BIND 10 and commands received vi bindctl\&.
+\fBb10\-stats\fR\&. It contains commands for
+\fBb10\-stats\fR\&. They can be invoked via
+bindctl(1)\&.
+.PP
+/usr/local/share/bind10\-devel/stats\-schema\&.spec
+\(em This is a spec file for data schema of of BIND 10 statistics\&. This schema cannot be configured via
+bindctl(1)\&.
 .SH "SEE ALSO"
 .PP
 
+\fBb10-stats-httpd\fR(8),
 \fBbind10\fR(8),
 \fBbindctl\fR(1),
 \fBb10-auth\fR(8),
diff --git a/src/bin/stats/b10-stats.xml b/src/bin/stats/b10-stats.xml
index f622439..f0c472d 100644
--- a/src/bin/stats/b10-stats.xml
+++ b/src/bin/stats/b10-stats.xml
@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "—">]>
 <!--
- - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010,2011  Internet Systems Consortium, Inc. ("ISC")
  -
  - Permission to use, copy, modify, and/or distribute this software for any
  - purpose with or without fee is hereby granted, provided that the above
@@ -64,7 +64,9 @@
       send stats data to stats module independently from
       implementation of stats module, so the frequency of sending data
       may not be constant. Stats module collects data and aggregates
-      it.
+      it. <command>b10-stats</command> invokes "sendstats" command
+      for <command>bind10</command> after its initial starting because it's
+      sure to collect statistics data from <command>bind10</command>.
     </para>
   </refsect1>
 
@@ -87,10 +89,17 @@
   <refsect1>
     <title>FILES</title>
     <para><filename>/usr/local/share/bind10-devel/stats.spec</filename>
+      <!--TODO: The filename should be computed from prefix-->
       — This is a spec file for <command>b10-stats</command>. It
-      contains definitions of statistics items of BIND 10 and commands
-      received via
-      <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+      contains commands for <command>b10-stats</command>. They can be
+      invoked
+      via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+    </para>
+    <para><filename>/usr/local/share/bind10-devel/stats-schema.spec</filename>
+      <!--TODO: The filename should be computed from prefix-->
+      — This is a spec file for data schema of
+      of BIND 10 statistics. This schema cannot be configured 
+      via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
     </para>
   </refsect1>
 
@@ -98,6 +107,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-stats-httpd</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/stats/run_b10-stats.sh.in b/src/bin/stats/run_b10-stats.sh.in
deleted file mode 100644
index 65b9737..0000000
--- a/src/bin/stats/run_b10-stats.sh.in
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python
-export PYTHONPATH
-
-BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
-export BIND10_MSGQ_SOCKET_FILE
-
-B10_FROM_BUILD=@abs_top_builddir@
-export B10_FROM_BUILD
-
-STATS_PATH=@abs_top_builddir@/src/bin/stats
-
-cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats "$@"
diff --git a/src/bin/stats/run_b10-stats_stub.sh.in b/src/bin/stats/run_b10-stats_stub.sh.in
deleted file mode 100644
index 19ade5c..0000000
--- a/src/bin/stats/run_b10-stats_stub.sh.in
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python
-export PYTHONPATH
-
-B10_FROM_BUILD=@abs_top_srcdir@
-export B10_FROM_BUILD
-
-BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
-export BIND10_MSGQ_SOCKET_FILE
-
-STATS_PATH=@abs_top_builddir@/src/bin/stats
-
-cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats_stub "$@"
diff --git a/src/bin/stats/stats-httpd-xml.tpl.in b/src/bin/stats/stats-httpd-xml.tpl.in
new file mode 100644
index 0000000..d5846ad
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xml.tpl.in
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="$xsl_url_path"?>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<stats:stats_data version="1.0"
+  xmlns:stats="$xsd_namespace"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="$xsd_namespace $xsd_url_path">
+  $xml_string
+</stats:stats_data>
diff --git a/src/bin/stats/stats-httpd-xsd.tpl.in b/src/bin/stats/stats-httpd-xsd.tpl.in
new file mode 100644
index 0000000..6ad1280
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xsd.tpl.in
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<schema targetNamespace="$xsd_namespace"
+  xmlns="http://www.w3.org/2001/XMLSchema"
+  xmlns:stats="$xsd_namespace">
+  <annotation>
+    <documentation xml:lang="en">XML schema of the statistics
+      data in BIND 10</documentation>
+  </annotation>
+  <element name="stats_data">
+    <annotation>
+      <documentation>A set of statistics data</documentation>
+    </annotation>
+    <complexType>
+      $xsd_string
+      <attribute name="version" type="token" use="optional" default="1.0">
+        <annotation>
+          <documentation>Version number of syntax</documentation>
+        </annotation>
+      </attribute>
+    </complexType>
+  </element>
+</schema>
diff --git a/src/bin/stats/stats-httpd-xsl.tpl.in b/src/bin/stats/stats-httpd-xsl.tpl.in
new file mode 100644
index 0000000..01ffdc6
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xsl.tpl.in
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:stats="$xsd_namespace">
+  <xsl:output method="html" encoding="UTF-8"
+    doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
+    doctype-system=" http://www.w3.org/TR/html4/loose.dtd " />
+  <xsl:template match="/">
+    <html lang="en">
+      <head>
+        <title>BIND 10 Statistics</title>
+        <style type="text/css"><![CDATA[
+table {
+  border: 1px #000000 solid;
+  border-collapse: collapse;
+}
+td, th {
+  padding: 3px 20px;
+  border: 1px #000000 solid;
+}
+td.title {
+  text-decoration:underline;
+}
+]]>
+        </style>
+      </head>
+      <body>
+        <h1>BIND 10 Statistics</h1>
+        <table>
+          <tr>
+            <th>Title</th>
+            <th>Value</th>
+          </tr>
+          <xsl:apply-templates />
+        </table>
+      </body>
+    </html>
+  </xsl:template>
+  $xsl_string
+</xsl:stylesheet>
diff --git a/src/bin/stats/stats-httpd.spec.in b/src/bin/stats/stats-httpd.spec.in
new file mode 100644
index 0000000..6307135
--- /dev/null
+++ b/src/bin/stats/stats-httpd.spec.in
@@ -0,0 +1,54 @@
+{
+  "module_spec": {
+    "module_name": "StatsHttpd",
+    "module_description": "Stats HTTP daemon",
+    "config_data": [
+      {
+        "item_name": "listen_on",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [
+          {
+            "address": "127.0.0.1",
+            "port": 8000
+          }
+        ],
+        "list_item_spec": {
+          "item_name": "address",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": {},
+          "map_item_spec": [
+            {
+              "item_name": "address",
+              "item_type": "string",
+              "item_optional": true,
+              "item_default": "127.0.0.1",
+              "item_description": "listen-on address for HTTP"
+            },
+            {
+              "item_name": "port",
+              "item_type": "integer",
+              "item_optional": true,
+              "item_default": 8000,
+              "item_description": "listen-on port for HTTP"
+            }
+          ]
+        },
+        "item_description": "http listen-on address and port"
+      }
+    ],
+    "commands": [
+      {
+        "command_name": "status",
+        "command_description": "Status of the stats httpd",
+        "command_args": []
+      },
+      {
+        "command_name": "shutdown",
+        "command_description": "Shut down the stats httpd",
+        "command_args": []
+      }
+    ]
+  }
+}
diff --git a/src/bin/stats/stats-schema.spec.in b/src/bin/stats/stats-schema.spec.in
new file mode 100644
index 0000000..37e9c1a
--- /dev/null
+++ b/src/bin/stats/stats-schema.spec.in
@@ -0,0 +1,87 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Statistics data schema",
+    "config_data": [
+      {
+        "item_name": "report_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "Report time",
+        "item_description": "A date time when stats module reports",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "bind10.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "bind10.BootTime",
+        "item_description": "A date time when bind10 process starts initially",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.BootTime",
+        "item_description": "A date time when the stats module starts initially or when the stats module restarts",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.start_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.StartTime",
+        "item_description": "A date time when the stats module starts collecting data or resetting values last time",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.last_update_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.LastUpdateTime",
+        "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.timestamp",
+        "item_type": "real",
+        "item_optional": false,
+        "item_default": 0.0,
+        "item_title": "stats.Timestamp",
+        "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
+        "item_format": "second"
+      },
+      {
+        "item_name": "stats.lname",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "",
+        "item_title": "stats.LocalName",
+        "item_description": "A localname of stats module given via CC protocol"
+      },
+      {
+        "item_name": "auth.queries.tcp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.tcp",
+        "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
+      },
+      {
+        "item_name": "auth.queries.udp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.udp",
+        "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
+      }
+    ],
+    "commands": []
+  }
+}
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
old mode 100755
new mode 100644
index 15e2980..969676e
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -1,6 +1,6 @@
 #!@PYTHON@
 
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010, 2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -15,8 +15,6 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-__version__ = "$Revision$"
-
 import sys; sys.path.append ('@@PYTHONPATH@@')
 import os
 import signal
@@ -26,26 +24,24 @@ from optparse import OptionParser, OptionValueError
 from collections import defaultdict
 from isc.config.ccsession import ModuleCCSession, create_answer
 from isc.cc import Session, SessionError
-# Note: Following lines are removed in b10-stats	#@@REMOVED@@
-if __name__ == 'stats':					#@@REMOVED@@
-    try:						#@@REMOVED@@
-        from fake_time import time, strftime, gmtime	#@@REMOVED@@
-    except ImportError:					#@@REMOVED@@
-        pass						#@@REMOVED@@
 
 # for setproctitle
 import isc.util.process
 isc.util.process.rename()
 
-# If B10_FROM_BUILD is set in the environment, we use data files
+# If B10_FROM_SOURCE is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
 # installed on the system
-if "B10_FROM_BUILD" in os.environ:
-    SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
+if "B10_FROM_SOURCE" in os.environ:
+    BASE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+        "src" + os.sep + "bin" + os.sep + "stats"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
-    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    BASE_LOCATION = "@datadir@" + os.sep + "@PACKAGE@"
+    BASE_LOCATION = BASE_LOCATION.replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats.spec"
+SCHEMA_SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-schema.spec"
 
 class Singleton(type):
     """
@@ -184,8 +180,7 @@ class CCSessionListener(Listener):
         self.session = self.subject.session = self.cc_session._session
 
         # initialize internal data
-        self.config_spec = self.cc_session.get_module_spec().get_config_spec()
-        self.stats_spec = self.config_spec
+        self.stats_spec = isc.config.module_spec_from_file(SCHEMA_SPECFILE_LOCATION).get_config_spec()
         self.stats_data = self.initialize_data(self.stats_spec)
 
         # add event handler invoked via SessionSubject object
@@ -220,7 +215,13 @@ class CCSessionListener(Listener):
         self.stats_data['stats.start_time'] = get_datetime()
         self.stats_data['stats.last_update_time'] = get_datetime()
         self.stats_data['stats.lname'] = self.session.lname
-        return self.cc_session.start()
+        self.cc_session.start()
+        # request Bob to send statistics data
+        if self.verbose:
+            sys.stdout.write("[b10-stats] request Bob to send statistics data\n")
+        cmd = isc.config.ccsession.create_command("sendstats", None)
+        seq = self.session.group_sendmsg(cmd, 'Boss')
+        self.session.group_recvmsg(True, seq)
 
     def stop(self):
         """
@@ -270,9 +271,6 @@ class CCSessionListener(Listener):
         """
         handle set command
         """
-        if self.verbose:
-            sys.stdout.write("[b10-stats] 'set' command received, args: "+str(args)+"\n")
-
         # 'args' must be dictionary type
         self.stats_data.update(args['stats_data'])
 
diff --git a/src/bin/stats/stats.spec.in b/src/bin/stats/stats.spec.in
new file mode 100644
index 0000000..25f6b54
--- /dev/null
+++ b/src/bin/stats/stats.spec.in
@@ -0,0 +1,61 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Stats daemon",
+    "config_data": [],
+    "commands": [
+      {
+        "command_name": "status",
+        "command_description": "identify whether stats module is alive or not",
+        "command_args": []
+      },
+      {
+        "command_name": "show",
+        "command_description": "show the specified/all statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_item_name",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": ""
+          }
+        ]
+      },
+      {
+        "command_name": "set",
+        "command_description": "set the value of specified name in statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_data",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {},
+            "map_item_spec": []
+          }
+        ]
+      },
+      {
+        "command_name": "remove",
+        "command_description": "remove the specified name from statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_item_name",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          }
+        ]
+      },
+      {
+        "command_name": "reset",
+        "command_description": "reset all statistics data to default values except for several constant names",
+        "command_args": []
+      },
+      {
+        "command_name": "shutdown",
+        "command_description": "Shut down the stats module",
+        "command_args": []
+      }
+    ]
+  }
+}
diff --git a/src/bin/stats/stats.spec.pre.in b/src/bin/stats/stats.spec.pre.in
deleted file mode 100644
index 6970250..0000000
--- a/src/bin/stats/stats.spec.pre.in
+++ /dev/null
@@ -1,140 +0,0 @@
-{
-  "module_spec": {
-    "module_name": "Stats",
-    "module_description": "Stats daemon",
-    "config_data": [
-      {
-        "item_name": "report_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "Report time",
-        "item_description": "A date time when stats module reports",
-        "item_format": "date-time"
-      },
-      {
-        "item_name": "bind10.boot_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "stats.BootTime",
-        "item_description": "A date time when bind10 process starts initially",
-        "item_format": "date-time"
-      },
-      {
-        "item_name": "stats.boot_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "stats.BootTime",
-        "item_description": "A date time when the stats module starts initially or when the stats module restarts",
-        "item_format": "date-time"
-      },
-      {
-        "item_name": "stats.start_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "stats.StartTime",
-        "item_description": "A date time when the stats module starts collecting data or resetting values last time",
-        "item_format": "date-time"
-      },
-      {
-        "item_name": "stats.last_update_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "stats.LastUpdateTime",
-        "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
-        "item_format": "date-time"
-      },
-      {
-        "item_name": "stats.timestamp",
-        "item_type": "real",
-        "item_optional": false,
-        "item_default": 0.0,
-        "item_title": "stats.Timestamp",
-        "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
-        "item_format": "second"
-      },
-      {
-        "item_name": "stats.lname",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "",
-        "item_title": "stats.LocalName",
-        "item_description": "A localname of stats module given via CC protocol"
-      },
-      {
-        "item_name": "auth.queries.tcp",
-        "item_type": "integer",
-        "item_optional": false,
-        "item_default": 0,
-        "item_title": "auth.queries.tcp",
-        "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
-      },
-      {
-        "item_name": "auth.queries.udp",
-        "item_type": "integer",
-        "item_optional": false,
-        "item_default": 0,
-        "item_title": "auth.queries.udp",
-        "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
-      }
-    ],
-    "commands": [
-      {
-        "command_name": "status",
-        "command_description": "identify whether stats module is alive or not",
-        "command_args": []
-      },
-      {
-        "command_name": "show",
-        "command_description": "show the specified/all statistics data",
-        "command_args": [
-          {
-            "item_name": "stats_item_name",
-            "item_type": "string",
-            "item_optional": true,
-            "item_default": ""
-          }
-        ]
-      },
-      {
-        "command_name": "set",
-        "command_description": "set the value of specified name in statistics data",
-        "command_args": [
-          {
-            "item_name": "stats_data",
-            "item_type": "map",
-            "item_optional": false,
-            "item_default": {},
-            "map_item_spec": []
-          }
-        ]
-      },
-      {
-        "command_name": "remove",
-        "command_description": "remove the specified name from statistics data",
-        "command_args": [
-          {
-            "item_name": "stats_item_name",
-            "item_type": "string",
-            "item_optional": false,
-            "item_default": ""
-          }
-        ]
-      },
-      {
-        "command_name": "reset",
-        "command_description": "reset all statistics data to default values except for several constant names",
-        "command_args": []
-      },
-      {
-        "command_name": "shutdown",
-        "command_description": "Shut down the stats module",
-        "command_args": []
-      }
-    ]
-  }
-}
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
new file mode 100644
index 0000000..97e9c78
--- /dev/null
+++ b/src/bin/stats/stats_httpd.py.in
@@ -0,0 +1,485 @@
+#!@PYTHON@
+
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A standalone HTTP server for HTTP/XML interface of statistics in BIND 10
+
+"""
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import os
+import time
+import errno
+import select
+from optparse import OptionParser, OptionValueError
+import http.server
+import socket
+import string
+import xml.etree.ElementTree
+
+import isc.cc
+import isc.config
+import isc.util.process
+
+# If B10_FROM_SOURCE is set in the environment, we use data files
+# from a directory relative to that, otherwise we use the ones
+# installed on the system
+if "B10_FROM_SOURCE" in os.environ:
+    BASE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+        "src" + os.sep + "bin" + os.sep + "stats"
+else:
+    PREFIX = "@prefix@"
+    DATAROOTDIR = "@datarootdir@"
+    BASE_LOCATION = "@datadir@" + os.sep + "@PACKAGE@"
+    BASE_LOCATION = BASE_LOCATION.replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd.spec"
+SCHEMA_SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-schema.spec"
+XML_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xml.tpl"
+XSD_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsd.tpl"
+XSL_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsl.tpl"
+
+# These variables are paths part of URL.
+# eg. "http://${address}" + XXX_URL_PATH
+XML_URL_PATH = '/bind10/statistics/xml'
+XSD_URL_PATH = '/bind10/statistics/xsd'
+XSL_URL_PATH = '/bind10/statistics/xsl'
+# TODO: This should be considered later.
+XSD_NAMESPACE = 'http://bind10.isc.org' + XSD_URL_PATH
+DEFAULT_CONFIG = dict(listen_on=[('127.0.0.1', 8000)])
+
+# Assign this process name
+isc.util.process.rename()
+
+class HttpHandler(http.server.BaseHTTPRequestHandler):
+    """HTTP handler class for HttpServer class. The class inhrits the super
+    class http.server.BaseHTTPRequestHandler. It implemets do_GET()
+    and do_HEAD() and orverrides log_message()"""
+    def do_GET(self):
+        body = self.send_head()
+        if body is not None:
+            self.wfile.write(body.encode())
+
+    def do_HEAD(self):
+        self.send_head()
+
+    def send_head(self):
+        try:
+            if self.path == XML_URL_PATH:
+                body = self.server.xml_handler()
+            elif self.path == XSD_URL_PATH:
+                body = self.server.xsd_handler()
+            elif self.path == XSL_URL_PATH:
+                body = self.server.xsl_handler()
+            else:
+                if self.path == '/' and 'Host' in self.headers.keys():
+                    # redirect to XML URL only when requested with '/'
+                    self.send_response(302)
+                    self.send_header(
+                        "Location",
+                        "http://" + self.headers.get('Host') + XML_URL_PATH)
+                    self.end_headers()
+                    return None
+                else:
+                    # Couldn't find HOST
+                    self.send_error(404)
+                    return None
+        except StatsHttpdError as err:
+            self.send_error(500)
+            if self.server.verbose:
+                self.server.log_writer(
+                    "[b10-stats-httpd] %s\n" % err)
+            return None
+        else:
+            self.send_response(200)
+            self.send_header("Content-type", "text/xml")
+            self.send_header("Content-Length", len(body))
+            self.end_headers()
+            return body
+
+    def log_message(self, format, *args):
+        """Change the default log format"""
+        if self.server.verbose:
+            self.server.log_writer(
+                "[b10-stats-httpd] %s - - [%s] %s\n" %
+                (self.address_string(),
+                 self.log_date_time_string(),
+                 format%args))
+
+class HttpServerError(Exception):
+    """Exception class for HttpServer class. It is intended to be
+    passed from the HttpServer object to the StatsHttpd object."""
+    pass
+
+class HttpServer(http.server.HTTPServer):
+    """HTTP Server class. The class inherits the super
+    http.server.HTTPServer. Some parameters are specified as
+    arguments, which are xml_handler, xsd_handler, xsl_handler, and
+    log_writer. These all are parameters which the StatsHttpd object
+    has. The handler parameters are references of functions which
+    return body of each document. The last parameter log_writer is
+    reference of writer function to just write to
+    sys.stderr.write. They are intended to be referred by HttpHandler
+    object."""
+    def __init__(self, server_address, handler,
+                 xml_handler, xsd_handler, xsl_handler, log_writer, verbose=False):
+        self.server_address = server_address
+        self.xml_handler = xml_handler
+        self.xsd_handler = xsd_handler
+        self.xsl_handler = xsl_handler
+        self.log_writer = log_writer
+        self.verbose = verbose
+        http.server.HTTPServer.__init__(self, server_address, handler)
+
+class StatsHttpdError(Exception):
+    """Exception class for StatsHttpd class. It is intended to be
+    thrown from the the StatsHttpd object to the HttpHandler object or
+    main routine."""
+    pass
+
+class StatsHttpd:
+    """The main class of HTTP server of HTTP/XML interface for
+    statistics module. It handles HTTP requests, and command channel
+    and config channel CC session. It uses select.select function
+    while waiting for clients requests."""
+    def __init__(self, verbose=False):
+        self.verbose = verbose
+        self.running = False
+        self.poll_intval = 0.5
+        self.write_log = sys.stderr.write
+        self.mccs = None
+        self.httpd = []
+        self.open_mccs()
+        self.load_config()
+        self.load_templates()
+        self.open_httpd()
+
+    def open_mccs(self):
+        """Opens a ModuleCCSession object"""
+        # create ModuleCCSession
+        if self.verbose:
+            self.write_log("[b10-stats-httpd] Starting CC Session\n")
+        self.mccs = isc.config.ModuleCCSession(
+            SPECFILE_LOCATION, self.config_handler, self.command_handler)
+        self.cc_session = self.mccs._session
+        # read spec file of stats module and subscribe 'Stats'
+        self.stats_module_spec = isc.config.module_spec_from_file(SCHEMA_SPECFILE_LOCATION)
+        self.stats_config_spec = self.stats_module_spec.get_config_spec()
+        self.stats_module_name = self.stats_module_spec.get_module_name()
+
+    def close_mccs(self):
+        """Closes a ModuleCCSession object"""
+        if self.mccs is None:
+            return
+        if self.verbose:
+            self.write_log("[b10-stats-httpd] Closing CC Session\n")
+        self.mccs.close()
+        self.mccs = None
+
+    def load_config(self, new_config={}):
+        """Loads configuration from spec file or new configuration
+        from the config manager"""
+        # load config
+        if len(new_config) > 0:
+            self.config.update(new_config)
+        else:
+            self.config = DEFAULT_CONFIG
+            self.config.update(
+                dict([
+                        (itm['item_name'], self.mccs.get_value(itm['item_name'])[0])
+                        for itm in self.mccs.get_module_spec().get_config_spec()
+                        ])
+                )
+        # set addresses and ports for HTTP
+        self.http_addrs = [ (cf['address'], cf['port']) for cf in self.config['listen_on'] ]
+
+    def open_httpd(self):
+        """Opens sockets for HTTP. Iterating each HTTP address to be
+        configured in spec file"""
+        for addr in self.http_addrs:
+            self.httpd.append(self._open_httpd(addr))
+
+    def _open_httpd(self, server_address, address_family=None):
+        try:
+            # try IPv6 at first
+            if address_family is not None:
+                HttpServer.address_family = address_family
+            elif socket.has_ipv6:
+                HttpServer.address_family = socket.AF_INET6
+            httpd = HttpServer(
+                server_address, HttpHandler,
+                self.xml_handler, self.xsd_handler, self.xsl_handler,
+                self.write_log, self.verbose)
+        except (socket.gaierror, socket.error,
+                OverflowError, TypeError) as err:
+            # try IPv4 next
+            if HttpServer.address_family == socket.AF_INET6:
+                httpd = self._open_httpd(server_address, socket.AF_INET)
+            else:
+                raise HttpServerError(
+                    "Invalid address %s, port %s: %s: %s" %
+                    (server_address[0], server_address[1],
+                     err.__class__.__name__, err))
+        else:
+            if self.verbose:
+                self.write_log(
+                    "[b10-stats-httpd] Started on address %s, port %s\n" %
+                    server_address)
+        return httpd
+
+    def close_httpd(self):
+        """Closes sockets for HTTP"""
+        if len(self.httpd) == 0:
+            return
+        for ht in self.httpd:
+            if self.verbose:
+                self.write_log(
+                    "[b10-stats-httpd] Closing address %s, port %s\n" %
+                    (ht.server_address[0], ht.server_address[1])
+                    )
+            ht.server_close()
+        self.httpd = []
+
+    def start(self):
+        """Starts StatsHttpd objects to run. Waiting for client
+        requests by using select.select functions"""
+        self.mccs.start()
+        self.running = True
+        while self.running:
+            try:
+                (rfd, wfd, xfd) = select.select(
+                    self.get_sockets(), [], [], self.poll_intval)
+            except select.error as err:
+                # select.error exception is caught only in the case of
+                # EINTR, or in other cases it is just thrown.
+                if err.args[0] == errno.EINTR:
+                    (rfd, wfd, xfd) = ([], [], [])
+                else:
+                    raise
+            # FIXME: This module can handle only one request at a
+            # time. If someone sends only part of the request, we block
+            # waiting for it until we time out.
+            # But it isn't so big issue for administration purposes.
+            for fd in rfd + xfd:
+                if fd == self.mccs.get_socket():
+                    self.mccs.check_command(nonblock=False)
+                    continue
+                for ht in self.httpd:
+                    if fd == ht.socket:
+                        ht.handle_request()
+                        break
+        self.stop()
+
+    def stop(self):
+        """Stops the running StatsHttpd objects. Closes CC session and
+        HTTP handling sockets"""
+        if self.verbose:
+            self.write_log("[b10-stats-httpd] Shutting down\n")
+        self.close_httpd()
+        self.close_mccs()
+
+    def get_sockets(self):
+        """Returns sockets to select.select"""
+        sockets = []
+        if self.mccs is not None:
+            sockets.append(self.mccs.get_socket())
+        if len(self.httpd) > 0:
+            for ht in self.httpd:
+                sockets.append(ht.socket)
+        return sockets
+
+    def config_handler(self, new_config):
+        """Config handler for the ModuleCCSession object. It resets
+        addresses and ports to listen HTTP requests on."""
+        if self.verbose:
+            self.write_log("[b10-stats-httpd] Loading config : %s\n" % str(new_config))
+        for key in new_config.keys():
+            if key not in DEFAULT_CONFIG:
+                if self.verbose:
+                    self.write_log(
+                        "[b10-stats-httpd] Unknown known config: %s" % key)
+                return isc.config.ccsession.create_answer(
+                    1, "Unknown known config: %s" % key)
+        # backup old config
+        old_config = self.config.copy()
+        self.close_httpd()
+        self.load_config(new_config)
+        try:
+            self.open_httpd()
+        except HttpServerError as err:
+            if self.verbose:
+                self.write_log("[b10-stats-httpd] %s\n" % err)
+                self.write_log("[b10-stats-httpd] Restoring old config\n")
+            # restore old config
+            self.config_handler(old_config)
+            return isc.config.ccsession.create_answer(
+                1, "[b10-stats-httpd] %s" % err)
+        else:
+            return isc.config.ccsession.create_answer(0)
+
+    def command_handler(self, command, args):
+        """Command handler for the ModuleCCSesson object. It handles
+        "status" and "shutdown" commands."""
+        if command == "status":
+            if self.verbose:
+                self.write_log("[b10-stats-httpd] Received 'status' command\n")
+            return isc.config.ccsession.create_answer(
+                0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")")
+        elif command == "shutdown":
+            if self.verbose:
+                self.write_log("[b10-stats-httpd] Received 'shutdown' command\n")
+            self.running = False
+            return isc.config.ccsession.create_answer(
+                0, "Stats Httpd is shutting down.")
+        else:
+            if self.verbose:
+                self.write_log("[b10-stats-httpd] Received unknown command\n")
+            return isc.config.ccsession.create_answer(
+                1, "Unknown command: " + str(command))
+
+    def get_stats_data(self):
+        """Requests statistics data to the Stats daemon and returns
+        the data which obtains from it"""
+        try:
+            seq = self.cc_session.group_sendmsg(
+                isc.config.ccsession.create_command('show'),
+                self.stats_module_name)
+            (answer, env) = self.cc_session.group_recvmsg(False, seq)
+            if answer:
+                (rcode, value) = isc.config.ccsession.parse_answer(answer)
+        except (isc.cc.session.SessionTimeout,
+                isc.cc.session.SessionError) as err:
+            raise StatsHttpdError("%s: %s" %
+                                  (err.__class__.__name__, err))
+        else:
+            if rcode == 0:
+                return value
+            else:
+                raise StatsHttpdError("Stats module: %s" % str(value))
+
+    def get_stats_spec(self):
+        """Just returns spec data"""
+        return self.stats_config_spec
+
+    def load_templates(self):
+        """Setup the bodies of XSD and XSL documents to be responds to
+        HTTP clients. Before that it also creates XML tag structures by
+        using xml.etree.ElementTree.Element class and substitutes
+        concrete strings with parameters embed in the string.Template
+        object."""
+        # for XSD
+        xsd_root = xml.etree.ElementTree.Element("all") # started with "all" tag
+        for item in self.get_stats_spec():
+            element = xml.etree.ElementTree.Element(
+                "element",
+                dict( name=item["item_name"],
+                      type=item["item_type"] if item["item_type"].lower() != 'real' else 'float',
+                      minOccurs="1",
+                      maxOccurs="1" ),
+                )
+            annotation = xml.etree.ElementTree.Element("annotation")
+            appinfo = xml.etree.ElementTree.Element("appinfo")
+            documentation = xml.etree.ElementTree.Element("documentation")
+            appinfo.text = item["item_title"]
+            documentation.text = item["item_description"]
+            annotation.append(appinfo)
+            annotation.append(documentation)
+            element.append(annotation)
+            xsd_root.append(element)
+        xsd_string = xml.etree.ElementTree.tostring(xsd_root)
+        self.xsd_body = self.open_template(XSD_TEMPLATE_LOCATION).substitute(
+            xsd_string=xsd_string,
+            xsd_namespace=XSD_NAMESPACE
+            )
+        assert self.xsd_body is not None
+
+        # for XSL
+        xsd_root = xml.etree.ElementTree.Element(
+            "xsl:template",
+            dict(match="*")) # started with xml:template tag
+        for item in self.get_stats_spec():
+            tr = xml.etree.ElementTree.Element("tr")
+            td1 = xml.etree.ElementTree.Element(
+                "td", { "class" : "title",
+                        "title" : item["item_description"] })
+            td1.text = item["item_title"]
+            td2 = xml.etree.ElementTree.Element("td")
+            xsl_valueof = xml.etree.ElementTree.Element(
+                "xsl:value-of",
+                dict(select=item["item_name"]))
+            td2.append(xsl_valueof)
+            tr.append(td1)
+            tr.append(td2)
+            xsd_root.append(tr)
+        xsl_string = xml.etree.ElementTree.tostring(xsd_root)
+        self.xsl_body = self.open_template(XSL_TEMPLATE_LOCATION).substitute(
+            xsl_string=xsl_string,
+            xsd_namespace=XSD_NAMESPACE)
+        assert self.xsl_body is not None
+
+    def xml_handler(self):
+        """Handler which requests to Stats daemon to obtain statistics
+        data and returns the body of XML document"""
+        xml_list=[]
+        for (k, v) in self.get_stats_data().items():
+            (k, v) = (str(k), str(v))
+            elem = xml.etree.ElementTree.Element(k)
+            elem.text = v
+            xml_list.append(
+                xml.etree.ElementTree.tostring(elem))
+        xml_string = "".join(xml_list)
+        self.xml_body = self.open_template(XML_TEMPLATE_LOCATION).substitute(
+            xml_string=xml_string,
+            xsd_namespace=XSD_NAMESPACE,
+            xsd_url_path=XSD_URL_PATH,
+            xsl_url_path=XSL_URL_PATH)
+        assert self.xml_body is not None
+        return self.xml_body
+
+    def xsd_handler(self):
+        """Handler which just returns the body of XSD document"""
+        return self.xsd_body
+
+    def xsl_handler(self):
+        """Handler which just returns the body of XSL document"""
+        return self.xsl_body
+
+    def open_template(self, file_name):
+        """It opens a template file, and it loads all lines to a
+        string variable and returns string. Template object includes
+        the variable. Limitation of a file size isn't needed there."""
+        lines = "".join(
+            open(file_name, 'r').readlines())
+        assert lines is not None
+        return string.Template(lines)
+
+if __name__ == "__main__":
+    try:
+        parser = OptionParser()
+        parser.add_option(
+            "-v", "--verbose", dest="verbose", action="store_true",
+            help="display more about what is going on")
+        (options, args) = parser.parse_args()
+        stats_httpd = StatsHttpd(verbose=options.verbose)
+        stats_httpd.start()
+    except OptionValueError:
+        sys.exit("[b10-stats-httpd] Error parsing options")
+    except isc.cc.session.SessionError as se:
+        sys.exit("[b10-stats-httpd] Error creating module, "
+                 + "is the command channel daemon running?")
+    except HttpServerError as hse:
+        sys.exit("[b10-stats-httpd] %s" % hse)
+    except KeyboardInterrupt as kie:
+        sys.exit("[b10-stats-httpd] Interrupted, exiting")
diff --git a/src/bin/stats/stats_stub.py.in b/src/bin/stats/stats_stub.py.in
deleted file mode 100755
index 4a4a641..0000000
--- a/src/bin/stats/stats_stub.py.in
+++ /dev/null
@@ -1,154 +0,0 @@
-#!@PYTHON@
-
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-__version__ = "$Revision$"
-
-import sys; sys.path.append ('@@PYTHONPATH@@')
-import os
-import time
-from optparse import OptionParser, OptionValueError
-from isc.config.ccsession import ModuleCCSession, create_command, parse_answer, parse_command, create_answer
-from isc.cc import Session, SessionError
-from stats import get_datetime
-
-# for setproctitle
-import isc.util.process
-isc.util.process.rename()
-
-# If B10_FROM_BUILD is set in the environment, we use data files
-# from a directory relative to that, otherwise we use the ones
-# installed on the system
-if "B10_FROM_BUILD" in os.environ:
-    SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
-else:
-    PREFIX = "@prefix@"
-    DATAROOTDIR = "@datarootdir@"
-    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
-
-class CCSessionStub:
-    """
-    This class is intended to behaves as a sender to Stats module. It
-    creates MoudleCCSession object and send specified command.
-    """
-    def __init__(self, session=None, verbose=False):
-        # create ModuleCCSession object
-        self.verbose = verbose
-        self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
-                                          self.__dummy, self.__dummy, session)
-        self.module_name = self.cc_session._module_name
-        self.session = self.cc_session._session
-
-    def __dummy(self, *args):
-        pass
-
-    def send_command(self, command, args):
-        """
-        send command to stats module with args
-        """
-        cmd = create_command(command, args)
-        if self.verbose:
-            sys.stdout.write("[b10-stats_stub] send command : " + str(cmd) + "\n")
-        seq = self.session.group_sendmsg(cmd, self.module_name)
-        msg, env = self.session.group_recvmsg(False, seq) # non-blocking is False
-        if self.verbose:
-            sys.stdout.write("[b10-stats_stub] received env : " + str(env) + "\n")
-            sys.stdout.write("[b10-stats_stub] received message : " + str(msg) + "\n")
-        (ret, arg) = (None, None)
-        if 'result' in msg:
-            ret, arg = parse_answer(msg)
-        elif 'command' in msg:
-            ret, arg = parse_command(msg)
-        self.session.group_reply(env, create_answer(0))
-        return ret, arg, env
-        
-class BossModuleStub:
-    """
-    This class is customized from CCSessionStub and is intended to behaves
-    as a virtual Boss module to send to Stats Module.
-    """
-    def __init__(self, session=None, verbose=False):
-        self.stub = CCSessionStub(session=session, verbose=verbose)
-    
-    def send_boottime(self):
-        return self.stub.send_command("set", {"stats_data": {"bind10.boot_time": get_datetime()}})
-
-class AuthModuleStub:
-    """
-    This class is customized CCSessionStub and is intended to behaves
-    as a virtual Auth module to send to Stats Module.
-    """
-    def __init__(self, session=None, verbose=False):
-        self.stub = CCSessionStub(session=session, verbose=verbose)
-        self.count = { "udp": 0, "tcp": 0 }
-    
-    def send_udp_query_count(self, cmd="set", cnt=0):
-        """
-        count up udp query count
-        """
-        prt = "udp"
-        self.count[prt] = 1
-        if cnt > 0:
-            self.count[prt] = cnt
-        return self.stub.send_command(cmd,
-                                      {"stats_data":
-                                           {"auth.queries."+prt: self.count[prt]}
-                                       })
-
-    def send_tcp_query_count(self, cmd="set", cnt=0):
-        """
-        set udp query count
-        """
-        prt = "tcp"
-        self.count[prt] = self.count[prt] + 1
-        if cnt > 0:
-            self.count[prt] = cnt
-        return self.stub.send_command(cmd,
-                                      {"stats_data":
-                                           {"auth.queries."+prt: self.count[prt]}
-                                       })
-
-def main(session=None):
-    try:
-        parser=OptionParser()
-        parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
-                      help="display more about what is going on")
-        (options, args) = parser.parse_args()
-        stub = CCSessionStub(session=session, verbose=options.verbose)
-        boss = BossModuleStub(session=stub.session, verbose=options.verbose)
-        auth = AuthModuleStub(session=stub.session, verbose=options.verbose)
-        stub.send_command("status", None)
-        boss.send_boottime()
-        t_cnt=0
-        u_cnt=81120
-        auth.send_udp_query_count(cnt=u_cnt) # This is an example.
-        while True:
-            u_cnt = u_cnt + 1
-            t_cnt = t_cnt + 1
-            auth.send_udp_query_count(cnt=u_cnt)
-            auth.send_tcp_query_count(cnt=t_cnt)
-            time.sleep(1)
-
-    except OptionValueError:
-        sys.stderr.write("[b10-stats_stub] Error parsing options\n")
-    except SessionError as se:
-        sys.stderr.write("[b10-stats_stub] Error creating Stats module, "
-              + "is the command channel daemon running?\n")
-    except KeyboardInterrupt as kie:
-        sys.stderr.write("[b10-stats_stub] Interrupted, exiting\n")
-
-if __name__ == "__main__":
-    main()
diff --git a/src/bin/stats/tests/Makefile.am b/src/bin/stats/tests/Makefile.am
index 9e94050..5a13277 100644
--- a/src/bin/stats/tests/Makefile.am
+++ b/src/bin/stats/tests/Makefile.am
@@ -1,8 +1,8 @@
-SUBDIRS = isc testdata
+SUBDIRS = isc http testdata
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = b10-stats_test.py b10-stats_stub_test.py
-EXTRA_DIST = $(PYTESTS) fake_time.py
-CLEANFILES = fake_time.pyc
+PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
+EXTRA_DIST = $(PYTESTS) fake_time.py fake_socket.py fake_select.py
+CLEANFILES = fake_time.pyc fake_socket.pyc fake_select.pyc
 
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
@@ -14,6 +14,6 @@ endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests \
-	B10_FROM_BUILD=$(abs_top_builddir) \
+	B10_FROM_SOURCE=$(abs_top_srcdir) \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
new file mode 100644
index 0000000..07999ea
--- /dev/null
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -0,0 +1,444 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import os
+import http.server
+import string
+import fake_select
+import imp
+import sys
+import fake_socket
+
+import isc.cc
+
+import stats_httpd
+stats_httpd.socket = fake_socket
+stats_httpd.select = fake_select
+
+DUMMY_DATA = {
+    "auth.queries.tcp": 10000,
+    "auth.queries.udp": 12000,
+    "bind10.boot_time": "2011-03-04T11:59:05Z",
+    "report_time": "2011-03-04T11:59:19Z",
+    "stats.boot_time": "2011-03-04T11:59:06Z",
+    "stats.last_update_time": "2011-03-04T11:59:07Z",
+    "stats.lname": "4d70d40a_c at host",
+    "stats.start_time": "2011-03-04T11:59:06Z",
+    "stats.timestamp": 1299239959.560846
+    }
+
+def push_answer(stats_httpd):
+    stats_httpd.cc_session.group_sendmsg(
+        { 'result': 
+          [ 0, DUMMY_DATA ] }, "Stats")
+
+def pull_query(stats_httpd):
+    (msg, env) = stats_httpd.cc_session.group_recvmsg()
+    if 'result' in msg:
+        (ret, arg) = isc.config.ccsession.parse_answer(msg)
+    else:
+        (ret, arg) = isc.config.ccsession.parse_command(msg)
+    return (ret, arg, env)
+
+class TestHttpHandler(unittest.TestCase):
+    """Tests for HttpHandler class"""
+
+    def setUp(self):
+        self.verbose = True
+        self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+        self.assertTrue(type(self.stats_httpd.httpd) is list)
+        self.httpd = self.stats_httpd.httpd
+        for ht in self.httpd:
+            self.assertTrue(ht.verbose)
+        self.stats_httpd.cc_session.verbose = False
+
+    def test_do_GET(self):
+        for ht in self.httpd:
+            self._test_do_GET(ht._handler)
+
+    def _test_do_GET(self, handler):
+
+        # URL is '/bind10/statistics/xml'
+        handler.path = stats_httpd.XML_URL_PATH
+        push_answer(self.stats_httpd)
+        handler.do_GET()
+        (ret, arg, env) = pull_query(self.stats_httpd)
+        self.assertEqual(ret, "show")
+        self.assertIsNone(arg)
+        self.assertTrue('group' in env)
+        self.assertEqual(env['group'], 'Stats')
+        self.assertEqual(handler.response.code, 200)
+        self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+        self.assertTrue(handler.response.headers["Content-Length"] > 0)
+        self.assertTrue(handler.response.wrote_headers)
+        self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+        self.assertTrue(handler.response.body.find(stats_httpd.XSD_URL_PATH)>0)
+        for (k, v) in DUMMY_DATA.items():
+            self.assertTrue(handler.response.body.find(str(k))>0)
+            self.assertTrue(handler.response.body.find(str(v))>0)
+
+        # URL is '/bind10/statitics/xsd'
+        handler.path = stats_httpd.XSD_URL_PATH
+        handler.do_GET()
+        self.assertEqual(handler.response.code, 200)
+        self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+        self.assertTrue(handler.response.headers["Content-Length"] > 0)
+        self.assertTrue(handler.response.wrote_headers)
+        self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+        for (k, v) in DUMMY_DATA.items():
+            self.assertTrue(handler.response.body.find(str(k))>0)
+
+        # URL is '/bind10/statitics/xsl'
+        handler.path = stats_httpd.XSL_URL_PATH
+        handler.do_GET()
+        self.assertEqual(handler.response.code, 200)
+        self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+        self.assertTrue(handler.response.headers["Content-Length"] > 0)
+        self.assertTrue(handler.response.wrote_headers)
+        self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+        for (k, v) in DUMMY_DATA.items():
+            self.assertTrue(handler.response.body.find(str(k))>0)
+
+        # 302 redirect
+        handler.path = '/'
+        handler.headers = {'Host': 'my.host.domain'}
+        handler.do_GET()
+        self.assertEqual(handler.response.code, 302)
+        self.assertEqual(handler.response.headers["Location"],
+                         "http://my.host.domain%s" % stats_httpd.XML_URL_PATH)
+
+        # 404 NotFound
+        handler.path = '/path/to/foo/bar'
+        handler.headers = {}
+        handler.do_GET()
+        self.assertEqual(handler.response.code, 404)
+
+        # failure case(connection with Stats is down)
+        handler.path = stats_httpd.XML_URL_PATH
+        push_answer(self.stats_httpd)
+        self.assertFalse(self.stats_httpd.cc_session._socket._closed)
+        self.stats_httpd.cc_session._socket._closed = True
+        handler.do_GET()
+        self.stats_httpd.cc_session._socket._closed = False
+        self.assertEqual(handler.response.code, 500)
+        self.stats_httpd.cc_session._clear_queues()
+
+        # failure case(Stats module returns err)
+        handler.path = stats_httpd.XML_URL_PATH
+        self.stats_httpd.cc_session.group_sendmsg(
+            { 'result': [ 1, "I have an error." ] }, "Stats")
+        self.assertFalse(self.stats_httpd.cc_session._socket._closed)
+        self.stats_httpd.cc_session._socket._closed = False
+        handler.do_GET()
+        self.assertEqual(handler.response.code, 500)
+        self.stats_httpd.cc_session._clear_queues()
+
+    def test_do_HEAD(self):
+        for ht in self.httpd:
+            self._test_do_HEAD(ht._handler)
+
+    def _test_do_HEAD(self, handler):
+        handler.path = '/path/to/foo/bar'
+        handler.do_HEAD()
+        self.assertEqual(handler.response.code, 404)
+
+    def test_log_message(self):
+        for ht in self.httpd:
+            self._test_log_message(ht._handler)
+
+    def _test_log_message(self, handler):
+        # switch write_log function
+        handler.server.log_writer = handler.response._write_log
+        log_message = 'ABCDEFG'
+        handler.log_message("%s", log_message)
+        self.assertEqual(handler.response.log, 
+                         "[b10-stats-httpd] %s - - [%s] %s\n" %
+                         (handler.address_string(),
+                          handler.log_date_time_string(),
+                          log_message))
+
+class TestHttpServerError(unittest.TestCase):
+    """Tests for HttpServerError exception"""
+
+    def test_raises(self):
+        try:
+            raise stats_httpd.HttpServerError('Nothing')
+        except stats_httpd.HttpServerError as err:
+            self.assertEqual(str(err), 'Nothing')
+
+class TestHttpServer(unittest.TestCase):
+    """Tests for HttpServer class"""
+
+    def test_httpserver(self):
+        self.verbose = True
+        self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+        self.stats_httpd.cc_session.verbose = False
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(ht.server_address in self.stats_httpd.http_addrs)
+            self.assertEqual(ht.verbose, self.verbose)
+            self.assertEqual(ht.xml_handler, self.stats_httpd.xml_handler)
+            self.assertEqual(ht.xsd_handler, self.stats_httpd.xsd_handler)
+            self.assertEqual(ht.xsl_handler, self.stats_httpd.xsl_handler)
+            self.assertEqual(ht.log_writer, self.stats_httpd.write_log)
+            self.assertTrue(isinstance(ht._handler, stats_httpd.HttpHandler))
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+
+class TestStatsHttpdError(unittest.TestCase):
+    """Tests for StatsHttpdError exception"""
+
+    def test_raises(self):
+        try:
+            raise stats_httpd.StatsHttpdError('Nothing')
+        except stats_httpd.StatsHttpdError as err:
+            self.assertEqual(str(err), 'Nothing')
+
+class TestStatsHttpd(unittest.TestCase):
+    """Tests for StatsHttpd class"""
+
+    def setUp(self):
+        self.verbose = True
+        fake_socket._CLOSED = False
+        fake_socket.has_ipv6 = True
+        self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+        self.stats_httpd.cc_session.verbose = False
+
+    def tearDown(self):
+        self.stats_httpd.stop()
+
+    def test_init(self):
+        self.assertTrue(self.stats_httpd.verbose)
+        self.assertFalse(self.stats_httpd.mccs.get_socket()._closed)
+        self.assertEqual(self.stats_httpd.mccs.get_socket().fileno(),
+                         id(self.stats_httpd.mccs.get_socket()))
+        for ht in self.stats_httpd.httpd:
+            self.assertFalse(ht.socket._closed)
+            self.assertEqual(ht.socket.fileno(), id(ht.socket))
+        fake_socket._CLOSED = True
+        self.assertRaises(isc.cc.session.SessionError,
+                          stats_httpd.StatsHttpd)
+        fake_socket._CLOSED = False
+
+    def test_mccs(self):
+        self.stats_httpd.open_mccs()
+        self.assertTrue(
+            isinstance(self.stats_httpd.mccs.get_socket(), fake_socket.socket))
+        self.assertTrue(
+            isinstance(self.stats_httpd.cc_session, isc.cc.session.Session))
+        self.assertTrue(
+            isinstance(self.stats_httpd.stats_module_spec, isc.config.ModuleSpec))
+        for cfg in self.stats_httpd.stats_config_spec:
+            self.assertTrue('item_name' in cfg)
+            self.assertTrue(cfg['item_name'] in DUMMY_DATA)
+        self.assertTrue(len(self.stats_httpd.stats_config_spec), len(DUMMY_DATA))
+
+    def test_load_config(self):
+        self.stats_httpd.load_config()
+        self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+
+    def test_httpd(self):
+        # dual stack (addresses is ipv4 and ipv6)
+        fake_socket.has_ipv6 = True
+        self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+        self.stats_httpd.http_addrs = [ ('::1', 8000), ('127.0.0.1', 8000) ]
+        self.assertTrue(
+            stats_httpd.HttpServer.address_family in set([fake_socket.AF_INET, fake_socket.AF_INET6]))
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        # dual stack (address is ipv6)
+        fake_socket.has_ipv6 = True
+        self.stats_httpd.http_addrs = [ ('::1', 8000) ]
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        # dual stack (address is ipv4)
+        fake_socket.has_ipv6 = True
+        self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        # only-ipv4 single stack
+        fake_socket.has_ipv6 = False
+        self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        # only-ipv4 single stack (force set ipv6 )
+        fake_socket.has_ipv6 = False
+        self.stats_httpd.http_addrs = [ ('::1', 8000) ]
+        self.assertRaises(stats_httpd.HttpServerError,
+            self.stats_httpd.open_httpd)
+
+        # hostname
+        self.stats_httpd.http_addrs = [ ('localhost', 8000) ]
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        self.stats_httpd.http_addrs = [ ('my.host.domain', 8000) ]
+        self.stats_httpd.open_httpd()
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+        self.stats_httpd.close_httpd()
+
+        # over flow of port number
+        self.stats_httpd.http_addrs = [ ('', 80000) ]
+        self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+        # negative
+        self.stats_httpd.http_addrs = [ ('', -8000) ]
+        self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+        # alphabet
+        self.stats_httpd.http_addrs = [ ('', 'ABCDE') ]
+        self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+
+    def test_start(self):
+        self.stats_httpd.cc_session.group_sendmsg(
+            { 'command': [ "shutdown" ] }, "StatsHttpd")
+        self.stats_httpd.start()
+        self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+        self.stats_httpd.cc_session.verbose = False
+        self.assertRaises(
+            fake_select.error, self.stats_httpd.start)
+
+    def test_stop(self):
+        # success case
+        fake_socket._CLOSED = False
+        self.stats_httpd.stop()
+        self.assertFalse(self.stats_httpd.running)
+        self.assertIsNone(self.stats_httpd.mccs)
+        for ht in self.stats_httpd.httpd:
+            self.assertTrue(ht.socket._closed)
+        self.assertTrue(self.stats_httpd.cc_session._socket._closed)
+        # failure case
+        self.stats_httpd.cc_session._socket._closed = False
+        self.stats_httpd.open_mccs()
+        self.stats_httpd.cc_session._socket._closed = True
+        self.stats_httpd.stop() # No excetion raises
+        self.stats_httpd.cc_session._socket._closed = False
+
+    def test_open_template(self):
+        # successful conditions
+        tmpl = self.stats_httpd.open_template(stats_httpd.XML_TEMPLATE_LOCATION)
+        self.assertTrue(isinstance(tmpl, string.Template))
+        opts = dict(
+            xml_string="<dummy></dummy>",
+            xsd_namespace="http://host/path/to/",
+            xsd_url_path="/path/to/",
+            xsl_url_path="/path/to/")
+        lines = tmpl.substitute(opts)
+        for n in opts:
+            self.assertTrue(lines.find(opts[n])>0)
+        tmpl = self.stats_httpd.open_template(stats_httpd.XSD_TEMPLATE_LOCATION)
+        self.assertTrue(isinstance(tmpl, string.Template))
+        opts = dict(
+            xsd_string="<dummy></dummy>",
+            xsd_namespace="http://host/path/to/")
+        lines = tmpl.substitute(opts)
+        for n in opts:
+            self.assertTrue(lines.find(opts[n])>0)
+        tmpl = self.stats_httpd.open_template(stats_httpd.XSL_TEMPLATE_LOCATION)
+        self.assertTrue(isinstance(tmpl, string.Template))
+        opts = dict(
+            xsl_string="<dummy></dummy>",
+            xsd_namespace="http://host/path/to/")
+        lines = tmpl.substitute(opts)
+        for n in opts:
+            self.assertTrue(lines.find(opts[n])>0)
+        # unsuccessful condition
+        self.assertRaises(
+            IOError,
+            self.stats_httpd.open_template, '/path/to/foo/bar')
+
+    def test_commands(self):
+        self.assertEqual(self.stats_httpd.command_handler("status", None),
+                         isc.config.ccsession.create_answer(
+                0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
+        self.stats_httpd.running = True
+        self.assertEqual(self.stats_httpd.command_handler("shutdown", None),
+                         isc.config.ccsession.create_answer(
+                0, "Stats Httpd is shutting down."))
+        self.assertFalse(self.stats_httpd.running)
+        self.assertEqual(
+            self.stats_httpd.command_handler("__UNKNOWN_COMMAND__", None),
+            isc.config.ccsession.create_answer(
+                1, "Unknown command: __UNKNOWN_COMMAND__"))
+
+    def test_config(self):
+        self.assertEqual(
+            self.stats_httpd.config_handler(dict(_UNKNOWN_KEY_=None)),
+            isc.config.ccsession.create_answer(
+                    1, "Unknown known config: _UNKNOWN_KEY_"))
+        self.assertEqual(
+            self.stats_httpd.config_handler(
+                        dict(listen_on=[dict(address="::2",port=8000)])),
+            isc.config.ccsession.create_answer(0))
+        self.assertTrue("listen_on" in self.stats_httpd.config)
+        for addr in self.stats_httpd.config["listen_on"]:
+            self.assertTrue("address" in addr)
+            self.assertTrue("port" in addr)
+            self.assertTrue(addr["address"] == "::2")
+            self.assertTrue(addr["port"] == 8000)
+
+        self.assertEqual(
+            self.stats_httpd.config_handler(
+                        dict(listen_on=[dict(address="::1",port=80)])),
+            isc.config.ccsession.create_answer(0))
+        self.assertTrue("listen_on" in self.stats_httpd.config)
+        for addr in self.stats_httpd.config["listen_on"]:
+            self.assertTrue("address" in addr)
+            self.assertTrue("port" in addr)
+            self.assertTrue(addr["address"] == "::1")
+            self.assertTrue(addr["port"] == 80)
+
+        self.assertEqual(
+            self.stats_httpd.config_handler(
+                        dict(listen_on=[dict(address="1.2.3.4",port=54321)])),
+            isc.config.ccsession.create_answer(0))
+        self.assertTrue("listen_on" in self.stats_httpd.config)
+        for addr in self.stats_httpd.config["listen_on"]:
+            self.assertTrue("address" in addr)
+            self.assertTrue("port" in addr)
+            self.assertTrue(addr["address"] == "1.2.3.4")
+            self.assertTrue(addr["port"] == 54321)
+        (ret, arg) = isc.config.ccsession.parse_answer(
+            self.stats_httpd.config_handler(
+                dict(listen_on=[dict(address="1.2.3.4",port=543210)]))
+            )
+        self.assertEqual(ret, 1)
+
+    def test_for_without_B10_FROM_SOURCE(self):
+        # just lets it go through the code without B10_FROM_SOURCE env
+        # variable
+        if "B10_FROM_SOURCE" in os.environ:
+            tmppath = os.environ["B10_FROM_SOURCE"]
+            os.environ.pop("B10_FROM_SOURCE")
+            imp.reload(stats_httpd)
+            os.environ["B10_FROM_SOURCE"] = tmppath
+            imp.reload(stats_httpd)
+            stats_httpd.socket = fake_socket
+            stats_httpd.select = fake_select
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/bin/stats/tests/b10-stats_stub_test.py b/src/bin/stats/tests/b10-stats_stub_test.py
deleted file mode 100644
index b8983c5..0000000
--- a/src/bin/stats/tests/b10-stats_stub_test.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-__version__ = "$Revision$"
-
-#
-# Tests for the stats stub module
-#
-import unittest
-import time
-import os
-import imp
-import stats_stub
-from isc.cc.session import Session
-from stats_stub import CCSessionStub, BossModuleStub, AuthModuleStub
-from stats import get_datetime
-
-class TestStats(unittest.TestCase):
-
-    def setUp(self):
-        self.session = Session()
-        self.stub = CCSessionStub(session=self.session, verbose=True)
-        self.boss = BossModuleStub(session=self.session, verbose=True)
-        self.auth = AuthModuleStub(session=self.session, verbose=True)
-        self.env = {'from': self.session.lname, 'group': 'Stats',
-                    'instance': '*', 'to':'*',
-                    'type':'send','seq':0}
-        self.result_ok = {'result': [0]}
-
-    def tearDown(self):
-        self.session.close()
-
-    def test_stub(self):
-        """
-        Test for send_command of CCSessionStub object
-        """
-        env = self.env
-        result_ok = self.result_ok
-        self.assertEqual(('status', None, env),
-                         self.stub.send_command('status', None))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(('shutdown', None, env),
-                         self.stub.send_command('shutdown', None))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(('show', None, env),
-                         self.stub.send_command('show', None))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(('set', {'atest': 100.0}, env),
-                         self.stub.send_command('set', {'atest': 100.0}))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
-    def test_boss_stub(self):
-        """
-        Test for send_command of BossModuleStub object
-        """
-        env = self.env
-        result_ok = self.result_ok
-        self.assertEqual(('set', {"stats_data":
-                                      {"bind10.boot_time": get_datetime()}
-                                  }, env), self.boss.send_boottime())
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
-    def test_auth_stub(self):
-        """
-        Test for send_command of AuthModuleStub object
-        """
-        env = self.env
-        result_ok = self.result_ok
-        self.assertEqual(
-            ('set', {"stats_data": {"auth.queries.udp": 1}}, env),
-            self.auth.send_udp_query_count())
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(
-            ('set', {"stats_data": {"auth.queries.tcp": 1}}, env),
-            self.auth.send_tcp_query_count())
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(
-            ('set', {"stats_data": {"auth.queries.udp": 100}}, env),
-            self.auth.send_udp_query_count(cmd='set', cnt=100))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-        self.assertEqual(
-            ('set', {"stats_data": {"auth.queries.tcp": 99}}, env),
-            self.auth.send_tcp_query_count(cmd='set', cnt=99))
-        self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
-    def test_func_main(self):
-        # explicitly make failed
-        self.session.close()
-        stats_stub.main(session=self.session)
-
-    def test_osenv(self):
-        """
-        test for not having environ "B10_FROM_BUILD"
-        """
-        if "B10_FROM_BUILD" in os.environ:
-            path = os.environ["B10_FROM_BUILD"]
-            os.environ.pop("B10_FROM_BUILD")
-            imp.reload(stats_stub)
-            os.environ["B10_FROM_BUILD"] = path
-            imp.reload(stats_stub)
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/bin/stats/tests/b10-stats_test.py b/src/bin/stats/tests/b10-stats_test.py
index e4e1a1e..eccabdc 100644
--- a/src/bin/stats/tests/b10-stats_test.py
+++ b/src/bin/stats/tests/b10-stats_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010, 2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -13,8 +13,6 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-__version__ = "$Revision$"
-
 #
 # Tests for the stats module
 #
@@ -25,7 +23,11 @@ import unittest
 import imp
 from isc.cc.session import Session, SessionError
 from isc.config.ccsession import ModuleCCSession, ModuleCCSessionError
+from fake_time import time, strftime, gmtime
 import stats
+stats.time = time
+stats.strftime = strftime
+stats.gmtime = gmtime
 from stats import SessionSubject, CCSessionListener, get_timestamp, get_datetime
 from fake_time import _TEST_TIME_SECS, _TEST_TIME_STRF
 
@@ -504,6 +506,13 @@ class TestStats(unittest.TestCase):
         self.assertEqual(result_ok(),
                          self.session.get_message("Stats", None))
 
+    def test_for_boss(self):
+        last_queue = self.session.old_message_queue.pop()
+        self.assertEqual(
+            last_queue.msg, {'command': ['sendstats']})
+        self.assertEqual(
+            last_queue.env['group'], 'Boss')
+
 class TestStats2(unittest.TestCase):
 
     def setUp(self):
@@ -530,12 +539,19 @@ class TestStats2(unittest.TestCase):
         Test for specfile
         
         """
-        if "B10_FROM_BUILD" in os.environ:
+        if "B10_FROM_SOURCE" in os.environ:
             self.assertEqual(stats.SPECFILE_LOCATION,
-                             os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec")
+                             os.environ["B10_FROM_SOURCE"] + os.sep + \
+                                 "src" + os.sep + "bin" + os.sep + "stats" + \
+                                 os.sep + "stats.spec")
+            self.assertEqual(stats.SCHEMA_SPECFILE_LOCATION,
+                             os.environ["B10_FROM_SOURCE"] + os.sep + \
+                                 "src" + os.sep + "bin" + os.sep + "stats" + \
+                                 os.sep + "stats-schema.spec")
         imp.reload(stats)
         # change path of SPECFILE_LOCATION
         stats.SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
+        stats.SCHEMA_SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
         self.assertEqual(stats.SPECFILE_LOCATION, TEST_SPECFILE_LOCATION)
         self.subject = stats.SessionSubject(session=self.session, verbose=True)
         self.session = self.subject.session
@@ -626,13 +642,13 @@ class TestStats2(unittest.TestCase):
 
     def test_osenv(self):
         """
-        test for not having environ "B10_FROM_BUILD"
+        test for not having environ "B10_FROM_SOURCE"
         """
-        if "B10_FROM_BUILD" in os.environ:
-            path = os.environ["B10_FROM_BUILD"]
-            os.environ.pop("B10_FROM_BUILD")
+        if "B10_FROM_SOURCE" in os.environ:
+            path = os.environ["B10_FROM_SOURCE"]
+            os.environ.pop("B10_FROM_SOURCE")
             imp.reload(stats)
-            os.environ["B10_FROM_BUILD"] = path
+            os.environ["B10_FROM_SOURCE"] = path
             imp.reload(stats)
 
 def result_ok(*args):
diff --git a/src/bin/stats/tests/fake_select.py b/src/bin/stats/tests/fake_select.py
new file mode 100644
index 0000000..ca0ca82
--- /dev/null
+++ b/src/bin/stats/tests/fake_select.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of select
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import fake_socket
+import errno
+
+class error(Exception):
+    pass
+
+def select(rlst, wlst, xlst, timeout):
+    if type(timeout) != int and type(timeout) != float:
+            raise TypeError("Error: %s must be integer or float"
+                            % timeout.__class__.__name__)
+    for s in rlst + wlst + xlst:
+        if type(s) != fake_socket.socket:
+            raise TypeError("Error: %s must be a dummy socket"
+                            % s.__class__.__name__)
+        s._called = s._called + 1
+        if s._called > 3:
+            raise error("Something is happened!")
+        elif s._called > 2:
+            raise error(errno.EINTR)
+    return (rlst, wlst, xlst)
diff --git a/src/bin/stats/tests/fake_socket.py b/src/bin/stats/tests/fake_socket.py
new file mode 100644
index 0000000..4e3a458
--- /dev/null
+++ b/src/bin/stats/tests/fake_socket.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of socket
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import re
+
+AF_INET = 'AF_INET'
+AF_INET6 = 'AF_INET6'
+_ADDRFAMILY = AF_INET
+has_ipv6 = True
+_CLOSED = False
+
+class gaierror(Exception):
+    pass
+
+class error(Exception):
+    pass
+
+class socket:
+
+    def __init__(self, family=None):
+        if family is None:
+            self.address_family = _ADDRFAMILY
+        else:
+            self.address_family = family
+        self._closed = _CLOSED
+        if self._closed:
+            raise error('socket is already closed!')
+        self._called = 0
+
+    def close(self):
+        self._closed = True
+
+    def fileno(self):
+        return id(self)
+
+    def bind(self, server_class):
+        (self.server_address, self.server_port) = server_class
+        if self.address_family not in set([AF_INET, AF_INET6]):
+            raise error("Address family not supported by protocol: %s" % self.address_family)
+        if self.address_family == AF_INET6 and not has_ipv6:
+            raise error("Address family not supported in this machine: %s has_ipv6: %s"
+                        % (self.address_family, str(has_ipv6)))
+        if self.address_family == AF_INET and re.search(':', self.server_address) is not None:
+            raise gaierror("Address family for hostname not supported : %s %s" % (self.server_address, self.address_family))
+        if self.address_family == AF_INET6 and re.search(':', self.server_address) is None:
+            raise error("Cannot assign requested address : %s" % str(self.server_address))
+        if type(self.server_port) is not int:
+            raise TypeError("an integer is required: %s" % str(self.server_port))
+        if self.server_port < 0 or self.server_port > 65535:
+            raise OverflowError("port number must be 0-65535.: %s" % str(self.server_port))
diff --git a/src/bin/stats/tests/http/Makefile.am b/src/bin/stats/tests/http/Makefile.am
new file mode 100644
index 0000000..879e8a8
--- /dev/null
+++ b/src/bin/stats/tests/http/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py server.py
+CLEANFILES = __init__.pyc server.pyc
diff --git a/src/bin/stats/tests/http/__init__.py b/src/bin/stats/tests/http/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/bin/stats/tests/http/server.py b/src/bin/stats/tests/http/server.py
new file mode 100644
index 0000000..70ed6fa
--- /dev/null
+++ b/src/bin/stats/tests/http/server.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of http.server
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import fake_socket
+
+class DummyHttpResponse:
+    def __init__(self, path):
+        self.path = path
+        self.headers={}
+        self.log = ""
+
+    def _write_log(self, msg):
+        self.log = self.log + msg
+
+class HTTPServer:
+    """
+    A mock-up class of http.server.HTTPServer
+    """
+    address_family = fake_socket.AF_INET
+    def __init__(self, server_class, handler_class):
+        self.socket = fake_socket.socket(self.address_family)
+        self.server_class = server_class
+        self.socket.bind(self.server_class)
+        self._handler = handler_class(None, None, self)
+
+    def handle_request(self):
+        pass
+
+    def server_close(self):
+        self.socket.close()
+
+class BaseHTTPRequestHandler:
+    """
+    A mock-up class of http.server.BaseHTTPRequestHandler
+    """
+
+    def __init__(self, request, client_address, server):
+        self.path = "/path/to"
+        self.headers = {}
+        self.server = server
+        self.response = DummyHttpResponse(path=self.path)
+        self.response.write = self._write
+        self.wfile = self.response
+
+    def send_response(self, code=0):
+        if self.path != self.response.path:
+            self.response = DummyHttpResponse(path=self.path)
+        self.response.code = code
+
+    def send_header(self, key, value):
+        if self.path != self.response.path:
+            self.response = DummyHttpResponse(path=self.path)
+        self.response.headers[key] = value
+
+    def end_headers(self):
+        if self.path != self.response.path:
+            self.response = DummyHttpResponse(path=self.path)
+        self.response.wrote_headers = True
+
+    def send_error(self, code, message=None):
+        if self.path != self.response.path:
+            self.response = DummyHttpResponse(path=self.path)
+        self.response.code = code
+        self.response.body = message
+
+    def address_string(self):
+        return 'dummyhost'
+
+    def log_date_time_string(self):
+        return '[DD/MM/YYYY HH:MI:SS]'
+
+    def _write(self, obj):
+        if self.path != self.response.path:
+            self.response = DummyHttpResponse(path=self.path)
+        self.response.body = obj.decode()
+
diff --git a/src/bin/stats/tests/isc/cc/session.py b/src/bin/stats/tests/isc/cc/session.py
index 4d12adc..e16d6a9 100644
--- a/src/bin/stats/tests/isc/cc/session.py
+++ b/src/bin/stats/tests/isc/cc/session.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010,2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -13,11 +13,16 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# This module is a mock-up class of isc.cc.session
+"""
+A mock-up module of isc.cc.session
 
-__version__ = "$Revision$"
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
 
 import sys
+import fake_socket
 
 # set a dummy lname
 _TEST_LNAME = '123abc at xxxx'
@@ -33,12 +38,18 @@ class Queue():
 class SessionError(Exception):
     pass
 
+class SessionTimeout(Exception):
+    pass
+
 class Session:
     def __init__(self, socket_file=None, verbose=False):
         self._lname = _TEST_LNAME
         self.message_queue = []
         self.old_message_queue = []
-        self._socket = True
+        try:
+            self._socket = fake_socket.socket()
+        except fake_socket.error as se:
+            raise SessionError(se)
         self.verbose = verbose
 
     @property
@@ -46,13 +57,17 @@ class Session:
         return self._lname
 
     def close(self):
-        self._socket = False
+        self._socket.close()
+
+    def _clear_queues(self):
+        while len(self.message_queue) > 0:
+            self.dequeue()
 
     def _next_sequence(self, que=None):
         return len(self.message_queue)
 
     def enqueue(self, msg=None, env={}):
-        if not self._socket:
+        if self._socket._closed:
             raise SessionError("Session has been closed.")
         seq = self._next_sequence()
         env.update({"seq": 0}) # fixed here
@@ -62,12 +77,12 @@ class Session:
             sys.stdout.write("[Session] enqueue: " + str(que.dump()) + "\n")
         return seq
 
-    def dequeue(self, seq=0):
-        if not self._socket:
+    def dequeue(self):
+        if self._socket._closed:
             raise SessionError("Session has been closed.")
         que = None
         try:
-            que = self.message_queue.pop(seq)
+            que = self.message_queue.pop(0) # always pop at index 0
             self.old_message_queue.append(que)
         except IndexError:
             que = Queue()
@@ -76,7 +91,7 @@ class Session:
         return que
 
     def get_queue(self, seq=None):
-        if not self._socket:
+        if self._socket._closed:
             raise SessionError("Session has been closed.")
         if seq is None:
             seq = len(self.message_queue) - 1
@@ -99,7 +114,7 @@ class Session:
                 "instance": instance })
 
     def group_recvmsg(self, nonblock=True, seq=0):
-        que = self.dequeue(seq)
+        que = self.dequeue()
         return que.msg, que.env
         
     def group_reply(self, routing, msg):
@@ -112,7 +127,7 @@ class Session:
                 "reply": routing["seq"] })
 
     def get_message(self, group, to='*'):
-        if not self._socket:
+        if self._socket._closed:
             raise SessionError("Session has been closed.")
         que = Queue()
         for q in self.message_queue:
@@ -124,3 +139,10 @@ class Session:
             sys.stdout.write("[Session] get_message: " + str(que.dump()) + "\n")
         return q.msg
 
+    def group_subscribe(self, group, instance = "*"):
+        if self._socket._closed:
+            raise SessionError("Session has been closed.")
+
+    def group_unsubscribe(self, group, instance = "*"):
+        if self._socket._closed:
+            raise SessionError("Session has been closed.")
diff --git a/src/bin/stats/tests/isc/config/ccsession.py b/src/bin/stats/tests/isc/config/ccsession.py
index fc285a7..a4e9c37 100644
--- a/src/bin/stats/tests/isc/config/ccsession.py
+++ b/src/bin/stats/tests/isc/config/ccsession.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010,2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -13,16 +13,22 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# This module is a mock-up class of isc.cc.session
+"""
+A mock-up module of isc.cc.session
 
-__version__ = "$Revision$"
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
 
 import json
+import os
 from isc.cc.session import Session
 
 COMMAND_CONFIG_UPDATE = "config_update"
 
 def parse_answer(msg):
+    assert 'result' in msg
     try:
         return msg['result'][0], msg['result'][1]
     except IndexError:
@@ -35,6 +41,7 @@ def create_answer(rcode, arg = None):
         return { 'result': [ rcode, arg ] }
 
 def parse_command(msg):
+    assert 'command' in msg
     try:
         return msg['command'][0], msg['command'][1]
     except IndexError:
@@ -47,9 +54,21 @@ def create_command(command_name, params = None):
         return {"command": [command_name, params]}
 
 def module_spec_from_file(spec_file, check = True):
-    file = open(spec_file)
-    module_spec = json.loads(file.read())
-    return ModuleSpec(module_spec['module_spec'], check)
+    try:
+        file = open(spec_file)
+        json_str = file.read()
+        module_spec = json.loads(json_str)
+        file.close()
+        return ModuleSpec(module_spec['module_spec'], check)
+    except IOError as ioe:
+        raise ModuleSpecError("JSON read error: " + str(ioe))
+    except ValueError as ve:
+        raise ModuleSpecError("JSON parse error: " + str(ve))
+    except KeyError as err:
+        raise ModuleSpecError("Data definition has no module_spec element")
+
+class ModuleSpecError(Exception):
+    pass
 
 class ModuleSpec:
     def __init__(self, module_spec, check = True):
@@ -67,10 +86,34 @@ class ModuleSpec:
 class ModuleCCSessionError(Exception):
     pass
 
+class DataNotFoundError(Exception):
+    pass
+
 class ConfigData:
     def __init__(self, specification):
         self.specification = specification
 
+    def get_value(self, identifier):
+        """Returns a tuple where the first item is the value at the
+           given identifier, and the second item is absolutely False
+           even if the value is an unset default or not. Raises an
+           DataNotFoundError if the identifier is not found in the
+           specification file.
+           *** NOTE ***
+           There are some differences from the original method. This
+           method never handles local settings like the original
+           method. But these different behaviors aren't so big issues
+           for a mock-up method of stats_httpd because stats_httpd
+           calls this method at only first."""
+        for config_map in self.get_module_spec().get_config_spec():
+            if config_map['item_name'] == identifier:
+                if 'item_default' in config_map:
+                    return config_map['item_default'], False
+        raise DataNotFoundError("item_name %s is not found in the specfile" % identifier)
+
+    def get_module_spec(self):
+        return self.specification
+
 class ModuleCCSession(ConfigData):
     def __init__(self, spec_file_name, config_handler, command_handler, cc_session = None):
         module_spec = module_spec_from_file(spec_file_name)
@@ -111,3 +154,7 @@ class ModuleCCSession(ConfigData):
 
     def get_module_spec(self):
         return self.specification
+
+    def get_socket(self):
+        return self._session._socket
+
diff --git a/src/bin/stats/tests/isc/util/process.py b/src/bin/stats/tests/isc/util/process.py
index 7274a48..0f764c1 100644
--- a/src/bin/stats/tests/isc/util/process.py
+++ b/src/bin/stats/tests/isc/util/process.py
@@ -13,6 +13,9 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# A dummy function of isc.util.process.rename()
+"""
+A dummy function of isc.util.process.rename()
+"""
+
 def rename(name=None):
     pass
diff --git a/src/bin/stats/tests/isc/utils/Makefile.am b/src/bin/stats/tests/isc/utils/Makefile.am
deleted file mode 100644
index b09fdee..0000000
--- a/src/bin/stats/tests/isc/utils/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_DIST = __init__.py process.py
-CLEANFILES = __init__.pyc process.pyc
diff --git a/src/bin/stats/tests/isc/utils/__init__.py b/src/bin/stats/tests/isc/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/bin/stats/tests/isc/utils/process.py b/src/bin/stats/tests/isc/utils/process.py
deleted file mode 100644
index 4c0cf8c..0000000
--- a/src/bin/stats/tests/isc/utils/process.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# A dummy function of isc.utils.process.rename()
-def rename(name=None):
-    pass
diff --git a/src/bin/stats/tests/stats_test.in b/src/bin/stats/tests/stats_test.in
deleted file mode 100644
index a3279a7..0000000
--- a/src/bin/stats/tests/stats_test.in
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/bin/stats:@abs_top_srcdir@/src/bin/stats/tests
-export PYTHONPATH
-
-B10_FROM_BUILD=@abs_top_builddir@
-export B10_FROM_BUILD
-
-TEST_PATH=@abs_top_srcdir@/src/bin/stats/tests
-
-cd ${TEST_PATH}
-${PYTHON_EXEC} -O b10-stats_test.py $*
-${PYTHON_EXEC} -O b10-stats_stub_test.py $*
diff --git a/src/bin/xfrin/b10-xfrin.8 b/src/bin/xfrin/b10-xfrin.8
index d0723b5..3ea2293 100644
--- a/src/bin/xfrin/b10-xfrin.8
+++ b/src/bin/xfrin/b10-xfrin.8
@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrin
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: September 8, 2010
+.\"      Date: May 19, 2011
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-XFRIN" "8" "September 8, 2010" "BIND10" "BIND10"
+.TH "B10\-XFRIN" "8" "May 19, 2011" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -43,7 +43,7 @@ boss process\&. When triggered it can request and receive a zone transfer and st
 .ps -1
 .br
 .sp
-The Y1 prototype release only supports AXFR\&. IXFR is not implemented\&.
+This prototype release only supports AXFR\&. IXFR is not implemented\&.
 .sp .5v
 .RE
 .PP
@@ -61,15 +61,34 @@ receives its configurations from
 .PP
 The configurable settings are:
 .PP
-\fImaster_addr\fR
-The default is 127\&.0\&.0\&.1\&.
-.PP
-\fImaster_port\fR
-The default is 53\&.
-.PP
 \fItransfers\-in\fR
 defines the maximum number of inbound zone transfers that can run concurrently\&. The default is 10\&.
 .PP
+
+\fIzones\fR
+is a list of zones known to the
+\fBb10\-xfrin\fR
+daemon\&. The list items are:
+\fIname\fR
+(the zone name),
+\fImaster_addr\fR
+(the zone master to transfer from),
+\fImaster_port\fR
+(defaults to 53), and
+\fItsig_key\fR
+(optional TSIG key to use)\&. The
+\fItsig_key\fR
+is specified using a full string colon\-delimited name:key:algorithm representation (e\&.g\&.
+\(lqfoo\&.example\&.org:EvABsfU2h7uofnmqaRCrhHunGsd=:hmac\-sha1\(rq)\&.
+.PP
+(The site\-wide
+\fImaster_addr\fR
+and
+\fImaster_port\fR
+configurations are deprecated; use the
+\fIzones\fR
+list configuration instead\&.)
+.PP
 The configuration commands are:
 .PP
 
@@ -106,7 +125,9 @@ to define the class (defaults to
 \fImaster\fR
 to define the IP address of the authoritative server to transfer from, and
 \fIport\fR
-to define the port number on the authoritative server (defaults to 53)\&.
+to define the port number on the authoritative server (defaults to 53)\&. If the address or port is not specified, it will use the values previously defined in the
+\fIzones\fR
+configuration\&.
 .PP
 
 \fBshutdown\fR
@@ -143,5 +164,5 @@ The
 daemon was implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2011 Internet Systems Consortium, Inc. ("ISC")
 .br
diff --git a/src/bin/xfrin/b10-xfrin.xml b/src/bin/xfrin/b10-xfrin.xml
index fdfe1ef..ea4c724 100644
--- a/src/bin/xfrin/b10-xfrin.xml
+++ b/src/bin/xfrin/b10-xfrin.xml
@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "—">]>
 <!--
- - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
  -
  - Permission to use, copy, modify, and/or distribute this software for any
  - purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>September 8, 2010</date>
+    <date>May 19, 2011</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2011</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -62,6 +62,12 @@
       the zone in a BIND 10 zone data store.
     </para>
 
+<!-- TODO:
+xfrin only does the transfer to make it as simple as possible.
+The logic for handling transfer triggers or zone management is handled
+in separate zonemgr process.
+-->
+
     <note><simpara>
       This prototype release only supports AXFR. IXFR is not implemented.
     </simpara></note>
@@ -86,20 +92,33 @@
       The configurable settings are:
     </para>
 
-    <para><varname>master_addr</varname>
-<!-- TODO: how can there be a single setting for this? -->
-       The default is 127.0.0.1.
+    <para><varname>transfers-in</varname>
+      defines the maximum number of inbound zone transfers
+      that can run concurrently. The default is 10.
     </para>
 
-    <para><varname>master_port</varname>
-<!-- TODO: what if custom is needed per zone? -->
-      The default is 53.
+<!-- TODO: is name okay for master_addr or just IP? -->
+    <para>
+      <varname>zones</varname> is a list of zones known to the
+      <command>b10-xfrin</command> daemon.
+      The list items are:
+      <varname>name</varname> (the zone name),
+      <varname>master_addr</varname> (the zone master to transfer from),
+      <varname>master_port</varname> (defaults to 53), and
+      <varname>tsig_key</varname> (optional TSIG key to use).
+      The <varname>tsig_key</varname> is specified using a full string
+      colon-delimited name:key:algorithm representation (e.g.
+      <quote>foo.example.org:EvABsfU2h7uofnmqaRCrhHunGsd=:hmac-sha1</quote>).
     </para>
+<!-- TODO: document this better -->
+<!-- TODO: the tsig_key format may change -->
 
-    <para><varname>transfers-in</varname>
-      defines the maximum number of inbound zone transfers
-      that can run concurrently. The default is 10.
+    <para>
+      (The site-wide <varname>master_addr</varname> and
+      <varname>master_port</varname> configurations are deprecated;
+      use the <varname>zones</varname> list configuration instead.)
     </para>
+<!-- NOTE: also tsig_key but not mentioning since so short lived. -->
 
 <!-- TODO: formating -->
     <para>
@@ -148,6 +167,9 @@
       the authoritative server to transfer from,
       and <varname>port</varname> to define the port number on the
       authoritative server (defaults to 53).
+      If the address or port is not specified, it will use the
+      values previously defined in the <varname>zones</varname>
+      configuration.
      </para>
 <!-- TODO: later hostname for master? -->
 
diff --git a/src/bin/xfrin/tests/Makefile.am b/src/bin/xfrin/tests/Makefile.am
index 755d76e..d4efbc7 100644
--- a/src/bin/xfrin/tests/Makefile.am
+++ b/src/bin/xfrin/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
 # required by loadable python modules.
 LIBRARY_PATH_PLACEHOLDER =
 if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
 # test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 04d04a6..f3e2ee4 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009  Internet Systems Consortium.
+# Copyright (C) 2009-2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -15,13 +15,16 @@
 
 import unittest
 import socket
+from isc.testutils.tsigctx_mock import MockTSIGContext
 from xfrin import *
 
 #
 # Commonly used (mostly constant) test parameters
 #
-TEST_ZONE_NAME = "example.com"
+TEST_ZONE_NAME_STR = "example.com."
+TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
 TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS_STR = 'IN'
 TEST_DB_FILE = 'db_file'
 TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
 TEST_MASTER_IPV4_ADDRINFO = (socket.AF_INET, socket.SOCK_STREAM,
@@ -35,15 +38,17 @@ TEST_MASTER_IPV6_ADDRINFO = (socket.AF_INET6, socket.SOCK_STREAM,
 # If some other process uses this port test will fail.
 TEST_MASTER_PORT = '53535'
 
+TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
+
 soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
                   'master.example.com. admin.example.com ' +
                   '1234 3600 1800 2419200 7200')
-soa_rrset = RRset(Name(TEST_ZONE_NAME), TEST_RRCLASS, RRType.SOA(),
+soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
                   RRTTL(3600))
 soa_rrset.add_rdata(soa_rdata)
-example_axfr_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+example_axfr_question = Question(TEST_ZONE_NAME, TEST_RRCLASS,
                                  RRType.AXFR())
-example_soa_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS,
                                  RRType.SOA())
 default_questions = [example_axfr_question]
 default_answers = [soa_rrset]
@@ -51,6 +56,13 @@ default_answers = [soa_rrset]
 class XfrinTestException(Exception):
     pass
 
+class MockCC():
+    def get_default_value(self, identifier):
+        if identifier == "zones/master_port":
+            return TEST_MASTER_PORT
+        if identifier == "zones/class":
+            return TEST_RRCLASS_STR
+
 class MockXfrin(Xfrin):
     # This is a class attribute of a callable object that specifies a non
     # default behavior triggered in _cc_check_command().  Specific test methods
@@ -60,6 +72,8 @@ class MockXfrin(Xfrin):
     check_command_hook = None
 
     def _cc_setup(self):
+        self._tsig_key = None
+        self._module_cc = MockCC()
         pass
 
     def _get_db_file(self):
@@ -70,6 +84,16 @@ class MockXfrin(Xfrin):
         if MockXfrin.check_command_hook:
             MockXfrin.check_command_hook()
 
+    def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
+                    tsig_key, check_soa=True):
+        # store some of the arguments for verification, then call this
+        # method in the superclass
+        self.xfrin_started_master_addr = master_addrinfo[2][0]
+        self.xfrin_started_master_port = master_addrinfo[2][1]
+        return Xfrin.xfrin_start(self, zone_name, rrclass, db_file,
+                                 master_addrinfo, tsig_key,
+                                 check_soa)
+
 class MockXfrinConnection(XfrinConnection):
     def __init__(self, sock_map, zone_name, rrclass, db_file, shutdown_event,
                  master_addr):
@@ -121,10 +145,11 @@ class MockXfrinConnection(XfrinConnection):
                 self.response_generator()
         return len(data)
 
-    def create_response_data(self, response = True, bad_qid = False,
-                             rcode = Rcode.NOERROR(),
-                             questions = default_questions,
-                             answers = default_answers):
+    def create_response_data(self, response=True, bad_qid=False,
+                             rcode=Rcode.NOERROR(),
+                             questions=default_questions,
+                             answers=default_answers,
+                             tsig_ctx=None):
         resp = Message(Message.RENDER)
         qid = self.qid
         if bad_qid:
@@ -138,7 +163,10 @@ class MockXfrinConnection(XfrinConnection):
         [resp.add_rrset(Message.SECTION_ANSWER, a) for a in answers]
 
         renderer = MessageRenderer()
-        resp.to_wire(renderer)
+        if tsig_ctx is not None:
+            resp.to_wire(renderer, tsig_ctx)
+        else:
+            resp.to_wire(renderer)
         reply_data = struct.pack('H', socket.htons(renderer.get_length()))
         reply_data += renderer.get_data()
 
@@ -153,20 +181,32 @@ class TestXfrinConnection(unittest.TestCase):
                                         TEST_RRCLASS, TEST_DB_FILE,
                                         threading.Event(),
                                         TEST_MASTER_IPV4_ADDRINFO)
-        self.axfr_after_soa = False
         self.soa_response_params = {
             'questions': [example_soa_question],
             'bad_qid': False,
             'response': True,
             'rcode': Rcode.NOERROR(),
+            'tsig': False,
             'axfr_after_soa': self._create_normal_response_data
             }
+        self.axfr_response_params = {
+            'tsig_1st': None,
+            'tsig_2nd': None
+            }
 
     def tearDown(self):
         self.conn.close()
         if os.path.exists(TEST_DB_FILE):
             os.remove(TEST_DB_FILE)
 
+    def __create_mock_tsig(self, key, error):
+        # This helper function creates a MockTSIGContext for a given key
+        # and TSIG error to be used as a result of verify (normally faked
+        # one)
+        mock_ctx = MockTSIGContext(key)
+        mock_ctx.error = error
+        return mock_ctx
+
     def test_close(self):
         # we shouldn't be using the global asyncore map.
         self.assertEqual(len(asyncore.socket_map), 0)
@@ -196,10 +236,53 @@ class TestXfrinConnection(unittest.TestCase):
                          RRClass.CH())
         c.close()
 
+    def test_send_query(self):
+        def create_msg(query_type):
+            msg = Message(Message.RENDER)
+            query_id = 0x1035
+            msg.set_qid(query_id)
+            msg.set_opcode(Opcode.QUERY())
+            msg.set_rcode(Rcode.NOERROR())
+            query_question = Question(Name("example.com."), RRClass.IN(), query_type)
+            msg.add_question(query_question)
+            return msg
+
+        def message_has_tsig(data):
+            # a simple check if the actual data contains a TSIG RR.
+            # At our level this simple check should suffice; other detailed
+            # tests regarding the TSIG protocol are done in pydnspp.
+            msg = Message(Message.PARSE)
+            msg.from_wire(data)
+            return msg.get_tsig_record() is not None
+
+        self.conn._create_query = create_msg
+        # soa request
+        self.conn._send_query(RRType.SOA())
+        self.assertEqual(self.conn.query_data, b'\x00\x1d\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x06\x00\x01')
+        # axfr request
+        self.conn._send_query(RRType.AXFR())
+        self.assertEqual(self.conn.query_data, b'\x00\x1d\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
+
+        # soa request with tsig
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._send_query(RRType.SOA())
+        self.assertTrue(message_has_tsig(self.conn.query_data[2:]))
+
+        # axfr request with tsig
+        self.conn._send_query(RRType.AXFR())
+        self.assertTrue(message_has_tsig(self.conn.query_data[2:]))
+
     def test_response_with_invalid_msg(self):
         self.conn.reply_data = b'aaaxxxx'
         self.assertRaises(XfrinTestException, self._handle_xfrin_response)
 
+    def test_response_with_tsigfail(self):
+        self.conn._tsig_key = TSIG_KEY
+        # server tsig check fail, return with RCODE 9 (NOTAUTH)
+        self.conn._send_query(RRType.SOA())
+        self.conn.reply_data = self.conn.create_response_data(rcode=Rcode.NOTAUTH())
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
     def test_response_without_end_soa(self):
         self.conn._send_query(RRType.AXFR())
         self.conn.reply_data = self.conn.create_response_data()
@@ -264,6 +347,54 @@ class TestXfrinConnection(unittest.TestCase):
         self.conn.response_generator = self._create_soa_response_data
         self.assertRaises(XfrinException, self.conn._check_soa_serial)
 
+    def test_soacheck_with_tsig(self):
+        # Use a mock tsig context emulating a validly signed response
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.NOERROR)
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertEqual(self.conn._check_soa_serial(), XFRIN_OK)
+        self.assertEqual(self.conn._tsig_ctx.get_error(), TSIGError.NOERROR)
+
+    def test_soacheck_with_tsig_notauth(self):
+        # emulate a valid error response
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
+        self.soa_response_params['rcode'] = Rcode.NOTAUTH()
+        self.conn.response_generator = self._create_soa_response_data
+
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_soacheck_with_tsig_noerror_badsig(self):
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
+
+        # emulate a normal response bad verification failure due to BADSIG.
+        # According RFC2845, in this case we should ignore it and keep
+        # waiting for a valid response until a timeout.  But we immediately
+        # treat this as a final failure (just as BIND 9 does).
+        self.conn.response_generator = self._create_soa_response_data
+
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_soacheck_with_tsig_unsigned_response(self):
+        # we can use a real TSIGContext for this.  the response doesn't
+        # contain a TSIG while we sent a signed query.  RFC2845 states
+        # we should wait for a valid response in this case, but we treat
+        # it as a fatal transaction failure, too.
+        self.conn._tsig_key = TSIG_KEY
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_soacheck_with_unexpected_tsig_response(self):
+        # we reject unexpected TSIG in responses (following BIND 9's
+        # behavior)
+        self.soa_response_params['tsig'] = True
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
     def test_response_shutdown(self):
         self.conn.response_generator = self._create_normal_response_data
         self.conn._shutdown_event.set()
@@ -297,6 +428,88 @@ class TestXfrinConnection(unittest.TestCase):
         self.conn.response_generator = self._create_normal_response_data
         self.assertEqual(self.conn.do_xfrin(False), XFRIN_OK)
 
+    def test_do_xfrin_with_tsig(self):
+        # use TSIG with a mock context.  we fake all verify results to
+        # emulate successful verification.
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.NOERROR)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_OK)
+        # We use two messages in the tests.  The same context should have been
+        # usef for both.
+        self.assertEqual(2, self.conn._tsig_ctx.verify_called)
+
+    def test_do_xfrin_with_tsig_fail(self):
+        # TSIG verify will fail for the first message.  xfrin should fail
+        # immediately.
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+        self.assertEqual(1, self.conn._tsig_ctx.verify_called)
+
+    def test_do_xfrin_with_tsig_fail_for_second_message(self):
+        # Similar to the previous test, but first verify succeeds.  There
+        # should be a second verify attempt, which will fail, which should
+        # make xfrin fail.
+        def fake_tsig_error(ctx):
+            if self.conn._tsig_ctx.verify_called == 1:
+                return TSIGError.NOERROR
+            return TSIGError.BAD_SIG
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, fake_tsig_error)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+        self.assertEqual(2, self.conn._tsig_ctx.verify_called)
+
+    def test_do_xfrin_with_missing_tsig(self):
+        # XFR request sent with TSIG, but the response doesn't have TSIG.
+        # xfr should fail.
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, None)
+        self.conn._tsig_ctx = MockTSIGContext(TSIG_KEY)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+        self.assertEqual(1, self.conn._tsig_ctx.verify_called)
+
+    def test_do_xfrin_with_missing_tsig_for_second_message(self):
+        # Similar to the previous test, but firt one contains TSIG and verify
+        # succeeds (due to fake).  The second message lacks TSIG.
+        #
+        # Note: this test case is actually not that trivial:  Skipping
+        # intermediate TSIG is allowed.  In this case, however, the second
+        # message is the last one, which must contain TSIG anyway, so the
+        # expected result is correct.  If/when we support skipping
+        # intermediate TSIGs, we'll need additional test cases.
+        def fake_tsig_error(ctx):
+            if self.conn._tsig_ctx.verify_called == 1:
+                return TSIGError.NOERROR
+            return TSIGError.FORMERR
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, fake_tsig_error)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+        self.assertEqual(2, self.conn._tsig_ctx.verify_called)
+
+    def test_do_xfrin_with_unexpected_tsig(self):
+        # XFR request wasn't signed, but response includes TSIG.  Like BIND 9,
+        # we reject that.
+        self.axfr_response_params['tsig_1st'] = TSIGContext(TSIG_KEY)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
+    def test_do_xfrin_with_unexpected_tsig_for_second_message(self):
+        # similar to the previous test, but the first message is normal.
+        # the second one contains an unexpected TSIG.  should be rejected.
+        self.axfr_response_params['tsig_2nd'] = TSIGContext(TSIG_KEY)
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
     def test_do_xfrin_empty_response(self):
         # skipping the creation of response data, so the transfer will fail.
         self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
@@ -315,6 +528,23 @@ class TestXfrinConnection(unittest.TestCase):
         self.conn.response_generator = self._create_soa_response_data
         self.assertEqual(self.conn.do_xfrin(True), XFRIN_OK)
 
+    def test_do_soacheck_and_xfrin_with_tsig(self):
+        # We are going to have a SOA query/response transaction, followed by
+        # AXFR, all TSIG signed.  xfrin should use a new TSIG context for
+        # AXFR.  We are not interested in whether verify works correctly in
+        # this test, so we simply fake the results (they need to succeed for
+        # this test)
+        self.conn._tsig_key = TSIG_KEY
+        self.conn._tsig_ctx_creator = \
+            lambda key: self.__create_mock_tsig(key, TSIGError.NOERROR)
+        self.soa_response_params['tsig'] = True
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertEqual(self.conn.do_xfrin(True), XFRIN_OK)
+        # We should've got 3 response messages: 1 SOA and two AXFR, but
+        # the context should be replaced for AXFR, so verify() should be
+        # called only twice for the latest context.
+        self.assertEqual(2, self.conn._tsig_ctx.verify_called)
+
     def test_do_soacheck_broken_response(self):
         self.conn.response_generator = self._create_broken_response_data
         # XXX: TODO: this test failed here, should xfr not raise an
@@ -342,21 +572,39 @@ class TestXfrinConnection(unittest.TestCase):
         # This helper method creates a simple sequence of DNS messages that
         # forms a valid XFR transaction.  It consists of two messages, each
         # containing just a single SOA RR.
-        self.conn.reply_data = self.conn.create_response_data()
-        self.conn.reply_data += self.conn.create_response_data()
+        tsig_1st = self.axfr_response_params['tsig_1st']
+        tsig_2nd = self.axfr_response_params['tsig_2nd']
+        self.conn.reply_data = self.conn.create_response_data(tsig_ctx=tsig_1st)
+        self.conn.reply_data += \
+            self.conn.create_response_data(tsig_ctx=tsig_2nd)
 
     def _create_soa_response_data(self):
         # This helper method creates a DNS message that is supposed to be
         # used a valid response to SOA queries prior to XFR.
+        # If tsig is True, it tries to verify the query with a locally
+        # created TSIG context (which may or may not succeed) so that the
+        # response will include a TSIG.
         # If axfr_after_soa is True, it resets the response_generator so that
         # a valid XFR messages will follow.
+
+        verify_ctx = None
+        if self.soa_response_params['tsig']:
+            # xfrin (curreently) always uses TCP.  strip off the length field.
+            query_data = self.conn.query_data[2:]
+            query_message = Message(Message.PARSE)
+            query_message.from_wire(query_data)
+            verify_ctx = TSIGContext(TSIG_KEY)
+            verify_ctx.verify(query_message.get_tsig_record(), query_data)
+
         self.conn.reply_data = self.conn.create_response_data(
             bad_qid=self.soa_response_params['bad_qid'],
             response=self.soa_response_params['response'],
             rcode=self.soa_response_params['rcode'],
-            questions=self.soa_response_params['questions'])
+            questions=self.soa_response_params['questions'],
+            tsig_ctx=verify_ctx)
         if self.soa_response_params['axfr_after_soa'] != None:
-            self.conn.response_generator = self.soa_response_params['axfr_after_soa']
+            self.conn.response_generator = \
+                self.soa_response_params['axfr_after_soa']
 
     def _create_broken_response_data(self):
         # This helper method creates a bogus "DNS message" that only contains
@@ -399,21 +647,28 @@ class TestXfrinRecorder(unittest.TestCase):
 
 class TestXfrin(unittest.TestCase):
     def setUp(self):
+        # redirect output
+        self.stderr_backup = sys.stderr
+        sys.stderr = open(os.devnull, 'w')
         self.xfr = MockXfrin()
         self.args = {}
-        self.args['zone_name'] = TEST_ZONE_NAME
+        self.args['zone_name'] = TEST_ZONE_NAME_STR
+        self.args['class'] = TEST_RRCLASS_STR
         self.args['port'] = TEST_MASTER_PORT
         self.args['master'] = TEST_MASTER_IPV4_ADDRESS
         self.args['db_file'] = TEST_DB_FILE
+        self.args['tsig_key'] = ''
 
     def tearDown(self):
         self.xfr.shutdown()
+        sys.stderr= self.stderr_backup
 
     def _do_parse_zone_name_class(self):
         return self.xfr._parse_zone_name_and_class(self.args)
 
     def _do_parse_master_port(self):
-        return self.xfr._parse_master_and_port(self.args)
+        name, rrclass = self._do_parse_zone_name_class()
+        return self.xfr._parse_master_and_port(self.args, name, rrclass)
 
     def test_parse_cmd_params(self):
         name, rrclass = self._do_parse_zone_name_class()
@@ -441,7 +696,7 @@ class TestXfrin(unittest.TestCase):
 
     def test_parse_cmd_params_bogusclass(self):
         self.args['zone_class'] = 'XXX'
-        self.assertRaises(XfrinException, self._do_parse_zone_name_class)
+        self.assertRaises(XfrinZoneInfoException, self._do_parse_zone_name_class)
 
     def test_parse_cmd_params_nozone(self):
         # zone name is mandatory.
@@ -451,8 +706,7 @@ class TestXfrin(unittest.TestCase):
     def test_parse_cmd_params_nomaster(self):
         # master address is mandatory.
         del self.args['master']
-        master_addrinfo = self._do_parse_master_port()
-        self.assertEqual(master_addrinfo[2][0], DEFAULT_MASTER)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_parse_cmd_params_bad_ip4(self):
         self.args['master'] = '3.3.3.3.3'
@@ -482,6 +736,77 @@ class TestXfrin(unittest.TestCase):
     def test_command_handler_retransfer(self):
         self.assertEqual(self.xfr.command_handler("retransfer",
                                                   self.args)['result'][0], 0)
+        self.assertEqual(self.args['master'], self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(self.args['port']), self.xfr.xfrin_started_master_port)
+
+    def test_command_handler_retransfer_short_command1(self):
+        # try it when only specifying the zone name (of unknown zone)
+        # this should fail because master address is not specified.
+        short_args = {}
+        short_args['zone_name'] = TEST_ZONE_NAME_STR
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  short_args)['result'][0], 1)
+
+    def test_command_handler_retransfer_short_command2(self):
+        # try it when only specifying the zone name (of known zone)
+        short_args = {}
+        short_args['zone_name'] = TEST_ZONE_NAME_STR
+
+        zones = { 'zones': [
+                  { 'name': TEST_ZONE_NAME_STR,
+                    'master_addr': TEST_MASTER_IPV4_ADDRESS,
+                    'master_port': TEST_MASTER_PORT
+                  }
+                ]}
+        self.xfr.config_handler(zones)
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  short_args)['result'][0], 0)
+        self.assertEqual(TEST_MASTER_IPV4_ADDRESS,
+                         self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(TEST_MASTER_PORT),
+                         self.xfr.xfrin_started_master_port)
+
+    def test_command_handler_retransfer_short_command3(self):
+        # try it when only specifying the zone name (of known zone)
+        short_args = {}
+        # test it without the trailing root dot
+        short_args['zone_name'] = TEST_ZONE_NAME_STR[:-1]
+
+        zones = { 'zones': [
+                  { 'name': TEST_ZONE_NAME_STR,
+                    'master_addr': TEST_MASTER_IPV4_ADDRESS,
+                    'master_port': TEST_MASTER_PORT
+                  }
+                ]}
+        self.xfr.config_handler(zones)
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  short_args)['result'][0], 0)
+        self.assertEqual(TEST_MASTER_IPV4_ADDRESS,
+                         self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(TEST_MASTER_PORT),
+                         self.xfr.xfrin_started_master_port)
+
+    def test_command_handler_retransfer_short_command4(self):
+        # try it when only specifying the zone name (of known zone, with
+        # different case)
+        short_args = {}
+
+        # swap the case of the zone name in our command
+        short_args['zone_name'] = TEST_ZONE_NAME_STR.swapcase()
+
+        zones = { 'zones': [
+                  { 'name': TEST_ZONE_NAME_STR,
+                    'master_addr': TEST_MASTER_IPV4_ADDRESS,
+                    'master_port': TEST_MASTER_PORT
+                  }
+                ]}
+        self.xfr.config_handler(zones)
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  short_args)['result'][0], 0)
+        self.assertEqual(TEST_MASTER_IPV4_ADDRESS,
+                         self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(TEST_MASTER_PORT),
+                         self.xfr.xfrin_started_master_port)
 
     def test_command_handler_retransfer_badcommand(self):
         self.args['master'] = 'invalid'
@@ -489,13 +814,15 @@ class TestXfrin(unittest.TestCase):
                                                   self.args)['result'][0], 1)
 
     def test_command_handler_retransfer_quota(self):
+        self.args['master'] = TEST_MASTER_IPV4_ADDRESS
+
         for i in range(self.xfr._max_transfers_in - 1):
-            self.xfr.recorder.increment(str(i) + TEST_ZONE_NAME)
+            self.xfr.recorder.increment(Name(str(i) + TEST_ZONE_NAME_STR))
         # there can be one more outstanding transfer.
         self.assertEqual(self.xfr.command_handler("retransfer",
                                                   self.args)['result'][0], 0)
         # make sure the # xfrs would excceed the quota
-        self.xfr.recorder.increment(str(self.xfr._max_transfers_in) + TEST_ZONE_NAME)
+        self.xfr.recorder.increment(Name(str(self.xfr._max_transfers_in) + TEST_ZONE_NAME_STR))
         # this one should fail
         self.assertEqual(self.xfr.command_handler("retransfer",
                                                   self.args)['result'][0], 1)
@@ -519,14 +846,43 @@ class TestXfrin(unittest.TestCase):
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
         self.assertEqual(self.xfr.command_handler("refresh",
                                                   self.args)['result'][0], 0)
+        self.assertEqual(TEST_MASTER_IPV6_ADDRESS,
+                         self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(TEST_MASTER_PORT),
+                         self.xfr.xfrin_started_master_port)
 
     def test_command_handler_notify(self):
         # at this level, refresh is no different than retransfer.
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
-        # ...but right now we disable the feature due to security concerns.
+        # ...but the zone is unknown so this would return an error
+        self.assertEqual(self.xfr.command_handler("notify",
+                                                  self.args)['result'][0], 1)
+
+    def test_command_handler_notify_known_zone(self):
+        # try it with a known zone
+        self.args['master'] = TEST_MASTER_IPV6_ADDRESS
+
+        # but use a different address in the actual command
+        zones = { 'zones': [
+                  { 'name': TEST_ZONE_NAME_STR,
+                    'master_addr': TEST_MASTER_IPV4_ADDRESS,
+                    'master_port': TEST_MASTER_PORT
+                  }
+                ]}
+        self.xfr.config_handler(zones)
         self.assertEqual(self.xfr.command_handler("notify",
                                                   self.args)['result'][0], 0)
 
+        # and see if we used the address from the command, and not from
+        # the config
+        # This is actually NOT the address given in the command, which
+        # would at this point not make sense, see the TODO in
+        # xfrin.py.in Xfrin.command_handler())
+        self.assertEqual(TEST_MASTER_IPV4_ADDRESS,
+                         self.xfr.xfrin_started_master_addr)
+        self.assertEqual(int(TEST_MASTER_PORT),
+                         self.xfr.xfrin_started_master_port)
+
     def test_command_handler_unknown(self):
         self.assertEqual(self.xfr.command_handler("xxx", None)['result'][0], 1)
 
@@ -535,20 +891,145 @@ class TestXfrin(unittest.TestCase):
         self.assertEqual(self.xfr.config_handler({'transfers_in': 3})['result'][0], 0)
         self.assertEqual(self.xfr._max_transfers_in, 3)
 
-    def test_command_handler_masters(self):
-        master_info = {'master_addr': '1.1.1.1', 'master_port':53}
-        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 0)
-
-        master_info = {'master_addr': '1111.1.1.1', 'master_port':53 }
-        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
-
-        master_info = {'master_addr': '2.2.2.2', 'master_port':530000 }
-        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
-
-        master_info = {'master_addr': '2.2.2.2', 'master_port':53 } 
-        self.xfr.config_handler(master_info)
-        self.assertEqual(self.xfr._master_addr, '2.2.2.2')
-        self.assertEqual(self.xfr._master_port, 53)
+    def _check_zones_config(self, config_given):
+        if 'transfers_in' in config_given:
+            self.assertEqual(config_given['transfers_in'],
+                             self.xfr._max_transfers_in)
+        for zone_config in config_given['zones']:
+            zone_name = zone_config['name']
+            zone_info = self.xfr._get_zone_info(Name(zone_name), RRClass.IN())
+            self.assertEqual(str(zone_info.master_addr), zone_config['master_addr'])
+            self.assertEqual(zone_info.master_port, zone_config['master_port'])
+            if 'tsig_key' in zone_config:
+                self.assertEqual(zone_info.tsig_key.to_text(), TSIGKey(zone_config['tsig_key']).to_text())
+            else:
+                self.assertIsNone(zone_info.tsig_key)
+
+    def test_command_handler_zones(self):
+        config1 = { 'transfers_in': 3,
+                   'zones': [
+                   { 'name': 'test.example.',
+                    'master_addr': '192.0.2.1',
+                    'master_port': 53
+                   }
+                 ]}
+        self.assertEqual(self.xfr.config_handler(config1)['result'][0], 0)
+        self._check_zones_config(config1)
+
+        config2 = { 'transfers_in': 4,
+                   'zones': [
+                   { 'name': 'test.example.',
+                    'master_addr': '192.0.2.2',
+                    'master_port': 53,
+                    'tsig_key': "example.com:SFuWd/q99SzF8Yzd1QbB9g=="
+                   }
+                 ]}
+        self.assertEqual(self.xfr.config_handler(config2)['result'][0], 0)
+        self._check_zones_config(config2)
+
+        # test that configuring the zone multiple times fails
+        zones = { 'transfers_in': 5,
+                  'zones': [
+                  { 'name': 'test.example.',
+                    'master_addr': '192.0.2.1',
+                    'master_port': 53
+                  },
+                  { 'name': 'test.example.',
+                    'master_addr': '192.0.2.2',
+                    'master_port': 53
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': 'test.example.',
+                    'master_addr': '192.0.2.3',
+                    'master_port': 53,
+                    'class': 'BADCLASS'
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'master_addr': '192.0.2.4',
+                    'master_port': 53
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': 'bad..zone.',
+                    'master_addr': '192.0.2.5',
+                    'master_port': 53
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': '',
+                    'master_addr': '192.0.2.6',
+                    'master_port': 53
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': 'test.example',
+                    'master_addr': 'badaddress',
+                    'master_port': 53
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': 'test.example',
+                    'master_addr': '192.0.2.7',
+                    'master_port': 'bad_port'
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        zones = { 'zones': [
+                  { 'name': 'test.example',
+                    'master_addr': '192.0.2.7',
+                    'master_port': 53,
+                    # using a bad TSIG key spec
+                    'tsig_key': "bad..example.com:SFuWd/q99SzF8Yzd1QbB9g=="
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
+
+        # let's also add a zone that is correct too, and make sure
+        # that the new config is not partially taken
+        zones = { 'zones': [
+                  { 'name': 'test.example.',
+                    'master_addr': '192.0.2.8',
+                    'master_port': 53
+                  },
+                  { 'name': 'test2.example.',
+                    'master_addr': '192.0.2.9',
+                    'master_port': 53,
+                    'tsig_key': 'badkey'
+                  }
+                ]}
+        self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
+        # since this has failed, we should still have the previous config
+        self._check_zones_config(config2)
 
 
 def raise_interrupt():
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 10a866e..7758a37 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -1,6 +1,6 @@
 #!@PYTHON@
 
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2009-2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -56,26 +56,67 @@ XFROUT_MODULE_NAME = 'Xfrout'
 ZONE_MANAGER_MODULE_NAME = 'Zonemgr'
 REFRESH_FROM_ZONEMGR = 'refresh_from_zonemgr'
 ZONE_XFRIN_FAILED = 'zone_xfrin_failed'
+
+# These two default are currently hard-coded. For config this isn't
+# necessary, but we need these defaults for optional command arguments
+# (TODO: have similar support to get default values for command
+# arguments as we do for config options)
+DEFAULT_MASTER_PORT = 53
+DEFAULT_ZONE_CLASS = RRClass.IN()
+
 __version__ = 'BIND10'
 # define xfrin rcode
 XFRIN_OK = 0
 XFRIN_FAIL = 1
 
-DEFAULT_MASTER_PORT = '53'
-DEFAULT_MASTER = '127.0.0.1'
-
 def log_error(msg):
     sys.stderr.write("[b10-xfrin] %s\n" % str(msg))
 
-class XfrinException(Exception): 
+class XfrinException(Exception):
+    pass
+
+class XfrinZoneInfoException(Exception):
+    """This exception is raised if there is an error in the given
+       configuration (part), or when a command does not have a required
+       argument or has bad arguments, for instance when the zone's master
+       address is not a valid IP address, when the zone does not
+       have a name, or when multiple settings are given for the same
+       zone."""
     pass
 
+def _check_zone_name(zone_name_str):
+    """Checks if the given zone name is a valid domain name, and returns
+    it as a Name object. Raises an XfrinException if it is not."""
+    try:
+        # In the _zones dict, part of the key is the zone name,
+        # but due to a limitation in the Name class, we
+        # cannot directly use it as a dict key, and we use to_text()
+        #
+        # Downcase the name here for that reason.
+        return Name(zone_name_str, True)
+    except (EmptyLabel, TooLongLabel, BadLabelType, BadEscape,
+            TooLongName, IncompleteName) as ne:
+        raise XfrinZoneInfoException("bad zone name: " + zone_name_str + " (" + str(ne) + ")")
+
+def _check_zone_class(zone_class_str):
+    """If the given argument is a string: checks if the given class is
+       a valid one, and returns an RRClass object if so.
+       Raises XfrinZoneInfoException if not.
+       If it is None, this function returns the default RRClass.IN()"""
+    if zone_class_str is None:
+        return DEFAULT_ZONE_CLASS
+    try:
+        return RRClass(zone_class_str)
+    except InvalidRRClass as irce:
+        raise XfrinZoneInfoException("bad zone class: " + zone_class_str + " (" + str(irce) + ")")
+
 class XfrinConnection(asyncore.dispatcher):
-    '''Do xfrin in this class. '''    
+    '''Do xfrin in this class. '''
 
     def __init__(self,
                  sock_map, zone_name, rrclass, db_file, shutdown_event,
-                 master_addrinfo, verbose = False, idle_timeout = 60): 
+                 master_addrinfo, tsig_key = None, verbose = False,
+                 idle_timeout = 60):
         ''' idle_timeout: max idle time for read data from socket.
             db_file: specify the data source file.
             check_soa: when it's true, check soa first before sending xfr query
@@ -93,6 +134,14 @@ class XfrinConnection(asyncore.dispatcher):
         self._shutdown_event = shutdown_event
         self._verbose = verbose
         self._master_address = master_addrinfo[2]
+        self._tsig_key = tsig_key
+        self._tsig_ctx = None
+        # tsig_ctx_creator is introduced to allow tests to use a mock class for
+        # easier tests (in normal case we always use the default)
+        self._tsig_ctx_creator = self.__create_tsig_ctx
+
+    def __create_tsig_ctx(self, key):
+        return TSIGContext(key)
 
     def connect_to_master(self):
         '''Connect to master in TCP.'''
@@ -130,9 +179,15 @@ class XfrinConnection(asyncore.dispatcher):
 
         msg = self._create_query(query_type)
         render = MessageRenderer()
-        msg.to_wire(render)
-        header_len = struct.pack('H', socket.htons(render.get_length()))
+        # XXX Currently, python wrapper doesn't accept 'None' parameter in this case,
+        # we should remove the if statement and use a universal interface later.
+        if self._tsig_key is not None:
+            self._tsig_ctx = self._tsig_ctx_creator(self._tsig_key)
+            msg.to_wire(render, self._tsig_ctx)
+        else:
+            msg.to_wire(render)
 
+        header_len = struct.pack('H', socket.htons(render.get_length()))
         self._send_data(header_len)
         self._send_data(render.get_data())
 
@@ -142,7 +197,7 @@ class XfrinConnection(asyncore.dispatcher):
         _get_request_response so that we can test the rest of the code without
         involving actual communication with a remote server.'''
         asyncore.loop(self._idle_timeout, map=self._sock_map, count=1)
-    
+
     def _get_request_response(self, size):
         recv_size = 0
         data = b''
@@ -158,6 +213,22 @@ class XfrinConnection(asyncore.dispatcher):
 
         return data
 
+    def _check_response_tsig(self, msg, response_data):
+        tsig_record = msg.get_tsig_record()
+        if self._tsig_ctx is not None:
+            tsig_error = self._tsig_ctx.verify(tsig_record, response_data)
+            if tsig_error != TSIGError.NOERROR:
+                raise XfrinException('TSIG verify fail: %s' % str(tsig_error))
+        elif tsig_record is not None:
+            # If the response includes a TSIG while we didn't sign the query,
+            # we treat it as an error.  RFC doesn't say anything about this
+            # case, but it clearly states the server must not sign a response
+            # to an unsigned request.  Although we could be flexible, no sane
+            # implementation would return such a response, and since this is
+            # part of security mechanism, it's probably better to be more
+            # strict.
+            raise XfrinException('Unexpected TSIG in response')
+
     def _check_soa_serial(self):
         ''' Compare the soa serial, if soa serial in master is less than
         the soa serial in local, Finish xfrin.
@@ -165,7 +236,7 @@ class XfrinConnection(asyncore.dispatcher):
         True: soa serial in master is bigger
         '''
 
-        self._send_query(RRType("SOA"))
+        self._send_query(RRType.SOA())
         data_len = self._get_request_response(2)
         msg_len = socket.htons(struct.unpack('H', data_len)[0])
         soa_response = self._get_request_response(msg_len)
@@ -176,7 +247,10 @@ class XfrinConnection(asyncore.dispatcher):
         # strict we should be (see the comment in _check_response_header())
         self._check_response_header(msg)
 
-        # TODO, need select soa record from data source then compare the two 
+        # TSIG related checks, including an unexpected signed response
+        self._check_response_tsig(msg, soa_response)
+
+        # TODO, need select soa record from data source then compare the two
         # serial, current just return OK, since this function hasn't been used
         # now.
         return XFRIN_OK
@@ -193,8 +267,7 @@ class XfrinConnection(asyncore.dispatcher):
             logstr = 'transfer of \'%s\': AXFR ' % self._zone_name
             if ret == XFRIN_OK:
                 self.log_msg(logstr + 'started')
-                # TODO: .AXFR() RRType.AXFR()
-                self._send_query(RRType(252))
+                self._send_query(RRType.AXFR())
                 isc.datasrc.sqlite3_ds.load(self._db_file, self._zone_name,
                                             self._handle_xfrin_response)
 
@@ -265,7 +338,7 @@ class XfrinConnection(asyncore.dispatcher):
 
             for rdata in rrset.get_rdata():
                 # Count the soa record count
-                if rrset.get_type() == RRType("SOA"):
+                if rrset.get_type() == RRType.SOA():
                     self._soa_rr_count += 1
 
                     # XXX: the current DNS message parser can't preserve the
@@ -290,14 +363,17 @@ class XfrinConnection(asyncore.dispatcher):
             msg = Message(Message.PARSE)
             msg.from_wire(recvdata)
             self._check_response_status(msg)
-            
+
+            # TSIG related checks, including an unexpected signed response
+            self._check_response_tsig(msg, recvdata)
+
             answer_section = msg.get_section(Message.SECTION_ANSWER)
             for rr in self._handle_answer_section(answer_section):
                 yield rr
 
             if self._soa_rr_count == 2:
                 break
-            
+
             if self._shutdown_event.is_set():
                 raise XfrinException('xfrin is forced to stop')
 
@@ -322,16 +398,18 @@ class XfrinConnection(asyncore.dispatcher):
             sys.stdout.write('[b10-xfrin] %s\n' % str(msg))
 
 
-def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file, 
-                  shutdown_event, master_addrinfo, check_soa, verbose):
+def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
+                  shutdown_event, master_addrinfo, check_soa, verbose,
+                  tsig_key):
     xfrin_recorder.increment(zone_name)
     sock_map = {}
     conn = XfrinConnection(sock_map, zone_name, rrclass, db_file,
-                           shutdown_event, master_addrinfo, verbose)
+                           shutdown_event, master_addrinfo,
+                           tsig_key, verbose)
     ret = XFRIN_FAIL
     if conn.connect_to_master():
         ret = conn.do_xfrin(check_soa)
-    
+
     # Publish the zone transfer result news, so zonemgr can reset the
     # zone timer, and xfrout can notify the zone's slaves if the result
     # is success.
@@ -367,23 +445,111 @@ class XfrinRecorder:
         self._lock.release()
         return ret
 
+class ZoneInfo:
+    def __init__(self, config_data, module_cc):
+        """Creates a zone_info with the config data element as
+           specified by the 'zones' list in xfrin.spec. Module_cc is
+           needed to get the defaults from the specification"""
+        self._module_cc = module_cc
+        self.set_name(config_data.get('name'))
+        self.set_master_addr(config_data.get('master_addr'))
+
+        self.set_master_port(config_data.get('master_port'))
+        self.set_zone_class(config_data.get('class'))
+        self.set_tsig_key(config_data.get('tsig_key'))
+
+    def set_name(self, name_str):
+        """Set the name for this zone given a name string.
+           Raises XfrinZoneInfoException if name_str is None or if it
+           cannot be parsed."""
+        if name_str is None:
+            raise XfrinZoneInfoException("Configuration zones list "
+                                         "element does not contain "
+                                         "'name' attribute")
+        else:
+            self.name = _check_zone_name(name_str)
+
+    def set_master_addr(self, master_addr_str):
+        """Set the master address for this zone given an IP address
+           string. Raises XfrinZoneInfoException if master_addr_str is
+           None or if it cannot be parsed."""
+        if master_addr_str is None:
+            raise XfrinZoneInfoException("master address missing from config data")
+        else:
+            try:
+                self.master_addr = isc.net.parse.addr_parse(master_addr_str)
+            except ValueError:
+                errmsg = "bad format for zone's master: " + master_addr_str
+                log_error(errmsg)
+                raise XfrinZoneInfoException(errmsg)
+
+    def set_master_port(self, master_port_str):
+        """Set the master port given a port number string. If
+           master_port_str is None, the default from the specification
+           for this module will be used. Raises XfrinZoneInfoException if
+           the string contains an invalid port number"""
+        if master_port_str is None:
+            self.master_port = self._module_cc.get_default_value("zones/master_port")
+        else:
+            try:
+                self.master_port = isc.net.parse.port_parse(master_port_str)
+            except ValueError:
+                errmsg = "bad format for zone's master port: " + master_port_str
+                log_error(errmsg)
+                raise XfrinZoneInfoException(errmsg)
+
+    def set_zone_class(self, zone_class_str):
+        """Set the zone class given an RR class str (e.g. "IN"). If
+           zone_class_str is None, it will default to what is specified
+           in the specification file for this module. Raises
+           XfrinZoneInfoException if the string cannot be parsed."""
+        # TODO: remove _str
+        self.class_str = zone_class_str or self._module_cc.get_default_value("zones/class")
+        if zone_class_str == None:
+            #TODO rrclass->zone_class
+            self.rrclass = RRClass(self._module_cc.get_default_value("zones/class"))
+        else:
+            try:
+                self.rrclass = RRClass(zone_class_str)
+            except InvalidRRClass:
+                errmsg = "invalid zone class: " + zone_class_str
+                log_error(errmsg)
+                raise XfrinZoneInfoException(errmsg)
+
+    def set_tsig_key(self, tsig_key_str):
+        """Set the tsig_key for this zone, given a TSIG key string
+           representation. If tsig_key_str is None, no TSIG key will
+           be set. Raises XfrinZoneInfoException if tsig_key_str cannot
+           be parsed."""
+        if tsig_key_str is None:
+            self.tsig_key = None
+        else:
+            try:
+                self.tsig_key = TSIGKey(tsig_key_str)
+            except InvalidParameter as ipe:
+                errmsg = "bad TSIG key string: " + tsig_key_str
+                log_error(errmsg)
+                raise XfrinZoneInfoException(errmsg)
+
+    def get_master_addr_info(self):
+        return (self.master_addr.family, socket.SOCK_STREAM,
+                (str(self.master_addr), self.master_port))
+
 class Xfrin:
     def __init__(self, verbose = False):
         self._max_transfers_in = 10
-        #TODO, this is the temp way to set the zone's master.
-        self._master_addr = DEFAULT_MASTER
-        self._master_port = DEFAULT_MASTER_PORT
+        self._zones = {}
         self._cc_setup()
         self.recorder = XfrinRecorder()
         self._shutdown_event = threading.Event()
         self._verbose = verbose
 
     def _cc_setup(self):
-        '''This method is used only as part of initialization, but is 
-        implemented separately for convenience of unit tests; by letting 
-        the test code override this method we can test most of this class 
+        '''This method is used only as part of initialization, but is
+        implemented separately for convenience of unit tests; by letting
+        the test code override this method we can test most of this class
         without requiring a command channel.'''
-        # Create one session for sending command to other modules, because the 
+        # Create one session for sending command to other modules, because the
         # listening session will block the send operation.
         self._send_cc_session = isc.cc.Session()
         self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
@@ -391,36 +557,55 @@ class Xfrin:
                                               self.command_handler)
         self._module_cc.start()
         config_data = self._module_cc.get_full_config()
-        self._max_transfers_in = config_data.get("transfers_in")
-        self._master_addr = config_data.get('master_addr') or self._master_addr
-        self._master_port = config_data.get('master_port') or self._master_port
+        self.config_handler(config_data)
 
     def _cc_check_command(self):
-        '''This is a straightforward wrapper for cc.check_command, 
-        but provided as a separate method for the convenience 
+        '''This is a straightforward wrapper for cc.check_command,
+        but provided as a separate method for the convenience
         of unit tests.'''
         self._module_cc.check_command(False)
 
+    def _get_zone_info(self, name, rrclass):
+        """Returns the ZoneInfo object containing the configured data
+           for the given zone name. If the zone name did not have any
+           data, returns None"""
+        return self._zones.get((name.to_text(), rrclass.to_text()))
+
+    def _add_zone_info(self, zone_info):
+        """Add the zone info. Raises a XfrinZoneInfoException if a zone
+           with the same name and class is already configured"""
+        key = (zone_info.name.to_text(), zone_info.class_str)
+        if key in self._zones:
+            raise XfrinZoneInfoException("zone " + str(key) +
+                                       " configured multiple times")
+        self._zones[key] = zone_info
+
+    def _clear_zone_info(self):
+        self._zones = {}
+
     def config_handler(self, new_config):
+        # backup all config data (should there be a problem in the new
+        # data)
+        old_max_transfers_in = self._max_transfers_in
+        old_zones = self._zones
+
         self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
-        if ('master_addr' in new_config) or ('master_port' in new_config):
-            # User should change the port and address together.
-            try:
-                addr = new_config.get('master_addr') or self._master_addr
-                port = new_config.get('master_port') or self._master_port
-                isc.net.parse.addr_parse(addr)
-                isc.net.parse.port_parse(port)
-                self._master_addr = addr
-                self._master_port = port
-            except ValueError:
-                errmsg = "bad format for zone's master: " + str(new_config)
-                log_error(errmsg)
-                return create_answer(1, errmsg)
+
+        if 'zones' in new_config:
+            self._clear_zone_info()
+            for zone_config in new_config.get('zones'):
+                try:
+                    zone_info = ZoneInfo(zone_config, self._module_cc)
+                    self._add_zone_info(zone_info)
+                except XfrinZoneInfoException as xce:
+                    self._zones = old_zones
+                    self._max_transfers_in = old_max_transfers_in
+                    return create_answer(1, str(xce))
 
         return create_answer(0)
 
     def shutdown(self):
-        ''' shutdown the xfrin process. the thread which is doing xfrin should be 
+        ''' shutdown the xfrin process. the thread which is doing xfrin should be
         terminated.
         '''
         self._shutdown_event.set()
@@ -436,30 +621,47 @@ class Xfrin:
             if command == 'shutdown':
                 self._shutdown_event.set()
             elif command == 'notify' or command == REFRESH_FROM_ZONEMGR:
-                # Xfrin receives the refresh/notify command from zone manager. 
-                # notify command maybe has the parameters which 
+                # Xfrin receives the refresh/notify command from zone manager.
+                # notify command maybe has the parameters which
                 # specify the notifyfrom address and port, according the RFC1996, zone
                 # transfer should starts first from the notifyfrom, but now, let 'TODO' it.
+                # (using the value now, while we can only set one master address, would be
+                # a security hole. Once we add the ability to have multiple master addresses,
+                # we should check if it matches one of them, and then use it.)
                 (zone_name, rrclass) = self._parse_zone_name_and_class(args)
-                (master_addr) = build_addr_info(self._master_addr, self._master_port)
-                ret = self.xfrin_start(zone_name, 
-                                       rrclass, 
-                                       self._get_db_file(),
-                                       master_addr,
-                                       True)
-                answer = create_answer(ret[0], ret[1])
+                zone_info = self._get_zone_info(zone_name, rrclass)
+                if zone_info is None:
+                    # TODO what to do? no info known about zone. defaults?
+                    errmsg = "Got notification to retransfer unknown zone " + zone_name.to_text()
+                    log_error(errmsg)
+                    answer = create_answer(1, errmsg)
+                else:
+                    master_addr = zone_info.get_master_addr_info()
+                    ret = self.xfrin_start(zone_name,
+                                           rrclass,
+                                           self._get_db_file(),
+                                           master_addr,
+                                           zone_info.tsig_key,
+                                           True)
+                    answer = create_answer(ret[0], ret[1])
 
             elif command == 'retransfer' or command == 'refresh':
                 # Xfrin receives the retransfer/refresh from cmdctl(sent by bindctl).
-                # If the command has specified master address, do transfer from the 
-                # master address, or else do transfer from the configured masters.                
+                # If the command has specified master address, do transfer from the
+                # master address, or else do transfer from the configured masters.
                 (zone_name, rrclass) = self._parse_zone_name_and_class(args)
-                master_addr = self._parse_master_and_port(args)
+                master_addr = self._parse_master_and_port(args, zone_name,
+                                                          rrclass)
+                zone_info = self._get_zone_info(zone_name, rrclass)
+                tsig_key = None
+                if zone_info:
+                    tsig_key = zone_info.tsig_key
                 db_file = args.get('db_file') or self._get_db_file()
-                ret = self.xfrin_start(zone_name, 
-                                       rrclass, 
-                                       db_file, 
+                ret = self.xfrin_start(zone_name,
+                                       rrclass,
+                                       db_file,
                                        master_addr,
+                                       tsig_key,
                                        (False if command == 'retransfer' else True))
                 answer = create_answer(ret[0], ret[1])
 
@@ -471,26 +673,52 @@ class Xfrin:
         return answer
 
     def _parse_zone_name_and_class(self, args):
-        zone_name = args.get('zone_name')
-        if not zone_name:
+        zone_name_str = args.get('zone_name')
+        if zone_name_str is None:
             raise XfrinException('zone name should be provided')
 
-        rrclass = args.get('zone_class')
-        if not rrclass:
-            rrclass = RRClass.IN()
+        return (_check_zone_name(zone_name_str), _check_zone_class(args.get('zone_class')))
+
+    def _parse_master_and_port(self, args, zone_name, zone_class):
+        """
+        Return tuple (family, socktype, sockaddr) for address and port in given
+        args dict.
+        IPv4 and IPv6 are the only supported addresses now, so sockaddr will be
+        (address, port). The socktype is socket.SOCK_STREAM for now.
+        """
+        # check if we have configured info about this zone, in case
+        # port or master are not specified
+        zone_info = self._get_zone_info(zone_name, zone_class)
+
+        addr_str = args.get('master')
+        if addr_str is None:
+            if zone_info is not None:
+                addr = zone_info.master_addr
+            else:
+                raise XfrinException("Master address not given or "
+                                     "configured for " + zone_name.to_text())
+        else:
+            try:
+                addr = isc.net.parse.addr_parse(addr_str)
+            except ValueError as err:
+                raise XfrinException("failed to resolve master address %s: %s" %
+                                     (addr_str, str(err)))
+
+        port_str = args.get('port')
+        if port_str is None:
+            if zone_info is not None:
+                port = zone_info.master_port
+            else:
+                port = DEFAULT_MASTER_PORT
         else:
             try:
-                rrclass = RRClass(rrclass)
-            except InvalidRRClass as e:
-                raise XfrinException('invalid RRClass: ' + rrclass)
-        
-        return zone_name, rrclass
-
-    def _parse_master_and_port(self, args):
-        port = args.get('port') or self._master_port
-        master = args.get('master') or self._master_addr
-        return build_addr_info(master, port)
- 
+                port = isc.net.parse.port_parse(port_str)
+            except ValueError as err:
+                raise XfrinException("failed to parse port=%s: %s" %
+                                     (port_str, str(err)))
+
+        return (addr.family, socket.SOCK_STREAM, (str(addr), port))
+
     def _get_db_file(self):
         #TODO, the db file path should be got in auth server's configuration
         # if we need access to this configuration more often, we
@@ -506,12 +734,12 @@ class Xfrin:
             db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
         self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
         return db_file
-       
+
     def publish_xfrin_news(self, zone_name, zone_class,  xfr_result):
         '''Send command to xfrout/zone manager module.
-        If xfrin has finished successfully for one zone, tell the good 
+        If xfrin has finished successfully for one zone, tell the good
         news(command: zone_new_data_ready) to zone manager and xfrout.
-        if xfrin failed, just tell the bad news to zone manager, so that 
+        if xfrin failed, just tell the bad news to zone manager, so that
         it can reset the refresh timer for that zone. '''
         param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
         if xfr_result == XFRIN_OK:
@@ -531,8 +759,8 @@ class Xfrin:
                                                                       seq)
                 except isc.cc.session.SessionTimeout:
                     pass        # for now we just ignore the failure
-            except socket.error as err: 
-                log_error("Fail to send message to %s and %s, msgq may has been killed" 
+            except socket.error as err:
+                log_error("Fail to send message to %s and %s, msgq may has been killed"
                           % (XFROUT_MODULE_NAME, ZONE_MANAGER_MODULE_NAME))
         else:
             msg = create_command(ZONE_XFRIN_FAILED, param)
@@ -545,14 +773,14 @@ class Xfrin:
                 except isc.cc.session.SessionTimeout:
                     pass        # for now we just ignore the failure
             except socket.error as err:
-                log_error("Fail to send message to %s, msgq may has been killed" 
+                log_error("Fail to send message to %s, msgq may has been killed"
                           % ZONE_MANAGER_MODULE_NAME)
 
     def startup(self):
         while not self._shutdown_event.is_set():
             self._cc_check_command()
 
-    def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
+    def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo, tsig_key,
                     check_soa = True):
         if "pydnspp" not in sys.modules:
             return (1, "xfrin failed, can't load dns message python library: 'pydnspp'")
@@ -567,11 +795,13 @@ class Xfrin:
         xfrin_thread = threading.Thread(target = process_xfrin,
                                         args = (self,
                                                 self.recorder,
-                                                zone_name, rrclass,
+                                                zone_name.to_text(),
+                                                rrclass,
                                                 db_file,
                                                 self._shutdown_event,
                                                 master_addrinfo, check_soa,
-                                                self._verbose))
+                                                self._verbose,
+                                                tsig_key))
 
         xfrin_thread.start()
         return (0, 'zone xfrin is started')
@@ -588,20 +818,6 @@ def set_signal_handler():
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)
 
-def build_addr_info(addrstr, portstr):
-    """
-    Return tuple (family, socktype, sockaddr) for given address and port.
-    IPv4 and IPv6 are the only supported addresses now, so sockaddr will be
-    (address, port). The socktype is socket.SOCK_STREAM for now.
-    """
-    try:
-        port = isc.net.parse.port_parse(portstr)
-        addr = isc.net.parse.addr_parse(addrstr)
-        return (addr.family, socket.SOCK_STREAM, (addrstr, port))
-    except ValueError as err:
-        raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
-                             (addrstr, portstr, str(err)))
-
 def set_cmd_options(parser):
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
             help="display more about what is going on")
diff --git a/src/bin/xfrin/xfrin.spec b/src/bin/xfrin/xfrin.spec
index 61ddaad..a3e62ce 100644
--- a/src/bin/xfrin/xfrin.spec
+++ b/src/bin/xfrin/xfrin.spec
@@ -9,16 +9,43 @@
         "item_optional": false,
         "item_default": 10
       },
-      {
-        "item_name": "master_addr",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": ""
-      },
-      { "item_name": "master_port",
-        "item_type": "integer",
+      { "item_name": "zones",
+        "item_type": "list",
         "item_optional": false,
-        "item_default": 53
+        "item_default": [],
+        "list_item_spec":
+        { "item_type": "map",
+          "item_name": "zone_info",
+          "item_optional": false,
+          "item_default": {},
+          "map_item_spec": [
+          { "item_name": "name",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          },
+          { "item_name": "class",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": "IN"
+          },
+          {
+            "item_name": "master_addr",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          },
+          { "item_name": "master_port",
+            "item_type": "integer",
+            "item_optional": false,
+            "item_default": 53
+          },
+          { "item_name": "tsig_key",
+            "item_type": "string",
+            "item_optional": true
+          }
+          ]
+        }
       }
     ],
     "commands": [
diff --git a/src/bin/xfrout/tests/Makefile.am b/src/bin/xfrout/tests/Makefile.am
index 01f2e40..11916af 100644
--- a/src/bin/xfrout/tests/Makefile.am
+++ b/src/bin/xfrout/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
 # required by loadable python modules.
 LIBRARY_PATH_PLACEHOLDER =
 if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
 # test using command-line arguments, so use check-local target instead of TESTS
@@ -18,7 +18,7 @@ if ENABLE_PYTHON_COVERAGE
 endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
+	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/util/io/.libs \
 	$(LIBRARY_PATH_PLACEHOLDER) \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done
diff --git a/src/bin/xfrout/tests/xfrout_test.py b/src/bin/xfrout/tests/xfrout_test.py
deleted file mode 100644
index 5aec072..0000000
--- a/src/bin/xfrout/tests/xfrout_test.py
+++ /dev/null
@@ -1,437 +0,0 @@
-# Copyright (C) 2010  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''Tests for the XfroutSession and UnixSockServer classes '''
-
-
-import unittest
-import os
-from isc.cc.session import *
-from pydnspp import *
-from xfrout import *
-
-# our fake socket, where we can read and insert messages
-class MySocket():
-    def __init__(self, family, type):
-        self.family = family
-        self.type = type
-        self.sendqueue = bytearray()
-
-    def connect(self, to):
-        pass
-
-    def close(self):
-        pass
-
-    def send(self, data):
-        self.sendqueue.extend(data);
-        return len(data)
-
-    def readsent(self):
-        if len(self.sendqueue) >= 2:
-            size = 2 + struct.unpack("!H", self.sendqueue[:2])[0]
-        else:
-            size = 0
-        result = self.sendqueue[:size]
-        self.sendqueue = self.sendqueue[size:]
-        return result
-
-    def read_msg(self):
-        sent_data = self.readsent()
-        get_msg = Message(Message.PARSE)
-        get_msg.from_wire(bytes(sent_data[2:]))
-        return get_msg
-
-    def clear_send(self):
-        del self.sendqueue[:]
-
-# We subclass the Session class we're testing here, only
-# to override the handle() and _send_data() method
-class MyXfroutSession(XfroutSession):
-    def handle(self):
-        pass
-
-    def _send_data(self, sock, data):
-        size = len(data)
-        total_count = 0
-        while total_count < size:
-            count = sock.send(data[total_count:])
-            total_count += count
-
-class Dbserver:
-    def __init__(self):
-        self._shutdown_event = threading.Event()
-    def get_db_file(self):
-        return None
-    def decrease_transfers_counter(self):
-        pass
-
-class TestXfroutSession(unittest.TestCase):
-    def getmsg(self):
-        msg = Message(Message.PARSE)
-        msg.from_wire(self.mdata)
-        return msg
-
-    def setUp(self):
-        self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
-        self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
-        self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), self.log)
-        self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
-        self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
-
-    def test_parse_query_message(self):
-        [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
-        self.assertEqual(get_rcode.to_text(), "NOERROR")
-
-    def test_get_query_zone_name(self):
-        msg = self.getmsg()
-        self.assertEqual(self.xfrsess._get_query_zone_name(msg), "example.com.")
-
-    def test_send_data(self):
-        self.xfrsess._send_data(self.sock, self.mdata)
-        senddata = self.sock.readsent()
-        self.assertEqual(senddata, self.mdata)
-
-    def test_reply_xfrout_query_with_error_rcode(self):
-        msg = self.getmsg()
-        self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
-        get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
-
-    def test_send_message(self):
-        msg = self.getmsg()
-        msg.make_response()
-        # soa record data with different cases
-        soa_record = (4, 3, 'Example.com.', 'com.Example.', 3600, 'SOA', None, 'master.Example.com. admin.exAmple.com. 1234 3600 1800 2419200 7200')
-        rrset_soa = self.xfrsess._create_rrset_from_db_record(soa_record)
-        msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
-        self.xfrsess._send_message(self.sock, msg)
-        send_out_data = self.sock.readsent()[2:]
-
-        # CASE_INSENSITIVE compression mode
-        render = MessageRenderer();
-        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
-        msg.to_wire(render)
-        self.assertNotEqual(render.get_data(), send_out_data)
-
-        # CASE_SENSITIVE compression mode
-        render.clear()
-        render.set_compress_mode(MessageRenderer.CASE_SENSITIVE)
-        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
-        msg.to_wire(render)
-        self.assertEqual(render.get_data(), send_out_data)
-
-    def test_clear_message(self):
-        msg = self.getmsg()
-        qid = msg.get_qid()
-        opcode = msg.get_opcode()
-        rcode = msg.get_rcode()
-
-        self.xfrsess._clear_message(msg)
-        self.assertEqual(msg.get_qid(), qid)
-        self.assertEqual(msg.get_opcode(), opcode)
-        self.assertEqual(msg.get_rcode(), rcode)
-        self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_AA))
-
-    def test_reply_query_with_format_error(self):
-        msg = self.getmsg()
-        self.xfrsess._reply_query_with_format_error(msg, self.sock)
-        get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rcode().to_text(), "FORMERR")
-
-    def test_create_rrset_from_db_record(self):
-        rrset = self.xfrsess._create_rrset_from_db_record(self.soa_record)
-        self.assertEqual(rrset.get_name().to_text(), "example.com.")
-        self.assertEqual(rrset.get_class(), RRClass("IN"))
-        self.assertEqual(rrset.get_type().to_text(), "SOA")
-        rdata = rrset.get_rdata()
-        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
-
-    def test_send_message_with_last_soa(self):
-        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
-
-        msg = self.getmsg()
-        msg.make_response()
-        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 0)
-        get_msg = self.sock.read_msg()
-
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
-
-        #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
-        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]#answer_rrset_iter.get_rrset()
-        self.assertEqual(answer.get_name().to_text(), "example.com.")
-        self.assertEqual(answer.get_class(), RRClass("IN"))
-        self.assertEqual(answer.get_type().to_text(), "SOA")
-        rdata = answer.get_rdata()
-        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
-
-    def test_trigger_send_message_with_last_soa(self):
-        rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
-        rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
-        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
-
-        msg = self.getmsg()
-        msg.make_response()
-
-        msg.add_rrset(Message.SECTION_ANSWER, rrset_a)
-        # give the function a value that is larger than MAX-len(rrset)
-        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 65520)
-
-        # this should have triggered the sending of two messages
-        # (1 with the rrset we added manually, and 1 that triggered
-        # the sending in _with_last_soa)
-        get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
-
-        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
-        self.assertEqual(answer.get_name().to_text(), "example.com.")
-        self.assertEqual(answer.get_class(), RRClass("IN"))
-        self.assertEqual(answer.get_type().to_text(), "A")
-        rdata = answer.get_rdata()
-        self.assertEqual(rdata[0].to_text(), "192.0.2.1")
-
-        get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 0)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
-
-        #answer_rrset_iter = section_iter(get_msg, Message.SECTION_ANSWER)
-        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
-        self.assertEqual(answer.get_name().to_text(), "example.com.")
-        self.assertEqual(answer.get_class(), RRClass("IN"))
-        self.assertEqual(answer.get_type().to_text(), "SOA")
-        rdata = answer.get_rdata()
-        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
-
-        # and it should not have sent anything else
-        self.assertEqual(0, len(self.sock.sendqueue))
-
-    def test_get_rrset_len(self):
-        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
-        self.assertEqual(82, get_rrset_len(rrset_soa))
-
-    def test_zone_has_soa(self):
-        global sqlite3_ds
-        def mydb1(zone, file):
-            return True
-        sqlite3_ds.get_zone_soa = mydb1
-        self.assertTrue(self.xfrsess._zone_has_soa(""))
-        def mydb2(zone, file):
-            return False
-        sqlite3_ds.get_zone_soa = mydb2
-        self.assertFalse(self.xfrsess._zone_has_soa(""))
-
-    def test_zone_exist(self):
-        global sqlite3_ds
-        def zone_exist(zone, file):
-            return zone
-        sqlite3_ds.zone_exist = zone_exist
-        self.assertTrue(self.xfrsess._zone_exist(True))
-        self.assertFalse(self.xfrsess._zone_exist(False))
-
-    def test_check_xfrout_available(self):
-        def zone_exist(zone):
-            return zone
-        def zone_has_soa(zone):
-            return (not zone)
-        self.xfrsess._zone_exist = zone_exist
-        self.xfrsess._zone_has_soa = zone_has_soa
-        self.assertEqual(self.xfrsess._check_xfrout_available(False).to_text(), "NOTAUTH")
-        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "SERVFAIL")
-
-        def zone_empty(zone):
-            return zone
-        self.xfrsess._zone_has_soa = zone_empty
-        def false_func():
-            return False
-        self.xfrsess._server.increase_transfers_counter = false_func
-        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "REFUSED")
-        def true_func():
-            return True
-        self.xfrsess._server.increase_transfers_counter = true_func
-        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "NOERROR")
-
-    def test_dns_xfrout_start_formerror(self):
-        # formerror
-        self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
-        sent_data = self.sock.readsent()
-        self.assertEqual(len(sent_data), 0)
-
-    def default(self, param):
-        return "example.com"
-
-    def test_dns_xfrout_start_notauth(self):
-        self.xfrsess._get_query_zone_name = self.default
-        def notauth(formpara):
-            return Rcode.NOTAUTH()
-        self.xfrsess._check_xfrout_available = notauth
-        self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
-        get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rcode().to_text(), "NOTAUTH")
-
-    def test_dns_xfrout_start_noerror(self):
-        self.xfrsess._get_query_zone_name = self.default
-        def noerror(form):
-            return Rcode.NOERROR()
-        self.xfrsess._check_xfrout_available = noerror
-
-        def myreply(msg, sock, zonename):
-            self.sock.send(b"success")
-
-        self.xfrsess._reply_xfrout_query = myreply
-        self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
-        self.assertEqual(self.sock.readsent(), b"success")
-
-    def test_reply_xfrout_query_noerror(self):
-        global sqlite3_ds
-        def get_zone_soa(zonename, file):
-            return self.soa_record
-
-        def get_zone_datas(zone, file):
-            return [self.soa_record]
-
-        sqlite3_ds.get_zone_soa = get_zone_soa
-        sqlite3_ds.get_zone_datas = get_zone_datas
-        self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
-        reply_msg = self.sock.read_msg()
-        self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
-
-class MyCCSession():
-    def __init__(self):
-        pass
-
-    def get_remote_config_value(self, module_name, identifier):
-        if module_name == "Auth" and identifier == "database_file":
-            return "initdb.file", False
-        else:
-            return "unknown", False
-
-
-class MyUnixSockServer(UnixSockServer):
-    def __init__(self):
-        self._lock = threading.Lock()
-        self._transfers_counter = 0
-        self._shutdown_event = threading.Event()
-        self._max_transfers_out = 10
-        self._cc = MyCCSession()
-        self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
-
-class TestUnixSockServer(unittest.TestCase):
-    def setUp(self):
-        self.write_sock, self.read_sock = socket.socketpair()
-        self.unix = MyUnixSockServer()
-
-    def test_receive_query_message(self):
-        send_msg = b"\xd6=\x00\x00\x00\x01\x00"
-        msg_len = struct.pack('H', socket.htons(len(send_msg)))
-        self.write_sock.send(msg_len)
-        self.write_sock.send(send_msg)
-        recv_msg = self.unix._receive_query_message(self.read_sock)
-        self.assertEqual(recv_msg, send_msg)
-
-    def test_updata_config_data(self):
-        self.unix.update_config_data({'transfers_out':10 })
-        self.assertEqual(self.unix._max_transfers_out, 10)
-
-    def test_get_db_file(self):
-        self.assertEqual(self.unix.get_db_file(), "initdb.file")
-
-    def test_increase_transfers_counter(self):
-        self.unix._max_transfers_out = 10
-        count = self.unix._transfers_counter
-        self.assertEqual(self.unix.increase_transfers_counter(), True)
-        self.assertEqual(count + 1, self.unix._transfers_counter)
-
-        self.unix._max_transfers_out = 0
-        count = self.unix._transfers_counter
-        self.assertEqual(self.unix.increase_transfers_counter(), False)
-        self.assertEqual(count, self.unix._transfers_counter)
-
-    def test_decrease_transfers_counter(self):
-        count = self.unix._transfers_counter
-        self.unix.decrease_transfers_counter()
-        self.assertEqual(count - 1, self.unix._transfers_counter)
-
-    def _remove_file(self, sock_file):
-        try:
-            os.remove(sock_file)
-        except OSError:
-            pass
-
-    def test_sock_file_in_use_file_exist(self):
-        sock_file = 'temp.sock.file'
-        self._remove_file(sock_file)
-        self.assertFalse(self.unix._sock_file_in_use(sock_file))
-        self.assertFalse(os.path.exists(sock_file))
-
-    def test_sock_file_in_use_file_not_exist(self):
-        self.assertFalse(self.unix._sock_file_in_use('temp.sock.file'))
-
-    def _start_unix_sock_server(self, sock_file):
-        serv = ThreadingUnixStreamServer(sock_file, BaseRequestHandler)
-        serv_thread = threading.Thread(target=serv.serve_forever)
-        serv_thread.setDaemon(True)
-        serv_thread.start()
-
-    def test_sock_file_in_use(self):
-        sock_file = 'temp.sock.file'
-        self._remove_file(sock_file)
-        self.assertFalse(self.unix._sock_file_in_use(sock_file))
-        self._start_unix_sock_server(sock_file)
-
-        old_stdout = sys.stdout
-        sys.stdout = open(os.devnull, 'w')
-        self.assertTrue(self.unix._sock_file_in_use(sock_file))
-        sys.stdout = old_stdout
-
-    def test_remove_unused_sock_file_in_use(self):
-        sock_file = 'temp.sock.file'
-        self._remove_file(sock_file)
-        self.assertFalse(self.unix._sock_file_in_use(sock_file))
-        self._start_unix_sock_server(sock_file)
-        old_stdout = sys.stdout
-        sys.stdout = open(os.devnull, 'w')
-        try:
-            self.unix._remove_unused_sock_file(sock_file)
-        except SystemExit:
-            pass
-        else:
-            # This should never happen
-            self.assertTrue(False)
-
-        sys.stdout = old_stdout
-
-    def test_remove_unused_sock_file_dir(self):
-        import tempfile
-        dir_name = tempfile.mkdtemp()
-        old_stdout = sys.stdout
-        sys.stdout = open(os.devnull, 'w')
-        try:
-            self.unix._remove_unused_sock_file(dir_name)
-        except SystemExit:
-            pass
-        else:
-            # This should never happen
-            self.assertTrue(False)
-
-        sys.stdout = old_stdout
-        os.rmdir(dir_name)
-
-if __name__== "__main__":
-    unittest.main()
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
new file mode 100644
index 0000000..472ef3c
--- /dev/null
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -0,0 +1,469 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''Tests for the XfroutSession and UnixSockServer classes '''
+
+
+import unittest
+import os
+from isc.cc.session import *
+from pydnspp import *
+from xfrout import *
+import xfrout
+
+# our fake socket, where we can read and insert messages
+class MySocket():
+    def __init__(self, family, type):
+        self.family = family
+        self.type = type
+        self.sendqueue = bytearray()
+
+    def connect(self, to):
+        pass
+
+    def close(self):
+        pass
+
+    def send(self, data):
+        self.sendqueue.extend(data);
+        return len(data)
+
+    def readsent(self):
+        if len(self.sendqueue) >= 2:
+            size = 2 + struct.unpack("!H", self.sendqueue[:2])[0]
+        else:
+            size = 0
+        result = self.sendqueue[:size]
+        self.sendqueue = self.sendqueue[size:]
+        return result
+
+    def read_msg(self):
+        sent_data = self.readsent()
+        get_msg = Message(Message.PARSE)
+        get_msg.from_wire(bytes(sent_data[2:]))
+        return get_msg
+
+    def clear_send(self):
+        del self.sendqueue[:]
+
+# We subclass the Session class we're testing here, only
+# to override the handle() and _send_data() method
+class MyXfroutSession(XfroutSession):
+    def handle(self):
+        pass
+
+    def _send_data(self, sock, data):
+        size = len(data)
+        total_count = 0
+        while total_count < size:
+            count = sock.send(data[total_count:])
+            total_count += count
+
+class Dbserver:
+    def __init__(self):
+        self._shutdown_event = threading.Event()
+    def get_db_file(self):
+        return None
+    def decrease_transfers_counter(self):
+        pass
+
+class TestXfroutSession(unittest.TestCase):
+    def getmsg(self):
+        msg = Message(Message.PARSE)
+        msg.from_wire(self.mdata)
+        return msg
+
+    def setUp(self):
+        self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
+        self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
+        self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), self.log)
+        self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
+        self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
+
+    def test_parse_query_message(self):
+        [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
+        self.assertEqual(get_rcode.to_text(), "NOERROR")
+
+    def test_get_query_zone_name(self):
+        msg = self.getmsg()
+        self.assertEqual(self.xfrsess._get_query_zone_name(msg), "example.com.")
+
+    def test_send_data(self):
+        self.xfrsess._send_data(self.sock, self.mdata)
+        senddata = self.sock.readsent()
+        self.assertEqual(senddata, self.mdata)
+
+    def test_reply_xfrout_query_with_error_rcode(self):
+        msg = self.getmsg()
+        self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
+
+    def test_send_message(self):
+        msg = self.getmsg()
+        msg.make_response()
+        # soa record data with different cases
+        soa_record = (4, 3, 'Example.com.', 'com.Example.', 3600, 'SOA', None, 'master.Example.com. admin.exAmple.com. 1234 3600 1800 2419200 7200')
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(soa_record)
+        msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
+        self.xfrsess._send_message(self.sock, msg)
+        send_out_data = self.sock.readsent()[2:]
+
+        # CASE_INSENSITIVE compression mode
+        render = MessageRenderer();
+        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
+        msg.to_wire(render)
+        self.assertNotEqual(render.get_data(), send_out_data)
+
+        # CASE_SENSITIVE compression mode
+        render.clear()
+        render.set_compress_mode(MessageRenderer.CASE_SENSITIVE)
+        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
+        msg.to_wire(render)
+        self.assertEqual(render.get_data(), send_out_data)
+
+    def test_clear_message(self):
+        msg = self.getmsg()
+        qid = msg.get_qid()
+        opcode = msg.get_opcode()
+        rcode = msg.get_rcode()
+
+        self.xfrsess._clear_message(msg)
+        self.assertEqual(msg.get_qid(), qid)
+        self.assertEqual(msg.get_opcode(), opcode)
+        self.assertEqual(msg.get_rcode(), rcode)
+        self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_AA))
+
+    def test_reply_query_with_format_error(self):
+        msg = self.getmsg()
+        self.xfrsess._reply_query_with_format_error(msg, self.sock)
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rcode().to_text(), "FORMERR")
+
+    def test_create_rrset_from_db_record(self):
+        rrset = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+        self.assertEqual(rrset.get_name().to_text(), "example.com.")
+        self.assertEqual(rrset.get_class(), RRClass("IN"))
+        self.assertEqual(rrset.get_type().to_text(), "SOA")
+        rdata = rrset.get_rdata()
+        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
+
+    def test_send_message_with_last_soa(self):
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+
+        msg = self.getmsg()
+        msg.make_response()
+        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 0)
+        get_msg = self.sock.read_msg()
+
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
+
+        #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]#answer_rrset_iter.get_rrset()
+        self.assertEqual(answer.get_name().to_text(), "example.com.")
+        self.assertEqual(answer.get_class(), RRClass("IN"))
+        self.assertEqual(answer.get_type().to_text(), "SOA")
+        rdata = answer.get_rdata()
+        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
+
+    def test_trigger_send_message_with_last_soa(self):
+        rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
+        rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+
+        msg = self.getmsg()
+        msg.make_response()
+
+        msg.add_rrset(Message.SECTION_ANSWER, rrset_a)
+        # give the function a value that is larger than MAX-len(rrset)
+        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 65520)
+
+        # this should have triggered the sending of two messages
+        # (1 with the rrset we added manually, and 1 that triggered
+        # the sending in _with_last_soa)
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
+
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
+        self.assertEqual(answer.get_name().to_text(), "example.com.")
+        self.assertEqual(answer.get_class(), RRClass("IN"))
+        self.assertEqual(answer.get_type().to_text(), "A")
+        rdata = answer.get_rdata()
+        self.assertEqual(rdata[0].to_text(), "192.0.2.1")
+
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 0)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
+
+        #answer_rrset_iter = section_iter(get_msg, Message.SECTION_ANSWER)
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
+        self.assertEqual(answer.get_name().to_text(), "example.com.")
+        self.assertEqual(answer.get_class(), RRClass("IN"))
+        self.assertEqual(answer.get_type().to_text(), "SOA")
+        rdata = answer.get_rdata()
+        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
+
+        # and it should not have sent anything else
+        self.assertEqual(0, len(self.sock.sendqueue))
+
+    def test_get_rrset_len(self):
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+        self.assertEqual(82, get_rrset_len(rrset_soa))
+
+    def test_zone_has_soa(self):
+        global sqlite3_ds
+        def mydb1(zone, file):
+            return True
+        sqlite3_ds.get_zone_soa = mydb1
+        self.assertTrue(self.xfrsess._zone_has_soa(""))
+        def mydb2(zone, file):
+            return False
+        sqlite3_ds.get_zone_soa = mydb2
+        self.assertFalse(self.xfrsess._zone_has_soa(""))
+
+    def test_zone_exist(self):
+        global sqlite3_ds
+        def zone_exist(zone, file):
+            return zone
+        sqlite3_ds.zone_exist = zone_exist
+        self.assertTrue(self.xfrsess._zone_exist(True))
+        self.assertFalse(self.xfrsess._zone_exist(False))
+
+    def test_check_xfrout_available(self):
+        def zone_exist(zone):
+            return zone
+        def zone_has_soa(zone):
+            return (not zone)
+        self.xfrsess._zone_exist = zone_exist
+        self.xfrsess._zone_has_soa = zone_has_soa
+        self.assertEqual(self.xfrsess._check_xfrout_available(False).to_text(), "NOTAUTH")
+        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "SERVFAIL")
+
+        def zone_empty(zone):
+            return zone
+        self.xfrsess._zone_has_soa = zone_empty
+        def false_func():
+            return False
+        self.xfrsess._server.increase_transfers_counter = false_func
+        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "REFUSED")
+        def true_func():
+            return True
+        self.xfrsess._server.increase_transfers_counter = true_func
+        self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "NOERROR")
+
+    def test_dns_xfrout_start_formerror(self):
+        # formerror
+        self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
+        sent_data = self.sock.readsent()
+        self.assertEqual(len(sent_data), 0)
+
+    def default(self, param):
+        return "example.com"
+
+    def test_dns_xfrout_start_notauth(self):
+        self.xfrsess._get_query_zone_name = self.default
+        def notauth(formpara):
+            return Rcode.NOTAUTH()
+        self.xfrsess._check_xfrout_available = notauth
+        self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rcode().to_text(), "NOTAUTH")
+
+    def test_dns_xfrout_start_noerror(self):
+        self.xfrsess._get_query_zone_name = self.default
+        def noerror(form):
+            return Rcode.NOERROR()
+        self.xfrsess._check_xfrout_available = noerror
+
+        def myreply(msg, sock, zonename):
+            self.sock.send(b"success")
+
+        self.xfrsess._reply_xfrout_query = myreply
+        self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
+        self.assertEqual(self.sock.readsent(), b"success")
+
+    def test_reply_xfrout_query_noerror(self):
+        global sqlite3_ds
+        def get_zone_soa(zonename, file):
+            return self.soa_record
+
+        def get_zone_datas(zone, file):
+            return [self.soa_record]
+
+        sqlite3_ds.get_zone_soa = get_zone_soa
+        sqlite3_ds.get_zone_datas = get_zone_datas
+        self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
+        reply_msg = self.sock.read_msg()
+        self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
+
+class MyCCSession():
+    def __init__(self):
+        pass
+
+    def get_remote_config_value(self, module_name, identifier):
+        if module_name == "Auth" and identifier == "database_file":
+            return "initdb.file", False
+        else:
+            return "unknown", False
+
+
+class MyUnixSockServer(UnixSockServer):
+    def __init__(self):
+        self._lock = threading.Lock()
+        self._transfers_counter = 0
+        self._shutdown_event = threading.Event()
+        self._max_transfers_out = 10
+        self._cc = MyCCSession()
+        self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
+
+class TestUnixSockServer(unittest.TestCase):
+    def setUp(self):
+        self.write_sock, self.read_sock = socket.socketpair()
+        self.unix = MyUnixSockServer()
+
+    def test_receive_query_message(self):
+        send_msg = b"\xd6=\x00\x00\x00\x01\x00"
+        msg_len = struct.pack('H', socket.htons(len(send_msg)))
+        self.write_sock.send(msg_len)
+        self.write_sock.send(send_msg)
+        recv_msg = self.unix._receive_query_message(self.read_sock)
+        self.assertEqual(recv_msg, send_msg)
+
+    def test_updata_config_data(self):
+        self.unix.update_config_data({'transfers_out':10 })
+        self.assertEqual(self.unix._max_transfers_out, 10)
+
+    def test_get_db_file(self):
+        self.assertEqual(self.unix.get_db_file(), "initdb.file")
+
+    def test_increase_transfers_counter(self):
+        self.unix._max_transfers_out = 10
+        count = self.unix._transfers_counter
+        self.assertEqual(self.unix.increase_transfers_counter(), True)
+        self.assertEqual(count + 1, self.unix._transfers_counter)
+
+        self.unix._max_transfers_out = 0
+        count = self.unix._transfers_counter
+        self.assertEqual(self.unix.increase_transfers_counter(), False)
+        self.assertEqual(count, self.unix._transfers_counter)
+
+    def test_decrease_transfers_counter(self):
+        count = self.unix._transfers_counter
+        self.unix.decrease_transfers_counter()
+        self.assertEqual(count - 1, self.unix._transfers_counter)
+
+    def _remove_file(self, sock_file):
+        try:
+            os.remove(sock_file)
+        except OSError:
+            pass
+
+    def test_sock_file_in_use_file_exist(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self.assertFalse(os.path.exists(sock_file))
+
+    def test_sock_file_in_use_file_not_exist(self):
+        self.assertFalse(self.unix._sock_file_in_use('temp.sock.file'))
+
+    def _start_unix_sock_server(self, sock_file):
+        serv = ThreadingUnixStreamServer(sock_file, BaseRequestHandler)
+        serv_thread = threading.Thread(target=serv.serve_forever)
+        serv_thread.setDaemon(True)
+        serv_thread.start()
+
+    def test_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        self.assertTrue(self.unix._sock_file_in_use(sock_file))
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(sock_file)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_dir(self):
+        import tempfile
+        dir_name = tempfile.mkdtemp()
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(dir_name)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+        os.rmdir(dir_name)
+
+class TestInitialization(unittest.TestCase):
+    def setEnv(self, name, value):
+        if value is None:
+            if name in os.environ:
+                del os.environ[name]
+        else:
+            os.environ[name] = value
+
+    def setUp(self):
+        self._oldSocket = os.getenv("BIND10_XFROUT_SOCKET_FILE")
+        self._oldFromBuild = os.getenv("B10_FROM_BUILD")
+
+    def tearDown(self):
+        self.setEnv("B10_FROM_BUILD", self._oldFromBuild)
+        self.setEnv("BIND10_XFROUT_SOCKET_FILE", self._oldSocket)
+        # Make sure even the computed values are back
+        xfrout.init_paths()
+
+    def testNoEnv(self):
+        self.setEnv("B10_FROM_BUILD", None)
+        self.setEnv("BIND10_XFROUT_SOCKET_FILE", None)
+        xfrout.init_paths()
+        self.assertEqual(xfrout.UNIX_SOCKET_FILE,
+                         "@@LOCALSTATEDIR@@/auth_xfrout_conn")
+
+    def testProvidedSocket(self):
+        self.setEnv("B10_FROM_BUILD", None)
+        self.setEnv("BIND10_XFROUT_SOCKET_FILE", "The/Socket/File")
+        xfrout.init_paths()
+        self.assertEqual(xfrout.UNIX_SOCKET_FILE, "The/Socket/File")
+
+if __name__== "__main__":
+    unittest.main()
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index b3f9e95..17ca3eb 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -37,29 +37,38 @@ from optparse import OptionParser, OptionValueError
 from isc.util import socketserver_mixin
 
 try:
-    from libxfr_python import *
+    from libutil_io_python import *
     from pydnspp import *
 except ImportError as e:
     # C++ loadable module may not be installed; even so the xfrout process
     # must keep running, so we warn about it and move forward.
-    sys.stderr.write('[b10-xfrout] failed to import DNS or XFR module: %s\n' % str(e))
+    sys.stderr.write('[b10-xfrout] failed to import DNS or isc.util.io module: %s\n' % str(e))
 
 isc.util.process.rename()
 
-if "B10_FROM_BUILD" in os.environ:
-    SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
-    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
-    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
-        UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"] + \
-            "/auth_xfrout_conn"
+def init_paths():
+    global SPECFILE_PATH
+    global AUTH_SPECFILE_PATH
+    global UNIX_SOCKET_FILE
+    if "B10_FROM_BUILD" in os.environ:
+        SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
+        AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
+        if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+            UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"] + \
+                "/auth_xfrout_conn"
+        else:
+            UNIX_SOCKET_FILE = os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
     else:
-        UNIX_SOCKET_FILE = os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
-else:
-    PREFIX = "@prefix@"
-    DATAROOTDIR = "@datarootdir@"
-    SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
-    AUTH_SPECFILE_PATH = SPECFILE_PATH
-    UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
+        PREFIX = "@prefix@"
+        DATAROOTDIR = "@datarootdir@"
+        SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+        AUTH_SPECFILE_PATH = SPECFILE_PATH
+        if "BIND10_XFROUT_SOCKET_FILE" in os.environ:
+            UNIX_SOCKET_FILE = os.environ["BIND10_XFROUT_SOCKET_FILE"]
+        else:
+            UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
+
+init_paths()
 
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
 AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
@@ -376,7 +385,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
             # This may happen when one xfrout process try to connect to
             # xfrout unix socket server, to check whether there is another
             # xfrout running.
-            if sock_fd == XFR_FD_RECEIVE_FAIL:
+            if sock_fd == FD_COMM_ERROR:
                 self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
             return
 
diff --git a/src/bin/zonemgr/b10-zonemgr.8 b/src/bin/zonemgr/b10-zonemgr.8
index fbd0602..bfc0a7b 100644
--- a/src/bin/zonemgr/b10-zonemgr.8
+++ b/src/bin/zonemgr/b10-zonemgr.8
@@ -2,12 +2,12 @@
 .\"     Title: b10-zonemgr
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: October 18, 2010
+.\"      Date: May 19, 2011
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-ZONEMGR" "8" "October 18, 2010" "BIND10" "BIND10"
+.TH "B10\-ZONEMGR" "8" "May 19, 2011" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -46,11 +46,6 @@ receives its configurations from
 The configurable settings are:
 .PP
 
-\fIjitter_scope\fR
-defines the random jitter range subtracted from the refresh and retry timers to avoid many zones from refreshing at the same time\&. The refresh or retry time actually used is a random time between the defined refresh or retry time and it multiplied by the
-\fIjitter_scope\fR\&. This is re\-evaluated after each refresh or retry\&. This value is a real number and the maximum is 0\&.5 (half of the refresh or retry time)\&. The default is 0\&.25\&. Set to 0 to disable the jitter\&.
-.PP
-
 \fIlowerbound_refresh\fR
 defines the minimum SOA REFRESH time in seconds\&. The default is 10\&.
 .PP
@@ -59,10 +54,36 @@ defines the minimum SOA REFRESH time in seconds\&. The default is 10\&.
 defines the minimum SOA RETRY time in seconds\&. The default is 5\&.
 .PP
 
+\fIrefresh_jitter\fR
+This value is a real number\&. The maximum amount is 0\&.5\&. The default is 0\&.25\&.
+.PP
+
+\fIreload_jitter\fR
+This value is a real number\&. The default is 0\&.75\&.
+.PP
+
 \fImax_transfer_timeout\fR
 defines the maximum amount of time in seconds for a transfer\&.
 The default is 14400 (4 hours)\&.
 .PP
+
+\fIsecondary_zones\fR
+is a list of slave zones that the
+\fBb10\-zonemgr\fR
+should keep timers for\&. The list items include the
+\fIname\fR
+(which defines the zone name) and the
+\fIclass\fR
+(which defaults to
+\(lqIN\(rq)\&.
+.PP
+(A deprecated configuration is
+\fIjitter_scope\fR
+which is superceded by
+\fIrefresh_jitter\fR
+and
+\fIreload_jitter\fR\&.)
+.PP
 The configuration commands are:
 .PP
 
@@ -107,5 +128,5 @@ The
 daemon was designed in July 2010 by CNNIC for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2011 Internet Systems Consortium, Inc. ("ISC")
 .br
diff --git a/src/bin/zonemgr/b10-zonemgr.xml b/src/bin/zonemgr/b10-zonemgr.xml
index 4d796ee..00f5d04 100644
--- a/src/bin/zonemgr/b10-zonemgr.xml
+++ b/src/bin/zonemgr/b10-zonemgr.xml
@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "—">]>
 <!--
- - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
  -
  - Permission to use, copy, modify, and/or distribute this software for any
  - purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>October 18, 2010</date>
+    <date>May 19, 2011</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2011</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -92,6 +92,39 @@
     <para>
       The configurable settings are:
     </para>
+
+    <para>
+      <varname>lowerbound_refresh</varname>
+      defines the minimum SOA REFRESH time in seconds.
+      The default is 10.
+    </para>
+
+    <para>
+      <varname>lowerbound_retry</varname>
+      defines the minimum SOA RETRY time in seconds.
+      The default is 5.
+    </para>
+
+    <para>
+      <varname>refresh_jitter</varname>
+      This value is a real number.
+      The maximum amount is 0.5.
+      The default is 0.25.
+    </para>
+<!-- TODO: needs to be documented -->
+<!-- TODO:      Set to 0 to disable the jitter.   -->
+
+    <para>
+      <varname>reload_jitter</varname>
+      This value is a real number.
+      The default is 0.75.
+    </para>
+<!-- TODO: needs to be documented -->
+<!-- TODO:      Set to 0 to disable the jitter.   -->
+<!-- what does 0 do? -->
+<!-- TODO: no max? -->
+
+<!-- TODO: remove this. This is old removed config
     <para>
       <varname>jitter_scope</varname>
       defines the random jitter range subtracted from the refresh
@@ -106,16 +139,8 @@
       The default is 0.25.
       Set to 0 to disable the jitter.
     </para>
-    <para>
-      <varname>lowerbound_refresh</varname>
-      defines the minimum SOA REFRESH time in seconds.
-      The default is 10.
-    </para>
-    <para>
-      <varname>lowerbound_retry</varname>
-      defines the minimum SOA RETRY time in seconds.
-      The default is 5.
-    </para>
+-->
+
     <para>
       <varname>max_transfer_timeout</varname>
       defines the maximum amount of time in seconds for a transfer.
@@ -123,6 +148,21 @@
       The default is 14400 (4 hours).
     </para>
 
+<!-- TODO: this duplicates list in Xfrin too -->
+    <para>
+      <varname>secondary_zones</varname> is a list of slave zones
+      that the <command>b10-zonemgr</command> should keep timers for.
+      The list items include the <varname>name</varname> (which
+      defines the zone name) and the <varname>class</varname>
+      (which defaults to <quote>IN</quote>).
+    </para>
+
+    <para>
+      (A deprecated configuration is <varname>jitter_scope</varname>
+      which is superceded by <varname>refresh_jitter</varname>
+      and <varname>reload_jitter</varname>.)
+    </para>
+
 <!-- TODO: formating -->
     <para>
       The configuration commands are:
diff --git a/src/bin/zonemgr/tests/zonemgr_test.py b/src/bin/zonemgr/tests/zonemgr_test.py
index 70dc1b0..496ce6b 100644
--- a/src/bin/zonemgr/tests/zonemgr_test.py
+++ b/src/bin/zonemgr/tests/zonemgr_test.py
@@ -21,16 +21,18 @@ import os
 import tempfile
 from zonemgr import *
 
-ZONE_NAME_CLASS1_IN = ("sd.cn.", "IN")
-ZONE_NAME_CLASS2_CH = ("tw.cn", "CH")
-ZONE_NAME_CLASS3_IN = ("example.com", "IN")
-ZONE_NAME_CLASS1_CH = ("sd.cn.", "CH")
-ZONE_NAME_CLASS2_IN = ("tw.cn", "IN")
+ZONE_NAME_CLASS1_IN = ("example.net.", "IN")
+ZONE_NAME_CLASS1_CH = ("example.net.", "CH")
+ZONE_NAME_CLASS2_IN = ("example.org.", "IN")
+ZONE_NAME_CLASS2_CH = ("example.org.", "CH")
+ZONE_NAME_CLASS3_IN = ("example.com.", "IN")
+ZONE_NAME_CLASS3_CH = ("example.com.", "CH")
 
 MAX_TRANSFER_TIMEOUT = 14400
 LOWERBOUND_REFRESH = 10
-LOWERBOUND_RETRY = 5 
-JITTER_SCOPE = 0.10
+LOWERBOUND_RETRY = 5
+REFRESH_JITTER = 0.10
+RELOAD_JITTER = 0.75
 
 class ZonemgrTestException(Exception):
     pass
@@ -46,36 +48,64 @@ class MySession():
     def group_recvmsg(self, nonblock, seq):
         return None, None
 
+class FakeConfig:
+    def __init__(self):
+        self.zone_list = []
+        self.set_zone_list_from_name_classes([ZONE_NAME_CLASS1_IN,
+                                              ZONE_NAME_CLASS2_CH])
+    def set_zone_list_from_name_classes(self, zones):
+        self.zone_list = map(lambda nc: {"name": nc[0], "class": nc[1]}, zones)
+    def get(self, name):
+        if name == 'lowerbound_refresh':
+            return LOWERBOUND_REFRESH
+        elif name == 'lowerbound_retry':
+            return LOWERBOUND_RETRY
+        elif name == 'max_transfer_timeout':
+            return MAX_TRANSFER_TIMEOUT
+        elif name == 'refresh_jitter':
+            return REFRESH_JITTER
+        elif name == 'reload_jitter':
+            return RELOAD_JITTER
+        elif name == 'secondary_zones':
+            return self.zone_list
+        else:
+            raise ValueError('Uknown config option')
+
 class MyZonemgrRefresh(ZonemgrRefresh):
     def __init__(self):
-        class FakeConfig:
-            def get(self, name):
-                if name == 'lowerbound_refresh':
-                    return LOWERBOUND_REFRESH
-                elif name == 'lowerbound_retry':
-                    return LOWERBOUND_RETRY
-                elif name == 'max_transfer_timeout':
-                    return MAX_TRANSFER_TIMEOUT
-                elif name == 'jitter_scope':
-                    return JITTER_SCOPE
-                else:
-                    raise ValueError('Uknown config option')
         self._master_socket, self._slave_socket = socket.socketpair()
+        self._zonemgr_refresh_info = {}
+        self._lowerbound_refresh = 10
+        self._lowerbound_retry = 5
+        self._reload_jitter = 0.75
+        self._refresh_jitter = 0.25
+
+        def get_zone_soa(zone_name, db_file):
+            if zone_name == 'example.net.':
+                return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+                        'a.example.net. root.example.net. 2009073106 7200 3600 2419200 21600')
+            elif zone_name == 'example.org.':
+                return (1, 2, 'example.org.', 'example.org.sd.', 21600, 'SOA', None,
+                        'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600')
+            else:
+                return None
+        sqlite3_ds.get_zone_soa = get_zone_soa
+
         ZonemgrRefresh.__init__(self, MySession(), "initdb.file",
             self._slave_socket, FakeConfig())
         current_time = time.time()
-        self._zonemgr_refresh_info = { 
-         ('sd.cn.', 'IN'): {
+        self._zonemgr_refresh_info = {
+         ('example.net.', 'IN'): {
          'last_refresh_time': current_time,
-         'next_refresh_time': current_time + 6500, 
-         'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
+         'next_refresh_time': current_time + 6500,
+         'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
          'zone_state': 0},
-         ('tw.cn', 'CH'): {
-         'last_refresh_time': current_time, 
-         'next_refresh_time': current_time + 6900, 
-         'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', 
+         ('example.org.', 'CH'): {
+         'last_refresh_time': current_time,
+         'next_refresh_time': current_time + 6900,
+         'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
          'zone_state': 0}
-        } 
+        }
 
 class TestZonemgrRefresh(unittest.TestCase):
     def setUp(self):
@@ -87,10 +117,10 @@ class TestZonemgrRefresh(unittest.TestCase):
         max = 100025.120
         jitter = 0
         self.assertEqual(max, self.zone_refresh._random_jitter(max, jitter))
-        jitter = max / 4
+        jitter = 0.3 * max
         for i in range (0, 150):
-            self.assertTrue((3 * max / 4) <= self.zone_refresh._random_jitter(max, jitter)) 
-            self.assertTrue(self.zone_refresh._random_jitter(max, jitter) <= max) 
+            self.assertTrue((max - jitter) <= self.zone_refresh._random_jitter(max, jitter))
+            self.assertTrue(self.zone_refresh._random_jitter(max, jitter) <= max)
             i += 1;
 
     def test_get_current_time(self):
@@ -111,7 +141,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.zone_refresh._set_zone_refresh_timer(ZONE_NAME_CLASS1_IN)
         zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
         time2 = time.time()
-        self.assertTrue((time1 + 7200 * 3 / 4) <= zone_timeout)
+        self.assertTrue((time1 + 7200 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout)
         self.assertTrue(zone_timeout <= time2 + 7200)
 
     def test_set_zone_retry_timer(self):
@@ -119,7 +149,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN)
         zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
         time2 = time.time()
-        self.assertTrue((time1 + 3600 * 3 / 4) <= zone_timeout)
+        self.assertTrue((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout)
         self.assertTrue(zone_timeout <= time2 + 3600)
 
     def test_zone_not_exist(self):
@@ -128,6 +158,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertFalse(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_CH))
         self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_IN))
         self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_IN))
+        self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_CH))
 
     def test_set_zone_notify_timer(self):
         time1 = time.time()
@@ -150,20 +181,20 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertTrue(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN))
 
     def test_get_zone_soa_rdata(self):
-        soa_rdata1  = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' 
-        soa_rdata2  = 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600' 
+        soa_rdata1  = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
+        soa_rdata2  = 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600'
         self.assertEqual(soa_rdata1, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS1_IN))
         self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS1_CH)
         self.assertEqual(soa_rdata2, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS2_CH))
         self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS2_IN)
-         
+
     def test_zonemgr_reload_zone(self):
-        soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+        soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         # We need to restore this not to harm other tests
         old_get_zone_soa = sqlite3_ds.get_zone_soa
         def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
-                    'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
         sqlite3_ds.get_zone_soa = get_zone_soa
 
         self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
@@ -212,7 +243,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         current_time = time.time()
         self.zone_refresh._set_zone_refresh_timeout(ZONE_NAME_CLASS1_IN, current_time)
         refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
-        self.assertEqual(current_time, refresh_time) 
+        self.assertEqual(current_time, refresh_time)
 
     def test_get_zone_next_refresh_time(self):
         current_time = time.time()
@@ -234,25 +265,26 @@ class TestZonemgrRefresh(unittest.TestCase):
         current_time = time.time()
         self.zone_refresh._set_zone_last_refresh_time(ZONE_NAME_CLASS1_IN, current_time)
         last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"]
-        self.assertEqual(current_time, last_refresh_time) 
+        self.assertEqual(current_time, last_refresh_time)
 
     def test_send_command(self):
         self.assertRaises(ZonemgrTestException, self.zone_refresh._send_command, "Unknown", "Notify", None)
 
     def test_zone_mgr_is_empty(self):
         self.assertFalse(self.zone_refresh._zone_mgr_is_empty())
-        self.zone_refresh._zonemgr_refresh_info = {} 
+        self.zone_refresh._zonemgr_refresh_info = {}
         self.assertTrue(self.zone_refresh._zone_mgr_is_empty())
 
     def test_zonemgr_add_zone(self):
-        soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+        soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         # This needs to be restored. The following test actually failed if we left
         # this unclean
         old_get_zone_soa = sqlite3_ds.get_zone_soa
+        time1 = time.time()
 
         def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
-                    'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
 
         sqlite3_ds.get_zone_soa = get_zone_soa
 
@@ -260,10 +292,14 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS1_IN)
         self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info))
         zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
-        self.assertEqual(soa_rdata, zone_soa_rdata) 
+        self.assertEqual(soa_rdata, zone_soa_rdata)
         self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
         self.assertTrue("last_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
         self.assertTrue("next_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
+        time2 = time.time()
+        zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
+        self.assertTrue((time1 + 900 * (1 - self.zone_refresh._reload_jitter)) <= zone_timeout)
+        self.assertTrue(zone_timeout <= time2 + 900)
 
         def get_zone_soa2(zone_name, db_file):
             return None
@@ -272,64 +308,42 @@ class TestZonemgrRefresh(unittest.TestCase):
                                          ZONE_NAME_CLASS1_IN)
         sqlite3_ds.get_zone_soa = old_get_zone_soa
 
-    def test_build_zonemgr_refresh_info(self):
-        soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
-
-        def get_zones_info(db_file):
-            return [("sd.cn.", "IN")] 
-
-        def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
-                    'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
-
-        sqlite3_ds.get_zones_info = get_zones_info
-        sqlite3_ds.get_zone_soa = get_zone_soa
-
-        self.zone_refresh._zonemgr_refresh_info = {}
-        self.zone_refresh._build_zonemgr_refresh_info()
-        self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info))
-        zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
-        self.assertEqual(soa_rdata, zone_soa_rdata) 
-        self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
-        self.assertTrue("last_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
-        self.assertTrue("next_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
-
     def test_zone_handle_notify(self):
         self.zone_refresh.zone_handle_notify(ZONE_NAME_CLASS1_IN,"127.0.0.1")
         notify_master = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"]
-        self.assertEqual("127.0.0.1", notify_master) 
+        self.assertEqual("127.0.0.1", notify_master)
         zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
         current_time = time.time()
         self.assertTrue(zone_timeout <= current_time)
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
-                          ("org.cn.", "IN"), "127.0.0.1")
+                          ZONE_NAME_CLASS3_CH, "127.0.0.1")
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
                           ZONE_NAME_CLASS3_IN, "127.0.0.1")
 
     def test_zone_refresh_success(self):
-        soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+        soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
-                    'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
         sqlite3_ds.get_zone_soa = get_zone_soa
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
         self.zone_refresh.zone_refresh_success(ZONE_NAME_CLASS1_IN)
         time2 = time.time()
         zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
-        self.assertEqual(soa_rdata, zone_soa_rdata) 
+        self.assertEqual(soa_rdata, zone_soa_rdata)
         next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
-        self.assertTrue((time1 + 3 * 1800 / 4) <= next_refresh_time) 
+        self.assertTrue((time1 + 1800 * (1 - self.zone_refresh._refresh_jitter)) <= next_refresh_time)
         self.assertTrue(next_refresh_time <= time2 + 1800)
         self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
         last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"]
         self.assertTrue(time1 <= last_refresh_time)
         self.assertTrue(last_refresh_time <= time2)
-        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("org.cn.", "CH"))
-        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN) 
+        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("example.test.", "CH"))
+        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN)
 
     def test_zone_refresh_fail(self):
-        soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' 
+        soa_rdata = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
         self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
@@ -337,80 +351,80 @@ class TestZonemgrRefresh(unittest.TestCase):
         zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
         self.assertEqual(soa_rdata, zone_soa_rdata)
         next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
-        self.assertTrue((time1 + 3 * 3600 / 4) <= next_refresh_time)
+        self.assertTrue(((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter))) <= next_refresh_time)
         self.assertTrue(next_refresh_time <= time2 + 3600)
         self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
 
-        self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = time1 - 2419200 
+        self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = time1 - 2419200
         self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
         self.assertEqual(ZONE_EXPIRED, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
 
-        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ("org.cn.", "CH"))
-        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN) 
+        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
+        self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
 
     def test_find_need_do_refresh_zone(self):
         time1 = time.time()
-        self.zone_refresh._zonemgr_refresh_info = { 
-                ("sd.cn.","IN"):{
+        self.zone_refresh._zonemgr_refresh_info = {
+                ("example.net.","IN"):{
                     'last_refresh_time': time1,
-                    'next_refresh_time': time1 + 7200, 
-                    'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
+                    'next_refresh_time': time1 + 7200,
+                    'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
                     'zone_state': ZONE_OK},
-                ("tw.cn","CH"):{
-                    'last_refresh_time': time1 - 7200, 
-                    'next_refresh_time': time1, 
-                    'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT, 
-                    'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', 
+                ("example.org.","CH"):{
+                    'last_refresh_time': time1 - 7200,
+                    'next_refresh_time': time1,
+                    'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT,
+                    'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
                     'zone_state': ZONE_REFRESHING}
                 }
         zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone()
         self.assertEqual(ZONE_NAME_CLASS1_IN, zone_need_refresh)
 
-        self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["refresh_timeout"] = time1 
+        self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["refresh_timeout"] = time1
         zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone()
         self.assertEqual(ZONE_NAME_CLASS2_CH, zone_need_refresh)
 
     def test_do_refresh(self):
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info = {
-                ("sd.cn.", "IN"):{
+                ("example.net.", "IN"):{
                     'last_refresh_time': time1 - 7200,
-                    'next_refresh_time': time1 - 1, 
-                    'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
+                    'next_refresh_time': time1 - 1,
+                    'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
                     'zone_state': ZONE_OK}
                 }
         self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN)
         time2 = time.time()
         zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
         self.assertEqual(ZONE_REFRESHING, zone_state)
-        refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] 
+        refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
         self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout)
-        self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout) 
+        self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout)
 
         self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] = "127.0.0.1"
         self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN)
         time2 = time.time()
         zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
-        self.assertEqual(ZONE_REFRESHING, zone_state) 
-        refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] 
+        self.assertEqual(ZONE_REFRESHING, zone_state)
+        refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
         self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout)
         self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout)
         self.assertFalse("notify_master" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
 
     def test_run_timer(self):
-        """This case will run timer in daemon thread. 
-        The zone's next_refresh_time is less than now, so zonemgr will do zone refresh 
-        immediately. The zone's state will become "refreshing". 
+        """This case will run timer in daemon thread.
+        The zone's next_refresh_time is less than now, so zonemgr will do zone refresh
+        immediately. The zone's state will become "refreshing".
         """
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info = {
-                ("sd.cn.", "IN"):{
+                ("example.net.", "IN"):{
                     'last_refresh_time': time1 - 7200,
-                    'next_refresh_time': time1 - 1, 
-                    'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
+                    'next_refresh_time': time1 - 1,
+                    'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
                     'zone_state': ZONE_OK}
                 }
-        self.zone_refresh._check_sock = self.zone_refresh._master_socket 
+        self.zone_refresh._check_sock = self.zone_refresh._master_socket
         listener = self.zone_refresh.run_timer(daemon=True)
         # Shut down the timer thread
         self.zone_refresh.shutdown()
@@ -420,26 +434,109 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertTrue(zone_state == ZONE_REFRESHING)
 
     def test_update_config_data(self):
+        # make sure it doesn't fail if we only provide secondary zones
+        config_data = {
+                    "secondary_zones": [ { "name": "example.net.",
+                                           "class": "IN" } ]
+                }
+        self.zone_refresh.update_config_data(config_data)
+
+        # update all values
+        config_data = {
+                    "lowerbound_refresh" : 60,
+                    "lowerbound_retry" : 30,
+                    "max_transfer_timeout" : 19800,
+                    "refresh_jitter" : 0.25,
+                    "reload_jitter" : 0.75,
+                    "secondary_zones": []
+                }
+        self.zone_refresh.update_config_data(config_data)
+        self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
+        self.assertEqual(30, self.zone_refresh._lowerbound_retry)
+        self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
+        self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
+        self.assertEqual(0.75, self.zone_refresh._reload_jitter)
+
+        # make sure they are not reset when we only update one
+        config_data = {
+                    "reload_jitter" : 0.35,
+                }
+        self.zone_refresh.update_config_data(config_data)
+        self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
+        self.assertEqual(30, self.zone_refresh._lowerbound_retry)
+        self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
+        self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
+        self.assertEqual(0.35, self.zone_refresh._reload_jitter)
+
+        # and make sure we restore the previous config if something
+        # goes wrong
+        config_data = {
+                    "lowerbound_refresh" : 61,
+                    "lowerbound_retry" : 31,
+                    "max_transfer_timeout" : 19801,
+                    "refresh_jitter" : 0.21,
+                    "reload_jitter" : 0.71,
+                    "secondary_zones": [ { "name": "doesnotexist",
+                                           "class": "IN" } ]
+                }
+        self.assertRaises(ZonemgrException,
+                          self.zone_refresh.update_config_data,
+                          config_data)
+        self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
+        self.assertEqual(30, self.zone_refresh._lowerbound_retry)
+        self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
+        self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
+        self.assertEqual(0.35, self.zone_refresh._reload_jitter)
+
+        # Make sure we accept 0 as a value
         config_data = {
                     "lowerbound_refresh" : 60,
                     "lowerbound_retry" : 30,
                     "max_transfer_timeout" : 19800,
-                    "jitter_scope" : 0.25
+                    "refresh_jitter" : 0,
+                    "reload_jitter" : 0.75,
+                    "secondary_zones": []
                 }
         self.zone_refresh.update_config_data(config_data)
         self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
         self.assertEqual(30, self.zone_refresh._lowerbound_retry)
         self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
-        self.assertEqual(0.25, self.zone_refresh._jitter_scope)
+        self.assertEqual(0, self.zone_refresh._refresh_jitter)
+        self.assertEqual(0.75, self.zone_refresh._reload_jitter)
 
     def test_shutdown(self):
-        self.zone_refresh._check_sock = self.zone_refresh._master_socket 
+        self.zone_refresh._check_sock = self.zone_refresh._master_socket
         listener = self.zone_refresh.run_timer()
         self.assertTrue(listener.is_alive())
         # Shut down the timer thread
         self.zone_refresh.shutdown()
         self.assertFalse(listener.is_alive())
 
+    def test_secondary_zones(self):
+        """Test that we can modify the list of secondary zones"""
+        config = FakeConfig()
+        config.zone_list = []
+        # First, remove everything
+        self.zone_refresh.update_config_data(config)
+        self.assertEqual(self.zone_refresh._zonemgr_refresh_info, {})
+        # Put something in
+        config.set_zone_list_from_name_classes([ZONE_NAME_CLASS1_IN])
+        self.zone_refresh.update_config_data(config)
+        self.assertTrue(("example.net.", "IN") in
+                        self.zone_refresh._zonemgr_refresh_info)
+        # This one does not exist
+        config.set_zone_list_from_name_classes(["example.net", "CH"])
+        self.assertRaises(ZonemgrException,
+                          self.zone_refresh.update_config_data, config)
+        # So it should not affect the old ones
+        self.assertTrue(("example.net.", "IN") in
+                        self.zone_refresh._zonemgr_refresh_info)
+        # Make sure it works even when we "accidentally" forget the final dot
+        config.set_zone_list_from_name_classes([("example.net", "IN")])
+        self.zone_refresh.update_config_data(config)
+        self.assertTrue(("example.net.", "IN") in
+                        self.zone_refresh._zonemgr_refresh_info)
+
     def tearDown(self):
         sys.stderr= self.stderr_backup
 
@@ -447,7 +544,7 @@ class TestZonemgrRefresh(unittest.TestCase):
 class MyCCSession():
     def __init__(self):
         pass
-                    
+
     def get_remote_config_value(self, module_name, identifier):
         if module_name == "Auth" and identifier == "database_file":
             return "initdb.file", False
@@ -464,10 +561,12 @@ class MyZonemgr(Zonemgr):
         self._cc = MySession()
         self._module_cc = MyCCSession()
         self._config_data = {
-                    "lowerbound_refresh" : 10, 
-                    "lowerbound_retry" : 5, 
+                    "lowerbound_refresh" : 10,
+                    "lowerbound_retry" : 5,
                     "max_transfer_timeout" : 14400,
-                    "jitter_scope" : 0.1
+                    "refresh_jitter" : 0.1,
+                    "reload_jitter" : 0.75,
+                    "secondary_zones": []
                     }
 
     def _start_zone_refresh_timer(self):
@@ -480,30 +579,42 @@ class TestZonemgr(unittest.TestCase):
 
     def test_config_handler(self):
         config_data1 = {
-                    "lowerbound_refresh" : 60, 
-                    "lowerbound_retry" : 30, 
+                    "lowerbound_refresh" : 60,
+                    "lowerbound_retry" : 30,
                     "max_transfer_timeout" : 14400,
-                    "jitter_scope" : 0.1
+                    "refresh_jitter" : 0.1,
+                    "reload_jitter" : 0.75,
+                    "secondary_zones": []
                     }
-        self.zonemgr.config_handler(config_data1)
+        self.assertEqual(self.zonemgr.config_handler(config_data1),
+                         {"result": [0]})
         self.assertEqual(config_data1, self.zonemgr._config_data)
-        config_data2 = {"zone_name" : "sd.cn.", "port" : "53", "master" : "192.168.1.1"}
+        config_data2 = {"zone_name" : "example.net.", "port" : "53", "master" : "192.168.1.1"}
         self.zonemgr.config_handler(config_data2)
         self.assertEqual(config_data1, self.zonemgr._config_data)
         # jitter should not be bigger than half of the original value
-        config_data3 = {"jitter_scope" : 0.7}
+        config_data3 = {"refresh_jitter" : 0.7}
         self.zonemgr.config_handler(config_data3)
-        self.assertEqual(0.5, self.zonemgr._config_data.get("jitter_scope"))
+        self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
+        # The zone doesn't exist in database, it should be rejected
+        self.zonemgr._zone_refresh = ZonemgrRefresh(None, "initdb.file", None,
+                                                    config_data1)
+        config_data1["secondary_zones"] = [{"name": "nonexistent.example",
+                                            "class": "IN"}]
+        self.assertNotEqual(self.zonemgr.config_handler(config_data1),
+                            {"result": [0]})
+        # As it is rejected, the old value should be kept
+        self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
 
     def test_get_db_file(self):
         self.assertEqual("initdb.file", self.zonemgr.get_db_file())
-    
+
     def test_parse_cmd_params(self):
-        params1 = {"zone_name" : "org.cn", "zone_class" : "CH", "master" : "127.0.0.1"}
-        answer1 = (("org.cn", "CH"), "127.0.0.1")
+        params1 = {"zone_name" : "example.com.", "zone_class" : "CH", "master" : "127.0.0.1"}
+        answer1 = (ZONE_NAME_CLASS3_CH, "127.0.0.1")
         self.assertEqual(answer1, self.zonemgr._parse_cmd_params(params1, ZONE_NOTIFY_COMMAND))
-        params2 = {"zone_name" : "org.cn", "zone_class" : "CH"}
-        answer2 = ("org.cn", "CH")
+        params2 = {"zone_name" : "example.com.", "zone_class" : "IN"}
+        answer2 = ZONE_NAME_CLASS3_IN
         self.assertEqual(answer2, self.zonemgr._parse_cmd_params(params2, ZONE_XFRIN_SUCCESS_COMMAND))
         self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
         params1 = {"zone_class" : "CH"}
@@ -511,12 +622,12 @@ class TestZonemgr(unittest.TestCase):
 
     def test_config_data_check(self):
         # jitter should not be bigger than half of the original value
-        config_data2 = {"jitter_scope" : 0.2}
-        config_data3 = {"jitter_scope" : 0.6}
+        config_data2 = {"refresh_jitter" : 0.2}
+        config_data3 = {"refresh_jitter" : 0.6}
         self.zonemgr._config_data_check(config_data2)
-        self.assertEqual(0.2, config_data2.get("jitter_scope"))
+        self.assertEqual(0.2, config_data2.get("refresh_jitter"))
         self.zonemgr._config_data_check(config_data3)
-        self.assertEqual(0.5, config_data3.get("jitter_scope"))
+        self.assertEqual(0.5, config_data3.get("refresh_jitter"))
 
     def tearDown(self):
         pass
diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in
index 2cededf..c6e3163 100755
--- a/src/bin/zonemgr/zonemgr.py.in
+++ b/src/bin/zonemgr/zonemgr.py.in
@@ -100,9 +100,13 @@ class ZonemgrRefresh:
         self._cc = cc
         self._check_sock = slave_socket
         self._db_file = db_file
-        self.update_config_data(config_data)
         self._zonemgr_refresh_info = {}
-        self._build_zonemgr_refresh_info()
+        self._lowerbound_refresh = None
+        self._lowerbound_retry = None
+        self._max_transfer_timeout = None
+        self._refresh_jitter = None
+        self._reload_jitter = None
+        self.update_config_data(config_data)
         self._running = False
 
     def _random_jitter(self, max, jitter):
@@ -126,19 +130,19 @@ class ZonemgrRefresh:
 
     def _set_zone_refresh_timer(self, zone_name_class):
         """Set zone next refresh time after zone refresh success.
-           now + refresh - jitter  <= next_refresh_time <= now + refresh
+           now + refresh - refresh_jitter <= next_refresh_time <= now + refresh
            """
         zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[REFRESH_OFFSET])
         zone_refresh_time = max(self._lowerbound_refresh, zone_refresh_time)
-        self._set_zone_timer(zone_name_class, zone_refresh_time, self._jitter_scope * zone_refresh_time)
+        self._set_zone_timer(zone_name_class, zone_refresh_time, self._refresh_jitter * zone_refresh_time)
 
     def _set_zone_retry_timer(self, zone_name_class):
         """Set zone next refresh time after zone refresh fail.
-           now + retry - jitter <= next_refresh_time <= now + retry
+           now + retry - retry_jitter <= next_refresh_time <= now + retry
            """
         zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
         zone_retry_time = max(self._lowerbound_retry, zone_retry_time)
-        self._set_zone_timer(zone_name_class, zone_retry_time, self._jitter_scope * zone_retry_time)
+        self._set_zone_timer(zone_name_class, zone_retry_time, self._refresh_jitter * zone_retry_time)
 
     def _set_zone_notify_timer(self, zone_name_class):
         """Set zone next refresh time after receiving notify
@@ -148,16 +152,13 @@ class ZonemgrRefresh:
 
     def _zone_not_exist(self, zone_name_class):
         """ Zone doesn't belong to zonemgr"""
-        if zone_name_class in self._zonemgr_refresh_info.keys():
-            return False
-        return True
+        return not zone_name_class in self._zonemgr_refresh_info
 
     def zone_refresh_success(self, zone_name_class):
         """Update zone info after zone refresh success"""
         if (self._zone_not_exist(zone_name_class)):
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                    "belong to zonemgr" % zone_name_class)
-            return
         self.zonemgr_reload_zone(zone_name_class)
         self._set_zone_refresh_timer(zone_name_class)
         self._set_zone_state(zone_name_class, ZONE_OK)
@@ -168,7 +169,6 @@ class ZonemgrRefresh:
         if (self._zone_not_exist(zone_name_class)):
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                    "belong to zonemgr" % zone_name_class)
-            return
         # Is zone expired?
         if (self._zone_is_expired(zone_name_class)):
             self._set_zone_state(zone_name_class, ZONE_EXPIRED)
@@ -181,7 +181,6 @@ class ZonemgrRefresh:
         if (self._zone_not_exist(zone_name_class)):
             raise ZonemgrException("[b10-zonemgr] Notified zone (%s, %s) "
                                    "doesn't belong to zonemgr" % zone_name_class)
-            return
         self._set_zone_notifier_master(zone_name_class, master)
         self._set_zone_notify_timer(zone_name_class)
 
@@ -192,6 +191,7 @@ class ZonemgrRefresh:
 
     def zonemgr_add_zone(self, zone_name_class):
         """ Add a zone into zone manager."""
+        log_msg("Loading zone (%s, %s)" % zone_name_class)
         zone_info = {}
         zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
         if not zone_soa:
@@ -199,17 +199,11 @@ class ZonemgrRefresh:
         zone_info["zone_soa_rdata"] = zone_soa[7]
         zone_info["zone_state"] = ZONE_OK
         zone_info["last_refresh_time"] = self._get_current_time()
-        zone_info["next_refresh_time"] = self._get_current_time() + \
-                                         float(zone_soa[7].split(" ")[REFRESH_OFFSET])
         self._zonemgr_refresh_info[zone_name_class] = zone_info
-
-    def _build_zonemgr_refresh_info(self):
-        """ Build zonemgr refresh info map."""
-        log_msg("Start loading zone into zonemgr.")
-        for zone_name, zone_class in sqlite3_ds.get_zones_info(self._db_file):
-            zone_name_class = (zone_name, zone_class)
-            self.zonemgr_add_zone(zone_name_class)
-        log_msg("Finish loading zone into zonemgr.")
+        # Imposes some random jitters to avoid many zones need to do refresh at the same time.
+        zone_reload_jitter = float(zone_soa[7].split(" ")[RETRY_OFFSET])
+        zone_reload_jitter = max(self._lowerbound_retry, zone_reload_jitter)
+        self._set_zone_timer(zone_name_class, zone_reload_jitter, self._reload_jitter * zone_reload_jitter)
 
     def _zone_is_expired(self, zone_name_class):
         """Judge whether a zone is expired or not."""
@@ -415,10 +409,73 @@ class ZonemgrRefresh:
 
     def update_config_data(self, new_config):
         """ update ZonemgrRefresh config """
-        self._lowerbound_refresh = new_config.get('lowerbound_refresh')
-        self._lowerbound_retry = new_config.get('lowerbound_retry')
-        self._max_transfer_timeout = new_config.get('max_transfer_timeout')
-        self._jitter_scope = new_config.get('jitter_scope')
+        # TODO: we probably want to store all this info in a nice
+        # class, so that we don't have to backup and restore every
+        # single value.
+        # TODO2: We also don't use get_default_value yet
+        backup = self._zonemgr_refresh_info.copy()
+
+        # Get a new value, but only if it is defined (commonly used below)
+        # We don't use "value or default", because if value would be
+        # 0, we would take default
+        def val_or_default(value, default):
+            if value is not None:
+                return value
+            else:
+                return default
+
+        # store the values so we can restore them if there is a problem
+        lowerbound_refresh_backup = self._lowerbound_refresh
+        self._lowerbound_refresh = val_or_default(
+            new_config.get('lowerbound_refresh'), self._lowerbound_refresh)
+
+        lowerbound_retry_backup = self._lowerbound_retry
+        self._lowerbound_retry = val_or_default(
+            new_config.get('lowerbound_retry'), self._lowerbound_retry)
+
+        max_transfer_timeout_backup = self._max_transfer_timeout
+        self._max_transfer_timeout = val_or_default(
+            new_config.get('max_transfer_timeout'), self._max_transfer_timeout)
+
+        refresh_jitter_backup = self._refresh_jitter
+        self._refresh_jitter = val_or_default(
+            new_config.get('refresh_jitter'), self._refresh_jitter)
+
+        reload_jitter_backup = self._reload_jitter
+        self._reload_jitter = val_or_default(
+            new_config.get('reload_jitter'), self._reload_jitter)
+        try:
+            required = {}
+            secondary_zones = new_config.get('secondary_zones')
+            if secondary_zones is not None:
+                # Add new zones
+                for secondary_zone in new_config.get('secondary_zones'):
+                    name = secondary_zone['name']
+                    # Be tolerant to sclerotic users who forget the final dot
+                    if name[-1] != '.':
+                        name = name + '.'
+                    name_class = (name, secondary_zone['class'])
+                    required[name_class] = True
+                    # Add it only if it isn't there already
+                    if not name_class in self._zonemgr_refresh_info:
+                        self.zonemgr_add_zone(name_class)
+                # Drop the zones that are no longer there
+                # Do it in two phases, python doesn't like deleting while iterating
+                to_drop = []
+                for old_zone in self._zonemgr_refresh_info:
+                    if not old_zone in required:
+                        to_drop.append(old_zone)
+                for drop in to_drop:
+                    del self._zonemgr_refresh_info[drop]
+        # If we are not able to find it in database, restore the original
+        except:
+            self._zonemgr_refresh_info = backup
+            self._lowerbound_refresh = lowerbound_refresh_backup
+            self._lowerbound_retry = lowerbound_retry_backup
+            self._max_transfer_timeout = max_transfer_timeout_backup
+            self._refresh_jitter = refresh_jitter_backup
+            self._reload_jitter = reload_jitter_backup
+            raise
 
 class Zonemgr:
     """Zone manager class."""
@@ -471,26 +528,37 @@ class Zonemgr:
     def config_handler(self, new_config):
         """ Update config data. """
         answer = create_answer(0)
+        ok = True
+        complete = self._config_data.copy()
         for key in new_config:
-            if key not in self._config_data:
+            if key not in complete:
                 answer = create_answer(1, "Unknown config data: " + str(key))
+                ok = False
                 continue
-            self._config_data[key] = new_config[key]
+            complete[key] = new_config[key]
 
-        self._config_data_check(self._config_data)
-        if (self._zone_refresh):
-            self._zone_refresh.update_config_data(self._config_data)
+        self._config_data_check(complete)
+        if self._zone_refresh is not None:
+            try:
+                self._zone_refresh.update_config_data(complete)
+            except Exception as e:
+                answer = create_answer(1, str(e))
+                ok = False
+        if ok:
+            self._config_data = complete
 
         return answer
 
     def _config_data_check(self, config_data):
-        """Check whether the new config data is valid or 
-        not. """ 
+        """Check whether the new config data is valid or
+        not. It contains only basic logic, not full check against
+        database."""
         # jitter should not be bigger than half of the original value
-        if config_data.get('jitter_scope') > 0.5:
-            config_data['jitter_scope'] = 0.5
-            log_msg("[b10-zonemgr] jitter_scope is too big, its value will "
-                      "be set to 0.5") 
+        if config_data.get('refresh_jitter') > 0.5:
+            config_data['refresh_jitter'] = 0.5
+            log_msg("[b10-zonemgr] refresh_jitter is too big, its value will "
+                      "be set to 0.5")
+
 
     def _parse_cmd_params(self, args, command):
         zone_name = args.get("zone_name")
diff --git a/src/bin/zonemgr/zonemgr.spec.pre.in b/src/bin/zonemgr/zonemgr.spec.pre.in
index 0539ef3..36f02df 100644
--- a/src/bin/zonemgr/zonemgr.spec.pre.in
+++ b/src/bin/zonemgr/zonemgr.spec.pre.in
@@ -12,19 +12,51 @@
          "item_name": "lowerbound_retry",
          "item_type": "integer",
          "item_optional": false,
-         "item_default": 5 
+         "item_default": 5
        },
        {
          "item_name": "max_transfer_timeout",
          "item_type": "integer",
          "item_optional": false,
-         "item_default": 14400 
+         "item_default": 14400
        },
        {
-         "item_name": "jitter_scope",
+         "item_name": "refresh_jitter",
          "item_type": "real",
          "item_optional": false,
          "item_default": 0.25
+       },
+       {
+         "item_name": "reload_jitter",
+         "item_type": "real",
+         "item_optional": false,
+         "item_default": 0.75
+       },
+       {
+         "item_name": "secondary_zones",
+         "item_type": "list",
+         "item_optional": false,
+         "item_default": [],
+         "list_item_spec": {
+           "item_name": "secondary_zone",
+           "item_type": "map",
+           "item_optional": false,
+           "item_default": {},
+           "map_item_spec": [
+             {
+               "item_name": "class",
+               "item_type": "string",
+               "item_optional": false,
+               "item_default": "IN"
+             },
+             {
+               "item_name": "name",
+               "item_type": "string",
+               "item_optional": false,
+               "item_default": ""
+             }
+           ]
+         }
        }
       ],
       "commands": [
diff --git a/src/cppcheck-suppress.lst b/src/cppcheck-suppress.lst
index 3e4dcd6..36b8e4c 100644
--- a/src/cppcheck-suppress.lst
+++ b/src/cppcheck-suppress.lst
@@ -3,13 +3,13 @@
 debug
 missingInclude
 // This is a template, and should be excluded from the check
-unreadVariable:src/lib/dns/rdata/template.cc:59
+unreadVariable:src/lib/dns/rdata/template.cc:60
 // These three trigger warnings due to the incomplete implementation.  This is
 // our problem, but we need to suppress the warnings for now.
 functionConst:src/lib/cache/resolver_cache.h
 functionConst:src/lib/cache/message_cache.h
 functionConst:src/lib/cache/rrset_cache.h
 // Intentional self assignment tests.  Suppress warning about them.
-selfAssignment:src/lib/dns/tests/name_unittest.cc:292
-selfAssignment:src/lib/dns/tests/rdata_unittest.cc:227
-selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:104
+selfAssignment:src/lib/dns/tests/name_unittest.cc:293
+selfAssignment:src/lib/dns/tests/rdata_unittest.cc:228
+selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:137
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 8525b8d..81ddd18 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,3 @@
-SUBDIRS = exceptions dns cc config python xfr bench log asiolink \
-          nsas cache resolve testutils datasrc server_common
+SUBDIRS = exceptions util log cryptolink dns cc config python xfr \
+          bench asiolink asiodns nsas cache resolve testutils datasrc \
+          server_common
diff --git a/src/lib/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am
new file mode 100644
index 0000000..2a6c3ac
--- /dev/null
+++ b/src/lib/asiodns/Makefile.am
@@ -0,0 +1,41 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink -I$(top_builddir)/src/lib/asiolink
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda asiodef.h asiodef.cc
+
+# Define rule to build logging source files from message file
+asiodef.h asiodef.cc: asiodef.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/asiodns/asiodef.mes
+
+BUILT_SOURCES = asiodef.h asiodef.cc
+
+lib_LTLIBRARIES = libasiodns.la
+libasiodns_la_SOURCES = dns_answer.h
+libasiodns_la_SOURCES += asiodns.h
+libasiodns_la_SOURCES += dns_lookup.h
+libasiodns_la_SOURCES += dns_server.h
+libasiodns_la_SOURCES += dns_service.cc dns_service.h
+libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
+libasiodns_la_SOURCES += udp_server.cc udp_server.h
+libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
+
+nodist_libasiodns_la_SOURCES = asiodef.cc asiodef.h
+
+EXTRA_DIST = asiodef.mes
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+libasiodns_la_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+libasiodns_la_CXXFLAGS += -Wno-error
+endif
+libasiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
+libasiodns_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/asiodns/README b/src/lib/asiodns/README
new file mode 100644
index 0000000..596d1df
--- /dev/null
+++ b/src/lib/asiodns/README
@@ -0,0 +1,157 @@
+The asiodns library is intended to provide an abstraction layer between
+BIND10 modules and asiolink library.
+
+These DNS server and client routines are written using the "stackless
+coroutine" pattern invented by Chris Kohlhoff and described at
+http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html.
+This is intended to simplify development a bit, since it allows the
+routines to be written in a straightfowrard step-step-step fashion rather
+than as a complex chain of separate handler functions.
+
+Coroutine objects (i.e., UDPServer, TCPServer and IOFetch) are objects
+with reenterable operator() members.  When an instance of one of these
+classes is called as a function, it resumes at the position where it left
+off.  Thus, a UDPServer can issue an asynchronous I/O call and specify
+itself as the handler object; when the call completes, the UDPServer
+carries on at the same position.  As a result, the code can look as
+if it were using synchronous, not asynchronous, I/O, providing some of
+the benefit of threading but with minimal switching overhead.
+
+So, in simplified form, the behavior of a DNS Server is:
+
+  REENTER:
+    while true:
+      YIELD packet = read_packet
+      FORK
+      if not parent:
+        break
+
+    # This callback informs the caller that a packet has arrived, and
+    # gives it a chance to update configuration, etc
+    SimpleCallback(packet)
+    YIELD answer = DNSLookup(packet, this)
+    response = DNSAnswer(answer)
+    YIELD send(response)
+
+At each "YIELD" point, the coroutine initiates an asynchronous operation,
+then pauses and turns over control to some other task on the ASIO service
+queue.  When the operation completes, the coroutine resumes.
+
+DNSLookup, DNSAnswer and SimpleCallback define callback methods
+used by a DNS Server to communicate with the module that called it.
+They are abstract-only classes whose concrete implementations
+are supplied by the calling module.
+
+The DNSLookup callback always runs asynchronously.  Concrete
+implementations must be sure to call the server's "resume" method when
+it is finished.
+
+In an authoritative server, the DNSLookup implementation would examine
+the query, look up the answer, then call "resume".  (See the diagram
+in doc/auth_process.jpg.)
+
+In a recursive server, the DNSLookup impelemtation would initiate a
+DNSQuery, which in turn would be responsible for calling the server's
+"resume" method.  (See the diagram in doc/recursive_process.jpg.)
+
+A DNSQuery object is intended to handle resolution of a query over
+the network when the local authoritative data sources or cache are not
+sufficient.  The plan is that it will make use of subsidiary DNSFetch
+calls to get data from particular authoritative servers, and when it has
+gotten a complete answer, it calls "resume".
+
+In current form, however, DNSQuery is much simpler; it forwards queries
+to a single upstream resolver and passes the answers back to the client.
+It is constructed with the address of the forward server.  Queries are
+initiated with the question to ask the forward server, a buffer into
+which to write the answer, and a pointer to the coroutine to be resumed
+when the answer has arrived.  In simplified form, the DNSQuery routine is:
+
+  REENTER:
+    render the question into a wire-format query packet
+    YIELD send(query)
+    YIELD response = read_packet
+    server->resume
+
+Currently, DNSQuery is only implemented for UDP queries.  In future work
+it will be necessary to write code to fall back to TCP when circumstances
+require it.
+
+
+Upstream Fetches
+================
+Upstream fetches (queries by the resolver on behalf of a client) are made
+using a slightly-modified version of the pattern described above.
+
+Sockets
+-------
+First, it will be useful to understand the class hierarchy used in the
+fetch logic:
+
+        IOSocket
+           |
+      IOAsioSocket
+           |
+     +-----+-----+                
+     |           |
+UDPSocket    TCPSocket
+
+IOSocket is a wrapper class for a socket and is used by the authoritative
+server code.  It is an abstract base class, providing little more that the ability to hold the socket and to return the protocol in use.
+
+Built on this is IOAsioSocket, which adds the open, close, asyncSend and
+asyncReceive methods.  This is a template class, which takes as template
+argument the class of the object that will be used as the callback when the
+asynchronous operation completes. This object can be of any type, but must
+include an operator() method with the signature:
+
+   operator()(asio::error_code ec, size_t length)
+
+... the two arguments being the status of the completed I/O operation and
+the number of bytes transferred. (In the case of the open method, the second
+argument will be zero.)
+
+Finally, the TCPSocket and UDPSocket classes provide the body of the
+asynchronous operations.
+
+Fetch Sequence
+--------------
+The fetch is implemented by the IOFetch class, which takes as argument the
+protocol to use.  The sequence is:
+
+  REENTER:
+    render the question into a wire-format query packet
+    open()                           // Open socket and optionally connect
+    if (! synchronous) {
+        YIELD;
+    }
+    YIELD asyncSend(query)           // Send query 
+    do {
+        YIELD asyncReceive(response) // Read response
+    } while (! complete(response))
+    close()                          // Drop connection and close socket
+    server->resume
+
+The open() method opens a socket for use.  On TCP, it also makes a
+connection to the remote end.  So under UDP the operation will complete
+immediately, but under TCP it could take a long time.  One solution would be
+for the open operation to post an event to the I/O queue; then both cases
+could be regarded as being equivalent, with the completion being signalled
+by the posting of the completion event.  However UDP is the most common case
+and that would involve extra overhead.  So the open() returns a status
+indicating whether the operation completed asynchronously.  If it did, the
+code yields back to the coroutine; if not the yield is bypassed.
+
+The asynchronous send is straightforward, invoking the underlying ASIO
+function.  (Note that the address/port is supplied to both the open() and
+asyncSend() methods - it is used by the TCPSocket in open() and by the
+UDPSocket in asyncSend().)
+
+The asyncReceive() method issues an asynchronous read and waits for completion.
+The fetch object keeps track of the amount of data received so far and when
+the receive completes it calls a method on the socket to determine if the
+entire message has been received.  (This will always be the case for UDP.  On
+TCP though, the message is preceded by a count field as several reads may be
+required to read all the data.)  The fetch loops until all the data is read.
+
+Finally, the socket is closed and the server called to resume operation.
diff --git a/src/lib/asiodns/asiodef.mes b/src/lib/asiodns/asiodef.mes
new file mode 100644
index 0000000..3f2e80c
--- /dev/null
+++ b/src/lib/asiodns/asiodef.mes
@@ -0,0 +1,56 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX ASIODNS_
+$NAMESPACE isc::asiodns
+
+% FETCHCOMP   upstream fetch to %1(%2) has now completed
+A debug message, this records the the upstream fetch (a query made by the
+resolver on behalf of its client) to the specified address has completed.
+
+% FETCHSTOP   upstream fetch to %1(%2) has been stopped
+An external component has requested the halting of an upstream fetch.  This
+is an allowed operation, and the message should only appear if debug is
+enabled.
+
+% OPENSOCK    error %1 opening %2 socket to %3(%4)
+The asynchronous I/O code encountered an error when trying to open a socket
+of the specified protocol in order to send a message to the target address.
+The the number of the system error that cause the problem is given in the
+message.
+
+% RECVSOCK    error %1 reading %2 data from %3(%4)
+The asynchronous I/O code encountered an error when trying read data from
+the specified address on the given protocol.  The the number of the system
+error that cause the problem is given in the message.
+
+% SENDSOCK    error %1 sending data using %2 to %3(%4)
+The asynchronous I/O code encountered an error when trying send data to
+the specified address on the given protocol.  The the number of the system
+error that cause the problem is given in the message.
+
+% RECVTMO     receive timeout while waiting for data from %1(%2)
+An upstream fetch from the specified address timed out.  This may happen for
+any number of reasons and is most probably a problem at the remote server
+or a problem on the network.  The message will only appear if debug is
+enabled.
+
+% UNKORIGIN  unknown origin for ASIO error code %1 (protocol: %2, address %3)
+This message should not appear and indicates an internal error if it does.
+Please enter a bug report.
+
+% UNKRESULT  unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3)
+The termination method of the resolver's upstream fetch class was called with
+an unknown result code (which is given in the message).  This message should
+not appear and may indicate an internal error.  Please enter a bug report.
diff --git a/src/lib/asiodns/asiodns.h b/src/lib/asiodns/asiodns.h
new file mode 100644
index 0000000..8791a72
--- /dev/null
+++ b/src/lib/asiodns/asiodns.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ASIODNS_H
+#define __ASIODNS_H 1
+
+#include <asiodns/dns_service.h>
+#include <asiodns/dns_server.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_answer.h>
+
+#endif // __ASIODNS_H
diff --git a/src/lib/asiodns/dns_answer.h b/src/lib/asiodns/dns_answer.h
new file mode 100644
index 0000000..3654369
--- /dev/null
+++ b/src/lib/asiodns/dns_answer.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ASIOLINK_DNS_ANSWER_H
+#define __ASIOLINK_DNS_ANSWER_H 1
+
+#include <asiolink/io_message.h>
+#include <util/buffer.h>
+#include <dns/message.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief The \c DNSAnswer class is an abstract base class for a DNS
+/// Answer provider function.
+///
+/// Specific derived class implementations are hidden within the
+/// implementation.  Instances of the derived classes can be called
+/// as functions via the operator() interface.  Pointers to these
+/// instances can then be provided to the \c IOService class
+/// via its constructor.
+///
+/// A DNS Answer provider function takes answer data that has been obtained
+/// from a DNS Lookup provider functon and readies it to be sent to the
+/// client.  After it has run, the OutputBuffer object passed to it should
+/// contain the answer to the query rendered into wire format.
+class DNSAnswer {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
+private:
+    DNSAnswer(const DNSAnswer& source);
+    DNSAnswer& operator=(const DNSAnswer& source);
+protected:
+    /// \brief The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class
+    /// should never be instantiated (except as part of a derived class).
+    DNSAnswer() {}
+public:
+    /// \brief The destructor
+    virtual ~DNSAnswer() {}
+    //@}
+    /// \brief The function operator
+    ///
+    /// This makes its call indirectly via the "self" pointer, ensuring
+    /// that the function ultimately invoked will be the one in the derived
+    /// class.
+    ///
+    /// \param io_message The event message to handle
+    /// \param query_message The DNS MessagePtr of the original query
+    /// \param answer_message The DNS MessagePtr of the answer we are
+    /// building
+    /// \param buffer Intermediate data results are put here
+    virtual void operator()(const asiolink::IOMessage& io_message,
+                            isc::dns::MessagePtr query_message,
+                            isc::dns::MessagePtr answer_message,
+                            isc::util::OutputBufferPtr buffer) const = 0;
+};
+
+}      // namespace asiodns
+}      // namespace isc
+#endif // __ASIOLINK_DNS_ANSWER_H
diff --git a/src/lib/asiodns/dns_lookup.h b/src/lib/asiodns/dns_lookup.h
new file mode 100644
index 0000000..40290e4
--- /dev/null
+++ b/src/lib/asiodns/dns_lookup.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ASIOLINK_DNS_LOOKUP_H
+#define __ASIOLINK_DNS_LOOKUP_H 1
+
+#include <asiolink/io_message.h>
+#include <asiodns/dns_server.h>
+#include <dns/message.h>
+#include <util/buffer.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief The \c DNSLookup class is an abstract base class for a DNS
+/// Lookup provider function.
+///
+/// Specific derived class implementations are hidden within the
+/// implementation.  Instances of the derived classes can be called
+/// as functions via the operator() interface.  Pointers to these
+/// instances can then be provided to the \c IOService class
+/// via its constructor.
+///
+/// A DNS Lookup provider function obtains the data needed to answer
+/// a DNS query (e.g., from authoritative data source, cache, or upstream
+/// query).  After it has run, the OutputBuffer object passed to it
+/// should contain the answer to the query, in an internal representation.
+class DNSLookup {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
+private:
+    DNSLookup(const DNSLookup& source);
+    DNSLookup& operator=(const DNSLookup& source);
+protected:
+    /// \brief The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class
+    /// should never be instantiated (except as part of a derived class).
+    DNSLookup() : self_(this) {}
+public:
+    /// \brief The destructor
+    virtual ~DNSLookup() {}
+    //@}
+    /// \brief The function operator
+    ///
+    /// This makes its call indirectly via the "self" pointer, ensuring
+    /// that the function ultimately invoked will be the one in the derived
+    /// class.
+    ///
+    /// \param io_message The event message to handle
+    /// \param message The DNS MessagePtr that needs handling
+    /// \param answer_message The final answer will be constructed in
+    ///                       this MessagePtr
+    /// \param buffer The final answer is put here
+    /// \param server DNSServer object to use
+    virtual void operator()(const asiolink::IOMessage& io_message,
+                            isc::dns::MessagePtr message,
+                            isc::dns::MessagePtr answer_message,
+                            isc::util::OutputBufferPtr buffer,
+                            DNSServer* server) const
+    {
+        (*self_)(io_message, message, answer_message, buffer, server);
+    }
+private:
+    DNSLookup* self_;
+};
+
+}      // namespace asiodns
+}      // namespace isc
+#endif // __ASIOLINK_DNS_LOOKUP_H
diff --git a/src/lib/asiodns/dns_server.h b/src/lib/asiodns/dns_server.h
new file mode 100644
index 0000000..f235860
--- /dev/null
+++ b/src/lib/asiodns/dns_server.h
@@ -0,0 +1,157 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ASIOLINK_DNS_SERVER_H
+#define __ASIOLINK_DNS_SERVER_H 1
+
+#include <asiolink/io_message.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief The \c DNSServer class is a wrapper (and base class) for
+/// classes which provide DNS server functionality.
+///
+/// The classes derived from this one, \c TCPServer and \c UDPServer,
+/// act as the interface layer between clients sending queries, and
+/// functions defined elsewhere that provide answers to those queries.
+/// Those functions are described in more detail below under
+/// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
+///
+/// Notes to developers:
+/// When constructed, this class (and its derived classes) will have its
+/// "self_" member set to point to "this".  Objects of this class (as
+/// instantiated through a base class) are sometimes passed by
+/// reference (as this superclass); calls to methods in the base
+/// class are then rerouted via this pointer to methods in the derived
+/// class.  This allows code from outside asiodns, with no specific
+/// knowledge of \c TCPServer or \c UDPServer, to access their methods.
+///
+/// This class is both assignable and copy-constructable.  Its subclasses
+/// use the "stackless coroutine" pattern, meaning that it will copy itself
+/// when "forking", and that instances will be posted as ASIO handler
+/// objects, which are always copied.
+///
+/// Because these objects are frequently copied, it is recommended
+/// that derived classes be kept small to reduce copy overhead.
+class DNSServer {
+protected:
+    ///
+    /// \name Constructors and destructors
+    ///
+    /// This is intentionally defined as \c protected, as this base class
+    /// should never be instantiated except as part of a derived class.
+    //@{
+    DNSServer() : self_(this) {}
+public:
+    /// \brief The destructor
+    virtual ~DNSServer() {}
+    //@}
+
+    ///
+    /// \name Class methods
+    ///
+    /// These methods all make their calls indirectly via the "self_"
+    /// pointer, ensuring that the functions ultimately invoked will be
+    /// the ones in the derived class.  This makes it possible to pass
+    /// instances of derived classes as references to this base class
+    /// without losing access to derived class data.
+    ///
+    //@{
+    /// \brief The funtion operator
+    virtual void operator()(asio::error_code ec = asio::error_code(),
+                            size_t length = 0)
+    {
+        (*self_)(ec, length);
+    }
+
+    /// \brief Stop current running server
+    virtual void stop() { self_->stop();}
+
+    /// \brief Resume processing of the server coroutine after an 
+    /// asynchronous call (e.g., to the DNS Lookup provider) has completed.
+    ///
+    /// \param done If true, this signals the system there is an answer
+    ///             to return.
+    virtual void resume(const bool done) { self_->resume(done); }
+
+    /// \brief Indicate whether the server is able to send an answer
+    /// to a query.
+    ///
+    /// This is presently used only for testing purposes.
+    virtual bool hasAnswer() { return (self_->hasAnswer()); }
+
+    /// \brief Returns the current value of the 'coroutine' object
+    ///
+    /// This is a temporary method, intended to be used for debugging
+    /// purposes during development and removed later.  It allows
+    /// callers from outside the coroutine object to retrieve information
+    /// about its current state.
+    ///
+    /// \return The value of the 'coroutine' object
+    virtual int value() { return (self_->value()); }
+
+    /// \brief Returns a pointer to a clone of this DNSServer object.
+    ///
+    /// When a \c DNSServer object is copied or assigned, the result will
+    /// normally be another \c DNSServer object containing a copy
+    /// of the original "self_" pointer.  Calling clone() guarantees
+    /// that the underlying object is also correctly copied.
+    ///
+    /// \return A deep copy of this DNSServer object
+    virtual DNSServer* clone() { return (self_->clone()); }
+    //@}
+
+protected:
+    /// \brief Lookup handler object.
+    ///
+    /// This is a protected class; it can only be instantiated
+    /// from within a derived class of \c DNSServer.
+    ///
+    /// A server object that has received a query creates an instance
+    /// of this class and scheudles it on the ASIO service queue
+    /// using asio::io_service::post().  When the handler executes, it
+    /// calls the asyncLookup() method in the server object to start a
+    /// DNS lookup.  When the lookup is complete, the server object is
+    /// scheduled to resume, again using io_service::post().
+    ///
+    /// Note that the calling object is copied into the handler object,
+    /// not referenced.  This is because, once the calling object yields
+    /// control to the handler, it falls out of scope and may disappear
+    template <typename T>
+    class AsyncLookup {
+    public:
+        AsyncLookup(T& caller) : caller_(caller) {}
+        void operator()() { caller_.asyncLookup(); }
+    private:
+        T caller_;
+    };
+
+    /// \brief Carries out a DNS lookup.
+    ///
+    /// This function calls the \c DNSLookup object specified by the
+    /// DNS server when the \c IOService was created, passing along
+    /// the details of the query and a pointer back to the current
+    /// server object.  It is called asynchronously via the AsyncLookup
+    /// handler class.
+    virtual void asyncLookup() { self_->asyncLookup(); }
+
+private:
+    DNSServer* self_;
+};
+
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_SERVER_H
diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc
new file mode 100644
index 0000000..94510fe
--- /dev/null
+++ b/src/lib/asiodns/dns_service.cc
@@ -0,0 +1,201 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+
+#include <boost/lexical_cast.hpp>
+
+#include <config.h>
+
+#include <log/dummylog.h>
+
+#include <asio.hpp>
+#include <dns_service.h>
+#include <asiolink/io_service.h>
+#include <asiolink/io_service.h>
+#include <tcp_server.h>
+#include <udp_server.h>
+
+#include <log/dummylog.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+
+using isc::log::dlog;
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+class DNSLookup;
+class DNSAnswer;
+
+namespace {
+
+asio::ip::address
+convertAddr(const std::string& address) {
+    asio::error_code err;
+    asio::ip::address addr = asio::ip::address::from_string(address, err);
+    if (err) {
+        isc_throw(IOError, "Invalid IP address '" << &address << "': "
+            << err.message());
+    }
+    return (addr);
+}
+
+}
+
+
+class DNSServiceImpl {
+public:
+    DNSServiceImpl(IOService& io_service, const char& port,
+                  const asio::ip::address* v4addr,
+                  const asio::ip::address* v6addr,
+                  SimpleCallback* checkin, DNSLookup* lookup,
+                  DNSAnswer* answer);
+
+    IOService& io_service_;
+
+    typedef boost::shared_ptr<UDPServer> UDPServerPtr;
+    typedef boost::shared_ptr<TCPServer> TCPServerPtr;
+    typedef boost::shared_ptr<DNSServer> DNSServerPtr;
+    std::vector<DNSServerPtr> servers_;
+    SimpleCallback *checkin_;
+    DNSLookup *lookup_;
+    DNSAnswer *answer_;
+
+    void addServer(uint16_t port, const asio::ip::address& address) {
+        try {
+            dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
+            TCPServerPtr tcpServer(new TCPServer(io_service_.get_io_service(),
+                address, port, checkin_, lookup_, answer_));
+            (*tcpServer)();
+            servers_.push_back(tcpServer);
+            dlog(std::string("Initialize UDP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
+            UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
+                address, port, checkin_, lookup_, answer_));
+            (*udpServer)();
+            servers_.push_back(udpServer);
+        }
+        catch (const asio::system_error& err) {
+            // We need to catch and convert any ASIO level exceptions.
+            // This can happen for unavailable address, binding a privilege port
+            // without the privilege, etc.
+            isc_throw(IOError, "Failed to initialize network servers: " <<
+                      err.what());
+        }
+    }
+    void addServer(const char& port, const asio::ip::address& address) {
+        uint16_t portnum;
+        try {
+            // XXX: SunStudio with stlport4 doesn't reject some invalid
+            // representation such as "-1" by lexical_cast<uint16_t>, so
+            // we convert it into a signed integer of a larger size and perform
+            // range check ourselves.
+            const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
+            if (portnum32 < 0 || portnum32 > 65535) {
+                isc_throw(IOError, "Invalid port number '" << &port);
+            }
+            portnum = portnum32;
+        } catch (const boost::bad_lexical_cast& ex) {
+            isc_throw(IOError, "Invalid port number '" << &port << "': " <<
+                      ex.what());
+        }
+        addServer(portnum, address);
+    }
+};
+
+DNSServiceImpl::DNSServiceImpl(IOService& io_service,
+                               const char& port,
+                               const asio::ip::address* const v4addr,
+                               const asio::ip::address* const v6addr,
+                               SimpleCallback* checkin,
+                               DNSLookup* lookup,
+                               DNSAnswer* answer) :
+    io_service_(io_service),
+    checkin_(checkin),
+    lookup_(lookup),
+    answer_(answer)
+{
+
+    if (v4addr) {
+        addServer(port, *v4addr);
+    }
+    if (v6addr) {
+        addServer(port, *v6addr);
+    }
+}
+
+DNSService::DNSService(IOService& io_service,
+                       const char& port, const char& address,
+                       SimpleCallback* checkin,
+                       DNSLookup* lookup,
+                       DNSAnswer* answer) :
+    impl_(new DNSServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
+        answer)), io_service_(io_service)
+{
+    addServer(port, &address);
+}
+
+DNSService::DNSService(IOService& io_service,
+                       const char& port,
+                       const bool use_ipv4, const bool use_ipv6,
+                       SimpleCallback* checkin,
+                       DNSLookup* lookup,
+                       DNSAnswer* answer) :
+    impl_(NULL), io_service_(io_service)
+{
+    const asio::ip::address v4addr_any =
+        asio::ip::address(asio::ip::address_v4::any());
+    const asio::ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL; 
+    const asio::ip::address v6addr_any =
+        asio::ip::address(asio::ip::address_v6::any());
+    const asio::ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
+    impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
+}
+
+DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
+    DNSLookup* lookup, DNSAnswer *answer) :
+    impl_(new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
+        answer)), io_service_(io_service)
+{
+}
+
+DNSService::~DNSService() {
+    delete impl_;
+}
+
+void
+DNSService::addServer(const char& port, const std::string& address) {
+    impl_->addServer(port, convertAddr(address));
+}
+
+void
+DNSService::addServer(uint16_t port, const std::string& address) {
+    impl_->addServer(port, convertAddr(address));
+}
+
+void
+DNSService::clearServers() {
+    BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
+        s->stop();
+    }
+    impl_->servers_.clear();
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h
new file mode 100644
index 0000000..6b6a6c0
--- /dev/null
+++ b/src/lib/asiodns/dns_service.h
@@ -0,0 +1,114 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ASIOLINK_DNS_SERVICE_H
+#define __ASIOLINK_DNS_SERVICE_H 1
+
+#include <resolve/resolver_interface.h>
+
+#include <asiolink/io_service.h>
+#include <asiolink/simple_callback.h>
+
+namespace isc {
+namespace asiodns {
+
+class DNSLookup;
+class DNSAnswer;
+class DNSServiceImpl;
+
+/// \brief Handle DNS Queries
+///
+/// DNSService is the service that handles DNS queries and answers with
+/// a given IOService. This class is mainly intended to hold all the
+/// logic that is shared between the authoritative and the recursive
+/// server implementations. As such, it handles asio, including config
+/// updates (through the 'Checkinprovider'), and listening sockets.
+class DNSService {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
+private:
+    DNSService(const DNSService& source);
+    DNSService& operator=(const DNSService& source);
+
+public:
+    /// \brief The constructor with a specific IP address and port on which
+    /// the services listen on.
+    ///
+    /// \param io_service The IOService to work with
+    /// \param port the port to listen on
+    /// \param address the IP address to listen on
+    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
+    /// \param lookup The lookup provider (see \c DNSLookup)
+    /// \param answer The answer provider (see \c DNSAnswer)
+    DNSService(asiolink::IOService& io_service, const char& port,
+               const char& address, isc::asiolink::SimpleCallback* checkin,
+               DNSLookup* lookup, DNSAnswer* answer);
+    /// \brief The constructor with a specific port on which the services
+    /// listen on.
+    ///
+    /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
+    /// IPv4/IPv6 services will be available if and only if \c use_ipv4
+    /// or \c use_ipv6 is \c true, respectively.
+    ///
+    /// \param io_service The IOService to work with
+    /// \param port the port to listen on
+    /// \param use_ipv4 If true, listen on ipv4 'any'
+    /// \param use_ipv6 If true, listen on ipv6 'any'
+    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
+    /// \param lookup The lookup provider (see \c DNSLookup)
+    /// \param answer The answer provider (see \c DNSAnswer)
+    DNSService(asiolink::IOService& io_service, const char& port,
+               const bool use_ipv4, const bool use_ipv6,
+               isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup,
+               DNSAnswer* answer);
+    /// \brief The constructor without any servers.
+    ///
+    /// Use addServer() to add some servers.
+    DNSService(asiolink::IOService& io_service, isc::asiolink::SimpleCallback* checkin,
+               DNSLookup* lookup, DNSAnswer* answer);
+    /// \brief The destructor.
+    ~DNSService();
+    //@}
+
+    /// \brief Add another server to the service
+    void addServer(uint16_t port, const std::string &address);
+    void addServer(const char &port, const std::string &address);
+    /// \brief Remove all servers from the service
+    void clearServers();
+
+    /// \brief Return the native \c io_service object used in this wrapper.
+    ///
+    /// This is a short term work around to support other BIND 10 modules
+    /// that share the same \c io_service with the authoritative server.
+    /// It will eventually be removed once the wrapper interface is
+    /// generalized.
+    asio::io_service& get_io_service() { return io_service_.get_io_service(); }
+
+    /// \brief Return the IO Service Object
+    ///
+    /// \return IOService object for this DNS service.
+    asiolink::IOService& getIOService() { return (io_service_);}
+
+private:
+    DNSServiceImpl* impl_;
+    asiolink::IOService& io_service_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_SERVICE_H
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
new file mode 100644
index 0000000..4b2edf9
--- /dev/null
+++ b/src/lib/asiodns/io_fetch.cc
@@ -0,0 +1,429 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <asio.hpp>
+#include <asio/deadline_timer.hpp>
+
+#include <asiolink/io_address.h>
+#include <asiolink/io_asio_socket.h>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_service.h>
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/tcp_socket.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <log/logger.h>
+#include <log/macros.h>
+
+#include <asiodns/asiodef.h>
+#include <asiodns/io_fetch.h>
+
+#include <util/buffer.h>
+#include <util/random/qid_gen.h>
+
+
+using namespace asio;
+using namespace isc::asiolink;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::random;
+using namespace isc::log;
+using namespace std;
+
+namespace isc {
+namespace asiodns {
+
+/// Use the ASIO logger
+
+namespace {
+
+isc::log::Logger logger("asiolink");
+// Log debug verbosity
+enum {
+    DBG_IMPORTANT = 1,
+    DBG_COMMON = 20,
+    DBG_ALL = 50
+};
+
+}
+
+/// \brief IOFetch Data
+///
+/// The data for IOFetch is held in a separate struct pointed to by a shared_ptr
+/// object.  This is because the IOFetch object will be copied often (it is used
+/// as a coroutine and passed as callback to many async_*() functions) and we
+/// want keep the same data).  Organising the data in this way keeps copying to
+/// a minimum.
+struct IOFetchData {
+
+    // The first two members are shared pointers to a base class because what is
+    // actually instantiated depends on whether the fetch is over UDP or TCP,
+    // which is not known until construction of the IOFetch.  Use of a shared
+    // pointer here is merely to ensure deletion when the data object is deleted.
+    boost::scoped_ptr<IOAsioSocket<IOFetch> > socket;
+                                             ///< Socket to use for I/O
+    boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
+    boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
+    OutputBufferPtr   msgbuf;      ///< Wire buffer for question
+    OutputBufferPtr   received;    ///< Received data put here
+    IOFetch::Callback*          callback;    ///< Called on I/O Completion
+    asio::deadline_timer        timer;       ///< Timer to measure timeouts
+    IOFetch::Protocol           protocol;    ///< Protocol being used
+    size_t                      cumulative;  ///< Cumulative received amount
+    size_t                      expected;    ///< Expected amount of data
+    size_t                      offset;      ///< Offset to receive data
+    bool                        stopped;     ///< Have we stopped running?
+    int                         timeout;     ///< Timeout in ms
+    bool                        packet;      ///< true if packet was supplied
+
+    // In case we need to log an error, the origin of the last asynchronous
+    // I/O is recorded.  To save time and simplify the code, this is recorded
+    // as the ID of the error message that would be generated if the I/O failed.
+    // This means that we must make sure that all possible "origins" take the
+    // same arguments in their message in the same order.
+    isc::log::MessageID         origin;     ///< Origin of last asynchronous I/O
+    uint8_t                     staging[IOFetch::STAGING_LENGTH];
+                                            ///< Temporary array for received data
+    isc::dns::qid_t             qid;         ///< The QID set in the query
+
+    /// \brief Constructor
+    ///
+    /// Just fills in the data members of the IOFetchData structure
+    ///
+    /// \param proto Either IOFetch::TCP or IOFetch::UDP.
+    /// \param service I/O Service object to handle the asynchronous
+    ///        operations.
+    /// \param address IP address of upstream server
+    /// \param port Port to use for the query
+    /// \param buff Output buffer into which the response (in wire format)
+    ///        is written (if a response is received).
+    /// \param cb Callback object containing the callback to be called
+    ///        when we terminate.  The caller is responsible for managing this
+    ///        object and deleting it if necessary.
+    /// \param wait Timeout for the fetch (in ms).
+    ///
+    /// TODO: May need to alter constructor (see comment 4 in Trac ticket #554)
+    IOFetchData(IOFetch::Protocol proto, IOService& service,
+        const IOAddress& address, uint16_t port, OutputBufferPtr& buff,
+        IOFetch::Callback* cb, int wait)
+        :
+        socket((proto == IOFetch::UDP) ?
+            static_cast<IOAsioSocket<IOFetch>*>(
+                new UDPSocket<IOFetch>(service)) :
+            static_cast<IOAsioSocket<IOFetch>*>(
+                new TCPSocket<IOFetch>(service))
+            ),
+        remote_snd((proto == IOFetch::UDP) ?
+            static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
+            static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
+            ),
+        remote_rcv((proto == IOFetch::UDP) ?
+            static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
+            static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
+            ),
+        msgbuf(new OutputBuffer(512)),
+        received(buff),
+        callback(cb),
+        timer(service.get_io_service()),
+        protocol(proto),
+        cumulative(0),
+        expected(0),
+        offset(0),
+        stopped(false),
+        timeout(wait),
+        packet(false),
+        origin(ASIODNS_UNKORIGIN),
+        staging(),
+        qid(QidGenerator::getInstance().generateQid())
+    {}
+
+    // Checks if the response we received was ok;
+    // - data contains the buffer we read, as well as the address
+    // we sent to and the address we received from.
+    // length is provided by the operator() in IOFetch.
+    // Addresses must match, number of octets read must be at least
+    // 2, and the first two octets must match the qid of the message
+    // we sent.
+    bool responseOK() {
+        return (*remote_snd == *remote_rcv && cumulative >= 2 &&
+                readUint16(received->getData()) == qid);
+    }
+};
+
+/// IOFetch Constructor - just initialize the private data
+
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+    const isc::dns::Question& question, const IOAddress& address, uint16_t port,
+    OutputBufferPtr& buff, Callback* cb, int wait)
+{
+    MessagePtr query_msg(new Message(Message::RENDER));
+    initIOFetch(query_msg, protocol, service, question, address, port, buff,
+                cb, wait);
+}
+
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+    OutputBufferPtr& outpkt, const IOAddress& address, uint16_t port,
+    OutputBufferPtr& buff, Callback* cb, int wait)
+    :
+    data_(new IOFetchData(protocol, service,
+          address, port, buff, cb, wait))
+{
+    data_->msgbuf = outpkt;
+    data_->packet = true;
+}
+
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+    ConstMessagePtr query_message, const IOAddress& address, uint16_t port,
+    OutputBufferPtr& buff, Callback* cb, int wait)
+{
+    MessagePtr msg(new Message(Message::RENDER));
+
+    msg->setHeaderFlag(Message::HEADERFLAG_RD,
+                       query_message->getHeaderFlag(Message::HEADERFLAG_RD));
+    msg->setHeaderFlag(Message::HEADERFLAG_CD,
+                       query_message->getHeaderFlag(Message::HEADERFLAG_CD));
+
+    initIOFetch(msg, protocol, service,
+                **(query_message->beginQuestion()),
+                address, port, buff, cb, wait);
+}
+
+void
+IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& service,
+                     const isc::dns::Question& question,
+                     const IOAddress& address, uint16_t port,
+                     OutputBufferPtr& buff, Callback* cb, int wait)
+{
+    data_ = boost::shared_ptr<IOFetchData>(new IOFetchData(
+        protocol, service, address, port, buff, cb, wait));
+
+    query_msg->setQid(data_->qid);
+    query_msg->setOpcode(Opcode::QUERY());
+    query_msg->setRcode(Rcode::NOERROR());
+    query_msg->setHeaderFlag(Message::HEADERFLAG_RD);
+    query_msg->addQuestion(question);
+    EDNSPtr edns_query(new EDNS());
+    edns_query->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
+    query_msg->setEDNS(edns_query);
+    MessageRenderer renderer(*data_->msgbuf);
+    query_msg->toWire(renderer);
+}
+
+// Return protocol in use.
+
+IOFetch::Protocol
+IOFetch::getProtocol() const {
+    return (data_->protocol);
+}
+
+/// The function operator is implemented with the "stackless coroutine"
+/// pattern; see internal/coroutine.h for details.
+
+void
+IOFetch::operator()(asio::error_code ec, size_t length) {
+
+    if (data_->stopped) {
+        return;
+    } else if (ec) {
+        logIOFailure(ec);
+        return;
+    }
+
+    CORO_REENTER (this) {
+
+        /// Generate the upstream query and render it to wire format
+        /// This is done in a different scope to allow inline variable
+        /// declarations.
+        {
+            if (data_->packet) {
+                // A packet was given, overwrite the QID (which is in the
+                // first two bytes of the packet).
+                data_->msgbuf->writeUint16At(data_->qid, 0);
+
+            } 
+        }
+
+        // If we timeout, we stop, which will can cancel outstanding I/Os and
+        // shutdown everything.
+        if (data_->timeout != -1) {
+            data_->timer.expires_from_now(boost::posix_time::milliseconds(
+                data_->timeout));
+            data_->timer.async_wait(boost::bind(&IOFetch::stop, *this,
+                TIME_OUT));
+        }
+
+        // Open a connection to the target system.  For speed, if the operation
+        // is synchronous (i.e. UDP operation) we bypass the yield.
+        data_->origin = ASIODNS_OPENSOCK;
+        if (data_->socket->isOpenSynchronous()) {
+            data_->socket->open(data_->remote_snd.get(), *this);
+        } else {
+            CORO_YIELD data_->socket->open(data_->remote_snd.get(), *this);
+        }
+
+        do {
+            // Begin an asynchronous send, and then yield.  When the send completes,
+            // we will resume immediately after this point.
+            data_->origin = ASIODNS_SENDSOCK;
+            CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
+                data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
+    
+            // Now receive the response.  Since TCP may not receive the entire
+            // message in one operation, we need to loop until we have received
+            // it. (This can't be done within the asyncReceive() method because
+            // each I/O operation will be done asynchronously and between each one
+            // we need to yield ... and we *really* don't want to set up another
+            // coroutine within that method.)  So after each receive (and yield),
+            // we check if the operation is complete and if not, loop to read again.
+            //
+            // Another concession to TCP is that the amount of is contained in the
+            // first two bytes.  This leads to two problems:
+            //
+            // a) We don't want those bytes in the return buffer.
+            // b) They may not both arrive in the first I/O.
+            //
+            // So... we need to loop until we have at least two bytes, then store
+            // the expected amount of data.  Then we need to loop until we have
+            // received all the data before copying it back to the user's buffer.
+            // And we want to minimise the amount of copying...
+    
+            data_->origin = ASIODNS_RECVSOCK;
+            data_->cumulative = 0;          // No data yet received
+            data_->offset = 0;              // First data into start of buffer
+            data_->received->clear();       // Clear the receive buffer
+            do {
+                CORO_YIELD data_->socket->asyncReceive(data_->staging,
+                                                       static_cast<size_t>(STAGING_LENGTH),
+                                                       data_->offset,
+                                                       data_->remote_rcv.get(), *this);
+            } while (!data_->socket->processReceivedData(data_->staging, length,
+                                                         data_->cumulative, data_->offset,
+                                                         data_->expected, data_->received));
+        } while (!data_->responseOK());
+
+        // Finished with this socket, so close it.  This will not generate an
+        // I/O error, but reset the origin to unknown in case we change this.
+        data_->origin = ASIODNS_UNKORIGIN;
+        data_->socket->close();
+
+        /// We are done
+        stop(SUCCESS);
+    }
+}
+
+// Function that stops the coroutine sequence.  It is called either when the
+// query finishes or when the timer times out.  Either way, it sets the
+// "stopped_" flag and cancels anything that is in progress.
+//
+// As the function may be entered multiple times as things wind down, it checks
+// if the stopped_ flag is already set.  If it is, the call is a no-op.
+
+void
+IOFetch::stop(Result result) {
+
+    if (!data_->stopped) {
+
+        // Mark the fetch as stopped to prevent other completion callbacks
+        // (invoked because of the calls to cancel()) from executing the
+        // cancel calls again.
+        //
+        // In a single threaded environment, the callbacks won't be invoked
+        // until this one completes. In a multi-threaded environment, they may
+        // well be, in which case the testing (and setting) of the stopped_
+        // variable should be done inside a mutex (and the stopped_ variable
+        // declared as "volatile").
+        //
+        // The numeric arguments indicate the debug level, with the lower
+        // numbers indicating the most important information.  The relative
+        // values are somewhat arbitrary.
+        //
+        // TODO: Update testing of stopped_ if threads are used.
+        data_->stopped = true;
+        switch (result) {
+            case TIME_OUT:
+                LOG_DEBUG(logger, DBG_COMMON, ASIODNS_RECVTMO).
+                    arg(data_->remote_snd->getAddress().toText()).
+                    arg(data_->remote_snd->getPort());
+                break;
+
+            case SUCCESS:
+                LOG_DEBUG(logger, DBG_ALL, ASIODNS_FETCHCOMP).
+                    arg(data_->remote_rcv->getAddress().toText()).
+                    arg(data_->remote_rcv->getPort());
+                break;
+
+            case STOPPED:
+                // Fetch has been stopped for some other reason.  This is
+                // allowed but as it is unusual it is logged, but with a lower
+                // debug level than a timeout (which is totally normal).
+                LOG_DEBUG(logger, DBG_IMPORTANT, ASIODNS_FETCHSTOP).
+                    arg(data_->remote_snd->getAddress().toText()).
+                    arg(data_->remote_snd->getPort());
+                break;
+
+            default:
+                LOG_ERROR(logger, ASIODNS_UNKRESULT).
+                    arg(data_->remote_snd->getAddress().toText()).
+                    arg(data_->remote_snd->getPort());
+        }
+
+        // Stop requested, cancel and I/O's on the socket and shut it down,
+        // and cancel the timer.
+        data_->socket->cancel();
+        data_->socket->close();
+
+        data_->timer.cancel();
+
+        // Execute the I/O completion callback (if present).
+        if (data_->callback) {
+            (*(data_->callback))(result);
+        }
+    }
+}
+
+// Log an error - called on I/O failure
+
+void IOFetch::logIOFailure(asio::error_code ec) {
+
+    // Should only get here with a known error code.
+    assert((data_->origin == ASIODNS_OPENSOCK) ||
+           (data_->origin == ASIODNS_SENDSOCK) ||
+           (data_->origin == ASIODNS_RECVSOCK) ||
+           (data_->origin == ASIODNS_UNKORIGIN));
+
+    static const char* PROTOCOL[2] = {"TCP", "UDP"};
+    LOG_ERROR(logger, data_->origin).arg(ec.value()).
+        arg((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
+                     PROTOCOL[0] : PROTOCOL[1]).
+        arg(data_->remote_snd->getAddress().toText()).
+        arg(data_->remote_snd->getPort());
+}
+
+} // namespace asiodns
+} // namespace isc {
diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h
new file mode 100644
index 0000000..9626ffe
--- /dev/null
+++ b/src/lib/asiodns/io_fetch.h
@@ -0,0 +1,228 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __IO_FETCH_H
+#define __IO_FETCH_H 1
+
+#include <config.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <coroutine.h>
+
+#include <asio/error_code.hpp>
+#include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
+
+#include <util/buffer.h>
+#include <dns/question.h>
+#include <dns/message.h>
+
+namespace isc {
+namespace asiodns {
+
+// Forward declarations
+class IOFetchData;
+
+/// \brief Upstream Fetch Processing
+///
+/// IOFetch is the class used to send upstream fetches and to handle responses.
+///
+/// \param E Endpoint type to use.
+
+class IOFetch : public coroutine {
+public:
+    /// \brief Protocol to use on the fetch
+    enum Protocol {
+        UDP = 0,
+        TCP = 1
+    };
+
+    /// \brief Origin of Asynchronous I/O Call
+    ///
+    /// Indicates what initiated an asynchronous I/O call and used in deciding
+    /// what error message to output if the I/O fails.
+    enum Origin {
+        NONE = 0,           ///< No asynchronous call outstanding
+        OPEN = 1,
+        SEND = 2,
+        RECEIVE = 3,
+        CLOSE = 4
+    };
+
+    /// \brief Result of Upstream Fetch
+    ///
+    /// Note that this applies to the status of I/Os in the fetch - a fetch
+    /// that resulted in a packet being received from the server is a SUCCESS,
+    /// even if the contents of the packet indicate that some error occurred.
+    enum Result {
+        SUCCESS = 0,        ///< Success, fetch completed
+        TIME_OUT = 1,       ///< Failure, fetch timed out
+        STOPPED = 2,        ///< Control code, fetch has been stopped
+        NOTSET = 3          ///< For testing, indicates value not set
+    };
+
+    // The next enum is a "trick" to allow constants to be defined in a class
+    // declaration.
+
+    /// \brief Integer Constants
+    enum {
+        STAGING_LENGTH = 8192   ///< Size of staging buffer
+    };
+
+    /// \brief I/O Fetch Callback
+    ///
+    /// Class of callback object for when the fetch itself has completed - an
+    /// object of this class is passed to the IOFetch constructor and its
+    /// operator() method called when the fetch completes.
+    ///
+    /// Note the difference between the two operator() methods:
+    /// - IOFetch::operator() callback is called when an asynchronous I/O has
+    ///   completed.
+    /// - IOFetch::Callback::operator() is called when an upstream fetch - which
+    ///   may have involved several asynchronous I/O operations - has completed.
+    ///
+    /// This is an abstract class.
+    class Callback {
+    public:
+        /// \brief Default Constructor
+        Callback()
+        {}
+
+        /// \brief Virtual Destructor
+        virtual ~Callback()
+        {}
+
+        /// \brief Callback method
+        ///
+        /// This is the method called when the fetch completes.
+        ///
+        /// \param result Result of the fetch
+        virtual void operator()(Result result) = 0;
+    };
+
+    /// \brief Constructor.
+    ///
+    /// Creates the object that will handle the upstream fetch.
+    ///
+    /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
+    /// \param service I/O Service object to handle the asynchronous
+    ///        operations.
+    /// \param question DNS question to send to the upstream server.
+    /// \param address IP address of upstream server
+    /// \param port Port to which to connect on the upstream server
+    /// \param buff Output buffer into which the response (in wire format)
+    ///        is written (if a response is received).
+    /// \param cb Callback object containing the callback to be called when we
+    ///        terminate.  The caller is responsible for managing this object
+    ///        and deleting it if necessary.
+    /// \param wait Timeout for the fetch (in ms).  The default value of
+    ///        -1 indicates no timeout.
+    IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+        const isc::dns::Question& question,
+        const isc::asiolink::IOAddress& address,
+        uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
+        int wait = -1);
+
+    /// \brief Constructor
+    ///  This constructor has one parameter "query_message", which
+    ///  is the shared_ptr to a full query message. It's different
+    ///  with above contructor which has only question section. All
+    ///  other parameters are same.
+    ///
+    /// \param query_message the shared_ptr to a full query message
+    ///        got from a query client.
+    IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+        isc::dns::ConstMessagePtr query_message,
+        const isc::asiolink::IOAddress& address,
+        uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
+        int wait = -1);
+
+    /// \brief Constructor.
+    ///
+    /// Creates the object that will handle the upstream fetch.
+    ///
+    /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
+    /// \param service I/O Service object to handle the asynchronous
+    ///     operations.
+    /// \param outpkt Packet to send to upstream server.  Note that the
+    ///     QID (first two bytes of the packet) may be altered in the sending.
+    /// \param buff Output buffer into which the response (in wire format)
+    ///     is written (if a response is received).
+    /// \param cb Callback object containing the callback to be called
+    ///     when we terminate.  The caller is responsible for managing this
+    ///     object and deleting it if necessary.
+    /// \param address IP address of upstream server
+    /// \param port Port to which to connect on the upstream server
+    /// (default = 53)
+    /// \param wait Timeout for the fetch (in ms).  The default value of
+    ///     -1 indicates no timeout.
+    IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+        isc::util::OutputBufferPtr& outpkt,
+        const isc::asiolink::IOAddress& address,
+        uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
+        int wait = -1);
+
+    /// \brief Return Current Protocol
+    ///
+    /// \return Protocol associated with this IOFetch object.
+    Protocol getProtocol() const;
+
+    /// \brief Coroutine entry point
+    ///
+    /// The operator() method is the method in which the coroutine code enters
+    /// this object when an operation has been completed.
+    ///
+    /// \param ec Error code, the result of the last asynchronous I/O operation.
+    /// \param length Amount of data received on the last asynchronous read
+    void operator()(asio::error_code ec = asio::error_code(), size_t length = 0);
+
+    /// \brief Terminate query
+    ///
+    /// This method can be called at any point.  It terminates the current
+    /// query with the specified reason.
+    ///
+    /// \param reason Reason for terminating the query
+    void stop(Result reason = STOPPED);
+
+private:
+    /// \brief IOFetch Initialization Function.
+    /// All the parameters are same with the constructor, except
+    /// parameter "query_message"
+    /// \param query_message the message to be sent out.
+    void initIOFetch(isc::dns::MessagePtr& query_message, Protocol protocol,
+            isc::asiolink::IOService& service, const isc::dns::Question& question,
+            const isc::asiolink::IOAddress& address, uint16_t port,
+            isc::util::OutputBufferPtr& buff, Callback* cb, int wait);
+
+    /// \brief Log I/O Failure
+    ///
+    /// Records an I/O failure to the log file
+    ///
+    /// \param ec ASIO error code
+    void logIOFailure(asio::error_code ec);
+
+    // Member variables.  All data is in a structure pointed to by a shared
+    // pointer.  The IOFetch object is copied a number of times during its
+    // life, and only requiring a pointer to be copied reduces overhead.
+    boost::shared_ptr<IOFetchData>  data_;   ///< Private data
+
+};
+
+} // namespace asiodns
+} // namespace isc
+
+#endif // __IO_FETCH_H
diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc
new file mode 100644
index 0000000..f91eb32
--- /dev/null
+++ b/src/lib/asiodns/tcp_server.cc
@@ -0,0 +1,244 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
+
+#include <boost/shared_array.hpp>
+
+#include <log/dummylog.h>
+
+#include <util/buffer.h>
+
+#include <asio.hpp>
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/tcp_socket.h>
+#include <tcp_server.h>
+
+
+using namespace asio;
+using asio::ip::udp;
+using asio::ip::tcp;
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+/// The following functions implement the \c TCPServer class.
+///
+/// The constructor
+TCPServer::TCPServer(io_service& io_service,
+                     const ip::address& addr, const uint16_t port, 
+                     const SimpleCallback* checkin,
+                     const DNSLookup* lookup,
+                     const DNSAnswer* answer) :
+    io_(io_service), done_(false),
+    checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer)
+{
+    tcp::endpoint endpoint(addr, port);
+    acceptor_.reset(new tcp::acceptor(io_service));
+    acceptor_->open(endpoint.protocol());
+    // Set v6-only (we use a separate instantiation for v4,
+    // otherwise asio will bind to both v4 and v6
+    if (addr.is_v6()) {
+        acceptor_->set_option(ip::v6_only(true));
+    }
+    acceptor_->set_option(tcp::acceptor::reuse_address(true));
+    acceptor_->bind(endpoint);
+    acceptor_->listen();
+}
+
+void
+TCPServer::operator()(error_code ec, size_t length) {
+    /// Because the coroutine reentry block is implemented as
+    /// a switch statement, inline variable declarations are not
+    /// permitted.  Certain variables used below can be declared here.
+
+    boost::array<const_buffer,2> bufs;
+    OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
+
+    CORO_REENTER (this) {
+        do {
+            /// Create a socket to listen for connections
+            socket_.reset(new tcp::socket(acceptor_->get_io_service()));
+
+            /// Wait for new connections. In the event of non-fatal error,
+            /// try again
+            do {
+                CORO_YIELD acceptor_->async_accept(*socket_, *this);
+
+                // Abort on fatal errors
+                // TODO: Log error?
+                if (ec) {
+                    using namespace asio::error;
+                    if (ec.value() != would_block && ec.value() != try_again &&
+                        ec.value() != connection_aborted &&
+                        ec.value() != interrupted) {
+                        return;
+                    }
+                }
+            } while (ec);
+
+            /// Fork the coroutine by creating a copy of this one and
+            /// scheduling it on the ASIO service queue.  The parent
+            /// will continue listening for DNS connections while the
+            /// handles the one that has just arrived.
+            CORO_FORK io_.post(TCPServer(*this));
+        } while (is_parent());
+
+        /// Instantiate the data buffer that will be used by the
+        /// asynchronous read call.
+        data_.reset(new char[MAX_LENGTH]);
+
+        /// Read the message, in two parts.  First, the message length:
+        CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
+                              TCP_MESSAGE_LENGTHSIZE), *this);
+        if (ec) {
+            socket_->close();
+            CORO_YIELD return;
+        }
+
+        /// Now read the message itself. (This is done in a different scope
+        /// to allow inline variable declarations.)
+        CORO_YIELD {
+            InputBuffer dnsbuffer(data_.get(), length);
+            uint16_t msglen = dnsbuffer.readUint16();
+            async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
+        }
+
+        if (ec) {
+            socket_->close();
+            CORO_YIELD return;
+        }
+
+
+        // Create an \c IOMessage object to store the query.
+        //
+        // (XXX: It would be good to write a factory function
+        // that would quickly generate an IOMessage object without
+        // all these calls to "new".)
+        peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
+
+        // The TCP socket class has been extended with asynchronous functions
+        // and takes as a template parameter a completion callback class.  As
+        // TCPServer does not use these extended functions (only those defined
+        // in the IOSocket base class) - but needs a TCPSocket to get hold of
+        // the underlying Boost TCP socket - DummyIOCallback is used.  This
+        // provides the appropriate operator() but is otherwise functionless.
+        iosock_.reset(new TCPSocket<DummyIOCallback>(*socket_));
+        io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
+        bytes_ = length;
+
+        // Perform any necessary operations prior to processing the incoming
+        // packet (e.g., checking for queued configuration messages).
+        //
+        // (XXX: it may be a performance issue to have this called for
+        // every single incoming packet; we may wish to throttle it somehow
+        // in the future.)
+        if (checkin_callback_ != NULL) {
+            (*checkin_callback_)(*io_message_);
+        }
+
+        // If we don't have a DNS Lookup provider, there's no point in
+        // continuing; we exit the coroutine permanently.
+        if (lookup_callback_ == NULL) {
+            socket_->close();
+            CORO_YIELD return;
+        }
+
+        // Reset or instantiate objects that will be needed by the
+        // DNS lookup and the write call.
+        respbuf_.reset(new OutputBuffer(0));
+        query_message_.reset(new Message(Message::PARSE));
+        answer_message_.reset(new Message(Message::RENDER));
+
+        // Schedule a DNS lookup, and yield.  When the lookup is
+        // finished, the coroutine will resume immediately after
+        // this point.
+        CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
+
+        // The 'done_' flag indicates whether we have an answer
+        // to send back.  If not, exit the coroutine permanently.
+        if (!done_) {
+            // TODO: should we keep the connection open for a short time
+            // to see if new requests come in?
+            socket_->close();
+            CORO_YIELD return;
+        }
+
+        if (ec) {
+            CORO_YIELD return;
+        }
+        // Call the DNS answer provider to render the answer into
+        // wire format
+        (*answer_callback_)(*io_message_, query_message_,
+                            answer_message_, respbuf_);
+
+        // Set up the response, beginning with two length bytes.
+        lenbuf.writeUint16(respbuf_->getLength());
+        bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
+        bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
+
+        // Begin an asynchronous send, and then yield.  When the
+        // send completes, we will resume immediately after this point
+        // (though we have nothing further to do, so the coroutine
+        // will simply exit at that time).
+        CORO_YIELD async_write(*socket_, bufs, *this);
+
+        // TODO: should we keep the connection open for a short time
+        // to see if new requests come in?
+        socket_->close();
+    }
+}
+
+/// Call the DNS lookup provider.  (Expected to be called by the
+/// AsyncLookup<TCPServer> handler.)
+void
+TCPServer::asyncLookup() {
+    (*lookup_callback_)(*io_message_, query_message_,
+                        answer_message_, respbuf_, this);
+}
+
+void TCPServer::stop() {
+    /// we use close instead of cancel, with the same reason
+    /// with udp server stop, refer to the udp server code
+
+    acceptor_->close();
+    // User may stop the server even when it hasn't started to
+    // run, in that that socket_ is empty
+    if (socket_) {
+        socket_->close();
+    }
+}
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off.  The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+TCPServer::resume(const bool done) {
+    done_ = done;
+    io_.post(*this);
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h
new file mode 100644
index 0000000..22a2f69
--- /dev/null
+++ b/src/lib/asiodns/tcp_server.h
@@ -0,0 +1,124 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TCP_SERVER_H
+#define __TCP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <asiolink/asiolink.h>
+#include <coroutine.h>
+#include "dns_server.h"
+#include "dns_lookup.h"
+#include "dns_answer.h"
+
+namespace isc {
+namespace asiodns {
+
+/// \brief A TCP-specific \c DNSServer object.
+///
+/// This class inherits from both \c DNSServer and from \c coroutine,
+/// defined in coroutine.h. 
+class TCPServer : public virtual DNSServer, public virtual coroutine {
+public:
+    explicit TCPServer(asio::io_service& io_service,
+                       const asio::ip::address& addr, const uint16_t port, 
+                       const isc::asiolink::SimpleCallback* checkin = NULL,
+                       const DNSLookup* lookup = NULL,
+                       const DNSAnswer* answer = NULL);
+
+    void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+    void asyncLookup();
+    void stop();
+    void resume(const bool done);
+    bool hasAnswer() { return (done_); }
+    int value() { return (get_value()); }
+
+    DNSServer* clone() {
+        TCPServer* s = new TCPServer(*this);
+        return (s);
+    }
+
+private:
+    enum { MAX_LENGTH = 65535 };
+    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
+
+    // The ASIO service object
+    asio::io_service& io_;
+
+    // Class member variables which are dynamic, and changes to which
+    // need to accessible from both sides of a coroutine fork or from
+    // outside of the coroutine (i.e., from an asynchronous I/O call),
+    // should be declared here as pointers and allocated in the
+    // constructor or in the coroutine.  This allows state information
+    // to persist when an individual copy of the coroutine falls out
+    // scope while waiting for an event, *so long as* there is another
+    // object that is referencing the same data.  As a side-benefit, using
+    // pointers also reduces copy overhead for coroutine objects.
+    //
+    // Note: Currently these objects are allocated by "new" in the
+    // constructor, or in the function operator while processing a query.
+    // Repeated allocations from the heap for every incoming query is
+    // clearly a performance issue; this must be optimized in the future.
+    // The plan is to have a structure pre-allocate several "server state"
+    // objects which can be pulled off a free list and placed on an in-use
+    // list whenever a query comes in.  This will serve the dual purpose
+    // of improving performance and guaranteeing that state information
+    // will *not* be destroyed when any one instance of the coroutine
+    // falls out of scope while waiting for an event.
+    //
+    // An ASIO acceptor object to handle new connections.  Created in
+    // the constructor.
+    boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
+
+    // Socket used to for listen for queries.  Created in the
+    // constructor and stored in a shared_ptr because socket objects
+    // are not copyable.
+    boost::shared_ptr<asio::ip::tcp::socket> socket_;
+
+    // The buffer into which the response is written
+    boost::shared_ptr<isc::util::OutputBuffer> respbuf_;
+
+    // \c IOMessage and \c Message objects to be passed to the
+    // DNS lookup and answer providers
+    boost::shared_ptr<isc::asiolink::IOMessage> io_message_;
+    isc::dns::MessagePtr query_message_;
+    isc::dns::MessagePtr answer_message_;
+
+    // The buffer into which the query packet is written
+    boost::shared_array<char>data_;
+
+    // State information that is entirely internal to a given instance
+    // of the coroutine can be declared here.
+    size_t bytes_;
+    bool done_;
+
+    // Callback functions provided by the caller
+    const isc::asiolink::SimpleCallback* checkin_callback_;
+    const DNSLookup* lookup_callback_;
+    const DNSAnswer* answer_callback_;
+
+    boost::shared_ptr<isc::asiolink::IOEndpoint> peer_;
+    boost::shared_ptr<isc::asiolink::IOSocket> iosock_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __TCP_SERVER_H
diff --git a/src/lib/asiodns/tests/Makefile.am b/src/lib/asiodns/tests/Makefile.am
new file mode 100644
index 0000000..fd65d0b
--- /dev/null
+++ b/src/lib/asiodns/tests/Makefile.am
@@ -0,0 +1,50 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc  -I$(top_builddir)/src/lib/util
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  = run_unittests.cc
+run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h
+run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
+run_unittests_SOURCES += io_service_unittest.cc
+run_unittests_SOURCES += dns_server_unittest.cc
+run_unittests_SOURCES += io_fetch_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+run_unittests_LDADD  = $(GTEST_LDADD)
+run_unittests_LDADD += $(SQLITE_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
+
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) 
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/asiodns/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc
new file mode 100644
index 0000000..1ef3192
--- /dev/null
+++ b/src/lib/asiodns/tests/dns_server_unittest.cc
@@ -0,0 +1,503 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <asio.hpp>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_error.h>
+#include <asiodns/udp_server.h>
+#include <asiodns/tcp_server.h>
+#include <asiodns/dns_answer.h>
+#include <asiodns/dns_lookup.h>
+#include <string>
+#include <csignal>
+#include <unistd.h> //for alarm
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+
+/// The following tests focus on stop interface for udp and
+/// tcp server, there are lots of things can be shared to test
+/// both tcp and udp server, so they are in the same unittest
+
+/// The general work flow for dns server, is that wait for user
+/// query, once get one query, we will check the data is valid or
+/// not, if it passed, we will try to loop up the question, then
+/// compose the answer and finally send it back to user. The server
+/// may be stopped at any point during this porcess, so the test strategy
+/// is that we define 5 stop point and stop the server at these
+/// 5 points, to check whether stop is successful
+/// The 5 test points are :
+///   Before the server start to run
+///   After we get the query and check whether it's valid
+///   After we lookup the query
+///   After we compoisite the answer
+///   After user get the final result.
+
+/// The standard about whether we stop the server successfully or not
+/// is based on the fact that if the server is still running, the io
+/// service won't quit since it will wait for some asynchronized event for
+/// server. So if the io service block function run returns we assume
+/// that the server is stopped. To avoid stop interface failure which
+/// will block followed tests, using alarm signal to stop the blocking
+/// io service
+///
+/// The whole test context including one server and one client, and
+/// five stop checkpoints, we call them ServerStopper exclude the first
+/// stop point. Once the unittest fired, the client will send message
+/// to server, and the stopper may stop the server at the checkpoint, then
+/// we check the client get feedback or not. Since there is no DNS logic
+/// involved so the message sending between client and server is plain text
+/// And the valid checker, question lookup and answer composition are dummy.
+
+using namespace isc::asiolink;
+using namespace isc::asiodns;
+using namespace asio;
+
+namespace {
+static const std::string server_ip = "127.0.0.1";
+const int server_port = 5553;
+//message client send to udp server, which isn't dns package
+//just for simple testing
+static const std::string query_message("BIND10 is awesome");
+
+// \brief provide capacity to derived class the ability
+// to stop DNSServer at certern point
+class ServerStopper {
+    public:
+        ServerStopper() : server_to_stop_(NULL) {}
+        virtual ~ServerStopper(){}
+
+        void setServerToStop(DNSServer* server) {
+            server_to_stop_ = server;
+        }
+
+        void stopServer() const {
+            if (server_to_stop_) {
+                server_to_stop_->stop();
+            }
+        }
+
+    private:
+        DNSServer* server_to_stop_;
+};
+
+// \brief no check logic at all,just provide a checkpoint to stop the server
+class DummyChecker : public SimpleCallback, public ServerStopper {
+    public:
+        virtual void operator()(const IOMessage&) const {
+            stopServer();
+        }
+};
+
+// \brief no lookup logic at all,just provide a checkpoint to stop the server
+class DummyLookup : public DNSLookup, public ServerStopper {
+    public:
+        void operator()(const IOMessage& io_message,
+                isc::dns::MessagePtr message,
+                isc::dns::MessagePtr answer_message,
+                isc::util::OutputBufferPtr buffer,
+                DNSServer* server) const {
+            stopServer();
+            server->resume(true);
+        }
+};
+
+// \brief copy the data received from user to the answer part
+//  provide checkpoint to stop server
+class SimpleAnswer : public DNSAnswer, public ServerStopper {
+    public:
+        void operator()(const IOMessage& message,
+                isc::dns::MessagePtr query_message,
+                isc::dns::MessagePtr answer_message,
+                isc::util::OutputBufferPtr buffer) const
+        {
+            //copy what we get from user
+            buffer->writeData(message.getData(), message.getDataSize());
+            stopServer();
+        }
+
+};
+
+// \brief simple client, send one string to server and wait for response
+//  in case, server stopped and client cann't get response, there is a timer wait
+//  for specified seconds (the value is just a estimate since server process logic is quite
+//  simple, and all the intercommunication is local) then cancel the waiting.
+class SimpleClient : public ServerStopper {
+    public:
+    static const size_t MAX_DATA_LEN = 256;
+    SimpleClient(asio::io_service& service,
+                 unsigned int wait_server_time_out)
+    {
+        wait_for_response_timer_.reset(new deadline_timer(service));
+        received_data_ = new char[MAX_DATA_LEN];
+        received_data_len_ = 0;
+        wait_server_time_out_ = wait_server_time_out;
+    }
+
+    virtual ~SimpleClient() {
+        delete [] received_data_;
+    }
+
+    void setGetFeedbackCallback(boost::function<void()>& func) {
+        get_response_call_back_ = func;
+    }
+
+    virtual void sendDataThenWaitForFeedback(const std::string& data)  = 0;
+    virtual std::string getReceivedData() const = 0;
+
+    void startTimer() {
+        wait_for_response_timer_->cancel();
+        wait_for_response_timer_->
+            expires_from_now(boost::posix_time::
+                             seconds(wait_server_time_out_));
+        wait_for_response_timer_->
+            async_wait(boost::bind(&SimpleClient::stopWaitingforResponse,
+                                   this));
+    }
+
+    void cancelTimer() { wait_for_response_timer_->cancel(); }
+
+    void getResponseCallBack(const asio::error_code& error, size_t
+                             received_bytes)
+    {
+        cancelTimer();
+        if (!error)
+            received_data_len_ = received_bytes;
+        if (!get_response_call_back_.empty()) {
+            get_response_call_back_();
+        }
+        stopServer();
+    }
+
+
+    protected:
+    virtual void stopWaitingforResponse() = 0;
+
+    boost::shared_ptr<deadline_timer> wait_for_response_timer_;
+    char* received_data_;
+    size_t received_data_len_;
+    boost::function<void()> get_response_call_back_;
+    unsigned int wait_server_time_out_;
+};
+
+
+
+class UDPClient : public SimpleClient {
+    public:
+    //After 1 seconds without feedback client will stop wait
+    static const unsigned int server_time_out = 1;
+
+    UDPClient(asio::io_service& service, const ip::udp::endpoint& server) :
+        SimpleClient(service, server_time_out)
+    {
+        server_ = server;
+        socket_.reset(new ip::udp::socket(service));
+        socket_->open(ip::udp::v4());
+    }
+
+
+    void sendDataThenWaitForFeedback(const std::string& data) {
+        received_data_len_ = 0;
+        socket_->send_to(buffer(data.c_str(), data.size() + 1), server_);
+        socket_->async_receive_from(buffer(received_data_, MAX_DATA_LEN),
+                                    received_from_,
+                                    boost::bind(&SimpleClient::
+                                                getResponseCallBack, this, _1,
+                                                _2));
+        startTimer();
+    }
+
+    virtual std::string getReceivedData() const {
+        return (received_data_len_ == 0 ? std::string("") :
+                                std::string(received_data_));
+    }
+
+    private:
+    void stopWaitingforResponse() {
+        socket_->close();
+    }
+
+    boost::shared_ptr<ip::udp::socket> socket_;
+    ip::udp::endpoint server_;
+    ip::udp::endpoint received_from_;
+};
+
+
+class TCPClient : public SimpleClient {
+    public:
+    // after 2 seconds without feedback client will stop wait,
+    // this includes connect, send message and recevice message
+    static const unsigned int server_time_out = 2;
+    TCPClient(asio::io_service& service, const ip::tcp::endpoint& server)
+        : SimpleClient(service, server_time_out)
+    {
+        server_ = server;
+        socket_.reset(new ip::tcp::socket(service));
+        socket_->open(ip::tcp::v4());
+    }
+
+
+    virtual void sendDataThenWaitForFeedback(const std::string &data) {
+        received_data_len_ = 0;
+        data_to_send_ = data;
+        data_to_send_len_ = data.size() + 1;
+        socket_->async_connect(server_, boost::bind(&TCPClient::connectHandler,
+                                                    this, _1));
+        startTimer();
+    }
+
+    virtual std::string getReceivedData() const {
+        return (received_data_len_ == 0 ? std::string("") :
+                                std::string(received_data_ + 2));
+    }
+
+    private:
+    void stopWaitingforResponse() {
+        socket_->close();
+    }
+
+    void connectHandler(const asio::error_code& error) {
+        if (!error) {
+            data_to_send_len_ = htons(data_to_send_len_);
+            socket_->async_send(buffer(&data_to_send_len_, 2),
+                                boost::bind(&TCPClient::sendMessageBodyHandler,
+                                            this, _1, _2));
+        }
+    }
+
+    void sendMessageBodyHandler(const asio::error_code& error,
+                                size_t send_bytes)
+    {
+        if (!error && send_bytes == 2) {
+            socket_->async_send(buffer(data_to_send_.c_str(),
+                                       data_to_send_.size() + 1),
+                    boost::bind(&TCPClient::finishSendHandler, this, _1, _2));
+        }
+    }
+
+    void finishSendHandler(const asio::error_code& error, size_t send_bytes) {
+        if (!error && send_bytes == data_to_send_.size() + 1) {
+            socket_->async_receive(buffer(received_data_, MAX_DATA_LEN),
+                   boost::bind(&SimpleClient::getResponseCallBack, this, _1,
+                               _2));
+        }
+    }
+
+    boost::shared_ptr<ip::tcp::socket> socket_;
+    ip::tcp::endpoint server_;
+    std::string data_to_send_;
+    uint16_t data_to_send_len_;
+};
+
+
+
+// \brief provide the context which including two client and
+// two server, udp client will only communicate with udp server, same for tcp client
+class DNSServerTest : public::testing::Test {
+    protected:
+        void SetUp() {
+            ip::address server_address = ip::address::from_string(server_ip);
+            checker_ = new DummyChecker();
+            lookup_ = new DummyLookup();
+            answer_ = new SimpleAnswer();
+            udp_server_ = new UDPServer(service, server_address, server_port,
+                    checker_, lookup_, answer_);
+            udp_client_ = new UDPClient(service,
+                    ip::udp::endpoint(server_address,
+                        server_port));
+            tcp_server_ = new TCPServer(service, server_address, server_port,
+                    checker_, lookup_, answer_);
+            tcp_client_ = new TCPClient(service,
+                    ip::tcp::endpoint(server_address,
+                        server_port));
+        }
+
+
+        void TearDown() {
+            udp_server_->stop();
+            tcp_server_->stop();
+            delete checker_;
+            delete lookup_;
+            delete answer_;
+            delete udp_server_;
+            delete udp_client_;
+            delete tcp_server_;
+            delete tcp_client_;
+        }
+
+
+        void testStopServerByStopper(DNSServer* server, SimpleClient* client,
+                ServerStopper* stopper)
+        {
+            static const unsigned int io_service_time_out = 5;
+            io_service_is_time_out = false;
+            stopper->setServerToStop(server);
+            (*server)();
+            client->sendDataThenWaitForFeedback(query_message);
+            // Since thread hasn't been introduced into the tool box, using signal
+            // to make sure run function will eventually return even server stop
+            // failed
+            void (*prev_handler)(int) = std::signal(SIGALRM, DNSServerTest::stopIOService);
+            alarm(io_service_time_out);
+            service.run();
+            service.reset();
+            //cancel scheduled alarm
+            alarm(0);
+            std::signal(SIGALRM, prev_handler);
+        }
+
+
+        static void stopIOService(int _no_use_parameter) {
+            io_service_is_time_out = true;
+            service.stop();
+        }
+
+        bool serverStopSucceed() const {
+            return (!io_service_is_time_out);
+        }
+
+        DummyChecker* checker_;
+        DummyLookup*  lookup_;
+        SimpleAnswer* answer_;
+        UDPServer*    udp_server_;
+        UDPClient*    udp_client_;
+        TCPClient*    tcp_client_;
+        TCPServer*    tcp_server_;
+
+        // To access them in signal handle function, the following
+        // variables have to be static.
+        static asio::io_service service;
+        static bool io_service_is_time_out;
+};
+
+bool DNSServerTest::io_service_is_time_out = false;
+asio::io_service DNSServerTest::service;
+
+// Test whether server stopped successfully after client get response
+// client will send query and start to wait for response, once client
+// get response, udp server will be stopped, the io service won't quit
+// if udp server doesn't stop successfully.
+TEST_F(DNSServerTest, stopUDPServerAfterOneQuery) {
+    testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+    EXPECT_EQ(query_message, udp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully before server start to serve
+TEST_F(DNSServerTest, stopUDPServerBeforeItStartServing) {
+    udp_server_->stop();
+    testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether udp server stopped successfully during message check
+TEST_F(DNSServerTest, stopUDPServerDuringMessageCheck) {
+    testStopServerByStopper(udp_server_, udp_client_, checker_);
+    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully during query lookup
+TEST_F(DNSServerTest, stopUDPServerDuringQueryLookup) {
+    testStopServerByStopper(udp_server_, udp_client_, lookup_);
+    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully during composing answer
+TEST_F(DNSServerTest, stopUDPServerDuringPrepareAnswer) {
+    testStopServerByStopper(udp_server_, udp_client_, answer_);
+    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+static void stopServerManyTimes(DNSServer *server, unsigned int times) {
+    for (int i = 0; i < times; ++i) {
+        server->stop();
+    }
+}
+
+// Test whether udp server stop interface can be invoked several times without
+// throw any exception
+TEST_F(DNSServerTest, stopUDPServeMoreThanOnce) {
+    ASSERT_NO_THROW({
+        boost::function<void()> stop_server_3_times
+            = boost::bind(stopServerManyTimes, udp_server_, 3);
+        udp_client_->setGetFeedbackCallback(stop_server_3_times);
+        testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+        EXPECT_EQ(query_message, udp_client_->getReceivedData());
+    });
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+
+TEST_F(DNSServerTest, stopTCPServerAfterOneQuery) {
+    testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+    EXPECT_EQ(query_message, tcp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stopped successfully before server start to serve
+TEST_F(DNSServerTest, stopTCPServerBeforeItStartServing) {
+    tcp_server_->stop();
+    testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stopped successfully during message check
+TEST_F(DNSServerTest, stopTCPServerDuringMessageCheck) {
+    testStopServerByStopper(tcp_server_, tcp_client_, checker_);
+    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether tcp server stopped successfully during query lookup
+TEST_F(DNSServerTest, stopTCPServerDuringQueryLookup) {
+    testStopServerByStopper(tcp_server_, tcp_client_, lookup_);
+    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether tcp server stopped successfully during composing answer
+TEST_F(DNSServerTest, stopTCPServerDuringPrepareAnswer) {
+    testStopServerByStopper(tcp_server_, tcp_client_, answer_);
+    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stop interface can be invoked several times without
+// throw any exception
+TEST_F(DNSServerTest, stopTCPServeMoreThanOnce) {
+    ASSERT_NO_THROW({
+        boost::function<void()> stop_server_3_times
+            = boost::bind(stopServerManyTimes, tcp_server_, 3);
+        tcp_client_->setGetFeedbackCallback(stop_server_3_times);
+        testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+        EXPECT_EQ(query_message, tcp_client_->getReceivedData());
+    });
+    EXPECT_TRUE(serverStopSucceed());
+}
+
+}
diff --git a/src/lib/asiodns/tests/io_fetch_unittest.cc b/src/lib/asiodns/tests/io_fetch_unittest.cc
new file mode 100644
index 0000000..52a51a1
--- /dev/null
+++ b/src/lib/asiodns/tests/io_fetch_unittest.cc
@@ -0,0 +1,731 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <algorithm>
+#include <cstdlib>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <iterator>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <asio.hpp>
+
+#include <util/buffer.h>
+#include <util/io_utilities.h>
+
+#include <dns/question.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/name.h>
+#include <dns/rcode.h>
+
+#include <asiolink/io_address.h>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_service.h>
+#include <asiodns/io_fetch.h>
+
+using namespace asio;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace asio::ip;
+using namespace std;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
+const uint16_t TEST_PORT(5301);
+const int SEND_INTERVAL = 250;      // Interval in ms between TCP sends
+const size_t MAX_SIZE = 64 * 1024;  // Should be able to take 64kB
+
+// The tests are complex, so debug output has been left in (although disabled).
+// Set this to true to enable it.
+const bool DEBUG = false;
+
+/// \brief Test fixture for the asiolink::IOFetch.
+class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback
+{
+public:
+    IOService       service_;       ///< Service to run the query
+    IOFetch::Result expected_;      ///< Expected result of the callback
+    bool            run_;           ///< Did the callback run already?
+    Question        question_;      ///< What to ask
+    OutputBufferPtr result_buff_;   ///< Buffer to hold result of fetch
+    OutputBufferPtr msgbuf_;        ///< Buffer corresponding to known question
+    IOFetch         udp_fetch_;     ///< For UDP query test
+    IOFetch         tcp_fetch_;     ///< For TCP query test
+    IOFetch::Protocol protocol_;    ///< Protocol being tested
+    size_t          cumulative_;    ///< Cumulative data received by "server".
+    deadline_timer  timer_;         ///< Timer to measure timeouts
+
+    // The next member is the buffer in which the "server" (implemented by the
+    // response handler methods in this class) receives the question sent by the
+    // fetch object.
+    uint8_t         receive_buffer_[MAX_SIZE]; ///< Server receive buffer
+    OutputBufferPtr expected_buffer_;          ///< Data we expect to receive
+    vector<uint8_t> send_buffer_;           ///< Server send buffer
+    uint16_t        send_cumulative_;       ///< Data sent so far
+
+    // Other data.
+    string          return_data_;           ///< Data returned by server
+    string          test_data_;             ///< Large string - here for convenience
+    bool            debug_;                 ///< true to enable debug output
+    size_t          tcp_send_size_;         ///< Max size of TCP send
+    uint8_t         qid_0;                  ///< First octet of qid
+    uint8_t         qid_1;                  ///< Second octet of qid
+
+    bool            tcp_short_send_;        ///< If set to true, we do not send
+                                            ///  all data in the tcp response
+
+    /// \brief Constructor
+    IOFetchTest() :
+        service_(),
+        expected_(IOFetch::NOTSET),
+        run_(false),
+        question_(Name("example.net"), RRClass::IN(), RRType::A()),
+        result_buff_(new OutputBuffer(512)),
+        msgbuf_(new OutputBuffer(512)),
+        udp_fetch_(IOFetch::UDP, service_, question_, IOAddress(TEST_HOST),
+            TEST_PORT, result_buff_, this, 100),
+        tcp_fetch_(IOFetch::TCP, service_, question_, IOAddress(TEST_HOST),
+            TEST_PORT, result_buff_, this, (16 * SEND_INTERVAL)),
+                                        // Timeout interval chosen to ensure no timeout
+        protocol_(IOFetch::TCP),        // for initialization - will be changed
+        cumulative_(0),
+        timer_(service_.get_io_service()),
+        receive_buffer_(),
+        expected_buffer_(new OutputBuffer(512)),
+        send_buffer_(),
+        send_cumulative_(0),
+        return_data_(""),
+        test_data_(""),
+        debug_(DEBUG),
+        tcp_send_size_(0),
+        qid_0(0),
+        qid_1(0),
+        tcp_short_send_(false)
+    {
+        // Construct the data buffer for question we expect to receive.
+        Message msg(Message::RENDER);
+        msg.setQid(0);
+        msg.setOpcode(Opcode::QUERY());
+        msg.setRcode(Rcode::NOERROR());
+        msg.setHeaderFlag(Message::HEADERFLAG_RD);
+        msg.addQuestion(question_);
+        EDNSPtr msg_edns(new EDNS());
+        msg_edns->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
+        msg.setEDNS(msg_edns);
+        MessageRenderer renderer(*msgbuf_);
+        msg.toWire(renderer);
+        MessageRenderer renderer2(*expected_buffer_);
+        msg.toWire(renderer2);
+
+        // Initialize the test data to be returned: tests will return a
+        // substring of this data. (It's convenient to have this as a member of
+        // the class.)
+        //
+        // We could initialize the data with a single character, but as an added
+        // check we'll make ssre that it has some structure.
+
+        test_data_.clear();
+        test_data_.reserve(MAX_SIZE);
+        while (test_data_.size() < MAX_SIZE) {
+            test_data_ += "A message to be returned to the client that has "
+                          "some sort of structure.";
+        }
+    }
+
+    /// \brief UDP Response handler (the "remote UDP DNS server")
+    ///
+    /// When IOFetch is sending data, this response handler emulates the remote
+    /// DNS server.  It checks that the data sent by the IOFetch object is what
+    /// was expected to have been sent, then sends back a known buffer of data.
+    ///
+    /// \param remote Endpoint to which to send the answer
+    /// \param socket Socket to use to send the answer
+    /// \param ec ASIO error code, completion code of asynchronous I/O issued
+    ///        by the "server" to receive data.
+    /// \param bad_qid If set to true, the QID in the response will be mangled
+    /// \param second_send If set to true, (and bad_qid is too), after the
+    ///        mangled qid response has been sent, a second packet will be
+    ///        sent with the correct QID.
+    /// \param length Amount of data received.
+    void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket,
+                    error_code ec = error_code(), size_t length = 0,
+                    bool bad_qid = false, bool second_send = false) {
+        if (debug_) {
+            cout << "udpReceiveHandler(): error = " << ec.value() <<
+                    ", length = " << length << endl;
+        }
+
+        // The QID in the incoming data is random so set it to 0 for the
+        // data comparison check. (It is set to 0 in the buffer containing
+        // the expected data.)
+        qid_0 = receive_buffer_[0];
+        qid_1 = receive_buffer_[1];
+        receive_buffer_[0] = receive_buffer_[1] = 0;
+
+        // Check that length of the received data and the expected data are
+        // identical, then check that the data is identical as well.
+        EXPECT_EQ(msgbuf_->getLength(), length);
+        EXPECT_TRUE(equal(receive_buffer_, (receive_buffer_ + length - 1),
+        static_cast<const uint8_t*>(msgbuf_->getData())));
+
+        // Return a message back to the IOFetch object.
+        if (!bad_qid) {
+            expected_buffer_->writeUint8At(qid_0, 0);
+            expected_buffer_->writeUint8At(qid_1, 1);
+        } else {
+            expected_buffer_->writeUint8At(qid_0 + 1, 0);
+            expected_buffer_->writeUint8At(qid_1 + 1, 1);
+        }
+        socket->send_to(asio::buffer(expected_buffer_->getData(), length), *remote);
+
+        if (bad_qid && second_send) {
+            expected_buffer_->writeUint8At(qid_0, 0);
+            expected_buffer_->writeUint8At(qid_1, 1);
+            socket->send_to(asio::buffer(expected_buffer_->getData(),
+                            expected_buffer_->getLength()), *remote);
+        }
+        if (debug_) {
+            cout << "udpReceiveHandler(): returned " << expected_buffer_->getLength() <<
+                    " bytes to the client" << endl;
+        }
+    }
+
+    /// \brief Completion Handler for accepting TCP data
+    ///
+    /// Called when the remote system connects to the "server".  It issues
+    /// an asynchronous read on the socket to read data.
+    ///
+    /// \param socket Socket on which data will be received
+    /// \param ec Boost error code, value should be zero.
+    void tcpAcceptHandler(tcp::socket* socket, error_code ec = error_code())
+    {
+        if (debug_) {
+            cout << "tcpAcceptHandler(): error = " << ec.value() << endl;
+        }
+
+        // Expect that the accept completed without a problem.
+        EXPECT_EQ(0, ec.value());
+
+        // Work out the maximum size of data we can send over it when we
+        // respond, then subtract 1kB or so for safety.
+        tcp::socket::send_buffer_size send_size;
+        socket->get_option(send_size);
+        if (send_size.value() < (2 * 1024)) {
+            FAIL() << "TCP send size is less than 2kB";
+        } else {
+            tcp_send_size_ = send_size.value() - 1024;
+            if (debug_) {
+                cout << "tcpacceptHandler(): will use send size = " << tcp_send_size_ << endl;
+            }
+        }
+
+        // Initiate a read on the socket.
+        cumulative_ = 0;
+        socket->async_receive(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
+            boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
+    }
+
+    /// \brief Completion handler for receiving TCP data
+    ///
+    /// When IOFetch is sending data, this response handler emulates the remote
+    /// DNS server.  It that all the data sent by the IOFetch object has been
+    /// received, issuing another read if not.  If the data is complete, it is
+    /// compared to what is expected and a reply sent back to the IOFetch.
+    ///
+    /// \param socket Socket to use to send the answer
+    /// \param ec ASIO error code, completion code of asynchronous I/O issued
+    ///        by the "server" to receive data.
+    /// \param length Amount of data received.
+    void tcpReceiveHandler(tcp::socket* socket, error_code ec = error_code(),
+                           size_t length = 0)
+    {
+        if (debug_) {
+            cout << "tcpReceiveHandler(): error = " << ec.value() <<
+                    ", length = " << length << endl;
+        }
+        // Expect that the receive completed without a problem.
+        EXPECT_EQ(0, ec.value());
+
+        // If we haven't received all the data, issue another read.
+        cumulative_ += length;
+        bool complete = false;
+        if (cumulative_ > 2) {
+            uint16_t dns_length = readUint16(receive_buffer_);
+            complete = ((dns_length + 2) == cumulative_);
+        }
+
+        if (!complete) {
+            socket->async_receive(asio::buffer((receive_buffer_ + cumulative_),
+                (sizeof(receive_buffer_) - cumulative_)),
+                boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
+            return;
+        }
+
+        // Check that length of the DNS message received is that expected, then
+        // compare buffers, zeroing the QID in the received buffer to match
+        // that set in our expected question.  Note that due to the length
+        // field the QID in the received buffer is in the third and fourth
+        // bytes.
+        EXPECT_EQ(msgbuf_->getLength() + 2, cumulative_);
+        qid_0 = receive_buffer_[2];
+        qid_1 = receive_buffer_[3];
+
+        receive_buffer_[2] = receive_buffer_[3] = 0;
+        EXPECT_TRUE(equal((receive_buffer_ + 2), (receive_buffer_ + cumulative_ - 2),
+            static_cast<const uint8_t*>(msgbuf_->getData())));
+
+        // ... and return a message back.  This has to be preceded by a two-byte
+        // count field.
+
+        send_buffer_.clear();
+        send_buffer_.push_back(0);
+        send_buffer_.push_back(0);
+        writeUint16(return_data_.size(), &send_buffer_[0]);
+        copy(return_data_.begin(), return_data_.end(), back_inserter(send_buffer_));
+        if (return_data_.size() >= 2) {
+            send_buffer_[2] = qid_0;
+            send_buffer_[3] = qid_1;
+        }
+        // Send the data.  This is done in multiple writes with a delay between
+        // each to check that the reassembly of TCP packets from fragments works.
+        send_cumulative_ = 0;
+        tcpSendData(socket);
+    }
+
+    /// \brief Sent Data Over TCP
+    ///
+    /// Send the TCP data back to the IOFetch object.  The data is sent in
+    /// three chunks - two of 16 bytes and the remainder, with a 250ms gap
+    /// between each. (Amounts of data smaller than one 32 bytes are sent in
+    /// one or two packets.)
+    ///
+    /// \param socket Socket over which send should take place
+    void tcpSendData(tcp::socket* socket) {
+        if (debug_) {
+            cout << "tcpSendData()" << endl;
+        }
+
+        // Decide what to send based on the cumulative count.  At most we'll do
+        // two chunks of 16 bytes (with a 250ms gap between) and then the
+        // remainder.
+        uint8_t* send_ptr = &send_buffer_[send_cumulative_];
+                                    // Pointer to data to send
+        size_t amount = 16;         // Amount of data to send
+        if (send_cumulative_ < (2 * amount)) {
+            
+            // First or second time through, send at most 16 bytes
+            amount = min(amount, (send_buffer_.size() - send_cumulative_));
+
+        } else {
+
+            // For all subsequent times, send the remainder, maximised to
+            // whatever we have chosen for the maximum send size.
+            amount = min(tcp_send_size_,
+                        (send_buffer_.size() - send_cumulative_));
+        }
+
+        // This is for the short send test; reduce the actual amount of
+        // data we send
+        if (tcp_short_send_) {
+            if (debug_) {
+                cout << "tcpSendData(): sending incomplete data (" <<
+                        (amount - 1) << " of " << amount << " bytes)" <<
+                        endl;
+            }
+            --amount;
+        } else {
+            if (debug_) {
+                cout << "tcpSendData(): sending " << amount << " bytes" << endl;
+            }
+        }
+
+        // ... and send it.  The amount sent is also passed as the first
+        // argument of the send callback, as a check.
+        socket->async_send(asio::buffer(send_ptr, amount),
+                           boost::bind(&IOFetchTest::tcpSendHandler, this,
+                                       amount, socket, _1, _2));
+    }
+
+    /// \brief Completion Handler for Sending TCP data
+    ///
+    /// Called when the asynchronous send of data back to the IOFetch object
+    /// by the TCP "server" in this class has completed.  (This send has to
+    /// be asynchronous because control needs to return to the caller in order
+    /// for the IOService "run()" method to be called to run the handlers.)
+    ///
+    /// If not all the data has been sent, a short delay is instigated (during
+    /// which control returns to the IOService).  This should force the queued
+    /// data to actually be sent and the IOFetch receive handler to be triggered.
+    /// In this way, the ability of IOFetch to handle fragmented TCP packets
+    /// should be checked.
+    ///
+    /// \param expected Number of bytes that were expected to have been sent.
+    /// \param socket Socket over which the send took place.  Only used to
+    ///        pass back to the send method.
+    /// \param ec Boost error code, value should be zero.
+    /// \param length Number of bytes sent.
+    void tcpSendHandler(size_t expected, tcp::socket* socket,
+                        error_code ec = error_code(), size_t length = 0)
+    {
+        if (debug_) {
+            cout << "tcpSendHandler(): error = " << ec.value() <<
+                    ", length = " << length << endl;
+        }
+
+        EXPECT_EQ(0, ec.value());       // Expect no error
+        EXPECT_EQ(expected, length);    // And that amount sent is as expected
+
+        // Do we need to send more?
+        send_cumulative_ += length;
+        if (send_cumulative_ < send_buffer_.size()) {
+
+            // Yes - set up a timer:  the callback handler for the timer is
+            // tcpSendData, which will then send the next chunk.  We pass the
+            // socket over which data should be sent as an argument to that
+            // function.
+            timer_.expires_from_now(boost::posix_time::milliseconds(SEND_INTERVAL));
+            timer_.async_wait(boost::bind(&IOFetchTest::tcpSendData, this,
+                                          socket));
+        }
+    }
+
+    /// \brief Fetch completion callback
+    ///
+    /// This is the callback's operator() method which is called when the fetch
+    /// is complete.  It checks that the data received is the wire format of the
+    /// data sent back by the server.
+    ///
+    /// \param result Result indicated by the callback
+    void operator()(IOFetch::Result result) {
+        if (debug_) {
+            cout << "operator()(): result = " << result << endl;
+        }
+
+        EXPECT_EQ(expected_, result);   // Check correct result returned
+        EXPECT_FALSE(run_);             // Check it is run only once
+        run_ = true;                    // Note success
+
+        // If the expected result for SUCCESS, then this should have been called
+        // when one of the "servers" in this class has sent back return_data_.
+        // Check the data is as expected/
+        if (expected_ == IOFetch::SUCCESS) {
+            // In the case of UDP, we actually send back a real looking packet
+            // in the case of TCP, we send back a 'random' string
+            if (protocol_ == IOFetch::UDP) {
+                EXPECT_EQ(expected_buffer_->getLength(), result_buff_->getLength());
+                EXPECT_EQ(0, memcmp(expected_buffer_->getData(), result_buff_->getData(),
+                          expected_buffer_->getLength()));
+            } else {
+                EXPECT_EQ(return_data_.size(), result_buff_->getLength());
+                // Overwrite the random qid with our own data for the
+                // comparison to succeed
+                if (result_buff_->getLength() >= 2) {
+                    result_buff_->writeUint8At(return_data_[0], 0);
+                    result_buff_->writeUint8At(return_data_[1], 1);
+                }
+                const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
+                EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
+            }
+        }
+
+        // ... and cause the run loop to exit.
+        service_.stop();
+    }
+
+    // The next set of methods are the tests themselves.  A number of the TCP
+    // and UDP tests are very similar.
+
+    /// \brief Check for stop()
+    ///
+    /// Test that when we run the query and stop it after it was run, it returns
+    /// "stopped" correctly. (That is why stop() is posted to the service_ as
+    /// well instead of calling it.)
+    ///
+    /// \param protocol Test protocol
+    /// \param fetch Fetch object being tested
+    void stopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+        protocol_ = protocol;
+        expected_ = IOFetch::STOPPED;
+
+        // Post the query
+        service_.get_io_service().post(fetch);
+
+        // Post query_.stop() (yes, the boost::bind thing is just
+        // query_.stop()).
+        service_.get_io_service().post(
+            boost::bind(&IOFetch::stop, fetch, IOFetch::STOPPED));
+
+        // Run both of them.  run() returns when everything in the I/O service
+        // queue has completed.
+        service_.run();
+        EXPECT_TRUE(run_);
+    }
+
+    /// \brief Premature stop test
+    ///
+    /// Test that when we queue the query to service_ and call stop() before it
+    /// gets executed, it acts sanely as well (eg. has the same result as
+    /// running stop() after - calls the callback).
+    ///
+    /// \param protocol Test protocol
+    /// \param fetch Fetch object being tested
+    void prematureStopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+        protocol_ = protocol;
+        expected_ = IOFetch::STOPPED;
+
+        // Stop before it is started
+        fetch.stop();
+        service_.get_io_service().post(fetch);
+
+        service_.run();
+        EXPECT_TRUE(run_);
+    }
+
+    /// \brief Timeout test
+    ///
+    /// Test that fetch times out when no answer arrives.
+    ///
+    /// \param protocol Test protocol
+    /// \param fetch Fetch object being tested
+    void timeoutTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+        protocol_ = protocol;
+        expected_ = IOFetch::TIME_OUT;
+
+        service_.get_io_service().post(fetch);
+        service_.run();
+        EXPECT_TRUE(run_);
+    }
+
+    /// \brief Send/Receive Test
+    ///
+    /// Send a query to the server then receives a response.
+    ///
+    /// \param Test data to return to client
+    /// \param short_send If true, do not send all data
+    ///                   (should result in timeout)
+    void tcpSendReturnTest(const std::string& return_data, bool short_send = false) {
+        if (debug_) {
+            cout << "tcpSendReturnTest(): data size = " << return_data.size() << endl;
+        }
+        return_data_ = return_data;
+        protocol_ = IOFetch::TCP;
+        if (short_send) {
+            tcp_short_send_ = true;
+            expected_ = IOFetch::TIME_OUT;
+        } else {
+            expected_ = IOFetch::SUCCESS;
+        }
+
+        // Socket into which the connection will be accepted.
+        tcp::socket socket(service_.get_io_service());
+
+        // Acceptor object - called when the connection is made, the handler
+        // will initiate a read on the socket.
+        tcp::acceptor acceptor(service_.get_io_service(),
+                               tcp::endpoint(tcp::v4(), TEST_PORT));
+        acceptor.async_accept(socket,
+            boost::bind(&IOFetchTest::tcpAcceptHandler, this, &socket, _1));
+
+        // Post the TCP fetch object to send the query and receive the response.
+        service_.get_io_service().post(tcp_fetch_);
+
+        // ... and execute all the callbacks.  This exits when the fetch
+        // completes.
+        service_.run();
+        EXPECT_TRUE(run_);  // Make sure the callback did execute
+
+        // Tidy up
+        socket.close();
+    }
+
+    /// Perform a send/receive test over UDP
+    ///
+    /// \param bad_qid If true, do the test where the QID is mangled
+    ///                in the response
+    /// \param second_send If true, do the test where the QID is
+    ///                    mangled in the response, but a second
+    ///                    (correct) packet is used
+    void udpSendReturnTest(bool bad_qid, bool second_send) {
+        protocol_ = IOFetch::UDP;
+
+        // Set up the server.
+        udp::socket socket(service_.get_io_service(), udp::v4());
+        socket.set_option(socket_base::reuse_address(true));
+        socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
+        return_data_ = "Message returned to the client";
+
+        udp::endpoint remote;
+        socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
+            remote,
+            boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
+                        _1, _2, bad_qid, second_send));
+        service_.get_io_service().post(udp_fetch_);
+        if (debug_) {
+            cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
+                    endl;
+        }
+        service_.run();
+
+        socket.close();
+
+        EXPECT_TRUE(run_);;
+    }
+};
+
+// Check the protocol
+TEST_F(IOFetchTest, Protocol) {
+    EXPECT_EQ(IOFetch::UDP, udp_fetch_.getProtocol());
+    EXPECT_EQ(IOFetch::TCP, tcp_fetch_.getProtocol());
+}
+
+// UDP Stop test - see IOFetchTest::stopTest() header.
+TEST_F(IOFetchTest, UdpStop) {
+    stopTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP premature stop test - see IOFetchTest::prematureStopTest() header.
+TEST_F(IOFetchTest, UdpPrematureStop) {
+    prematureStopTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP premature stop test - see IOFetchTest::timeoutTest() header.
+TEST_F(IOFetchTest, UdpTimeout) {
+    timeoutTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP SendReceive test.  Set up a UDP server then ports a UDP fetch object.
+// This will send question_ to the server and receive the answer back from it.
+TEST_F(IOFetchTest, UdpSendReceive) {
+    expected_ = IOFetch::SUCCESS;
+
+    udpSendReturnTest(false, false);
+
+    EXPECT_TRUE(run_);;
+}
+
+TEST_F(IOFetchTest, UdpSendReceiveBadQid) {
+    expected_ = IOFetch::TIME_OUT;
+
+    udpSendReturnTest(true, false);
+
+    EXPECT_TRUE(run_);;
+}
+
+TEST_F(IOFetchTest, UdpSendReceiveBadQidResend) {
+    expected_ = IOFetch::SUCCESS;
+
+    udpSendReturnTest(true, true);
+
+    EXPECT_TRUE(run_);;
+}
+
+// Do the same tests for TCP transport
+
+TEST_F(IOFetchTest, TcpStop) {
+    stopTest(IOFetch::TCP, tcp_fetch_);
+}
+
+TEST_F(IOFetchTest, TcpPrematureStop) {
+    prematureStopTest(IOFetch::TCP, tcp_fetch_);
+}
+
+TEST_F(IOFetchTest, TcpTimeout) {
+    timeoutTest(IOFetch::TCP, tcp_fetch_);
+}
+
+// Test with values at or near 2, then at or near the chunk size (16 and 32
+// bytes, the sizes of the first two packets) then up to 65535.  These are done
+// in separate tests because in practice a new IOFetch is created for each
+// query/response exchange and we don't want to confuse matters in the test
+// by running the test with an IOFetch that has already done one exchange.
+//
+// Don't do 0 or 1; the server would not accept the packet
+// (since the length is too short to check the qid)
+TEST_F(IOFetchTest, TcpSendReceive2) {
+    tcpSendReturnTest(test_data_.substr(0, 2));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive3) {
+    tcpSendReturnTest(test_data_.substr(0, 3));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive15) {
+    tcpSendReturnTest(test_data_.substr(0, 15));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive16) {
+    tcpSendReturnTest(test_data_.substr(0, 16));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive17) {
+    tcpSendReturnTest(test_data_.substr(0, 17));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive31) {
+    tcpSendReturnTest(test_data_.substr(0, 31));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive32) {
+    tcpSendReturnTest(test_data_.substr(0, 32));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive33) {
+    tcpSendReturnTest(test_data_.substr(0, 33));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive4096) {
+    tcpSendReturnTest(test_data_.substr(0, 4096));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive8192) {
+    tcpSendReturnTest(test_data_.substr(0, 8192));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive16384) {
+    tcpSendReturnTest(test_data_.substr(0, 16384));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive32768) {
+    tcpSendReturnTest(test_data_.substr(0, 32768));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive65535) {
+    tcpSendReturnTest(test_data_.substr(0, 65535));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive2ShortSend) {
+    tcpSendReturnTest(test_data_.substr(0, 2), true);
+}
+
+TEST_F(IOFetchTest, TcpSendReceive15ShortSend) {
+    tcpSendReturnTest(test_data_.substr(0, 15), true);
+}
+
+TEST_F(IOFetchTest, TcpSendReceive8192ShortSend) {
+    tcpSendReturnTest(test_data_.substr(0, 8192), true);
+}
+
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/tests/io_service_unittest.cc b/src/lib/asiodns/tests/io_service_unittest.cc
new file mode 100644
index 0000000..cc64022
--- /dev/null
+++ b/src/lib/asiodns/tests/io_service_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <asio.hpp>
+#include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
+
+using namespace isc::asiolink;
+using namespace isc::asiodns;
+
+const char* const TEST_SERVER_PORT = "53535";
+const char* const TEST_CLIENT_PORT = "53536";
+const char* const TEST_IPV6_ADDR = "::1";
+const char* const TEST_IPV4_ADDR = "127.0.0.1";
+
+TEST(IOServiceTest, badPort) {
+    IOService io_service;
+    EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"53210.0", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, badAddress) {
+    IOService io_service;
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, unavailableAddress) {
+    IOService io_service;
+    // These addresses should generally be unavailable as a valid local
+    // address, although there's no guarantee in theory.
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.0", NULL, NULL, NULL), IOError);
+
+    // Some OSes would simply reject binding attempt for an AF_INET6 socket
+    // to an IPv4-mapped IPv6 address.  Even if those that allow it, since
+    // the corresponding IPv4 address is the same as the one used in the
+    // AF_INET socket case above, it should at least show the same result
+    // as the previous one.
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:192.0.2.0", NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, duplicateBind_v6) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
+
+    // IPv6, "any" address
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v6_address) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
+
+    // IPv6, specific address
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
+
+    // IPv4, "any" address
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4_address) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
+
+    // IPv4, specific address
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
+    delete dns_service;
+}
+
+// Disabled because IPv4-mapped addresses don't seem to be working with
+// the IOService constructor
+TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
+    IOService io_service;
+    // Duplicate bind on IPv4-mapped IPv6 address
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+    // XXX:
+    // Currently, this throws an "invalid argument" exception.  I have
+    // not been able to get IPv4-mapped addresses to work.
+    dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
+    delete dns_service;
+}
+
diff --git a/src/lib/asiodns/tests/run_unittests.cc b/src/lib/asiodns/tests/run_unittests.cc
new file mode 100644
index 0000000..c285f9e
--- /dev/null
+++ b/src/lib/asiodns/tests/run_unittests.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <log/root_logger_name.h>
+#include <dns/tests/unittest_util.h>
+
+int
+main(int argc, char* argv[])
+{
+    ::testing::InitGoogleTest(&argc, argv);         // Initialize Google test
+    isc::log::setRootLoggerName("unittest");        // Set a root logger name
+    isc::UnitTestUtil::addDataPath(TEST_DATA_DIR);  // Add location of test data
+
+    return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/asiodns/udp_server.cc b/src/lib/asiodns/udp_server.cc
new file mode 100644
index 0000000..f103e5a
--- /dev/null
+++ b/src/lib/asiodns/udp_server.cc
@@ -0,0 +1,325 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
+
+#include <boost/shared_array.hpp>
+
+#include <config.h>
+
+#include <log/dummylog.h>
+
+#include <asio.hpp>
+#include <asio/error.hpp>
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+#include "udp_server.h"
+
+#include <dns/opcode.h>
+
+using namespace asio;
+using asio::ip::udp;
+using isc::log::dlog;
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+/*
+ * Some of the member variables here are shared_ptrs and some are
+ * auto_ptrs. There will be one instance of Data for the lifetime
+ * of packet. The variables that are state only for a single packet
+ * use auto_ptr, as it is more lightweight. In the case of shared
+ * configuration (eg. the callbacks, socket), we use shared_ptrs.
+ */
+struct UDPServer::Data {
+    /*
+     * Constructor from parameters passed to UDPServer constructor.
+     * This instance will not be used to retrieve and answer the actual
+     * query, it will only hold parameters until we wait for the
+     * first packet. But we do initialize the socket in here.
+     */
+    Data(io_service& io_service, const ip::address& addr, const uint16_t port,
+        SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
+        io_(io_service), done_(false),
+        checkin_callback_(checkin),lookup_callback_(lookup),
+        answer_callback_(answer)
+    {
+        // We must use different instantiations for v4 and v6;
+        // otherwise ASIO will bind to both
+        udp proto = addr.is_v4() ? udp::v4() : udp::v6();
+        socket_.reset(new udp::socket(io_service, proto));
+        socket_->set_option(socket_base::reuse_address(true));
+        if (addr.is_v6()) {
+            socket_->set_option(asio::ip::v6_only(true));
+        }
+        socket_->bind(udp::endpoint(addr, port));
+    }
+
+    /*
+     * Copy constructor. Default one would probably do, but it is unnecessary
+     * to copy many of the member variables every time we fork to handle
+     * another packet.
+     *
+     * We also allocate data for receiving the packet here.
+     */
+    Data(const Data& other) :
+        io_(other.io_), socket_(other.socket_), done_(false),
+        checkin_callback_(other.checkin_callback_),
+        lookup_callback_(other.lookup_callback_),
+        answer_callback_(other.answer_callback_)
+    {
+        // Instantiate the data buffer and endpoint that will
+        // be used by the asynchronous receive call.
+        data_.reset(new char[MAX_LENGTH]);
+        sender_.reset(new udp::endpoint());
+    }
+
+    // The ASIO service object
+    asio::io_service& io_;
+
+    // Class member variables which are dynamic, and changes to which
+    // need to accessible from both sides of a coroutine fork or from
+    // outside of the coroutine (i.e., from an asynchronous I/O call),
+    // should be declared here as pointers and allocated in the
+    // constructor or in the coroutine.  This allows state information
+    // to persist when an individual copy of the coroutine falls out
+    // scope while waiting for an event, *so long as* there is another
+    // object that is referencing the same data.  As a side-benefit, using
+    // pointers also reduces copy overhead for coroutine objects.
+    //
+    // Note: Currently these objects are allocated by "new" in the
+    // constructor, or in the function operator while processing a query.
+    // Repeated allocations from the heap for every incoming query is
+    // clearly a performance issue; this must be optimized in the future.
+    // The plan is to have a structure pre-allocate several "Data"
+    // objects which can be pulled off a free list and placed on an in-use
+    // list whenever a query comes in.  This will serve the dual purpose
+    // of improving performance and guaranteeing that state information
+    // will *not* be destroyed when any one instance of the coroutine
+    // falls out of scope while waiting for an event.
+    //
+    // Socket used to for listen for queries.  Created in the
+    // constructor and stored in a shared_ptr because socket objects
+    // are not copyable.
+    boost::shared_ptr<asio::ip::udp::socket> socket_;
+
+    // The ASIO-internal endpoint object representing the client
+    std::auto_ptr<asio::ip::udp::endpoint> sender_;
+
+    // \c IOMessage and \c Message objects to be passed to the
+    // DNS lookup and answer providers
+    std::auto_ptr<asiolink::IOMessage> io_message_;
+
+    // The original query as sent by the client
+    isc::dns::MessagePtr query_message_;
+
+    // The response message we are building
+    isc::dns::MessagePtr answer_message_;
+
+    // The buffer into which the response is written
+    isc::util::OutputBufferPtr respbuf_;
+
+    // The buffer into which the query packet is written
+    boost::shared_array<char> data_;
+
+    // State information that is entirely internal to a given instance
+    // of the coroutine can be declared here.
+    size_t bytes_;
+    bool done_;
+
+
+    // Callback functions provided by the caller
+    const SimpleCallback* checkin_callback_;
+    const DNSLookup* lookup_callback_;
+    const DNSAnswer* answer_callback_;
+
+    std::auto_ptr<IOEndpoint> peer_;
+    std::auto_ptr<IOSocket> iosock_;
+};
+
+/// The following functions implement the \c UDPServer class.
+///
+/// The constructor. It just creates new internal state object
+/// and lets it handle the initialization.
+UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
+    const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
+    DNSAnswer* answer) :
+    data_(new Data(io_service, addr, port, checkin, lookup, answer))
+{ }
+
+/// The function operator is implemented with the "stackless coroutine"
+/// pattern; see internal/coroutine.h for details.
+void
+UDPServer::operator()(error_code ec, size_t length) {
+    /// Because the coroutine reentry block is implemented as
+    /// a switch statement, inline variable declarations are not
+    /// permitted.  Certain variables used below can be declared here.
+
+    CORO_REENTER (this) {
+        do {
+            /*
+             * This is preparation for receiving a packet. We get a new
+             * state object for the lifetime of the next packet to come.
+             * It allocates the buffers to receive data into.
+             */
+            data_.reset(new Data(*data_));
+
+            do {
+                // Begin an asynchronous receive, then yield.
+                // When the receive event is posted, the coroutine
+                // will resume immediately after this point.
+                CORO_YIELD data_->socket_->async_receive_from(
+                    buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
+                    *this);
+
+                // Abort on fatal errors
+                // TODO: add log
+                if (ec) {
+                    using namespace asio::error;
+                    if (ec.value() != would_block && ec.value() != try_again &&
+                        ec.value() != interrupted) {
+                        return;
+                    }
+                }
+
+            } while (ec || length == 0);
+
+            data_->bytes_ = length;
+
+            /*
+             * We fork the coroutine now. One (the child) will keep
+             * the current state and handle the packet, then die and
+             * drop ownership of the state. The other (parent) will just
+             * go into the loop again and replace the current state with
+             * a new one for a new object.
+             *
+             * Actually, both of the coroutines will be a copy of this
+             * one, but that's just internal implementation detail.
+             */
+            CORO_FORK data_->io_.post(UDPServer(*this));
+        } while (is_parent());
+
+        // Create an \c IOMessage object to store the query.
+        //
+        // (XXX: It would be good to write a factory function
+        // that would quickly generate an IOMessage object without
+        // all these calls to "new".)
+        data_->peer_.reset(new UDPEndpoint(*data_->sender_));
+
+        // The UDP socket class has been extended with asynchronous functions
+        // and takes as a template parameter a completion callback class.  As
+        // UDPServer does not use these extended functions (only those defined
+        // in the IOSocket base class) - but needs a UDPSocket to get hold of
+        // the underlying Boost UDP socket - DummyIOCallback is used.  This
+        // provides the appropriate operator() but is otherwise functionless.
+        data_->iosock_.reset(
+            new UDPSocket<DummyIOCallback>(*data_->socket_));
+
+        data_->io_message_.reset(new IOMessage(data_->data_.get(),
+            data_->bytes_, *data_->iosock_, *data_->peer_));
+
+        // Perform any necessary operations prior to processing an incoming
+        // query (e.g., checking for queued configuration messages).
+        //
+        // (XXX: it may be a performance issue to check in for every single
+        // incoming query; we may wish to throttle this in the future.)
+        if (data_->checkin_callback_ != NULL) {
+            (*data_->checkin_callback_)(*data_->io_message_);
+        }
+
+        // If we don't have a DNS Lookup provider, there's no point in
+        // continuing; we exit the coroutine permanently.
+        if (data_->lookup_callback_ == NULL) {
+            CORO_YIELD return;
+        }
+
+        // Instantiate objects that will be needed by the
+        // asynchronous DNS lookup and/or by the send call.
+        data_->respbuf_.reset(new OutputBuffer(0));
+        data_->query_message_.reset(new Message(Message::PARSE));
+        data_->answer_message_.reset(new Message(Message::RENDER));
+
+        // Schedule a DNS lookup, and yield.  When the lookup is
+        // finished, the coroutine will resume immediately after
+        // this point.
+        CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
+
+        // The 'done_' flag indicates whether we have an answer
+        // to send back.  If not, exit the coroutine permanently.
+        if (!data_->done_) {
+            CORO_YIELD return;
+        }
+
+        // Call the DNS answer provider to render the answer into
+        // wire format
+        (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
+            data_->answer_message_, data_->respbuf_);
+
+        // Begin an asynchronous send, and then yield.  When the
+        // send completes, we will resume immediately after this point
+        // (though we have nothing further to do, so the coroutine
+        // will simply exit at that time).
+        CORO_YIELD data_->socket_->async_send_to(
+            buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
+            *data_->sender_, *this);
+    }
+}
+
+/// Call the DNS lookup provider.  (Expected to be called by the
+/// AsyncLookup<UDPServer> handler.)
+void
+UDPServer::asyncLookup() {
+    (*data_->lookup_callback_)(*data_->io_message_,
+        data_->query_message_, data_->answer_message_, data_->respbuf_, this);
+}
+
+/// Stop the UDPServer
+void
+UDPServer::stop() {
+    /// Using close instead of cancel, because cancel
+    /// will only cancel the asynchornized event already submitted
+    /// to io service, the events post to io service after
+    /// cancel still can be scheduled by io service, if
+    /// the socket is cloesed, all the asynchronized event
+    /// for it won't be scheduled by io service not matter it is
+    /// submit to io serice before or after close call. And we will
+    //. get bad_descriptor error
+    data_->socket_->close();
+}
+
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off.  The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+UDPServer::resume(const bool done) {
+    data_->done_ = done;
+    data_->io_.post(*this);
+}
+
+bool
+UDPServer::hasAnswer() {
+    return (data_->done_);
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/udp_server.h b/src/lib/asiodns/udp_server.h
new file mode 100644
index 0000000..4c19544
--- /dev/null
+++ b/src/lib/asiodns/udp_server.h
@@ -0,0 +1,108 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UDP_SERVER_H
+#define __UDP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/simple_callback.h>
+#include <asiodns/dns_answer.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_server.h>
+
+#include <coroutine.h>
+
+namespace isc {
+namespace asiodns {
+
+//
+// Asynchronous UDP server coroutine
+//
+///
+/// \brief This class implements the coroutine to handle UDP
+///        DNS query event. As such, it is both a \c DNSServer and
+///        a \c coroutine
+///
+class UDPServer : public virtual DNSServer, public virtual coroutine {
+public:
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param addr the IP address to listen for queries on
+    /// \param port the port to listen for queries on
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    explicit UDPServer(asio::io_service& io_service,
+                       const asio::ip::address& addr, const uint16_t port,
+                       isc::asiolink::SimpleCallback* checkin = NULL,
+                       DNSLookup* lookup = NULL,
+                       DNSAnswer* answer = NULL);
+
+    /// \brief The function operator
+    void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+
+    /// \brief Calls the lookup callback
+    void asyncLookup();
+
+    /// \brief Stop the running server
+    /// \note once the server stopped, it can't restart
+    void stop();
+
+    /// \brief Resume operation
+    ///
+    /// \param done Set this to true if the lookup action is done and
+    ///        we have an answer
+    void resume(const bool done);
+
+    /// \brief Check if we have an answer
+    ///
+    /// \return true if we have an answer
+    bool hasAnswer();
+
+    /// \brief Returns the coroutine state value
+    ///
+    /// \return the coroutine state value
+    int value() { return (get_value()); }
+
+    /// \brief Clones the object
+    ///
+    /// \return a newly allocated copy of this object
+    DNSServer* clone() {
+        UDPServer* s = new UDPServer(*this);
+        return (s);
+    }
+
+private:
+    enum { MAX_LENGTH = 4096 };
+
+    /**
+     * \brief Internal state and data.
+     *
+     * We use the pimple design pattern, but not because we need to hide
+     * internal data. This class and whole header is for private use anyway.
+     * It turned out that UDPServer is copied a lot, because it is a coroutine.
+     * This way the overhead of copying is lower, we copy only one shared
+     * pointer instead of about 10 of them.
+     */
+    class Data;
+    boost::shared_ptr<Data> data_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __UDP_SERVER_H
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index 2fda728..22b3a8e 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -2,7 +2,6 @@ SUBDIRS = . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
@@ -13,33 +12,21 @@ CLEANFILES = *.gcno *.gcda
 # which would make the build fail with -Werror (our default setting).
 lib_LTLIBRARIES = libasiolink.la
 libasiolink_la_SOURCES  = asiolink.h
-libasiolink_la_SOURCES += asiolink_utilities.h
-libasiolink_la_SOURCES += asiodef.cc asiodef.h
-libasiolink_la_SOURCES += dns_answer.h
-libasiolink_la_SOURCES += dns_lookup.h
-libasiolink_la_SOURCES += dns_server.h
-libasiolink_la_SOURCES += dns_service.cc dns_service.h
 libasiolink_la_SOURCES += dummy_io_cb.h
 libasiolink_la_SOURCES += interval_timer.cc interval_timer.h
 libasiolink_la_SOURCES += io_address.cc io_address.h
 libasiolink_la_SOURCES += io_asio_socket.h
 libasiolink_la_SOURCES += io_endpoint.cc io_endpoint.h
 libasiolink_la_SOURCES += io_error.h
-libasiolink_la_SOURCES += io_fetch.cc io_fetch.h
 libasiolink_la_SOURCES += io_message.h
-libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
 libasiolink_la_SOURCES += io_service.h io_service.cc
 libasiolink_la_SOURCES += io_socket.h io_socket.cc
 libasiolink_la_SOURCES += simple_callback.h
 libasiolink_la_SOURCES += tcp_endpoint.h
-libasiolink_la_SOURCES += tcp_server.cc tcp_server.h
 libasiolink_la_SOURCES += tcp_socket.h
 libasiolink_la_SOURCES += udp_endpoint.h
-libasiolink_la_SOURCES += udp_server.cc udp_server.h
 libasiolink_la_SOURCES += udp_socket.h
 
-EXTRA_DIST = asiodef.msg
-
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/asiolink/README b/src/lib/asiolink/README
index 6bd1a73..66091b1 100644
--- a/src/lib/asiolink/README
+++ b/src/lib/asiolink/README
@@ -16,167 +16,7 @@ including:
     them in only one place allows us to relax strictness here, while
     leaving it in place elsewhere.
 
-Currently, the asiolink library only supports DNS servers (i.e., b10-auth
-and b10-resolver).  The plan is to make it more generic and allow it to
-support other modules as well.
-
 Some of the classes defined here--for example, IOSocket, IOEndpoint,
 and IOAddress--are to be used by BIND 10 modules as wrappers around
 ASIO-specific classes.
 
-Other classes implement the DNS protocol on behalf of BIND 10 modules.
-
-These DNS server and client routines are written using the "stackless
-coroutine" pattern invented by Chris Kohlhoff and described at
-http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html.
-This is intended to simplify development a bit, since it allows the
-routines to be written in a straightfowrard step-step-step fashion rather
-than as a complex chain of separate handler functions.
-
-Coroutine objects (i.e., UDPServer, TCPServer and IOFetch) are objects
-with reenterable operator() members.  When an instance of one of these
-classes is called as a function, it resumes at the position where it left
-off.  Thus, a UDPServer can issue an asynchronous I/O call and specify
-itself as the handler object; when the call completes, the UDPServer
-carries on at the same position.  As a result, the code can look as
-if it were using synchronous, not asynchronous, I/O, providing some of
-the benefit of threading but with minimal switching overhead.
-
-So, in simplified form, the behavior of a DNS Server is:
-
-  REENTER:
-    while true:
-      YIELD packet = read_packet
-      FORK
-      if not parent:
-        break
-
-    # This callback informs the caller that a packet has arrived, and
-    # gives it a chance to update configuration, etc
-    SimpleCallback(packet)
-    YIELD answer = DNSLookup(packet, this)
-    response = DNSAnswer(answer)
-    YIELD send(response)
-
-At each "YIELD" point, the coroutine initiates an asynchronous operation,
-then pauses and turns over control to some other task on the ASIO service
-queue.  When the operation completes, the coroutine resumes.
-
-DNSLookup, DNSAnswer and SimpleCallback define callback methods
-used by a DNS Server to communicate with the module that called it.
-They are abstract-only classes whose concrete implementations
-are supplied by the calling module.
-
-The DNSLookup callback always runs asynchronously.  Concrete
-implementations must be sure to call the server's "resume" method when
-it is finished.
-
-In an authoritative server, the DNSLookup implementation would examine
-the query, look up the answer, then call "resume".  (See the diagram
-in doc/auth_process.jpg.)
-
-In a recursive server, the DNSLookup impelemtation would initiate a
-DNSQuery, which in turn would be responsible for calling the server's
-"resume" method.  (See the diagram in doc/recursive_process.jpg.)
-
-A DNSQuery object is intended to handle resolution of a query over
-the network when the local authoritative data sources or cache are not
-sufficient.  The plan is that it will make use of subsidiary DNSFetch
-calls to get data from particular authoritative servers, and when it has
-gotten a complete answer, it calls "resume".
-
-In current form, however, DNSQuery is much simpler; it forwards queries
-to a single upstream resolver and passes the answers back to the client.
-It is constructed with the address of the forward server.  Queries are
-initiated with the question to ask the forward server, a buffer into
-which to write the answer, and a pointer to the coroutine to be resumed
-when the answer has arrived.  In simplified form, the DNSQuery routine is:
-
-  REENTER:
-    render the question into a wire-format query packet
-    YIELD send(query)
-    YIELD response = read_packet
-    server->resume
-
-Currently, DNSQuery is only implemented for UDP queries.  In future work
-it will be necessary to write code to fall back to TCP when circumstances
-require it.
-
-
-Upstream Fetches
-================
-Upstream fetches (queries by the resolver on behalf of a client) are made
-using a slightly-modified version of the pattern described above.
-
-Sockets
--------
-First, it will be useful to understand the class hierarchy used in the
-fetch logic:
-
-        IOSocket
-           |
-      IOAsioSocket
-           |
-     +-----+-----+                
-     |           |
-UDPSocket    TCPSocket
-
-IOSocket is a wrapper class for a socket and is used by the authoritative
-server code.  It is an abstract base class, providing little more that the ability to hold the socket and to return the protocol in use.
-
-Built on this is IOAsioSocket, which adds the open, close, asyncSend and
-asyncReceive methods.  This is a template class, which takes as template
-argument the class of the object that will be used as the callback when the
-asynchronous operation completes. This object can be of any type, but must
-include an operator() method with the signature:
-
-   operator()(asio::error_code ec, size_t length)
-
-... the two arguments being the status of the completed I/O operation and
-the number of bytes transferred. (In the case of the open method, the second
-argument will be zero.)
-
-Finally, the TCPSocket and UDPSocket classes provide the body of the
-asynchronous operations.
-
-Fetch Sequence
---------------
-The fetch is implemented by the IOFetch class, which takes as argument the
-protocol to use.  The sequence is:
-
-  REENTER:
-    render the question into a wire-format query packet
-    open()                           // Open socket and optionally connect
-    if (! synchronous) {
-        YIELD;
-    }
-    YIELD asyncSend(query)           // Send query 
-    do {
-        YIELD asyncReceive(response) // Read response
-    } while (! complete(response))
-    close()                          // Drop connection and close socket
-    server->resume
-
-The open() method opens a socket for use.  On TCP, it also makes a
-connection to the remote end.  So under UDP the operation will complete
-immediately, but under TCP it could take a long time.  One solution would be
-for the open operation to post an event to the I/O queue; then both cases
-could be regarded as being equivalent, with the completion being signalled
-by the posting of the completion event.  However UDP is the most common case
-and that would involve extra overhead.  So the open() returns a status
-indicating whether the operation completed asynchronously.  If it did, the
-code yields back to the coroutine; if not the yield is bypassed.
-
-The asynchronous send is straightforward, invoking the underlying ASIO
-function.  (Note that the address/port is supplied to both the open() and
-asyncSend() methods - it is used by the TCPSocket in open() and by the
-UDPSocket in asyncSend().)
-
-The asyncReceive() method issues an asynchronous read and waits for completion.
-The fetch object keeps track of the amount of data received so far and when
-the receive completes it calls a method on the socket to determine if the
-entire message has been received.  (This will always be the case for UDP.  On
-TCP though, the message is preceded by a count field as several reads may be
-required to read all the data.)  The fetch loops until all the data is read.
-
-Finally, the socket is closed and the server called to resume operation.
diff --git a/src/lib/asiolink/asiodef.cc b/src/lib/asiolink/asiodef.cc
deleted file mode 100644
index 94c71b5..0000000
--- a/src/lib/asiolink/asiodef.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#include <cstddef>
-#include <log/message_types.h>
-#include <log/message_initializer.h>
-
-namespace asiolink {
-
-extern const isc::log::MessageID ASIO_FETCHCOMP = "FETCHCOMP";
-extern const isc::log::MessageID ASIO_FETCHSTOP = "FETCHSTOP";
-extern const isc::log::MessageID ASIO_OPENSOCK = "OPENSOCK";
-extern const isc::log::MessageID ASIO_RECVSOCK = "RECVSOCK";
-extern const isc::log::MessageID ASIO_RECVTMO = "RECVTMO";
-extern const isc::log::MessageID ASIO_SENDSOCK = "SENDSOCK";
-extern const isc::log::MessageID ASIO_UNKORIGIN = "UNKORIGIN";
-extern const isc::log::MessageID ASIO_UNKRESULT = "UNKRESULT";
-
-} // namespace asiolink
-
-namespace {
-
-const char* values[] = {
-    "FETCHCOMP", "upstream fetch to %s(%d) has now completed",
-    "FETCHSTOP", "upstream fetch to %s(%d) has been stopped",
-    "OPENSOCK", "error %d opening %s socket to %s(%d)",
-    "RECVSOCK", "error %d reading %s data from %s(%d)",
-    "RECVTMO", "receive timeout while waiting for data from %s(%d)",
-    "SENDSOCK", "error %d sending data using %s to %s(%d)",
-    "UNKORIGIN", "unknown origin for ASIO error code %d (protocol: %s, address %s)",
-    "UNKRESULT", "unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)",
-    NULL
-};
-
-const isc::log::MessageInitializer initializer(values);
-
-} // Anonymous namespace
-
diff --git a/src/lib/asiolink/asiodef.h b/src/lib/asiolink/asiodef.h
deleted file mode 100644
index ba77817..0000000
--- a/src/lib/asiolink/asiodef.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#ifndef __ASIODEF_H
-#define __ASIODEF_H
-
-#include <log/message_types.h>
-
-namespace asiolink {
-
-extern const isc::log::MessageID ASIO_FETCHCOMP;
-extern const isc::log::MessageID ASIO_FETCHSTOP;
-extern const isc::log::MessageID ASIO_OPENSOCK;
-extern const isc::log::MessageID ASIO_RECVSOCK;
-extern const isc::log::MessageID ASIO_RECVTMO;
-extern const isc::log::MessageID ASIO_SENDSOCK;
-extern const isc::log::MessageID ASIO_UNKORIGIN;
-extern const isc::log::MessageID ASIO_UNKRESULT;
-
-} // namespace asiolink
-
-#endif // __ASIODEF_H
diff --git a/src/lib/asiolink/asiodef.msg b/src/lib/asiolink/asiodef.msg
deleted file mode 100644
index 2fcadd1..0000000
--- a/src/lib/asiolink/asiodef.msg
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-$PREFIX ASIO_
-$NAMESPACE asiolink
-
-FETCHCOMP   upstream fetch to %s(%d) has now completed
-+ A debug message, this records the the upstream fetch (a query made by the
-+ resolver on behalf of its client) to the specified address has completed.
-
-FETCHSTOP   upstream fetch to %s(%d) has been stopped
-+ An external component has requested the halting of an upstream fetch.  This
-+ is an allowed operation, and the message should only appear if debug is
-+ enabled.
-
-OPENSOCK    error %d opening %s socket to %s(%d)
-+ The asynchronous I/O code encountered an error when trying to open a socket
-+ of the specified protocol in order to send a message to the target address.
-+ The the number of the system error that cause the problem is given in the
-+ message.
-
-RECVSOCK    error %d reading %s data from %s(%d)
-+ The asynchronous I/O code encountered an error when trying read data from
-+ the specified address on the given protocol.  The the number of the system
-+ error that cause the problem is given in the message.
-
-SENDSOCK    error %d sending data using %s to %s(%d)
-+ The asynchronous I/O code encountered an error when trying send data to
-+ the specified address on the given protocol.  The the number of the system
-+ error that cause the problem is given in the message.
-
-RECVTMO     receive timeout while waiting for data from %s(%d)
-+ An upstream fetch from the specified address timed out.  This may happen for
-+ any number of reasons and is most probably a problem at the remote server
-+ or a problem on the network.  The message will only appear if debug is
-+ enabled.
-
-UNKORIGIN  unknown origin for ASIO error code %d (protocol: %s, address %s)
-+ This message should not appear and indicates an internal error if it does.
-+ Please enter a bug report.
-
-UNKRESULT  unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)
-+ The termination method of the resolver's upstream fetch class was called with
-+ an unknown result code (which is given in the message).  This message should
-+ not appear and may indicate an internal error.  Please enter a bug report.
diff --git a/src/lib/asiolink/asiolink.h b/src/lib/asiolink/asiolink.h
index 6e8fe84..51d3a14 100644
--- a/src/lib/asiolink/asiolink.h
+++ b/src/lib/asiolink/asiolink.h
@@ -20,10 +20,6 @@
 // See the description of the namespace below.
 
 #include <asiolink/io_service.h>
-#include <asiolink/dns_service.h>
-#include <asiolink/dns_server.h>
-#include <asiolink/dns_lookup.h>
-#include <asiolink/dns_answer.h>
 #include <asiolink/simple_callback.h>
 #include <asiolink/interval_timer.h>
 
@@ -62,11 +58,6 @@
 /// this module.  The resulting interfaces are thus straightforward mapping
 /// to the ASIO counterparts.
 ///
-/// Notes to developers:
-/// Currently the wrapper interface is fairly specific to use by a
-/// DNS server, i.e., b10-auth or b10-resolver.  But the plan is to
-/// generalize it and have other modules use it as well.
-///
 /// One obvious drawback of this approach is performance overhead
 /// due to the additional layer.  We should eventually evaluate the cost
 /// of the wrapper abstraction in benchmark tests. Another drawback is
diff --git a/src/lib/asiolink/asiolink_utilities.h b/src/lib/asiolink/asiolink_utilities.h
deleted file mode 100644
index 659e6a0..0000000
--- a/src/lib/asiolink/asiolink_utilities.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __ASIOLINK_UTILITIES_H
-#define __ASIOLINK_UTILITIES_H
-
-#include <cstddef>
-
-namespace asiolink {
-
-/// \brief Read Unsigned 16-Bit Integer from Buffer
-///
-/// This is essentially a copy of the isc::dns::InputBuffer::readUint16.  It
-/// should really be moved into a separate library.
-///
-/// \param buffer Data buffer at least two bytes long of which the first two
-///        bytes are assumed to represent a 16-bit integer in network-byte
-///        order.
-///
-/// \return Value of 16-bit integer
-inline uint16_t
-readUint16(const void* buffer) {
-    const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
-
-    uint16_t result = (static_cast<uint16_t>(byte_buffer[0])) << 8;
-    result |= static_cast<uint16_t>(byte_buffer[1]);
-
-    return (result);
-}
-
-/// \brief Write Unisgned 16-Bit Integer to Buffer
-///
-/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16.  It
-/// should really be moved into a separate library.
-///
-/// \param value 16-bit value to convert
-/// \param buffer Data buffer at least two bytes long into which the 16-bit
-///        value is written in network-byte order.
-
-inline void
-writeUint16(uint16_t value, void* buffer) {
-    uint8_t* byte_buffer = static_cast<uint8_t*>(buffer);
-
-    byte_buffer[0] = static_cast<uint8_t>((value & 0xff00U) >> 8);
-    byte_buffer[1] = static_cast<uint8_t>(value & 0x00ffU);
-}
-
-} // namespace asiolink
-
-#endif // __ASIOLINK_UTILITIES_H
diff --git a/src/lib/asiolink/dns_answer.h b/src/lib/asiolink/dns_answer.h
deleted file mode 100644
index 84e1f6f..0000000
--- a/src/lib/asiolink/dns_answer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __ASIOLINK_DNS_ANSWER_H
-#define __ASIOLINK_DNS_ANSWER_H 1
-
-#include <asiolink/io_message.h>
-
-namespace asiolink {
-
-/// \brief The \c DNSAnswer class is an abstract base class for a DNS
-/// Answer provider function.
-///
-/// Specific derived class implementations are hidden within the
-/// implementation.  Instances of the derived classes can be called
-/// as functions via the operator() interface.  Pointers to these
-/// instances can then be provided to the \c IOService class
-/// via its constructor.
-///
-/// A DNS Answer provider function takes answer data that has been obtained
-/// from a DNS Lookup provider functon and readies it to be sent to the
-/// client.  After it has run, the OutputBuffer object passed to it should
-/// contain the answer to the query rendered into wire format.
-class DNSAnswer {
-    ///
-    /// \name Constructors and Destructor
-    ///
-    /// Note: The copy constructor and the assignment operator are
-    /// intentionally defined as private, making this class non-copyable.
-    //@{
-private:
-    DNSAnswer(const DNSAnswer& source);
-    DNSAnswer& operator=(const DNSAnswer& source);
-protected:
-    /// \brief The default constructor.
-    ///
-    /// This is intentionally defined as \c protected as this base class
-    /// should never be instantiated (except as part of a derived class).
-    DNSAnswer() {}
-public:
-    /// \brief The destructor
-    virtual ~DNSAnswer() {}
-    //@}
-    /// \brief The function operator
-    ///
-    /// This makes its call indirectly via the "self" pointer, ensuring
-    /// that the function ultimately invoked will be the one in the derived
-    /// class.
-    ///
-    /// \param io_message The event message to handle
-    /// \param query_message The DNS MessagePtr of the original query
-    /// \param answer_message The DNS MessagePtr of the answer we are
-    /// building
-    /// \param buffer Intermediate data results are put here
-    virtual void operator()(const IOMessage& io_message,
-                            isc::dns::MessagePtr query_message,
-                            isc::dns::MessagePtr answer_message,
-                            isc::dns::OutputBufferPtr buffer) const = 0;
-};
-
-}      // namespace asiolink
-#endif // __ASIOLINK_DNS_ANSWER_H
diff --git a/src/lib/asiolink/dns_lookup.h b/src/lib/asiolink/dns_lookup.h
deleted file mode 100644
index a79976f..0000000
--- a/src/lib/asiolink/dns_lookup.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __ASIOLINK_DNS_LOOKUP_H
-#define __ASIOLINK_DNS_LOOKUP_H 1
-
-#include <asiolink/io_message.h>
-#include <asiolink/dns_server.h>
-#include <dns/buffer.h>
-#include <dns/message.h>
-
-namespace asiolink {
-
-/// \brief The \c DNSLookup class is an abstract base class for a DNS
-/// Lookup provider function.
-///
-/// Specific derived class implementations are hidden within the
-/// implementation.  Instances of the derived classes can be called
-/// as functions via the operator() interface.  Pointers to these
-/// instances can then be provided to the \c IOService class
-/// via its constructor.
-///
-/// A DNS Lookup provider function obtains the data needed to answer
-/// a DNS query (e.g., from authoritative data source, cache, or upstream
-/// query).  After it has run, the OutputBuffer object passed to it
-/// should contain the answer to the query, in an internal representation.
-class DNSLookup {
-    ///
-    /// \name Constructors and Destructor
-    ///
-    /// Note: The copy constructor and the assignment operator are
-    /// intentionally defined as private, making this class non-copyable.
-    //@{
-private:
-    DNSLookup(const DNSLookup& source);
-    DNSLookup& operator=(const DNSLookup& source);
-protected:
-    /// \brief The default constructor.
-    ///
-    /// This is intentionally defined as \c protected as this base class
-    /// should never be instantiated (except as part of a derived class).
-    DNSLookup() : self_(this) {}
-public:
-    /// \brief The destructor
-    virtual ~DNSLookup() {}
-    //@}
-    /// \brief The function operator
-    ///
-    /// This makes its call indirectly via the "self" pointer, ensuring
-    /// that the function ultimately invoked will be the one in the derived
-    /// class.
-    ///
-    /// \param io_message The event message to handle
-    /// \param message The DNS MessagePtr that needs handling
-    /// \param answer_message The final answer will be constructed in
-    ///                       this MessagePtr
-    /// \param buffer The final answer is put here
-    /// \param server DNSServer object to use
-    virtual void operator()(const IOMessage& io_message,
-                            isc::dns::MessagePtr message,
-                            isc::dns::MessagePtr answer_message,
-                            isc::dns::OutputBufferPtr buffer,
-                            DNSServer* server) const
-    {
-        (*self_)(io_message, message, answer_message, buffer, server);
-    }
-private:
-    DNSLookup* self_;
-};
-
-}      // namespace asiolink
-#endif // __ASIOLINK_DNS_LOOKUP_H
diff --git a/src/lib/asiolink/dns_server.h b/src/lib/asiolink/dns_server.h
deleted file mode 100644
index f15f808..0000000
--- a/src/lib/asiolink/dns_server.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __ASIOLINK_DNS_SERVER_H
-#define __ASIOLINK_DNS_SERVER_H 1
-
-#include <asiolink/io_message.h>
-
-namespace asiolink {
-
-/// \brief The \c DNSServer class is a wrapper (and base class) for
-/// classes which provide DNS server functionality.
-///
-/// The classes derived from this one, \c TCPServer and \c UDPServer,
-/// act as the interface layer between clients sending queries, and
-/// functions defined elsewhere that provide answers to those queries.
-/// Those functions are described in more detail below under
-/// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
-///
-/// Notes to developers:
-/// When constructed, this class (and its derived classes) will have its
-/// "self_" member set to point to "this".  Objects of this class (as
-/// instantiated through a base class) are sometimes passed by
-/// reference (as this superclass); calls to methods in the base
-/// class are then rerouted via this pointer to methods in the derived
-/// class.  This allows code from outside asiolink, with no specific
-/// knowledge of \c TCPServer or \c UDPServer, to access their methods.
-///
-/// This class is both assignable and copy-constructable.  Its subclasses
-/// use the "stackless coroutine" pattern, meaning that it will copy itself
-/// when "forking", and that instances will be posted as ASIO handler
-/// objects, which are always copied.
-///
-/// Because these objects are frequently copied, it is recommended
-/// that derived classes be kept small to reduce copy overhead.
-class DNSServer {
-protected:
-    ///
-    /// \name Constructors and destructors
-    ///
-    /// This is intentionally defined as \c protected, as this base class
-    /// should never be instantiated except as part of a derived class.
-    //@{
-    DNSServer() : self_(this) {}
-public:
-    /// \brief The destructor
-    virtual ~DNSServer() {}
-    //@}
-
-    ///
-    /// \name Class methods
-    ///
-    /// These methods all make their calls indirectly via the "self_"
-    /// pointer, ensuring that the functions ultimately invoked will be
-    /// the ones in the derived class.  This makes it possible to pass
-    /// instances of derived classes as references to this base class
-    /// without losing access to derived class data.
-    ///
-    //@{
-    /// \brief The funtion operator
-    virtual void operator()(asio::error_code ec = asio::error_code(),
-                            size_t length = 0)
-    {
-        (*self_)(ec, length);
-    }
-
-    /// \brief Stop current running server
-    virtual void stop() { self_->stop();}
-
-    /// \brief Resume processing of the server coroutine after an 
-    /// asynchronous call (e.g., to the DNS Lookup provider) has completed.
-    ///
-    /// \param done If true, this signals the system there is an answer
-    ///             to return.
-    virtual void resume(const bool done) { self_->resume(done); }
-
-    /// \brief Indicate whether the server is able to send an answer
-    /// to a query.
-    ///
-    /// This is presently used only for testing purposes.
-    virtual bool hasAnswer() { return (self_->hasAnswer()); }
-
-    /// \brief Returns the current value of the 'coroutine' object
-    ///
-    /// This is a temporary method, intended to be used for debugging
-    /// purposes during development and removed later.  It allows
-    /// callers from outside the coroutine object to retrieve information
-    /// about its current state.
-    ///
-    /// \return The value of the 'coroutine' object
-    virtual int value() { return (self_->value()); }
-
-    /// \brief Returns a pointer to a clone of this DNSServer object.
-    ///
-    /// When a \c DNSServer object is copied or assigned, the result will
-    /// normally be another \c DNSServer object containing a copy
-    /// of the original "self_" pointer.  Calling clone() guarantees
-    /// that the underlying object is also correctly copied.
-    ///
-    /// \return A deep copy of this DNSServer object
-    virtual DNSServer* clone() { return (self_->clone()); }
-    //@}
-
-protected:
-    /// \brief Lookup handler object.
-    ///
-    /// This is a protected class; it can only be instantiated
-    /// from within a derived class of \c DNSServer.
-    ///
-    /// A server object that has received a query creates an instance
-    /// of this class and scheudles it on the ASIO service queue
-    /// using asio::io_service::post().  When the handler executes, it
-    /// calls the asyncLookup() method in the server object to start a
-    /// DNS lookup.  When the lookup is complete, the server object is
-    /// scheduled to resume, again using io_service::post().
-    ///
-    /// Note that the calling object is copied into the handler object,
-    /// not referenced.  This is because, once the calling object yields
-    /// control to the handler, it falls out of scope and may disappear
-    template <typename T>
-    class AsyncLookup {
-    public:
-        AsyncLookup(T& caller) : caller_(caller) {}
-        void operator()() { caller_.asyncLookup(); }
-    private:
-        T caller_;
-    };
-
-    /// \brief Carries out a DNS lookup.
-    ///
-    /// This function calls the \c DNSLookup object specified by the
-    /// DNS server when the \c IOService was created, passing along
-    /// the details of the query and a pointer back to the current
-    /// server object.  It is called asynchronously via the AsyncLookup
-    /// handler class.
-    virtual void asyncLookup() { self_->asyncLookup(); }
-
-private:
-    DNSServer* self_;
-};
-
-
-}      // asiolink
-#endif // __ASIOLINK_DNS_SERVER_H
diff --git a/src/lib/asiolink/dns_service.cc b/src/lib/asiolink/dns_service.cc
deleted file mode 100644
index f17bb44..0000000
--- a/src/lib/asiolink/dns_service.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>             // for some IPC/network system calls
-
-#include <boost/lexical_cast.hpp>
-
-#include <config.h>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asiolink/dns_service.h>
-#include <asiolink/io_service.h>
-#include <asiolink/io_service.h>
-#include <asiolink/tcp_server.h>
-#include <asiolink/udp_server.h>
-
-#include <log/dummylog.h>
-
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-
-using isc::log::dlog;
-
-namespace asiolink {
-
-class SimpleCallback;
-class DNSLookup;
-class DNSAnswer;
-
-namespace {
-
-asio::ip::address
-convertAddr(const std::string& address) {
-    asio::error_code err;
-    asio::ip::address addr = asio::ip::address::from_string(address, err);
-    if (err) {
-        isc_throw(IOError, "Invalid IP address '" << &address << "': "
-            << err.message());
-    }
-    return (addr);
-}
-
-}
-
-
-class DNSServiceImpl {
-public:
-    DNSServiceImpl(IOService& io_service, const char& port,
-                  const asio::ip::address* v4addr,
-                  const asio::ip::address* v6addr,
-                  SimpleCallback* checkin, DNSLookup* lookup,
-                  DNSAnswer* answer);
-
-    IOService& io_service_;
-
-    typedef boost::shared_ptr<UDPServer> UDPServerPtr;
-    typedef boost::shared_ptr<TCPServer> TCPServerPtr;
-    typedef boost::shared_ptr<DNSServer> DNSServerPtr;
-    std::vector<DNSServerPtr> servers_;
-    SimpleCallback *checkin_;
-    DNSLookup *lookup_;
-    DNSAnswer *answer_;
-
-    void addServer(uint16_t port, const asio::ip::address& address) {
-        try {
-            dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
-            TCPServerPtr tcpServer(new TCPServer(io_service_.get_io_service(),
-                address, port, checkin_, lookup_, answer_));
-            (*tcpServer)();
-            servers_.push_back(tcpServer);
-            dlog(std::string("Initialize UDP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
-            UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
-                address, port, checkin_, lookup_, answer_));
-            (*udpServer)();
-            servers_.push_back(udpServer);
-        }
-        catch (const asio::system_error& err) {
-            // We need to catch and convert any ASIO level exceptions.
-            // This can happen for unavailable address, binding a privilege port
-            // without the privilege, etc.
-            isc_throw(IOError, "Failed to initialize network servers: " <<
-                      err.what());
-        }
-    }
-    void addServer(const char& port, const asio::ip::address& address) {
-        uint16_t portnum;
-        try {
-            // XXX: SunStudio with stlport4 doesn't reject some invalid
-            // representation such as "-1" by lexical_cast<uint16_t>, so
-            // we convert it into a signed integer of a larger size and perform
-            // range check ourselves.
-            const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
-            if (portnum32 < 0 || portnum32 > 65535) {
-                isc_throw(IOError, "Invalid port number '" << &port);
-            }
-            portnum = portnum32;
-        } catch (const boost::bad_lexical_cast& ex) {
-            isc_throw(IOError, "Invalid port number '" << &port << "': " <<
-                      ex.what());
-        }
-        addServer(portnum, address);
-    }
-};
-
-DNSServiceImpl::DNSServiceImpl(IOService& io_service,
-                               const char& port,
-                               const asio::ip::address* const v4addr,
-                               const asio::ip::address* const v6addr,
-                               SimpleCallback* checkin,
-                               DNSLookup* lookup,
-                               DNSAnswer* answer) :
-    io_service_(io_service),
-    checkin_(checkin),
-    lookup_(lookup),
-    answer_(answer)
-{
-
-    if (v4addr) {
-        addServer(port, *v4addr);
-    }
-    if (v6addr) {
-        addServer(port, *v6addr);
-    }
-}
-
-DNSService::DNSService(IOService& io_service,
-                       const char& port, const char& address,
-                       SimpleCallback* checkin,
-                       DNSLookup* lookup,
-                       DNSAnswer* answer) :
-    impl_(new DNSServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
-        answer)), io_service_(io_service)
-{
-    addServer(port, &address);
-}
-
-DNSService::DNSService(IOService& io_service,
-                       const char& port,
-                       const bool use_ipv4, const bool use_ipv6,
-                       SimpleCallback* checkin,
-                       DNSLookup* lookup,
-                       DNSAnswer* answer) :
-    impl_(NULL), io_service_(io_service)
-{
-    const asio::ip::address v4addr_any =
-        asio::ip::address(asio::ip::address_v4::any());
-    const asio::ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL; 
-    const asio::ip::address v6addr_any =
-        asio::ip::address(asio::ip::address_v6::any());
-    const asio::ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
-    impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
-}
-
-DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
-    DNSLookup* lookup, DNSAnswer *answer) :
-    impl_(new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
-        answer)), io_service_(io_service)
-{
-}
-
-DNSService::~DNSService() {
-    delete impl_;
-}
-
-void
-DNSService::addServer(const char& port, const std::string& address) {
-    impl_->addServer(port, convertAddr(address));
-}
-
-void
-DNSService::addServer(uint16_t port, const std::string& address) {
-    impl_->addServer(port, convertAddr(address));
-}
-
-void
-DNSService::clearServers() {
-    BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
-        s->stop();
-    }
-    impl_->servers_.clear();
-}
-
-
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/dns_service.h b/src/lib/asiolink/dns_service.h
deleted file mode 100644
index 9a3fb4c..0000000
--- a/src/lib/asiolink/dns_service.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __ASIOLINK_DNS_SERVICE_H
-#define __ASIOLINK_DNS_SERVICE_H 1
-
-#include <resolve/resolver_interface.h>
-
-#include <asiolink/io_service.h>
-
-namespace asiolink {
-
-class SimpleCallback;
-class DNSLookup;
-class DNSAnswer;
-class DNSServiceImpl;
-
-/// \brief Handle DNS Queries
-///
-/// DNSService is the service that handles DNS queries and answers with
-/// a given IOService. This class is mainly intended to hold all the
-/// logic that is shared between the authoritative and the recursive
-/// server implementations. As such, it handles asio, including config
-/// updates (through the 'Checkinprovider'), and listening sockets.
-class DNSService {
-    ///
-    /// \name Constructors and Destructor
-    ///
-    /// Note: The copy constructor and the assignment operator are
-    /// intentionally defined as private, making this class non-copyable.
-    //@{
-private:
-    DNSService(const DNSService& source);
-    DNSService& operator=(const DNSService& source);
-
-public:
-    /// \brief The constructor with a specific IP address and port on which
-    /// the services listen on.
-    ///
-    /// \param io_service The IOService to work with
-    /// \param port the port to listen on
-    /// \param address the IP address to listen on
-    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
-    /// \param lookup The lookup provider (see \c DNSLookup)
-    /// \param answer The answer provider (see \c DNSAnswer)
-    DNSService(IOService& io_service, const char& port,
-               const char& address, SimpleCallback* checkin,
-               DNSLookup* lookup, DNSAnswer* answer);
-    /// \brief The constructor with a specific port on which the services
-    /// listen on.
-    ///
-    /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
-    /// IPv4/IPv6 services will be available if and only if \c use_ipv4
-    /// or \c use_ipv6 is \c true, respectively.
-    ///
-    /// \param io_service The IOService to work with
-    /// \param port the port to listen on
-    /// \param use_ipv4 If true, listen on ipv4 'any'
-    /// \param use_ipv6 If true, listen on ipv6 'any'
-    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
-    /// \param lookup The lookup provider (see \c DNSLookup)
-    /// \param answer The answer provider (see \c DNSAnswer)
-    DNSService(IOService& io_service, const char& port,
-               const bool use_ipv4, const bool use_ipv6,
-               SimpleCallback* checkin, DNSLookup* lookup,
-               DNSAnswer* answer);
-    /// \brief The constructor without any servers.
-    ///
-    /// Use addServer() to add some servers.
-    DNSService(IOService& io_service, SimpleCallback* checkin,
-               DNSLookup* lookup, DNSAnswer* answer);
-    /// \brief The destructor.
-    ~DNSService();
-    //@}
-
-    /// \brief Add another server to the service
-    void addServer(uint16_t port, const std::string &address);
-    void addServer(const char &port, const std::string &address);
-    /// \brief Remove all servers from the service
-    void clearServers();
-
-    /// \brief Return the native \c io_service object used in this wrapper.
-    ///
-    /// This is a short term work around to support other BIND 10 modules
-    /// that share the same \c io_service with the authoritative server.
-    /// It will eventually be removed once the wrapper interface is
-    /// generalized.
-    asio::io_service& get_io_service() { return io_service_.get_io_service(); }
-
-    /// \brief Return the IO Service Object
-    ///
-    /// \return IOService object for this DNS service.
-    asiolink::IOService& getIOService() { return (io_service_);}
-
-private:
-    DNSServiceImpl* impl_;
-    IOService& io_service_;
-};
-
-}      // namespace asiolink
-#endif // __ASIOLINK_DNS_SERVICE_H
diff --git a/src/lib/asiolink/dummy_io_cb.h b/src/lib/asiolink/dummy_io_cb.h
index 0006b95..2081906 100644
--- a/src/lib/asiolink/dummy_io_cb.h
+++ b/src/lib/asiolink/dummy_io_cb.h
@@ -20,6 +20,7 @@
 #include <asio/error.hpp>
 #include <asio/error_code.hpp>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief Asynchronous I/O Completion Callback
@@ -55,5 +56,6 @@ public:
 };
 
 } // namespace asiolink
+} // namespace isc
 
 #endif // __DUMMY_IO_CB_H
diff --git a/src/lib/asiolink/interval_timer.cc b/src/lib/asiolink/interval_timer.cc
index 8efb102..0ed06eb 100644
--- a/src/lib/asiolink/interval_timer.cc
+++ b/src/lib/asiolink/interval_timer.cc
@@ -26,6 +26,7 @@
 #include <asiolink/interval_timer.h>
 #include <asiolink/io_service.h>
 
+namespace isc {
 namespace asiolink {
 
 class IntervalTimerImpl {
@@ -133,4 +134,5 @@ IntervalTimer::getInterval() const {
     return (impl_->getInterval());
 }
 
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/interval_timer.h b/src/lib/asiolink/interval_timer.h
index 6c43327..8de16cb 100644
--- a/src/lib/asiolink/interval_timer.h
+++ b/src/lib/asiolink/interval_timer.h
@@ -19,9 +19,10 @@
 
 #include <asiolink/io_service.h>
 
+namespace isc {
 namespace asiolink {
 
-struct IntervalTimerImpl;
+class IntervalTimerImpl;
 
 /// \brief The \c IntervalTimer class is a wrapper for the ASIO
 /// \c asio::deadline_timer class.
@@ -129,5 +130,6 @@ private:
     IntervalTimerImpl* impl_;
 };
 
-}      // namespace asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __ASIOLINK_INTERVAL_TIMER_H
diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc
index 70e8374..7f7a6fc 100644
--- a/src/lib/asiolink/io_address.cc
+++ b/src/lib/asiolink/io_address.cc
@@ -31,6 +31,7 @@ using asio::ip::tcp;
 
 using namespace std;
 
+namespace isc {
 namespace asiolink {
 
 // XXX: we cannot simply construct the address in the initialization list,
@@ -62,4 +63,5 @@ IOAddress::getFamily() const {
     }
 }
 
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index 53c1a7a..655b727 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -26,6 +26,7 @@
 
 #include <exceptions/exceptions.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c IOAddress class represents an IP addresses (version
@@ -119,5 +120,6 @@ private:
     asio::ip::address asio_address_;
 };
 
-}      // asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __IO_ADDRESS_H
diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h
index ac793a6..864708c 100644
--- a/src/lib/asiolink/io_asio_socket.h
+++ b/src/lib/asiolink/io_asio_socket.h
@@ -26,12 +26,12 @@
 #include <exceptions/exceptions.h>
 #include <coroutine.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 
 #include <asiolink/io_error.h>
 #include <asiolink/io_socket.h>
 
-
+namespace isc {
 namespace asiolink {
 
 /// \brief Socket not open
@@ -270,7 +270,7 @@ public:
     virtual bool processReceivedData(const void* staging, size_t length,
                                      size_t& cumulative, size_t& offset,
                                      size_t& expected,
-                                     isc::dns::OutputBufferPtr& outbuff) = 0;
+                                     isc::util::OutputBufferPtr& outbuff) = 0;
 
     /// \brief Cancel I/O On AsioSocket
     virtual void cancel() = 0;
@@ -372,7 +372,7 @@ public:
     virtual bool receiveComplete(const void* staging, size_t length,
                                  size_t& cumulative, size_t& offset,
                                  size_t& expected,
-                                 isc::dns::OutputBufferPtr& outbuff)
+                                 isc::util::OutputBufferPtr& outbuff)
     {
         return (true);
     }
@@ -395,5 +395,6 @@ private:
 };
 
 } // namespace asiolink
+} // namespace isc
 
 #endif // __IO_ASIO_SOCKET_H
diff --git a/src/lib/asiolink/io_endpoint.cc b/src/lib/asiolink/io_endpoint.cc
index e0b1a9e..63830a5 100644
--- a/src/lib/asiolink/io_endpoint.cc
+++ b/src/lib/asiolink/io_endpoint.cc
@@ -28,6 +28,7 @@
 
 using namespace std;
 
+namespace isc {
 namespace asiolink {
 
 const IOEndpoint*
@@ -57,4 +58,5 @@ IOEndpoint::operator!=(const IOEndpoint& other) const {
     return (!operator==(other));
 }
 
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_endpoint.h b/src/lib/asiolink/io_endpoint.h
index d21da96..756fa3b 100644
--- a/src/lib/asiolink/io_endpoint.h
+++ b/src/lib/asiolink/io_endpoint.h
@@ -26,6 +26,7 @@
 #include <exceptions/exceptions.h>
 #include <asiolink/io_address.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c IOEndpoint class is an abstract base class to represent
@@ -117,5 +118,6 @@ public:
                                     const unsigned short port);
 };
 
-}      // asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __IO_ENDPOINT_H
diff --git a/src/lib/asiolink/io_error.h b/src/lib/asiolink/io_error.h
index 2869e0b..c19d91c 100644
--- a/src/lib/asiolink/io_error.h
+++ b/src/lib/asiolink/io_error.h
@@ -18,6 +18,7 @@
 
 #include <exceptions/exceptions.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief An exception that is thrown if an error occurs within the IO
@@ -30,6 +31,7 @@ public:
 };
 
 
-}      // asiolink
+} // namespace asiolink
+} // namespace isc
 
 #endif // __IO_ERROR_H
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
deleted file mode 100644
index 3e61e4c..0000000
--- a/src/lib/asiolink/io_fetch.cc
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <unistd.h>             // for some IPC/network system calls
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <boost/bind.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-#include <log/logger.h>
-
-#include <asiolink/qid_gen.h>
-
-#include <asio.hpp>
-#include <asio/deadline_timer.hpp>
-
-#include <asiolink/asiodef.h>
-#include <asiolink/io_address.h>
-#include <asiolink/io_asio_socket.h>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
-#include <asiolink/io_service.h>
-#include <asiolink/tcp_endpoint.h>
-#include <asiolink/tcp_socket.h>
-#include <asiolink/udp_endpoint.h>
-#include <asiolink/udp_socket.h>
-#include <asiolink/qid_gen.h>
-
-#include <stdint.h>
-
-using namespace asio;
-using namespace isc::dns;
-using namespace isc::log;
-using namespace std;
-
-namespace asiolink {
-
-/// Use the ASIO logger
-
-isc::log::Logger logger("asiolink");
-
-/// \brief IOFetch Data
-///
-/// The data for IOFetch is held in a separate struct pointed to by a shared_ptr
-/// object.  This is because the IOFetch object will be copied often (it is used
-/// as a coroutine and passed as callback to many async_*() functions) and we
-/// want keep the same data).  Organising the data in this way keeps copying to
-/// a minimum.
-struct IOFetchData {
-
-    // The first two members are shared pointers to a base class because what is
-    // actually instantiated depends on whether the fetch is over UDP or TCP,
-    // which is not known until construction of the IOFetch.  Use of a shared
-    // pointer here is merely to ensure deletion when the data object is deleted.
-    boost::scoped_ptr<IOAsioSocket<IOFetch> > socket;
-                                             ///< Socket to use for I/O
-    boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
-    boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
-    isc::dns::Question          question;    ///< Question to be asked
-    isc::dns::OutputBufferPtr   msgbuf;      ///< Wire buffer for question
-    isc::dns::OutputBufferPtr   received;    ///< Received data put here
-    IOFetch::Callback*          callback;    ///< Called on I/O Completion
-    asio::deadline_timer        timer;       ///< Timer to measure timeouts
-    IOFetch::Protocol           protocol;    ///< Protocol being used
-    size_t                      cumulative;  ///< Cumulative received amount
-    size_t                      expected;    ///< Expected amount of data
-    size_t                      offset;      ///< Offset to receive data
-    bool                        stopped;     ///< Have we stopped running?
-    int                         timeout;     ///< Timeout in ms
-
-    // In case we need to log an error, the origin of the last asynchronous
-    // I/O is recorded.  To save time and simplify the code, this is recorded
-    // as the ID of the error message that would be generated if the I/O failed.
-    // This means that we must make sure that all possible "origins" take the
-    // same arguments in their message in the same order.
-    isc::log::MessageID         origin;     ///< Origin of last asynchronous I/O
-    uint8_t                     staging[IOFetch::STAGING_LENGTH];
-                                            ///< Temporary array for received data
-    isc::dns::qid_t             qid;         ///< The QID set in the query
-
-    /// \brief Constructor
-    ///
-    /// Just fills in the data members of the IOFetchData structure
-    ///
-    /// \param proto Either IOFetch::TCP or IOFetch::UDP.
-    /// \param service I/O Service object to handle the asynchronous
-    ///        operations.
-    /// \param query DNS question to send to the upstream server.
-    /// \param address IP address of upstream server
-    /// \param port Port to use for the query
-    /// \param buff Output buffer into which the response (in wire format)
-    ///        is written (if a response is received).
-    /// \param cb Callback object containing the callback to be called
-    ///        when we terminate.  The caller is responsible for managing this
-    ///        object and deleting it if necessary.
-    /// \param wait Timeout for the fetch (in ms).
-    ///
-    /// TODO: May need to alter constructor (see comment 4 in Trac ticket #554)
-    IOFetchData(IOFetch::Protocol proto, IOService& service,
-        const isc::dns::Question& query, const IOAddress& address,
-        uint16_t port, isc::dns::OutputBufferPtr& buff, IOFetch::Callback* cb,
-        int wait)
-        :
-        socket((proto == IOFetch::UDP) ?
-            static_cast<IOAsioSocket<IOFetch>*>(
-                new UDPSocket<IOFetch>(service)) :
-            static_cast<IOAsioSocket<IOFetch>*>(
-                new TCPSocket<IOFetch>(service))
-            ),
-        remote_snd((proto == IOFetch::UDP) ?
-            static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
-            static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
-            ),
-        remote_rcv((proto == IOFetch::UDP) ?
-            static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
-            static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
-            ),
-        question(query),
-        msgbuf(new isc::dns::OutputBuffer(512)),
-        received(buff),
-
-        callback(cb),
-        timer(service.get_io_service()),
-        protocol(proto),
-        cumulative(0),
-        expected(0),
-        offset(0),
-        stopped(false),
-        timeout(wait),
-        origin(ASIO_UNKORIGIN),
-        staging(),
-        qid(QidGenerator::getInstance().generateQid())
-    {}
-
-    // Checks if the response we received was ok;
-    // - data contains the buffer we read, as well as the address
-    // we sent to and the address we received from.
-    // length is provided by the operator() in IOFetch.
-    // Addresses must match, number of octets read must be at least
-    // 2, and the first two octets must match the qid of the message
-    // we sent.
-    bool responseOK() {
-        return (*remote_snd == *remote_rcv && cumulative >= 2 &&
-                readUint16(received->getData()) == qid);
-    }
-};
-
-/// IOFetch Constructor - just initialize the private data
-
-IOFetch::IOFetch(Protocol protocol, IOService& service,
-    const isc::dns::Question& question, const IOAddress& address, uint16_t port,
-    OutputBufferPtr& buff, Callback* cb, int wait)
-    :
-    data_(new IOFetchData(protocol, service, question, address,
-        port, buff, cb, wait))
-{
-}
-
-// Return protocol in use.
-
-IOFetch::Protocol
-IOFetch::getProtocol() const {
-    return (data_->protocol);
-}
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-
-void
-IOFetch::operator()(asio::error_code ec, size_t length) {
-
-    if (data_->stopped) {
-        return;
-    } else if (ec) {
-        logIOFailure(ec);
-        return;
-    }
-
-    CORO_REENTER (this) {
-
-        /// Generate the upstream query and render it to wire format
-        /// This is done in a different scope to allow inline variable
-        /// declarations.
-        {
-            Message msg(Message::RENDER);
-            msg.setQid(data_->qid);
-            msg.setOpcode(Opcode::QUERY());
-            msg.setRcode(Rcode::NOERROR());
-            msg.setHeaderFlag(Message::HEADERFLAG_RD);
-            msg.addQuestion(data_->question);
-            EDNSPtr edns_response(new EDNS());
-            edns_response->setDNSSECAwareness(true);
-
-            // TODO: We should make our own edns bufsize length configurable
-            edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
-            msg.setEDNS(edns_response);
-            MessageRenderer renderer(*data_->msgbuf);
-            msg.toWire(renderer);
-        }
-
-        // If we timeout, we stop, which will can cancel outstanding I/Os and
-        // shutdown everything.
-        if (data_->timeout != -1) {
-            data_->timer.expires_from_now(boost::posix_time::milliseconds(
-                data_->timeout));
-            data_->timer.async_wait(boost::bind(&IOFetch::stop, *this,
-                TIME_OUT));
-        }
-
-        // Open a connection to the target system.  For speed, if the operation
-        // is synchronous (i.e. UDP operation) we bypass the yield.
-        data_->origin = ASIO_OPENSOCK;
-        if (data_->socket->isOpenSynchronous()) {
-            data_->socket->open(data_->remote_snd.get(), *this);
-        } else {
-            CORO_YIELD data_->socket->open(data_->remote_snd.get(), *this);
-        }
-
-        do {
-            // Begin an asynchronous send, and then yield.  When the send completes,
-            // we will resume immediately after this point.
-            data_->origin = ASIO_SENDSOCK;
-            CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
-                data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
-    
-            // Now receive the response.  Since TCP may not receive the entire
-            // message in one operation, we need to loop until we have received
-            // it. (This can't be done within the asyncReceive() method because
-            // each I/O operation will be done asynchronously and between each one
-            // we need to yield ... and we *really* don't want to set up another
-            // coroutine within that method.)  So after each receive (and yield),
-            // we check if the operation is complete and if not, loop to read again.
-            //
-            // Another concession to TCP is that the amount of is contained in the
-            // first two bytes.  This leads to two problems:
-            //
-            // a) We don't want those bytes in the return buffer.
-            // b) They may not both arrive in the first I/O.
-            //
-            // So... we need to loop until we have at least two bytes, then store
-            // the expected amount of data.  Then we need to loop until we have
-            // received all the data before copying it back to the user's buffer.
-            // And we want to minimise the amount of copying...
-    
-            data_->origin = ASIO_RECVSOCK;
-            data_->cumulative = 0;          // No data yet received
-            data_->offset = 0;              // First data into start of buffer
-            data_->received->clear();       // Clear the receive buffer
-            do {
-                CORO_YIELD data_->socket->asyncReceive(data_->staging,
-                                                       static_cast<size_t>(STAGING_LENGTH),
-                                                       data_->offset,
-                                                       data_->remote_rcv.get(), *this);
-            } while (!data_->socket->processReceivedData(data_->staging, length,
-                                                         data_->cumulative, data_->offset,
-                                                         data_->expected, data_->received));
-        } while (!data_->responseOK());
-
-        // Finished with this socket, so close it.  This will not generate an
-        // I/O error, but reset the origin to unknown in case we change this.
-        data_->origin = ASIO_UNKORIGIN;
-        data_->socket->close();
-
-        /// We are done
-        stop(SUCCESS);
-    }
-}
-
-// Function that stops the coroutine sequence.  It is called either when the
-// query finishes or when the timer times out.  Either way, it sets the
-// "stopped_" flag and cancels anything that is in progress.
-//
-// As the function may be entered multiple times as things wind down, it checks
-// if the stopped_ flag is already set.  If it is, the call is a no-op.
-
-void
-IOFetch::stop(Result result) {
-
-    if (!data_->stopped) {
-
-        // Mark the fetch as stopped to prevent other completion callbacks
-        // (invoked because of the calls to cancel()) from executing the
-        // cancel calls again.
-        //
-        // In a single threaded environment, the callbacks won't be invoked
-        // until this one completes. In a multi-threaded environment, they may
-        // well be, in which case the testing (and setting) of the stopped_
-        // variable should be done inside a mutex (and the stopped_ variable
-        // declared as "volatile").
-        //
-        // The numeric arguments indicate the debug level, with the lower
-        // numbers indicating the most important information.  The relative
-        // values are somewhat arbitrary.
-        //
-        // Although Logger::debug checks the debug flag internally, doing it
-        // below before calling Logger::debug avoids the overhead of a string
-        // conversion in the common case when debug is not enabled.
-        //
-        // TODO: Update testing of stopped_ if threads are used.
-        data_->stopped = true;
-        switch (result) {
-            case TIME_OUT:
-                if (logger.isDebugEnabled(1)) {
-                    logger.debug(20, ASIO_RECVTMO,
-                                 data_->remote_snd->getAddress().toText().c_str(),
-                                 static_cast<int>(data_->remote_snd->getPort()));
-                }
-                break;
-
-            case SUCCESS:
-                if (logger.isDebugEnabled(50)) {
-                    logger.debug(30, ASIO_FETCHCOMP,
-                                 data_->remote_rcv->getAddress().toText().c_str(),
-                                 static_cast<int>(data_->remote_rcv->getPort()));
-                }
-                break;
-
-            case STOPPED:
-                // Fetch has been stopped for some other reason.  This is
-                // allowed but as it is unusual it is logged, but with a lower
-                // debug level than a timeout (which is totally normal).
-                logger.debug(1, ASIO_FETCHSTOP,
-                             data_->remote_snd->getAddress().toText().c_str(),
-                             static_cast<int>(data_->remote_snd->getPort()));
-                break;
-
-            default:
-                logger.error(ASIO_UNKRESULT, static_cast<int>(result),
-                             data_->remote_snd->getAddress().toText().c_str(),
-                             static_cast<int>(data_->remote_snd->getPort()));
-        }
-
-        // Stop requested, cancel and I/O's on the socket and shut it down,
-        // and cancel the timer.
-        data_->socket->cancel();
-        data_->socket->close();
-
-        data_->timer.cancel();
-
-        // Execute the I/O completion callback (if present).
-        if (data_->callback) {
-            (*(data_->callback))(result);
-        }
-    }
-}
-
-// Log an error - called on I/O failure
-
-void IOFetch::logIOFailure(asio::error_code ec) {
-
-    // Should only get here with a known error code.
-    assert((data_->origin == ASIO_OPENSOCK) ||
-           (data_->origin == ASIO_SENDSOCK) ||
-           (data_->origin == ASIO_RECVSOCK) ||
-           (data_->origin == ASIO_UNKORIGIN));
-
-    static const char* PROTOCOL[2] = {"TCP", "UDP"};
-    logger.error(data_->origin,
-                 ec.value(),
-                 ((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
-                     PROTOCOL[0] : PROTOCOL[1]),
-                 data_->remote_snd->getAddress().toText().c_str(),
-                 static_cast<int>(data_->remote_snd->getPort()));
-}
-
-} // namespace asiolink
-
diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiolink/io_fetch.h
deleted file mode 100644
index 0723777..0000000
--- a/src/lib/asiolink/io_fetch.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __IO_FETCH_H
-#define __IO_FETCH_H 1
-
-#include <config.h>
-
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <coroutine.h>
-
-#include <asio/error_code.hpp>
-
-#include <dns/buffer.h>
-#include <dns/question.h>
-
-namespace asiolink {
-
-// Forward declarations
-class IOAddress;
-class IOFetchData;
-class IOService;
-
-/// \brief Upstream Fetch Processing
-///
-/// IOFetch is the class used to send upstream fetches and to handle responses.
-///
-/// \param E Endpoint type to use.
-
-class IOFetch : public coroutine {
-public:
-    /// \brief Protocol to use on the fetch
-    enum Protocol {
-        UDP = 0,
-        TCP = 1
-    };
-
-    /// \brief Origin of Asynchronous I/O Call
-    ///
-    /// Indicates what initiated an asynchronous I/O call and used in deciding
-    /// what error message to output if the I/O fails.
-    enum Origin {
-        NONE = 0,           ///< No asynchronous call outstanding
-        OPEN = 1,
-        SEND = 2,
-        RECEIVE = 3,
-        CLOSE = 4
-    };
-
-    /// \brief Result of Upstream Fetch
-    ///
-    /// Note that this applies to the status of I/Os in the fetch - a fetch
-    /// that resulted in a packet being received from the server is a SUCCESS,
-    /// even if the contents of the packet indicate that some error occurred.
-    enum Result {
-        SUCCESS = 0,        ///< Success, fetch completed
-        TIME_OUT = 1,       ///< Failure, fetch timed out
-        STOPPED = 2,        ///< Control code, fetch has been stopped
-        NOTSET = 3          ///< For testing, indicates value not set
-    };
-
-    // The next enum is a "trick" to allow constants to be defined in a class
-    // declaration.
-
-    /// \brief Integer Constants
-    enum {
-        STAGING_LENGTH = 8192   ///< Size of staging buffer
-    };
-
-    /// \brief I/O Fetch Callback
-    ///
-    /// Class of callback object for when the fetch itself has completed - an
-    /// object of this class is passed to the IOFetch constructor and its
-    /// operator() method called when the fetch completes.
-    ///
-    /// Note the difference between the two operator() methods:
-    /// - IOFetch::operator() callback is called when an asynchronous I/O has
-    ///   completed.
-    /// - IOFetch::Callback::operator() is called when an upstream fetch - which
-    ///   may have involved several asynchronous I/O operations - has completed.
-    ///
-    /// This is an abstract class.
-    class Callback {
-    public:
-        /// \brief Default Constructor
-        Callback()
-        {}
-
-        /// \brief Virtual Destructor
-        virtual ~Callback()
-        {}
-
-        /// \brief Callback method
-        ///
-        /// This is the method called when the fetch completes.
-        ///
-        /// \param result Result of the fetch
-        virtual void operator()(Result result) = 0;
-    };
-
-    /// \brief Constructor.
-    ///
-    /// Creates the object that will handle the upstream fetch.
-    ///
-    /// TODO: Need to randomise the source port
-    ///
-    /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
-    /// \param service I/O Service object to handle the asynchronous
-    ///     operations.
-    /// \param question DNS question to send to the upstream server.
-    /// \param buff Output buffer into which the response (in wire format)
-    ///     is written (if a response is received).
-    /// \param cb Callback object containing the callback to be called
-    ///     when we terminate.  The caller is responsible for managing this
-    ///     object and deleting it if necessary.
-    /// \param address IP address of upstream server
-    /// \param port Port to which to connect on the upstream server
-    /// (default = 53)
-    /// \param wait Timeout for the fetch (in ms).  The default value of
-    ///     -1 indicates no timeout.
-    IOFetch(Protocol protocol, IOService& service,
-        const isc::dns::Question& question, const IOAddress& address,
-        uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
-        int wait = -1);
-
-    /// \brief Return Current Protocol
-    ///
-    /// \return Protocol associated with this IOFetch object.
-    Protocol getProtocol() const;
-
-    /// \brief Coroutine entry point
-    ///
-    /// The operator() method is the method in which the coroutine code enters
-    /// this object when an operation has been completed.
-    ///
-    /// \param ec Error code, the result of the last asynchronous I/O operation.
-    /// \param length Amount of data received on the last asynchronous read
-    void operator()(asio::error_code ec = asio::error_code(), size_t length = 0);
-
-    /// \brief Terminate query
-    ///
-    /// This method can be called at any point.  It terminates the current
-    /// query with the specified reason.
-    ///
-    /// \param reason Reason for terminating the query
-    void stop(Result reason = STOPPED);
-
-private:
-    /// \brief Log I/O Failure
-    ///
-    /// Records an I/O failure to the log file
-    ///
-    /// \param ec ASIO error code
-    void logIOFailure(asio::error_code ec);
-
-    // Member variables.  All data is in a structure pointed to by a shared
-    // pointer.  The IOFetch object is copied a number of times during its
-    // life, and only requiring a pointer to be copied reduces overhead.
-    boost::shared_ptr<IOFetchData>  data_;   ///< Private data
-
-};
-
-} // namespace asiolink
-
-#endif // __IO_FETCH_H
diff --git a/src/lib/asiolink/io_message.h b/src/lib/asiolink/io_message.h
index e857bd9..81f6da1 100644
--- a/src/lib/asiolink/io_message.h
+++ b/src/lib/asiolink/io_message.h
@@ -28,6 +28,7 @@
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_socket.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c IOMessage class encapsulates an incoming message received
@@ -96,5 +97,6 @@ private:
 };
 
 
-}      // asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __IO_MESSAGE_H
diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc
index 55fc4b3..70cc18b 100644
--- a/src/lib/asiolink/io_service.cc
+++ b/src/lib/asiolink/io_service.cc
@@ -21,6 +21,7 @@
 #include <asio.hpp>
 #include <asiolink/io_service.h>
 
+namespace isc {
 namespace asiolink {
 
 class IOServiceImpl {
@@ -95,4 +96,5 @@ IOService::get_io_service() {
     return (io_impl_->get_io_service());
 }
 
-} // namepsace asiolink
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h
index 66558b7..75aaee6 100644
--- a/src/lib/asiolink/io_service.h
+++ b/src/lib/asiolink/io_service.h
@@ -19,9 +19,10 @@ namespace asio {
     class io_service;
 }
 
+namespace isc {
 namespace asiolink {
 
-struct IOServiceImpl;
+class IOServiceImpl;
 
 /// \brief The \c IOService class is a wrapper for the ASIO \c io_service
 /// class.
@@ -73,5 +74,6 @@ private:
     IOServiceImpl* io_impl_;
 };
 
-}      // namespace asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __ASIOLINK_IO_SERVICE_H
diff --git a/src/lib/asiolink/io_socket.cc b/src/lib/asiolink/io_socket.cc
index c386ca1..e1498dc 100644
--- a/src/lib/asiolink/io_socket.cc
+++ b/src/lib/asiolink/io_socket.cc
@@ -16,8 +16,7 @@
 
 #include <asio.hpp>
 
-using namespace asio;
-
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c DummySocket class is a concrete derived class of
@@ -62,4 +61,5 @@ IOSocket::getDummyTCPSocket() {
     return (socket);
 }
 
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_socket.h b/src/lib/asiolink/io_socket.h
index bebc8b6..ab6479c 100644
--- a/src/lib/asiolink/io_socket.h
+++ b/src/lib/asiolink/io_socket.h
@@ -25,6 +25,7 @@
 
 #include <exceptions/exceptions.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c IOSocket class is an abstract base class to represent
@@ -120,5 +121,6 @@ public:
 };
 
 } // namespace asiolink
+} // namespace isc
 
 #endif // __IO_SOCKET_H
diff --git a/src/lib/asiolink/qid_gen.cc b/src/lib/asiolink/qid_gen.cc
deleted file mode 100644
index 4063b39..0000000
--- a/src/lib/asiolink/qid_gen.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#include <asiolink/qid_gen.h>
-
-#include <sys/time.h>
-
-namespace {
-    asiolink::QidGenerator qid_generator_instance;
-}
-
-namespace asiolink {
-
-QidGenerator&
-QidGenerator::getInstance() {
-    return (qid_generator_instance);
-}
-
-QidGenerator::QidGenerator() : dist_(0, 65535),
-                               vgen_(generator_, dist_)
-{
-    seed();
-}
-
-void
-QidGenerator::seed() {
-    struct timeval tv;
-    gettimeofday(&tv, 0);
-    generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec);
-}
-
-isc::dns::qid_t
-QidGenerator::generateQid() {
-    return (vgen_());
-}
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/qid_gen.h b/src/lib/asiolink/qid_gen.h
deleted file mode 100644
index a5caa17..0000000
--- a/src/lib/asiolink/qid_gen.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#ifndef __QID_GEN_H
-#define __QID_GEN_H
-
-#include <dns/message.h>
-#include <boost/random/mersenne_twister.hpp>
-#include <boost/random/uniform_int.hpp>
-#include <boost/random/variate_generator.hpp>
-
-
-namespace asiolink {
-
-/// This class generates Qids for outgoing queries
-///
-/// It is implemented as a singleton; the public way to access it
-/// is to call getInstance()->generateQid().
-///
-/// It automatically seeds it with the current time when it is first
-/// used.
-class QidGenerator {
-public:
-    /// \brief Returns the singleton instance of the QidGenerator
-    ///
-    /// Returns a reference to the singleton instance of the generator
-    static QidGenerator& getInstance();
-
-    /// \brief Default constructor
-    ///
-    /// It is recommended that getInstance is used rather than creating
-    /// separate instances of this class.
-    ///
-    /// The constructor automatically seeds the generator with the
-    /// current time.
-    QidGenerator();
-
-    /// Generate a Qid
-    ///
-    /// \return A random Qid
-    isc::dns::qid_t generateQid();
-
-    /// \brief Seeds the QidGenerator (based on the current time)
-    ///
-    /// This is automatically called by the constructor
-    void seed();
-
-private:
-    // "Mersenne Twister: A 623-dimensionally equidistributed
-    // uniform pseudo-random number generator", Makoto Matsumoto and
-    // Takuji Nishimura, ACM Transactions on Modeling and Computer
-    // Simulation: Special Issue on Uniform Random Number Generation,
-    // Vol. 8, No. 1, January 1998, pp. 3-30.
-    //
-    // mt19937 is an implementation of one of the pseudo random
-    // generators described in this paper.
-    boost::mt19937 generator_;
-
-    // For qid's we want a uniform distribution
-    boost::uniform_int<> dist_;
-
-    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
-};
-
-
-} // namespace asiolink
-
-#endif // __QID_GEN_H
diff --git a/src/lib/asiolink/simple_callback.h b/src/lib/asiolink/simple_callback.h
index ab5deaf..92093ec 100644
--- a/src/lib/asiolink/simple_callback.h
+++ b/src/lib/asiolink/simple_callback.h
@@ -17,6 +17,7 @@
 
 #include <asiolink/io_message.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c SimpleCallback class is an abstract base class for a
@@ -67,5 +68,6 @@ private:
     SimpleCallback* self_;
 };
 
-}      // namespace asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __ASIOLINK_SIMPLE_CALLBACK_H
diff --git a/src/lib/asiolink/tcp_endpoint.h b/src/lib/asiolink/tcp_endpoint.h
index 158ca4a..3e420f3 100644
--- a/src/lib/asiolink/tcp_endpoint.h
+++ b/src/lib/asiolink/tcp_endpoint.h
@@ -21,6 +21,7 @@
 
 #include <asiolink/io_endpoint.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c TCPEndpoint class is a concrete derived class of
@@ -109,5 +110,6 @@ private:
     asio::ip::tcp::endpoint& asio_endpoint_;
 };
 
-}      // namespace asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __TCP_ENDPOINT_H
diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiolink/tcp_server.cc
deleted file mode 100644
index db59551..0000000
--- a/src/lib/asiolink/tcp_server.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>             // for some IPC/network system calls
-#include <errno.h>
-
-#include <boost/shared_array.hpp>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asiolink/dummy_io_cb.h>
-#include <asiolink/tcp_endpoint.h>
-#include <asiolink/tcp_socket.h>
-#include <asiolink/tcp_server.h>
-
-
-using namespace asio;
-using asio::ip::udp;
-using asio::ip::tcp;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-
-/// The following functions implement the \c TCPServer class.
-///
-/// The constructor
-TCPServer::TCPServer(io_service& io_service,
-                     const ip::address& addr, const uint16_t port, 
-                     const SimpleCallback* checkin,
-                     const DNSLookup* lookup,
-                     const DNSAnswer* answer) :
-    io_(io_service), done_(false),
-    checkin_callback_(checkin), lookup_callback_(lookup),
-    answer_callback_(answer)
-{
-    tcp::endpoint endpoint(addr, port);
-    acceptor_.reset(new tcp::acceptor(io_service));
-    acceptor_->open(endpoint.protocol());
-    // Set v6-only (we use a separate instantiation for v4,
-    // otherwise asio will bind to both v4 and v6
-    if (addr.is_v6()) {
-        acceptor_->set_option(ip::v6_only(true));
-    }
-    acceptor_->set_option(tcp::acceptor::reuse_address(true));
-    acceptor_->bind(endpoint);
-    acceptor_->listen();
-}
-
-void
-TCPServer::operator()(error_code ec, size_t length) {
-    /// Because the coroutine reentry block is implemented as
-    /// a switch statement, inline variable declarations are not
-    /// permitted.  Certain variables used below can be declared here.
-
-    boost::array<const_buffer,2> bufs;
-    OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
-
-    CORO_REENTER (this) {
-        do {
-            /// Create a socket to listen for connections
-            socket_.reset(new tcp::socket(acceptor_->get_io_service()));
-
-            /// Wait for new connections. In the event of non-fatal error,
-            /// try again
-            do {
-                CORO_YIELD acceptor_->async_accept(*socket_, *this);
-
-                // Abort on fatal errors
-                // TODO: Log error?
-                if (ec) {
-                    using namespace asio::error;
-                    if (ec.value() != would_block && ec.value() != try_again &&
-                        ec.value() != connection_aborted &&
-                        ec.value() != interrupted) {
-                        return;
-                    }
-                }
-            } while (ec);
-
-            /// Fork the coroutine by creating a copy of this one and
-            /// scheduling it on the ASIO service queue.  The parent
-            /// will continue listening for DNS connections while the
-            /// handles the one that has just arrived.
-            CORO_FORK io_.post(TCPServer(*this));
-        } while (is_parent());
-
-        /// Instantiate the data buffer that will be used by the
-        /// asynchronous read call.
-        data_.reset(new char[MAX_LENGTH]);
-
-        /// Read the message, in two parts.  First, the message length:
-        CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
-                              TCP_MESSAGE_LENGTHSIZE), *this);
-        if (ec) {
-            socket_->close();
-            CORO_YIELD return;
-        }
-
-        /// Now read the message itself. (This is done in a different scope
-        /// to allow inline variable declarations.)
-        CORO_YIELD {
-            InputBuffer dnsbuffer(data_.get(), length);
-            uint16_t msglen = dnsbuffer.readUint16();
-            async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
-        }
-
-        if (ec) {
-            socket_->close();
-            CORO_YIELD return;
-        }
-
-
-        // Create an \c IOMessage object to store the query.
-        //
-        // (XXX: It would be good to write a factory function
-        // that would quickly generate an IOMessage object without
-        // all these calls to "new".)
-        peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
-
-        // The TCP socket class has been extended with asynchronous functions
-        // and takes as a template parameter a completion callback class.  As
-        // TCPServer does not use these extended functions (only those defined
-        // in the IOSocket base class) - but needs a TCPSocket to get hold of
-        // the underlying Boost TCP socket - DummyIOCallback is used.  This
-        // provides the appropriate operator() but is otherwise functionless.
-        iosock_.reset(new TCPSocket<DummyIOCallback>(*socket_));
-        io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
-        bytes_ = length;
-
-        // Perform any necessary operations prior to processing the incoming
-        // packet (e.g., checking for queued configuration messages).
-        //
-        // (XXX: it may be a performance issue to have this called for
-        // every single incoming packet; we may wish to throttle it somehow
-        // in the future.)
-        if (checkin_callback_ != NULL) {
-            (*checkin_callback_)(*io_message_);
-        }
-
-        // If we don't have a DNS Lookup provider, there's no point in
-        // continuing; we exit the coroutine permanently.
-        if (lookup_callback_ == NULL) {
-            socket_->close();
-            CORO_YIELD return;
-        }
-
-        // Reset or instantiate objects that will be needed by the
-        // DNS lookup and the write call.
-        respbuf_.reset(new OutputBuffer(0));
-        query_message_.reset(new Message(Message::PARSE));
-        answer_message_.reset(new Message(Message::RENDER));
-
-        // Schedule a DNS lookup, and yield.  When the lookup is
-        // finished, the coroutine will resume immediately after
-        // this point.
-        CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
-
-        // The 'done_' flag indicates whether we have an answer
-        // to send back.  If not, exit the coroutine permanently.
-        if (!done_) {
-            // TODO: should we keep the connection open for a short time
-            // to see if new requests come in?
-            socket_->close();
-            CORO_YIELD return;
-        }
-
-        if (ec) {
-            CORO_YIELD return;
-        }
-        // Call the DNS answer provider to render the answer into
-        // wire format
-        (*answer_callback_)(*io_message_, query_message_,
-                            answer_message_, respbuf_);
-
-        // Set up the response, beginning with two length bytes.
-        lenbuf.writeUint16(respbuf_->getLength());
-        bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
-        bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
-
-        // Begin an asynchronous send, and then yield.  When the
-        // send completes, we will resume immediately after this point
-        // (though we have nothing further to do, so the coroutine
-        // will simply exit at that time).
-        CORO_YIELD async_write(*socket_, bufs, *this);
-
-        // TODO: should we keep the connection open for a short time
-        // to see if new requests come in?
-        socket_->close();
-    }
-}
-
-/// Call the DNS lookup provider.  (Expected to be called by the
-/// AsyncLookup<TCPServer> handler.)
-void
-TCPServer::asyncLookup() {
-    (*lookup_callback_)(*io_message_, query_message_,
-                        answer_message_, respbuf_, this);
-}
-
-void TCPServer::stop() {
-    /// we use close instead of cancel, with the same reason
-    /// with udp server stop, refer to the udp server code
-
-    acceptor_->close();
-    // User may stop the server even when it hasn't started to
-    // run, in that that socket_ is empty
-    if (socket_) {
-        socket_->close();
-    }
-}
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off.  The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-TCPServer::resume(const bool done) {
-    done_ = done;
-    io_.post(*this);
-}
-
-} // namespace asiolink
-
diff --git a/src/lib/asiolink/tcp_server.h b/src/lib/asiolink/tcp_server.h
deleted file mode 100644
index 2fe0d37..0000000
--- a/src/lib/asiolink/tcp_server.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __TCP_SERVER_H
-#define __TCP_SERVER_H 1
-
-#ifndef ASIO_HPP
-#error "asio.hpp must be included before including this, see asiolink.h as to why"
-#endif
-
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <asiolink/asiolink.h>
-#include <coroutine.h>
-
-
-namespace asiolink {
-
-/// \brief A TCP-specific \c DNSServer object.
-///
-/// This class inherits from both \c DNSServer and from \c coroutine,
-/// defined in coroutine.h. 
-class TCPServer : public virtual DNSServer, public virtual coroutine {
-public:
-    explicit TCPServer(asio::io_service& io_service,
-                       const asio::ip::address& addr, const uint16_t port, 
-                       const SimpleCallback* checkin = NULL,
-                       const DNSLookup* lookup = NULL,
-                       const DNSAnswer* answer = NULL);
-
-    void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0);
-    void asyncLookup();
-    void stop();
-    void resume(const bool done);
-    bool hasAnswer() { return (done_); }
-    int value() { return (get_value()); }
-
-    DNSServer* clone() {
-        TCPServer* s = new TCPServer(*this);
-        return (s);
-    }
-
-private:
-    enum { MAX_LENGTH = 65535 };
-    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
-
-    // The ASIO service object
-    asio::io_service& io_;
-
-    // Class member variables which are dynamic, and changes to which
-    // need to accessible from both sides of a coroutine fork or from
-    // outside of the coroutine (i.e., from an asynchronous I/O call),
-    // should be declared here as pointers and allocated in the
-    // constructor or in the coroutine.  This allows state information
-    // to persist when an individual copy of the coroutine falls out
-    // scope while waiting for an event, *so long as* there is another
-    // object that is referencing the same data.  As a side-benefit, using
-    // pointers also reduces copy overhead for coroutine objects.
-    //
-    // Note: Currently these objects are allocated by "new" in the
-    // constructor, or in the function operator while processing a query.
-    // Repeated allocations from the heap for every incoming query is
-    // clearly a performance issue; this must be optimized in the future.
-    // The plan is to have a structure pre-allocate several "server state"
-    // objects which can be pulled off a free list and placed on an in-use
-    // list whenever a query comes in.  This will serve the dual purpose
-    // of improving performance and guaranteeing that state information
-    // will *not* be destroyed when any one instance of the coroutine
-    // falls out of scope while waiting for an event.
-    //
-    // An ASIO acceptor object to handle new connections.  Created in
-    // the constructor.
-    boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
-
-    // Socket used to for listen for queries.  Created in the
-    // constructor and stored in a shared_ptr because socket objects
-    // are not copyable.
-    boost::shared_ptr<asio::ip::tcp::socket> socket_;
-
-    // The buffer into which the response is written
-    boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
-
-    // \c IOMessage and \c Message objects to be passed to the
-    // DNS lookup and answer providers
-    boost::shared_ptr<asiolink::IOMessage> io_message_;
-    isc::dns::MessagePtr query_message_;
-    isc::dns::MessagePtr answer_message_;
-
-    // The buffer into which the query packet is written
-    boost::shared_array<char>data_;
-
-    // State information that is entirely internal to a given instance
-    // of the coroutine can be declared here.
-    size_t bytes_;
-    bool done_;
-
-    // Callback functions provided by the caller
-    const SimpleCallback* checkin_callback_;
-    const DNSLookup* lookup_callback_;
-    const DNSAnswer* answer_callback_;
-
-    boost::shared_ptr<IOEndpoint> peer_;
-    boost::shared_ptr<IOSocket> iosock_;
-};
-
-}      // namespace asiolink
-#endif // __TCP_SERVER_H
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
index e6e0863..c8876c8 100644
--- a/src/lib/asiolink/tcp_socket.h
+++ b/src/lib/asiolink/tcp_socket.h
@@ -33,14 +33,15 @@
 
 #include <config.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/io_utilities.h>
 
-#include <asiolink/asiolink_utilities.h>
 #include <asiolink/io_asio_socket.h>
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_service.h>
 #include <asiolink/tcp_endpoint.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief Buffer Too Large
@@ -155,7 +156,7 @@ public:
     virtual bool processReceivedData(const void* staging, size_t length,
                                      size_t& cumulative, size_t& offset,
                                      size_t& expected,
-                                     isc::dns::OutputBufferPtr& outbuff);
+                                     isc::util::OutputBufferPtr& outbuff);
 
     /// \brief Cancel I/O On Socket
     virtual void cancel();
@@ -185,7 +186,7 @@ private:
     // The option of sending the data in two operations, the count followed by
     // the data was discounted as that would lead to two callbacks which would
     // cause problems with the stackless coroutine code.
-    isc::dns::OutputBufferPtr   send_buffer_;   ///< Send buffer
+    isc::util::OutputBufferPtr   send_buffer_;   ///< Send buffer
 };
 
 // Constructor - caller manages socket
@@ -268,7 +269,7 @@ TCPSocket<C>::asyncSend(const void* data, size_t length,
             uint16_t count = boost::numeric_cast<uint16_t>(length);
 
             // Copy data into a buffer preceded by the count field.
-            send_buffer_.reset(new isc::dns::OutputBuffer(length + 2));
+            send_buffer_.reset(new isc::util::OutputBuffer(length + 2));
             send_buffer_->writeUint16(count);
             send_buffer_->writeData(data, length);
 
@@ -333,7 +334,7 @@ template <typename C> bool
 TCPSocket<C>::processReceivedData(const void* staging, size_t length,
                                   size_t& cumulative, size_t& offset,
                                   size_t& expected,
-                                  isc::dns::OutputBufferPtr& outbuff)
+                                  isc::util::OutputBufferPtr& outbuff)
 {
     // Point to the data in the staging buffer and note how much there is.
     const uint8_t* data = static_cast<const uint8_t*>(staging);
@@ -358,7 +359,7 @@ TCPSocket<C>::processReceivedData(const void* staging, size_t length,
         }
 
         // Have enough data to interpret the packet count, so do so now.
-        expected = readUint16(data);
+        expected = isc::util::readUint16(data);
 
         // We have two bytes less of data to process.  Point to the start of the
         // data and adjust the packet size.  Note that at this point,
@@ -412,5 +413,6 @@ TCPSocket<C>::close() {
 }
 
 } // namespace asiolink
+} // namespace isc
 
 #endif // __TCP_SOCKET_H
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index f67e547..c0d7af6 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -1,6 +1,6 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/util -I$(top_srcdir)/src/util
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 
@@ -10,34 +10,33 @@ if USE_STATIC_LINK
 AM_LDFLAGS = -static
 endif
 
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
 CLEANFILES = *.gcno *.gcda
 
 TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
-run_unittests_SOURCES += asiolink_utilities_unittest.cc
 run_unittests_SOURCES += io_address_unittest.cc
 run_unittests_SOURCES += io_endpoint_unittest.cc
-run_unittests_SOURCES += io_fetch_unittest.cc
 run_unittests_SOURCES += io_socket_unittest.cc
-run_unittests_SOURCES += io_service_unittest.cc
 run_unittests_SOURCES += interval_timer_unittest.cc
 run_unittests_SOURCES += tcp_endpoint_unittest.cc
 run_unittests_SOURCES += tcp_socket_unittest.cc
 run_unittests_SOURCES += udp_endpoint_unittest.cc
 run_unittests_SOURCES += udp_socket_unittest.cc
-run_unittests_SOURCES += dns_server_unittest.cc
-run_unittests_SOURCES += qid_gen_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 
diff --git a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc b/src/lib/asiolink/tests/asiolink_utilities_unittest.cc
deleted file mode 100644
index 51f565f..0000000
--- a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-/// \brief Test of asiolink utilties
-///
-/// Tests the fuctionality of the asiolink utilities code by comparing them
-/// with the equivalent methods in isc::dns::[Input/Output]Buffer.
-
-#include <cstddef>
-
-#include <gtest/gtest.h>
-
-#include <dns/buffer.h>
-#include <asiolink/asiolink_utilities.h>
-
-using namespace asiolink;
-using namespace isc::dns;
-
-TEST(asioutil, readUint16) {
-
-    // Reference buffer
-    uint8_t data[2];
-    isc::dns::InputBuffer buffer(data, sizeof(data));
-
-    // Avoid possible compiler warnings by only setting uint8_t variables to
-    // uint8_t values.
-    uint8_t i8 = 0;
-    uint8_t j8 = 0;
-    for (int i = 0; i < (2 << 8); ++i, ++i8) {
-        for (int j = 0; j < (2 << 8); ++j, ++j8) {
-            data[0] = i8;
-            data[1] = j8;
-            buffer.setPosition(0);
-            EXPECT_EQ(buffer.readUint16(), readUint16(data));
-        }
-    }
-}
-
-
-TEST(asioutil, writeUint16) {
-
-    // Reference buffer
-    isc::dns::OutputBuffer buffer(2);
-    uint8_t test[2];
-
-    // Avoid possible compiler warnings by only setting uint16_t variables to
-    // uint16_t values.
-    uint16_t i16 = 0;
-    for (uint32_t i = 0; i < (2 << 16); ++i, ++i16) {
-
-        // Write the reference data
-        buffer.clear();
-        buffer.writeUint16(i16);
-
-        // ... and the test data
-        writeUint16(i16, test);
-
-        // ... and compare
-        const uint8_t* ref = static_cast<const uint8_t*>(buffer.getData());
-        EXPECT_EQ(ref[0], test[0]);
-        EXPECT_EQ(ref[1], test[1]);
-    }
-}
diff --git a/src/lib/asiolink/tests/dns_server_unittest.cc b/src/lib/asiolink/tests/dns_server_unittest.cc
deleted file mode 100644
index 5b8b683..0000000
--- a/src/lib/asiolink/tests/dns_server_unittest.cc
+++ /dev/null
@@ -1,501 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <gtest/gtest.h>
-
-#include <asio.hpp>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_error.h>
-#include <asiolink/udp_server.h>
-#include <asiolink/tcp_server.h>
-#include <asiolink/dns_answer.h>
-#include <asiolink/dns_lookup.h>
-#include <string>
-#include <csignal>
-#include <unistd.h> //for alarm
-
-#include <boost/shared_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-
-
-/// The following tests focus on stop interface for udp and
-/// tcp server, there are lots of things can be shared to test
-/// both tcp and udp server, so they are in the same unittest
-
-/// The general work flow for dns server, is that wait for user
-/// query, once get one query, we will check the data is valid or
-/// not, if it passed, we will try to loop up the question, then
-/// compose the answer and finally send it back to user. The server
-/// may be stopped at any point during this porcess, so the test strategy
-/// is that we define 5 stop point and stop the server at these
-/// 5 points, to check whether stop is successful
-/// The 5 test points are :
-///   Before the server start to run
-///   After we get the query and check whether it's valid
-///   After we lookup the query
-///   After we compoisite the answer
-///   After user get the final result.
-
-/// The standard about whether we stop the server successfully or not
-/// is based on the fact that if the server is still running, the io
-/// service won't quit since it will wait for some asynchronized event for
-/// server. So if the io service block function run returns we assume
-/// that the server is stopped. To avoid stop interface failure which
-/// will block followed tests, using alarm signal to stop the blocking
-/// io service
-///
-/// The whole test context including one server and one client, and
-/// five stop checkpoints, we call them ServerStopper exclude the first
-/// stop point. Once the unittest fired, the client will send message
-/// to server, and the stopper may stop the server at the checkpoint, then
-/// we check the client get feedback or not. Since there is no DNS logic
-/// involved so the message sending between client and server is plain text
-/// And the valid checker, question lookup and answer composition are dummy.
-
-using namespace asiolink;
-using namespace asio;
-namespace {
-static const std::string server_ip = "127.0.0.1";
-const int server_port = 5553;
-//message client send to udp server, which isn't dns package
-//just for simple testing
-static const std::string query_message("BIND10 is awesome");
-
-// \brief provide capacity to derived class the ability
-// to stop DNSServer at certern point
-class ServerStopper {
-    public:
-        ServerStopper() : server_to_stop_(NULL) {}
-        virtual ~ServerStopper(){}
-
-        void setServerToStop(DNSServer* server) {
-            server_to_stop_ = server;
-        }
-
-        void stopServer() const {
-            if (server_to_stop_) {
-                server_to_stop_->stop();
-            }
-        }
-
-    private:
-        DNSServer* server_to_stop_;
-};
-
-// \brief no check logic at all,just provide a checkpoint to stop the server
-class DummyChecker : public SimpleCallback, public ServerStopper {
-    public:
-        virtual void operator()(const IOMessage&) const {
-            stopServer();
-        }
-};
-
-// \brief no lookup logic at all,just provide a checkpoint to stop the server
-class DummyLookup : public DNSLookup, public ServerStopper {
-    public:
-        void operator()(const IOMessage& io_message,
-                isc::dns::MessagePtr message,
-                isc::dns::MessagePtr answer_message,
-                isc::dns::OutputBufferPtr buffer,
-                DNSServer* server) const {
-            stopServer();
-            server->resume(true);
-        }
-};
-
-// \brief copy the data received from user to the answer part
-//  provide checkpoint to stop server
-class SimpleAnswer : public DNSAnswer, public ServerStopper {
-    public:
-        void operator()(const IOMessage& message,
-                isc::dns::MessagePtr query_message,
-                isc::dns::MessagePtr answer_message,
-                isc::dns::OutputBufferPtr buffer) const
-        {
-            //copy what we get from user
-            buffer->writeData(message.getData(), message.getDataSize());
-            stopServer();
-        }
-
-};
-
-// \brief simple client, send one string to server and wait for response
-//  in case, server stopped and client cann't get response, there is a timer wait
-//  for specified seconds (the value is just a estimate since server process logic is quite
-//  simple, and all the intercommunication is local) then cancel the waiting.
-class SimpleClient : public ServerStopper {
-    public:
-    static const size_t MAX_DATA_LEN = 256;
-    SimpleClient(asio::io_service& service,
-                 unsigned int wait_server_time_out)
-    {
-        wait_for_response_timer_.reset(new deadline_timer(service));
-        received_data_ = new char[MAX_DATA_LEN];
-        received_data_len_ = 0;
-        wait_server_time_out_ = wait_server_time_out;
-    }
-
-    virtual ~SimpleClient() {
-        delete [] received_data_;
-    }
-
-    void setGetFeedbackCallback(boost::function<void()>& func) {
-        get_response_call_back_ = func;
-    }
-
-    virtual void sendDataThenWaitForFeedback(const std::string& data)  = 0;
-    virtual std::string getReceivedData() const = 0;
-
-    void startTimer() {
-        wait_for_response_timer_->cancel();
-        wait_for_response_timer_->
-            expires_from_now(boost::posix_time::
-                             seconds(wait_server_time_out_));
-        wait_for_response_timer_->
-            async_wait(boost::bind(&SimpleClient::stopWaitingforResponse,
-                                   this));
-    }
-
-    void cancelTimer() { wait_for_response_timer_->cancel(); }
-
-    void getResponseCallBack(const asio::error_code& error, size_t
-                             received_bytes)
-    {
-        cancelTimer();
-        if (!error)
-            received_data_len_ = received_bytes;
-        if (!get_response_call_back_.empty()) {
-            get_response_call_back_();
-        }
-        stopServer();
-    }
-
-
-    protected:
-    virtual void stopWaitingforResponse() = 0;
-
-    boost::shared_ptr<deadline_timer> wait_for_response_timer_;
-    char* received_data_;
-    size_t received_data_len_;
-    boost::function<void()> get_response_call_back_;
-    unsigned int wait_server_time_out_;
-};
-
-
-
-class UDPClient : public SimpleClient {
-    public:
-    //After 1 seconds without feedback client will stop wait
-    static const unsigned int server_time_out = 1;
-
-    UDPClient(asio::io_service& service, const ip::udp::endpoint& server) :
-        SimpleClient(service, server_time_out)
-    {
-        server_ = server;
-        socket_.reset(new ip::udp::socket(service));
-        socket_->open(ip::udp::v4());
-    }
-
-
-    void sendDataThenWaitForFeedback(const std::string& data) {
-        received_data_len_ = 0;
-        socket_->send_to(buffer(data.c_str(), data.size() + 1), server_);
-        socket_->async_receive_from(buffer(received_data_, MAX_DATA_LEN),
-                                    received_from_,
-                                    boost::bind(&SimpleClient::
-                                                getResponseCallBack, this, _1,
-                                                _2));
-        startTimer();
-    }
-
-    virtual std::string getReceivedData() const {
-        return (received_data_len_ == 0 ? std::string("") :
-                                std::string(received_data_));
-    }
-
-    private:
-    void stopWaitingforResponse() {
-        socket_->close();
-    }
-
-    boost::shared_ptr<ip::udp::socket> socket_;
-    ip::udp::endpoint server_;
-    ip::udp::endpoint received_from_;
-};
-
-
-class TCPClient : public SimpleClient {
-    public:
-    // after 2 seconds without feedback client will stop wait,
-    // this includes connect, send message and recevice message
-    static const unsigned int server_time_out = 2;
-    TCPClient(asio::io_service& service, const ip::tcp::endpoint& server)
-        : SimpleClient(service, server_time_out)
-    {
-        server_ = server;
-        socket_.reset(new ip::tcp::socket(service));
-        socket_->open(ip::tcp::v4());
-    }
-
-
-    virtual void sendDataThenWaitForFeedback(const std::string &data) {
-        received_data_len_ = 0;
-        data_to_send_ = data;
-        data_to_send_len_ = data.size() + 1;
-        socket_->async_connect(server_, boost::bind(&TCPClient::connectHandler,
-                                                    this, _1));
-        startTimer();
-    }
-
-    virtual std::string getReceivedData() const {
-        return (received_data_len_ == 0 ? std::string("") :
-                                std::string(received_data_ + 2));
-    }
-
-    private:
-    void stopWaitingforResponse() {
-        socket_->close();
-    }
-
-    void connectHandler(const asio::error_code& error) {
-        if (!error) {
-            data_to_send_len_ = htons(data_to_send_len_);
-            socket_->async_send(buffer(&data_to_send_len_, 2),
-                                boost::bind(&TCPClient::sendMessageBodyHandler,
-                                            this, _1, _2));
-        }
-    }
-
-    void sendMessageBodyHandler(const asio::error_code& error,
-                                size_t send_bytes)
-    {
-        if (!error && send_bytes == 2) {
-            socket_->async_send(buffer(data_to_send_.c_str(),
-                                       data_to_send_.size() + 1),
-                    boost::bind(&TCPClient::finishSendHandler, this, _1, _2));
-        }
-    }
-
-    void finishSendHandler(const asio::error_code& error, size_t send_bytes) {
-        if (!error && send_bytes == data_to_send_.size() + 1) {
-            socket_->async_receive(buffer(received_data_, MAX_DATA_LEN),
-                   boost::bind(&SimpleClient::getResponseCallBack, this, _1,
-                               _2));
-        }
-    }
-
-    boost::shared_ptr<ip::tcp::socket> socket_;
-    ip::tcp::endpoint server_;
-    std::string data_to_send_;
-    uint16_t data_to_send_len_;
-};
-
-
-
-// \brief provide the context which including two client and
-// two server, udp client will only communicate with udp server, same for tcp client
-class DNSServerTest : public::testing::Test {
-    protected:
-        void SetUp() {
-            ip::address server_address = ip::address::from_string(server_ip);
-            checker_ = new DummyChecker();
-            lookup_ = new DummyLookup();
-            answer_ = new SimpleAnswer();
-            udp_server_ = new UDPServer(service, server_address, server_port,
-                    checker_, lookup_, answer_);
-            udp_client_ = new UDPClient(service,
-                    ip::udp::endpoint(server_address,
-                        server_port));
-            tcp_server_ = new TCPServer(service, server_address, server_port,
-                    checker_, lookup_, answer_);
-            tcp_client_ = new TCPClient(service,
-                    ip::tcp::endpoint(server_address,
-                        server_port));
-        }
-
-
-        void TearDown() {
-            udp_server_->stop();
-            tcp_server_->stop();
-            delete checker_;
-            delete lookup_;
-            delete answer_;
-            delete udp_server_;
-            delete udp_client_;
-            delete tcp_server_;
-            delete tcp_client_;
-        }
-
-
-        void testStopServerByStopper(DNSServer* server, SimpleClient* client,
-                ServerStopper* stopper)
-        {
-            static const unsigned int io_service_time_out = 5;
-            io_service_is_time_out = false;
-            stopper->setServerToStop(server);
-            (*server)();
-            client->sendDataThenWaitForFeedback(query_message);
-            // Since thread hasn't been introduced into the tool box, using signal
-            // to make sure run function will eventually return even server stop
-            // failed
-            void (*prev_handler)(int) = std::signal(SIGALRM, DNSServerTest::stopIOService);
-            alarm(io_service_time_out);
-            service.run();
-            service.reset();
-            //cancel scheduled alarm
-            alarm(0);
-            std::signal(SIGALRM, prev_handler);
-        }
-
-
-        static void stopIOService(int _no_use_parameter) {
-            io_service_is_time_out = true;
-            service.stop();
-        }
-
-        bool serverStopSucceed() const {
-            return (!io_service_is_time_out);
-        }
-
-        DummyChecker* checker_;
-        DummyLookup*  lookup_;
-        SimpleAnswer* answer_;
-        UDPServer*    udp_server_;
-        UDPClient*    udp_client_;
-        TCPClient*    tcp_client_;
-        TCPServer*    tcp_server_;
-
-        // To access them in signal handle function, the following
-        // variables have to be static.
-        static asio::io_service service;
-        static bool io_service_is_time_out;
-};
-
-bool DNSServerTest::io_service_is_time_out = false;
-asio::io_service DNSServerTest::service;
-
-// Test whether server stopped successfully after client get response
-// client will send query and start to wait for response, once client
-// get response, udp server will be stopped, the io service won't quit
-// if udp server doesn't stop successfully.
-TEST_F(DNSServerTest, stopUDPServerAfterOneQuery) {
-    testStopServerByStopper(udp_server_, udp_client_, udp_client_);
-    EXPECT_EQ(query_message, udp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully before server start to serve
-TEST_F(DNSServerTest, stopUDPServerBeforeItStartServing) {
-    udp_server_->stop();
-    testStopServerByStopper(udp_server_, udp_client_, udp_client_);
-    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether udp server stopped successfully during message check
-TEST_F(DNSServerTest, stopUDPServerDuringMessageCheck) {
-    testStopServerByStopper(udp_server_, udp_client_, checker_);
-    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully during query lookup
-TEST_F(DNSServerTest, stopUDPServerDuringQueryLookup) {
-    testStopServerByStopper(udp_server_, udp_client_, lookup_);
-    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully during composing answer
-TEST_F(DNSServerTest, stopUDPServerDuringPrepareAnswer) {
-    testStopServerByStopper(udp_server_, udp_client_, answer_);
-    EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-static void stopServerManyTimes(DNSServer *server, unsigned int times) {
-    for (int i = 0; i < times; ++i) {
-        server->stop();
-    }
-}
-
-// Test whether udp server stop interface can be invoked several times without
-// throw any exception
-TEST_F(DNSServerTest, stopUDPServeMoreThanOnce) {
-    ASSERT_NO_THROW({
-        boost::function<void()> stop_server_3_times
-            = boost::bind(stopServerManyTimes, udp_server_, 3);
-        udp_client_->setGetFeedbackCallback(stop_server_3_times);
-        testStopServerByStopper(udp_server_, udp_client_, udp_client_);
-        EXPECT_EQ(query_message, udp_client_->getReceivedData());
-    });
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-
-TEST_F(DNSServerTest, stopTCPServerAfterOneQuery) {
-    testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
-    EXPECT_EQ(query_message, tcp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stopped successfully before server start to serve
-TEST_F(DNSServerTest, stopTCPServerBeforeItStartServing) {
-    tcp_server_->stop();
-    testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
-    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stopped successfully during message check
-TEST_F(DNSServerTest, stopTCPServerDuringMessageCheck) {
-    testStopServerByStopper(tcp_server_, tcp_client_, checker_);
-    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether tcp server stopped successfully during query lookup
-TEST_F(DNSServerTest, stopTCPServerDuringQueryLookup) {
-    testStopServerByStopper(tcp_server_, tcp_client_, lookup_);
-    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether tcp server stopped successfully during composing answer
-TEST_F(DNSServerTest, stopTCPServerDuringPrepareAnswer) {
-    testStopServerByStopper(tcp_server_, tcp_client_, answer_);
-    EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stop interface can be invoked several times without
-// throw any exception
-TEST_F(DNSServerTest, stopTCPServeMoreThanOnce) {
-    ASSERT_NO_THROW({
-        boost::function<void()> stop_server_3_times
-            = boost::bind(stopServerManyTimes, tcp_server_, 3);
-        tcp_client_->setGetFeedbackCallback(stop_server_3_times);
-        testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
-        EXPECT_EQ(query_message, tcp_client_->getReceivedData());
-    });
-    EXPECT_TRUE(serverStopSucceed());
-}
-
-}
diff --git a/src/lib/asiolink/tests/interval_timer_unittest.cc b/src/lib/asiolink/tests/interval_timer_unittest.cc
index 7e0e7bc..8e8ef81 100644
--- a/src/lib/asiolink/tests/interval_timer_unittest.cc
+++ b/src/lib/asiolink/tests/interval_timer_unittest.cc
@@ -18,7 +18,7 @@
 #include <asio.hpp>
 #include <asiolink/asiolink.h>
 
-#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 namespace {
 // TODO: Consider this margin
@@ -26,7 +26,7 @@ const boost::posix_time::time_duration TIMER_MARGIN_MSEC =
     boost::posix_time::milliseconds(50);
 }
 
-using namespace asiolink;
+using namespace isc::asiolink;
 
 // This fixture is for testing IntervalTimer. Some callback functors are 
 // registered as callback function of the timer to test if they are called
@@ -166,16 +166,22 @@ TEST_F(IntervalTimerTest, startIntervalTimer) {
     io_service_.run();
     // reaches here after timer expired
     // delta: difference between elapsed time and 100 milliseconds.
+    boost::posix_time::time_duration test_runtime =
+        boost::posix_time::microsec_clock::universal_time() - start;
+    EXPECT_FALSE(test_runtime.is_negative()) << 
+                 "test duration " << test_runtime << 
+                 " negative - clock skew?";
     boost::posix_time::time_duration delta =
-        (boost::posix_time::microsec_clock::universal_time() - start)
-         - boost::posix_time::millisec(100);
+        test_runtime - boost::posix_time::milliseconds(100);
     if (delta.is_negative()) {
         delta.invert_sign();
     }
     // expect TimerCallBack is called; timer_called_ is true
     EXPECT_TRUE(timer_called_);
     // expect interval is 100 milliseconds +/- TIMER_MARGIN_MSEC.
-    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC) << 
+                "delta " << delta.total_milliseconds() << "msec " <<
+                ">= " << TIMER_MARGIN_MSEC.total_milliseconds();
 }
 
 TEST_F(IntervalTimerTest, destructIntervalTimer) {
@@ -283,14 +289,20 @@ TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
     //   + 400 milliseconds for TimerCallBackOverwriter (stop)
     //   = 800 milliseconds.
     // delta: difference between elapsed time and 400 + 100 milliseconds
+    boost::posix_time::time_duration test_runtime =
+        boost::posix_time::microsec_clock::universal_time() - start;
+    EXPECT_FALSE(test_runtime.is_negative()) << 
+                 "test duration " << test_runtime << 
+                 " negative - clock skew?";
     boost::posix_time::time_duration delta =
-        (boost::posix_time::microsec_clock::universal_time() - start)
-         - boost::posix_time::millisec(400 + 100);
+        test_runtime - boost::posix_time::milliseconds(400 + 100);
     if (delta.is_negative()) {
         delta.invert_sign();
     }
     // expect callback function is updated: TimerCallBack is called
     EXPECT_TRUE(timer_called_);
     // expect interval is updated
-    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC) << 
+                "delta " << delta.total_milliseconds() << " msec " <<
+                ">= " << TIMER_MARGIN_MSEC.total_milliseconds();
 }
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc
index 894f143..18b181e 100644
--- a/src/lib/asiolink/tests/io_address_unittest.cc
+++ b/src/lib/asiolink/tests/io_address_unittest.cc
@@ -18,7 +18,7 @@
 #include <asiolink/io_error.h>
 #include <asiolink/io_address.h>
 
-using namespace asiolink;
+using namespace isc::asiolink;
 
 TEST(IOAddressTest, fromText) {
     IOAddress io_address_v4("192.0.2.1");
diff --git a/src/lib/asiolink/tests/io_endpoint_unittest.cc b/src/lib/asiolink/tests/io_endpoint_unittest.cc
index 5170f7d..ce21fde 100644
--- a/src/lib/asiolink/tests/io_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/io_endpoint_unittest.cc
@@ -18,7 +18,7 @@
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_error.h>
 
-using namespace asiolink;
+using namespace isc::asiolink;
 
 TEST(IOEndpointTest, createUDPv4) {
     const IOEndpoint* ep;
diff --git a/src/lib/asiolink/tests/io_fetch_unittest.cc b/src/lib/asiolink/tests/io_fetch_unittest.cc
deleted file mode 100644
index 2b258b8..0000000
--- a/src/lib/asiolink/tests/io_fetch_unittest.cc
+++ /dev/null
@@ -1,723 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <algorithm>
-#include <cstdlib>
-#include <string>
-#include <iostream>
-#include <iomanip>
-#include <iterator>
-#include <vector>
-
-#include <gtest/gtest.h>
-#include <boost/bind.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <asio.hpp>
-
-#include <dns/buffer.h>
-#include <dns/question.h>
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <dns/opcode.h>
-#include <dns/name.h>
-#include <dns/rcode.h>
-
-#include <asiolink/asiolink_utilities.h>
-#include <asiolink/io_address.h>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
-#include <asiolink/io_service.h>
-
-using namespace asio;
-using namespace isc::dns;
-using namespace asio::ip;
-using namespace std;
-
-namespace asiolink {
-
-const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
-const uint16_t TEST_PORT(5301);
-const int SEND_INTERVAL = 250;      // Interval in ms between TCP sends
-const size_t MAX_SIZE = 64 * 1024;  // Should be able to take 64kB
-
-// The tests are complex, so debug output has been left in (although disabled).
-// Set this to true to enable it.
-const bool DEBUG = false;
-
-/// \brief Test fixture for the asiolink::IOFetch.
-class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback
-{
-public:
-    IOService       service_;       ///< Service to run the query
-    IOFetch::Result expected_;      ///< Expected result of the callback
-    bool            run_;           ///< Did the callback run already?
-    Question        question_;      ///< What to ask
-    OutputBufferPtr result_buff_;   ///< Buffer to hold result of fetch
-    OutputBufferPtr msgbuf_;        ///< Buffer corresponding to known question
-    IOFetch         udp_fetch_;     ///< For UDP query test
-    IOFetch         tcp_fetch_;     ///< For TCP query test
-    IOFetch::Protocol protocol_;    ///< Protocol being tested
-    size_t          cumulative_;    ///< Cumulative data received by "server".
-    deadline_timer  timer_;         ///< Timer to measure timeouts
-
-    // The next member is the buffer in which the "server" (implemented by the
-    // response handler methods in this class) receives the question sent by the
-    // fetch object.
-    uint8_t         receive_buffer_[MAX_SIZE]; ///< Server receive buffer
-    OutputBufferPtr expected_buffer_;          ///< Data we expect to receive
-    vector<uint8_t> send_buffer_;           ///< Server send buffer
-    uint16_t        send_cumulative_;       ///< Data sent so far
-
-    // Other data.
-    string          return_data_;           ///< Data returned by server
-    string          test_data_;             ///< Large string - here for convenience
-    bool            debug_;                 ///< true to enable debug output
-    size_t          tcp_send_size_;         ///< Max size of TCP send
-    uint8_t         qid_0;                  ///< First octet of qid
-    uint8_t         qid_1;                  ///< Second octet of qid
-
-    bool            tcp_short_send_;        ///< If set to true, we do not send
-                                            ///  all data in the tcp response
-
-    /// \brief Constructor
-    IOFetchTest() :
-        service_(),
-        expected_(IOFetch::NOTSET),
-        run_(false),
-        question_(Name("example.net"), RRClass::IN(), RRType::A()),
-        result_buff_(new OutputBuffer(512)),
-        msgbuf_(new OutputBuffer(512)),
-        udp_fetch_(IOFetch::UDP, service_, question_, IOAddress(TEST_HOST),
-            TEST_PORT, result_buff_, this, 100),
-        tcp_fetch_(IOFetch::TCP, service_, question_, IOAddress(TEST_HOST),
-            TEST_PORT, result_buff_, this, (16 * SEND_INTERVAL)),
-                                        // Timeout interval chosen to ensure no timeout
-        protocol_(IOFetch::TCP),        // for initialization - will be changed
-        cumulative_(0),
-        timer_(service_.get_io_service()),
-        receive_buffer_(),
-        expected_buffer_(new OutputBuffer(512)),
-        send_buffer_(),
-        send_cumulative_(0),
-        return_data_(""),
-        test_data_(""),
-        debug_(DEBUG),
-        tcp_send_size_(0),
-        qid_0(0),
-        qid_1(0),
-        tcp_short_send_(false)
-    {
-        // Construct the data buffer for question we expect to receive.
-        Message msg(Message::RENDER);
-        msg.setQid(0);
-        msg.setOpcode(Opcode::QUERY());
-        msg.setRcode(Rcode::NOERROR());
-        msg.setHeaderFlag(Message::HEADERFLAG_RD);
-        msg.addQuestion(question_);
-        MessageRenderer renderer(*msgbuf_);
-        msg.toWire(renderer);
-        MessageRenderer renderer2(*expected_buffer_);
-        msg.toWire(renderer2);
-
-        // Initialize the test data to be returned: tests will return a
-        // substring of this data. (It's convenient to have this as a member of
-        // the class.)
-        //
-        // We could initialize the data with a single character, but as an added
-        // check we'll make ssre that it has some structure.
-
-        test_data_.clear();
-        test_data_.reserve(MAX_SIZE);
-        while (test_data_.size() < MAX_SIZE) {
-            test_data_ += "A message to be returned to the client that has "
-                          "some sort of structure.";
-        }
-    }
-
-    /// \brief UDP Response handler (the "remote UDP DNS server")
-    ///
-    /// When IOFetch is sending data, this response handler emulates the remote
-    /// DNS server.  It checks that the data sent by the IOFetch object is what
-    /// was expected to have been sent, then sends back a known buffer of data.
-    ///
-    /// \param remote Endpoint to which to send the answer
-    /// \param socket Socket to use to send the answer
-    /// \param ec ASIO error code, completion code of asynchronous I/O issued
-    ///        by the "server" to receive data.
-    /// \param bad_qid If set to true, the QID in the response will be mangled
-    /// \param second_send If set to true, (and bad_qid is too), after the
-    ///        mangled qid response has been sent, a second packet will be
-    ///        sent with the correct QID.
-    /// \param length Amount of data received.
-    void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket,
-                    error_code ec = error_code(), size_t length = 0,
-                    bool bad_qid = false, bool second_send = false) {
-        if (debug_) {
-            cout << "udpReceiveHandler(): error = " << ec.value() <<
-                    ", length = " << length << endl;
-        }
-
-        // The QID in the incoming data is random so set it to 0 for the
-        // data comparison check. (It is set to 0 in the buffer containing
-        // the expected data.)
-        qid_0 = receive_buffer_[0];
-        qid_1 = receive_buffer_[1];
-        receive_buffer_[0] = receive_buffer_[1] = 0;
-
-        // Check that length of the received data and the expected data are
-        // identical, then check that the data is identical as well.
-        EXPECT_EQ(msgbuf_->getLength(), length);
-        EXPECT_TRUE(equal(receive_buffer_, (receive_buffer_ + length - 1),
-        static_cast<const uint8_t*>(msgbuf_->getData())));
-
-        // Return a message back to the IOFetch object.
-        if (!bad_qid) {
-            expected_buffer_->writeUint8At(qid_0, 0);
-            expected_buffer_->writeUint8At(qid_1, 1);
-        } else {
-            expected_buffer_->writeUint8At(qid_0 + 1, 0);
-            expected_buffer_->writeUint8At(qid_1 + 1, 1);
-        }
-        socket->send_to(asio::buffer(expected_buffer_->getData(), length), *remote);
-
-        if (bad_qid && second_send) {
-            expected_buffer_->writeUint8At(qid_0, 0);
-            expected_buffer_->writeUint8At(qid_1, 1);
-            socket->send_to(asio::buffer(expected_buffer_->getData(),
-                            expected_buffer_->getLength()), *remote);
-        }
-        if (debug_) {
-            cout << "udpReceiveHandler(): returned " << expected_buffer_->getLength() <<
-                    " bytes to the client" << endl;
-        }
-    }
-
-    /// \brief Completion Handler for accepting TCP data
-    ///
-    /// Called when the remote system connects to the "server".  It issues
-    /// an asynchronous read on the socket to read data.
-    ///
-    /// \param socket Socket on which data will be received
-    /// \param ec Boost error code, value should be zero.
-    void tcpAcceptHandler(tcp::socket* socket, error_code ec = error_code())
-    {
-        if (debug_) {
-            cout << "tcpAcceptHandler(): error = " << ec.value() << endl;
-        }
-
-        // Expect that the accept completed without a problem.
-        EXPECT_EQ(0, ec.value());
-
-        // Work out the maximum size of data we can send over it when we
-        // respond, then subtract 1kB or so for safety.
-        tcp::socket::send_buffer_size send_size;
-        socket->get_option(send_size);
-        if (send_size.value() < (2 * 1024)) {
-            FAIL() << "TCP send size is less than 2kB";
-        } else {
-            tcp_send_size_ = send_size.value() - 1024;
-            if (debug_) {
-                cout << "tcpacceptHandler(): will use send size = " << tcp_send_size_ << endl;
-            }
-        }
-
-        // Initiate a read on the socket.
-        cumulative_ = 0;
-        socket->async_receive(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
-            boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
-    }
-
-    /// \brief Completion handler for receiving TCP data
-    ///
-    /// When IOFetch is sending data, this response handler emulates the remote
-    /// DNS server.  It that all the data sent by the IOFetch object has been
-    /// received, issuing another read if not.  If the data is complete, it is
-    /// compared to what is expected and a reply sent back to the IOFetch.
-    ///
-    /// \param socket Socket to use to send the answer
-    /// \param ec ASIO error code, completion code of asynchronous I/O issued
-    ///        by the "server" to receive data.
-    /// \param length Amount of data received.
-    void tcpReceiveHandler(tcp::socket* socket, error_code ec = error_code(),
-                           size_t length = 0)
-    {
-        if (debug_) {
-            cout << "tcpReceiveHandler(): error = " << ec.value() <<
-                    ", length = " << length << endl;
-        }
-        // Expect that the receive completed without a problem.
-        EXPECT_EQ(0, ec.value());
-
-        // If we haven't received all the data, issue another read.
-        cumulative_ += length;
-        bool complete = false;
-        if (cumulative_ > 2) {
-            uint16_t dns_length = readUint16(receive_buffer_);
-            complete = ((dns_length + 2) == cumulative_);
-        }
-
-        if (!complete) {
-            socket->async_receive(asio::buffer((receive_buffer_ + cumulative_),
-                (sizeof(receive_buffer_) - cumulative_)),
-                boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
-            return;
-        }
-
-        // Check that length of the DNS message received is that expected, then
-        // compare buffers, zeroing the QID in the received buffer to match
-        // that set in our expected question.  Note that due to the length
-        // field the QID in the received buffer is in the third and fourth
-        // bytes.
-        EXPECT_EQ(msgbuf_->getLength() + 2, cumulative_);
-        qid_0 = receive_buffer_[2];
-        qid_1 = receive_buffer_[3];
-
-        receive_buffer_[2] = receive_buffer_[3] = 0;
-        EXPECT_TRUE(equal((receive_buffer_ + 2), (receive_buffer_ + cumulative_ - 2),
-            static_cast<const uint8_t*>(msgbuf_->getData())));
-
-        // ... and return a message back.  This has to be preceded by a two-byte
-        // count field.
-
-        send_buffer_.clear();
-        send_buffer_.push_back(0);
-        send_buffer_.push_back(0);
-        writeUint16(return_data_.size(), &send_buffer_[0]);
-        copy(return_data_.begin(), return_data_.end(), back_inserter(send_buffer_));
-        if (return_data_.size() >= 2) {
-            send_buffer_[2] = qid_0;
-            send_buffer_[3] = qid_1;
-        }
-        // Send the data.  This is done in multiple writes with a delay between
-        // each to check that the reassembly of TCP packets from fragments works.
-        send_cumulative_ = 0;
-        tcpSendData(socket);
-    }
-
-    /// \brief Sent Data Over TCP
-    ///
-    /// Send the TCP data back to the IOFetch object.  The data is sent in
-    /// three chunks - two of 16 bytes and the remainder, with a 250ms gap
-    /// between each. (Amounts of data smaller than one 32 bytes are sent in
-    /// one or two packets.)
-    ///
-    /// \param socket Socket over which send should take place
-    void tcpSendData(tcp::socket* socket) {
-        if (debug_) {
-            cout << "tcpSendData()" << endl;
-        }
-
-        // Decide what to send based on the cumulative count.  At most we'll do
-        // two chunks of 16 bytes (with a 250ms gap between) and then the
-        // remainder.
-        uint8_t* send_ptr = &send_buffer_[send_cumulative_];
-                                    // Pointer to data to send
-        size_t amount = 16;         // Amount of data to send
-        if (send_cumulative_ < (2 * amount)) {
-            
-            // First or second time through, send at most 16 bytes
-            amount = min(amount, (send_buffer_.size() - send_cumulative_));
-
-        } else {
-
-            // For all subsequent times, send the remainder, maximised to
-            // whatever we have chosen for the maximum send size.
-            amount = min(tcp_send_size_,
-                        (send_buffer_.size() - send_cumulative_));
-        }
-
-        // This is for the short send test; reduce the actual amount of
-        // data we send
-        if (tcp_short_send_) {
-            if (debug_) {
-                cout << "tcpSendData(): sending incomplete data (" <<
-                        (amount - 1) << " of " << amount << " bytes)" <<
-                        endl;
-            }
-            --amount;
-        } else {
-            if (debug_) {
-                cout << "tcpSendData(): sending " << amount << " bytes" << endl;
-            }
-        }
-
-        // ... and send it.  The amount sent is also passed as the first
-        // argument of the send callback, as a check.
-        socket->async_send(asio::buffer(send_ptr, amount),
-                           boost::bind(&IOFetchTest::tcpSendHandler, this,
-                                       amount, socket, _1, _2));
-    }
-
-    /// \brief Completion Handler for Sending TCP data
-    ///
-    /// Called when the asynchronous send of data back to the IOFetch object
-    /// by the TCP "server" in this class has completed.  (This send has to
-    /// be asynchronous because control needs to return to the caller in order
-    /// for the IOService "run()" method to be called to run the handlers.)
-    ///
-    /// If not all the data has been sent, a short delay is instigated (during
-    /// which control returns to the IOService).  This should force the queued
-    /// data to actually be sent and the IOFetch receive handler to be triggered.
-    /// In this way, the ability of IOFetch to handle fragmented TCP packets
-    /// should be checked.
-    ///
-    /// \param expected Number of bytes that were expected to have been sent.
-    /// \param socket Socket over which the send took place.  Only used to
-    ///        pass back to the send method.
-    /// \param ec Boost error code, value should be zero.
-    /// \param length Number of bytes sent.
-    void tcpSendHandler(size_t expected, tcp::socket* socket,
-                        error_code ec = error_code(), size_t length = 0)
-    {
-        if (debug_) {
-            cout << "tcpSendHandler(): error = " << ec.value() <<
-                    ", length = " << length << endl;
-        }
-
-        EXPECT_EQ(0, ec.value());       // Expect no error
-        EXPECT_EQ(expected, length);    // And that amount sent is as expected
-
-        // Do we need to send more?
-        send_cumulative_ += length;
-        if (send_cumulative_ < send_buffer_.size()) {
-
-            // Yes - set up a timer:  the callback handler for the timer is
-            // tcpSendData, which will then send the next chunk.  We pass the
-            // socket over which data should be sent as an argument to that
-            // function.
-            timer_.expires_from_now(boost::posix_time::milliseconds(SEND_INTERVAL));
-            timer_.async_wait(boost::bind(&IOFetchTest::tcpSendData, this,
-                                          socket));
-        }
-    }
-
-    /// \brief Fetch completion callback
-    ///
-    /// This is the callback's operator() method which is called when the fetch
-    /// is complete.  It checks that the data received is the wire format of the
-    /// data sent back by the server.
-    ///
-    /// \param result Result indicated by the callback
-    void operator()(IOFetch::Result result) {
-        if (debug_) {
-            cout << "operator()(): result = " << result << endl;
-        }
-
-        EXPECT_EQ(expected_, result);   // Check correct result returned
-        EXPECT_FALSE(run_);             // Check it is run only once
-        run_ = true;                    // Note success
-
-        // If the expected result for SUCCESS, then this should have been called
-        // when one of the "servers" in this class has sent back return_data_.
-        // Check the data is as expected/
-        if (expected_ == IOFetch::SUCCESS) {
-            // In the case of UDP, we actually send back a real looking packet
-            // in the case of TCP, we send back a 'random' string
-            if (protocol_ == IOFetch::UDP) {
-                EXPECT_EQ(expected_buffer_->getLength(), result_buff_->getLength());
-                EXPECT_EQ(0, memcmp(expected_buffer_->getData(), result_buff_->getData(),
-                          expected_buffer_->getLength()));
-            } else {
-                EXPECT_EQ(return_data_.size(), result_buff_->getLength());
-                // Overwrite the random qid with our own data for the
-                // comparison to succeed
-                if (result_buff_->getLength() >= 2) {
-                    result_buff_->writeUint8At(return_data_[0], 0);
-                    result_buff_->writeUint8At(return_data_[1], 1);
-                }
-                const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
-                EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
-            }
-        }
-
-        // ... and cause the run loop to exit.
-        service_.stop();
-    }
-
-    // The next set of methods are the tests themselves.  A number of the TCP
-    // and UDP tests are very similar.
-
-    /// \brief Check for stop()
-    ///
-    /// Test that when we run the query and stop it after it was run, it returns
-    /// "stopped" correctly. (That is why stop() is posted to the service_ as
-    /// well instead of calling it.)
-    ///
-    /// \param protocol Test protocol
-    /// \param fetch Fetch object being tested
-    void stopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
-        protocol_ = protocol;
-        expected_ = IOFetch::STOPPED;
-
-        // Post the query
-        service_.get_io_service().post(fetch);
-
-        // Post query_.stop() (yes, the boost::bind thing is just
-        // query_.stop()).
-        service_.get_io_service().post(
-            boost::bind(&IOFetch::stop, fetch, IOFetch::STOPPED));
-
-        // Run both of them.  run() returns when everything in the I/O service
-        // queue has completed.
-        service_.run();
-        EXPECT_TRUE(run_);
-    }
-
-    /// \brief Premature stop test
-    ///
-    /// Test that when we queue the query to service_ and call stop() before it
-    /// gets executed, it acts sanely as well (eg. has the same result as
-    /// running stop() after - calls the callback).
-    ///
-    /// \param protocol Test protocol
-    /// \param fetch Fetch object being tested
-    void prematureStopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
-        protocol_ = protocol;
-        expected_ = IOFetch::STOPPED;
-
-        // Stop before it is started
-        fetch.stop();
-        service_.get_io_service().post(fetch);
-
-        service_.run();
-        EXPECT_TRUE(run_);
-    }
-
-    /// \brief Timeout test
-    ///
-    /// Test that fetch times out when no answer arrives.
-    ///
-    /// \param protocol Test protocol
-    /// \param fetch Fetch object being tested
-    void timeoutTest(IOFetch::Protocol protocol, IOFetch& fetch) {
-        protocol_ = protocol;
-        expected_ = IOFetch::TIME_OUT;
-
-        service_.get_io_service().post(fetch);
-        service_.run();
-        EXPECT_TRUE(run_);
-    }
-
-    /// \brief Send/Receive Test
-    ///
-    /// Send a query to the server then receives a response.
-    ///
-    /// \param Test data to return to client
-    /// \param short_send If true, do not send all data
-    ///                   (should result in timeout)
-    void tcpSendReturnTest(const std::string& return_data, bool short_send = false) {
-        if (debug_) {
-            cout << "tcpSendReturnTest(): data size = " << return_data.size() << endl;
-        }
-        return_data_ = return_data;
-        protocol_ = IOFetch::TCP;
-        if (short_send) {
-            tcp_short_send_ = true;
-            expected_ = IOFetch::TIME_OUT;
-        } else {
-            expected_ = IOFetch::SUCCESS;
-        }
-
-        // Socket into which the connection will be accepted.
-        tcp::socket socket(service_.get_io_service());
-
-        // Acceptor object - called when the connection is made, the handler
-        // will initiate a read on the socket.
-        tcp::acceptor acceptor(service_.get_io_service(),
-                               tcp::endpoint(tcp::v4(), TEST_PORT));
-        acceptor.async_accept(socket,
-            boost::bind(&IOFetchTest::tcpAcceptHandler, this, &socket, _1));
-
-        // Post the TCP fetch object to send the query and receive the response.
-        service_.get_io_service().post(tcp_fetch_);
-
-        // ... and execute all the callbacks.  This exits when the fetch
-        // completes.
-        service_.run();
-        EXPECT_TRUE(run_);  // Make sure the callback did execute
-
-        // Tidy up
-        socket.close();
-    }
-
-    /// Perform a send/receive test over UDP
-    ///
-    /// \param bad_qid If true, do the test where the QID is mangled
-    ///                in the response
-    /// \param second_send If true, do the test where the QID is
-    ///                    mangled in the response, but a second
-    ///                    (correct) packet is used
-    void udpSendReturnTest(bool bad_qid, bool second_send) {
-        protocol_ = IOFetch::UDP;
-
-        // Set up the server.
-        udp::socket socket(service_.get_io_service(), udp::v4());
-        socket.set_option(socket_base::reuse_address(true));
-        socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
-        return_data_ = "Message returned to the client";
-
-        udp::endpoint remote;
-        socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
-            remote,
-            boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
-                        _1, _2, bad_qid, second_send));
-        service_.get_io_service().post(udp_fetch_);
-        if (debug_) {
-            cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
-                    endl;
-        }
-        service_.run();
-
-        socket.close();
-
-        EXPECT_TRUE(run_);;
-    }
-};
-
-// Check the protocol
-TEST_F(IOFetchTest, Protocol) {
-    EXPECT_EQ(IOFetch::UDP, udp_fetch_.getProtocol());
-    EXPECT_EQ(IOFetch::TCP, tcp_fetch_.getProtocol());
-}
-
-// UDP Stop test - see IOFetchTest::stopTest() header.
-TEST_F(IOFetchTest, UdpStop) {
-    stopTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP premature stop test - see IOFetchTest::prematureStopTest() header.
-TEST_F(IOFetchTest, UdpPrematureStop) {
-    prematureStopTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP premature stop test - see IOFetchTest::timeoutTest() header.
-TEST_F(IOFetchTest, UdpTimeout) {
-    timeoutTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP SendReceive test.  Set up a UDP server then ports a UDP fetch object.
-// This will send question_ to the server and receive the answer back from it.
-TEST_F(IOFetchTest, UdpSendReceive) {
-    expected_ = IOFetch::SUCCESS;
-
-    udpSendReturnTest(false, false);
-
-    EXPECT_TRUE(run_);;
-}
-
-TEST_F(IOFetchTest, UdpSendReceiveBadQid) {
-    expected_ = IOFetch::TIME_OUT;
-
-    udpSendReturnTest(true, false);
-
-    EXPECT_TRUE(run_);;
-}
-
-TEST_F(IOFetchTest, UdpSendReceiveBadQidResend) {
-    expected_ = IOFetch::SUCCESS;
-
-    udpSendReturnTest(true, true);
-
-    EXPECT_TRUE(run_);;
-}
-
-// Do the same tests for TCP transport
-
-TEST_F(IOFetchTest, TcpStop) {
-    stopTest(IOFetch::TCP, tcp_fetch_);
-}
-
-TEST_F(IOFetchTest, TcpPrematureStop) {
-    prematureStopTest(IOFetch::TCP, tcp_fetch_);
-}
-
-TEST_F(IOFetchTest, TcpTimeout) {
-    timeoutTest(IOFetch::TCP, tcp_fetch_);
-}
-
-// Test with values at or near 2, then at or near the chunk size (16 and 32
-// bytes, the sizes of the first two packets) then up to 65535.  These are done
-// in separate tests because in practice a new IOFetch is created for each
-// query/response exchange and we don't want to confuse matters in the test
-// by running the test with an IOFetch that has already done one exchange.
-//
-// Don't do 0 or 1; the server would not accept the packet
-// (since the length is too short to check the qid)
-TEST_F(IOFetchTest, TcpSendReceive2) {
-    tcpSendReturnTest(test_data_.substr(0, 2));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive3) {
-    tcpSendReturnTest(test_data_.substr(0, 3));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive15) {
-    tcpSendReturnTest(test_data_.substr(0, 15));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive16) {
-    tcpSendReturnTest(test_data_.substr(0, 16));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive17) {
-    tcpSendReturnTest(test_data_.substr(0, 17));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive31) {
-    tcpSendReturnTest(test_data_.substr(0, 31));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive32) {
-    tcpSendReturnTest(test_data_.substr(0, 32));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive33) {
-    tcpSendReturnTest(test_data_.substr(0, 33));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive4096) {
-    tcpSendReturnTest(test_data_.substr(0, 4096));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive8192) {
-    tcpSendReturnTest(test_data_.substr(0, 8192));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive16384) {
-    tcpSendReturnTest(test_data_.substr(0, 16384));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive32768) {
-    tcpSendReturnTest(test_data_.substr(0, 32768));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive65535) {
-    tcpSendReturnTest(test_data_.substr(0, 65535));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive2ShortSend) {
-    tcpSendReturnTest(test_data_.substr(0, 2), true);
-}
-
-TEST_F(IOFetchTest, TcpSendReceive15ShortSend) {
-    tcpSendReturnTest(test_data_.substr(0, 15), true);
-}
-
-TEST_F(IOFetchTest, TcpSendReceive8192ShortSend) {
-    tcpSendReturnTest(test_data_.substr(0, 8192), true);
-}
-
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiolink/tests/io_service_unittest.cc
deleted file mode 100644
index 779d03e..0000000
--- a/src/lib/asiolink/tests/io_service_unittest.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <gtest/gtest.h>
-
-#include <asio.hpp>
-#include <asiolink/asiolink.h>
-
-using namespace asiolink;
-
-const char* const TEST_SERVER_PORT = "53535";
-const char* const TEST_CLIENT_PORT = "53536";
-const char* const TEST_IPV6_ADDR = "::1";
-const char* const TEST_IPV4_ADDR = "127.0.0.1";
-
-TEST(IOServiceTest, badPort) {
-    IOService io_service;
-    EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(DNSService(io_service, *"53210.0", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, badAddress) {
-    IOService io_service;
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, unavailableAddress) {
-    IOService io_service;
-    // These addresses should generally be unavailable as a valid local
-    // address, although there's no guarantee in theory.
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.0", NULL, NULL, NULL), IOError);
-
-    // Some OSes would simply reject binding attempt for an AF_INET6 socket
-    // to an IPv4-mapped IPv6 address.  Even if those that allow it, since
-    // the corresponding IPv4 address is the same as the one used in the
-    // AF_INET socket case above, it should at least show the same result
-    // as the previous one.
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:192.0.2.0", NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, duplicateBind_v6) {
-    // In each sub test case, second attempt should fail due to duplicate bind
-    IOService io_service;
-
-    // IPv6, "any" address
-    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
-    delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v6_address) {
-    // In each sub test case, second attempt should fail due to duplicate bind
-    IOService io_service;
-
-    // IPv6, specific address
-    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
-    delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v4) {
-    // In each sub test case, second attempt should fail due to duplicate bind
-    IOService io_service;
-
-    // IPv4, "any" address
-    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
-    delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v4_address) {
-    // In each sub test case, second attempt should fail due to duplicate bind
-    IOService io_service;
-
-    // IPv4, specific address
-    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
-    delete dns_service;
-}
-
-// Disabled because IPv4-mapped addresses don't seem to be working with
-// the IOService constructor
-TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
-    IOService io_service;
-    // Duplicate bind on IPv4-mapped IPv6 address
-    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
-    delete dns_service;
-
-    // XXX:
-    // Currently, this throws an "invalid argument" exception.  I have
-    // not been able to get IPv4-mapped addresses to work.
-    dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
-    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
-    delete dns_service;
-}
-
diff --git a/src/lib/asiolink/tests/io_socket_unittest.cc b/src/lib/asiolink/tests/io_socket_unittest.cc
index 6538550..15afc17 100644
--- a/src/lib/asiolink/tests/io_socket_unittest.cc
+++ b/src/lib/asiolink/tests/io_socket_unittest.cc
@@ -20,7 +20,7 @@
 #include <asio.hpp>
 #include <asiolink/io_socket.h>
 
-using namespace asiolink;
+using namespace isc::asiolink;
 
 TEST(IOSocketTest, dummySockets) {
     EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol());
diff --git a/src/lib/asiolink/tests/qid_gen_unittest.cc b/src/lib/asiolink/tests/qid_gen_unittest.cc
deleted file mode 100644
index 3ad8a03..0000000
--- a/src/lib/asiolink/tests/qid_gen_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-
-/// \brief Test of QidGenerator
-///
-
-#include <gtest/gtest.h>
-
-#include <asiolink/qid_gen.h>
-#include <dns/message.h>
-
-// Tests the operation of the Qid generator
-
-// Check that getInstance returns a singleton
-TEST(QidGenerator, singleton) {
-    asiolink::QidGenerator& g1 = asiolink::QidGenerator::getInstance();
-    asiolink::QidGenerator& g2 = asiolink::QidGenerator::getInstance();
-
-    EXPECT_TRUE(&g1 == &g2);
-}
-
-TEST(QidGenerator, generate) {
-    // We'll assume that boost's generator is 'good enough', and won't
-    // do full statistical checking here. Let's just call it the xkcd
-    // test (http://xkcd.com/221/), and check if three consecutive
-    // generates are not all the same.
-    isc::dns::qid_t one, two, three;
-    asiolink::QidGenerator& gen = asiolink::QidGenerator::getInstance();
-    one = gen.generateQid();
-    two = gen.generateQid();
-    three = gen.generateQid();
-    ASSERT_FALSE((one == two) && (one == three));
-}
diff --git a/src/lib/asiolink/tests/run_unittests.cc b/src/lib/asiolink/tests/run_unittests.cc
index c285f9e..97bcb65 100644
--- a/src/lib/asiolink/tests/run_unittests.cc
+++ b/src/lib/asiolink/tests/run_unittests.cc
@@ -22,7 +22,6 @@ main(int argc, char* argv[])
 {
     ::testing::InitGoogleTest(&argc, argv);         // Initialize Google test
     isc::log::setRootLoggerName("unittest");        // Set a root logger name
-    isc::UnitTestUtil::addDataPath(TEST_DATA_DIR);  // Add location of test data
 
     return (RUN_ALL_TESTS());
 }
diff --git a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
index 3787e1c..6988082 100644
--- a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
@@ -22,7 +22,7 @@
 #include <asiolink/io_address.h>
 #include <asiolink/tcp_endpoint.h>
 
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace std;
 
 // This test checks that the endpoint can manage its own internal
diff --git a/src/lib/asiolink/tests/tcp_socket_unittest.cc b/src/lib/asiolink/tests/tcp_socket_unittest.cc
index f0a45ee..538cf48 100644
--- a/src/lib/asiolink/tests/tcp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_socket_unittest.cc
@@ -35,19 +35,19 @@
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/io_utilities.h>
 
 #include <asio.hpp>
 
-#include <asiolink/asiolink_utilities.h>
 #include <asiolink/io_service.h>
 #include <asiolink/tcp_endpoint.h>
 #include <asiolink/tcp_socket.h>
 
 using namespace asio;
 using namespace asio::ip;
-using namespace asiolink;
-using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::asiolink;
 using namespace std;
 
 namespace {
diff --git a/src/lib/asiolink/tests/udp_endpoint_unittest.cc b/src/lib/asiolink/tests/udp_endpoint_unittest.cc
index 18135ec..03de6b8 100644
--- a/src/lib/asiolink/tests/udp_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/udp_endpoint_unittest.cc
@@ -22,7 +22,7 @@
 #include <asiolink/io_address.h>
 #include <asiolink/udp_endpoint.h>
 
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace std;
 
 // This test checks that the endpoint can manage its own internal
diff --git a/src/lib/asiolink/tests/udp_socket_unittest.cc b/src/lib/asiolink/tests/udp_socket_unittest.cc
index 8563d22..1ab1a09 100644
--- a/src/lib/asiolink/tests/udp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/udp_socket_unittest.cc
@@ -35,18 +35,18 @@
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/io_utilities.h>
 
 #include <asio.hpp>
 
-#include <asiolink/asiolink_utilities.h>
 #include <asiolink/io_service.h>
 #include <asiolink/udp_endpoint.h>
 #include <asiolink/udp_socket.h>
 
 using namespace asio;
-using namespace asiolink;
-using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::asiolink;
 using namespace std;
 
 namespace {
diff --git a/src/lib/asiolink/udp_endpoint.h b/src/lib/asiolink/udp_endpoint.h
index 99dc27f..5c8a1fe 100644
--- a/src/lib/asiolink/udp_endpoint.h
+++ b/src/lib/asiolink/udp_endpoint.h
@@ -21,6 +21,7 @@
 
 #include <asiolink/io_endpoint.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c UDPEndpoint class is a concrete derived class of
@@ -109,5 +110,6 @@ private:
     asio::ip::udp::endpoint& asio_endpoint_;
 };
 
-}      // namespace asiolink
+} // namespace asiolink
+} // namespace isc
 #endif // __UDP_ENDPOINT_H
diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiolink/udp_server.cc
deleted file mode 100644
index 5b48f28..0000000
--- a/src/lib/asiolink/udp_server.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>             // for some IPC/network system calls
-#include <errno.h>
-
-#include <boost/shared_array.hpp>
-
-#include <config.h>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asio/error.hpp>
-#include <asiolink/dummy_io_cb.h>
-#include <asiolink/udp_endpoint.h>
-#include <asiolink/udp_server.h>
-#include <asiolink/udp_socket.h>
-
-#include <dns/opcode.h>
-
-using namespace asio;
-using asio::ip::udp;
-using isc::log::dlog;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-
-/*
- * Some of the member variables here are shared_ptrs and some are
- * auto_ptrs. There will be one instance of Data for the lifetime
- * of packet. The variables that are state only for a single packet
- * use auto_ptr, as it is more lightweight. In the case of shared
- * configuration (eg. the callbacks, socket), we use shared_ptrs.
- */
-struct UDPServer::Data {
-    /*
-     * Constructor from parameters passed to UDPServer constructor.
-     * This instance will not be used to retrieve and answer the actual
-     * query, it will only hold parameters until we wait for the
-     * first packet. But we do initialize the socket in here.
-     */
-    Data(io_service& io_service, const ip::address& addr, const uint16_t port,
-        SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
-        io_(io_service), done_(false),
-        checkin_callback_(checkin),lookup_callback_(lookup),
-        answer_callback_(answer)
-    {
-        // We must use different instantiations for v4 and v6;
-        // otherwise ASIO will bind to both
-        udp proto = addr.is_v4() ? udp::v4() : udp::v6();
-        socket_.reset(new udp::socket(io_service, proto));
-        socket_->set_option(socket_base::reuse_address(true));
-        if (addr.is_v6()) {
-            socket_->set_option(asio::ip::v6_only(true));
-        }
-        socket_->bind(udp::endpoint(addr, port));
-    }
-
-    /*
-     * Copy constructor. Default one would probably do, but it is unnecessary
-     * to copy many of the member variables every time we fork to handle
-     * another packet.
-     *
-     * We also allocate data for receiving the packet here.
-     */
-    Data(const Data& other) :
-        io_(other.io_), socket_(other.socket_), done_(false),
-        checkin_callback_(other.checkin_callback_),
-        lookup_callback_(other.lookup_callback_),
-        answer_callback_(other.answer_callback_)
-    {
-        // Instantiate the data buffer and endpoint that will
-        // be used by the asynchronous receive call.
-        data_.reset(new char[MAX_LENGTH]);
-        sender_.reset(new udp::endpoint());
-    }
-
-    // The ASIO service object
-    asio::io_service& io_;
-
-    // Class member variables which are dynamic, and changes to which
-    // need to accessible from both sides of a coroutine fork or from
-    // outside of the coroutine (i.e., from an asynchronous I/O call),
-    // should be declared here as pointers and allocated in the
-    // constructor or in the coroutine.  This allows state information
-    // to persist when an individual copy of the coroutine falls out
-    // scope while waiting for an event, *so long as* there is another
-    // object that is referencing the same data.  As a side-benefit, using
-    // pointers also reduces copy overhead for coroutine objects.
-    //
-    // Note: Currently these objects are allocated by "new" in the
-    // constructor, or in the function operator while processing a query.
-    // Repeated allocations from the heap for every incoming query is
-    // clearly a performance issue; this must be optimized in the future.
-    // The plan is to have a structure pre-allocate several "Data"
-    // objects which can be pulled off a free list and placed on an in-use
-    // list whenever a query comes in.  This will serve the dual purpose
-    // of improving performance and guaranteeing that state information
-    // will *not* be destroyed when any one instance of the coroutine
-    // falls out of scope while waiting for an event.
-    //
-    // Socket used to for listen for queries.  Created in the
-    // constructor and stored in a shared_ptr because socket objects
-    // are not copyable.
-    boost::shared_ptr<asio::ip::udp::socket> socket_;
-
-    // The ASIO-internal endpoint object representing the client
-    std::auto_ptr<asio::ip::udp::endpoint> sender_;
-
-    // \c IOMessage and \c Message objects to be passed to the
-    // DNS lookup and answer providers
-    std::auto_ptr<asiolink::IOMessage> io_message_;
-
-    // The original query as sent by the client
-    isc::dns::MessagePtr query_message_;
-
-    // The response message we are building
-    isc::dns::MessagePtr answer_message_;
-
-    // The buffer into which the response is written
-    isc::dns::OutputBufferPtr respbuf_;
-
-    // The buffer into which the query packet is written
-    boost::shared_array<char> data_;
-
-    // State information that is entirely internal to a given instance
-    // of the coroutine can be declared here.
-    size_t bytes_;
-    bool done_;
-
-
-    // Callback functions provided by the caller
-    const SimpleCallback* checkin_callback_;
-    const DNSLookup* lookup_callback_;
-    const DNSAnswer* answer_callback_;
-
-    std::auto_ptr<IOEndpoint> peer_;
-    std::auto_ptr<IOSocket> iosock_;
-};
-
-/// The following functions implement the \c UDPServer class.
-///
-/// The constructor. It just creates new internal state object
-/// and lets it handle the initialization.
-UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
-    const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
-    DNSAnswer* answer) :
-    data_(new Data(io_service, addr, port, checkin, lookup, answer))
-{ }
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-void
-UDPServer::operator()(error_code ec, size_t length) {
-    /// Because the coroutine reentry block is implemented as
-    /// a switch statement, inline variable declarations are not
-    /// permitted.  Certain variables used below can be declared here.
-
-    CORO_REENTER (this) {
-        do {
-            /*
-             * This is preparation for receiving a packet. We get a new
-             * state object for the lifetime of the next packet to come.
-             * It allocates the buffers to receive data into.
-             */
-            data_.reset(new Data(*data_));
-
-            do {
-                // Begin an asynchronous receive, then yield.
-                // When the receive event is posted, the coroutine
-                // will resume immediately after this point.
-                CORO_YIELD data_->socket_->async_receive_from(
-                    buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
-                    *this);
-
-                // Abort on fatal errors
-                // TODO: add log
-                if (ec) {
-                    using namespace asio::error;
-                    if (ec.value() != would_block && ec.value() != try_again &&
-                        ec.value() != interrupted) {
-                        return;
-                    }
-                }
-
-            } while (ec || length == 0);
-
-            data_->bytes_ = length;
-
-            /*
-             * We fork the coroutine now. One (the child) will keep
-             * the current state and handle the packet, then die and
-             * drop ownership of the state. The other (parent) will just
-             * go into the loop again and replace the current state with
-             * a new one for a new object.
-             *
-             * Actually, both of the coroutines will be a copy of this
-             * one, but that's just internal implementation detail.
-             */
-            CORO_FORK data_->io_.post(UDPServer(*this));
-        } while (is_parent());
-
-        // Create an \c IOMessage object to store the query.
-        //
-        // (XXX: It would be good to write a factory function
-        // that would quickly generate an IOMessage object without
-        // all these calls to "new".)
-        data_->peer_.reset(new UDPEndpoint(*data_->sender_));
-
-        // The UDP socket class has been extended with asynchronous functions
-        // and takes as a template parameter a completion callback class.  As
-        // UDPServer does not use these extended functions (only those defined
-        // in the IOSocket base class) - but needs a UDPSocket to get hold of
-        // the underlying Boost UDP socket - DummyIOCallback is used.  This
-        // provides the appropriate operator() but is otherwise functionless.
-        data_->iosock_.reset(
-            new UDPSocket<DummyIOCallback>(*data_->socket_));
-
-        data_->io_message_.reset(new IOMessage(data_->data_.get(),
-            data_->bytes_, *data_->iosock_, *data_->peer_));
-
-        // Perform any necessary operations prior to processing an incoming
-        // query (e.g., checking for queued configuration messages).
-        //
-        // (XXX: it may be a performance issue to check in for every single
-        // incoming query; we may wish to throttle this in the future.)
-        if (data_->checkin_callback_ != NULL) {
-            (*data_->checkin_callback_)(*data_->io_message_);
-        }
-
-        // If we don't have a DNS Lookup provider, there's no point in
-        // continuing; we exit the coroutine permanently.
-        if (data_->lookup_callback_ == NULL) {
-            CORO_YIELD return;
-        }
-
-        // Instantiate objects that will be needed by the
-        // asynchronous DNS lookup and/or by the send call.
-        data_->respbuf_.reset(new OutputBuffer(0));
-        data_->query_message_.reset(new Message(Message::PARSE));
-        data_->answer_message_.reset(new Message(Message::RENDER));
-
-        // Schedule a DNS lookup, and yield.  When the lookup is
-        // finished, the coroutine will resume immediately after
-        // this point.
-        CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
-
-        // The 'done_' flag indicates whether we have an answer
-        // to send back.  If not, exit the coroutine permanently.
-        if (!data_->done_) {
-            CORO_YIELD return;
-        }
-
-        // Call the DNS answer provider to render the answer into
-        // wire format
-        (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
-            data_->answer_message_, data_->respbuf_);
-
-        // Begin an asynchronous send, and then yield.  When the
-        // send completes, we will resume immediately after this point
-        // (though we have nothing further to do, so the coroutine
-        // will simply exit at that time).
-        CORO_YIELD data_->socket_->async_send_to(
-            buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
-            *data_->sender_, *this);
-    }
-}
-
-/// Call the DNS lookup provider.  (Expected to be called by the
-/// AsyncLookup<UDPServer> handler.)
-void
-UDPServer::asyncLookup() {
-    (*data_->lookup_callback_)(*data_->io_message_,
-        data_->query_message_, data_->answer_message_, data_->respbuf_, this);
-}
-
-/// Stop the UDPServer
-void
-UDPServer::stop() {
-    /// Using close instead of cancel, because cancel
-    /// will only cancel the asynchornized event already submitted
-    /// to io service, the events post to io service after
-    /// cancel still can be scheduled by io service, if
-    /// the socket is cloesed, all the asynchronized event
-    /// for it won't be scheduled by io service not matter it is
-    /// submit to io serice before or after close call. And we will
-    //. get bad_descriptor error
-    data_->socket_->close();
-}
-
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off.  The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-UDPServer::resume(const bool done) {
-    data_->done_ = done;
-    data_->io_.post(*this);
-}
-
-bool
-UDPServer::hasAnswer() {
-    return (data_->done_);
-}
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/udp_server.h b/src/lib/asiolink/udp_server.h
deleted file mode 100644
index 1d37471..0000000
--- a/src/lib/asiolink/udp_server.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __UDP_SERVER_H
-#define __UDP_SERVER_H 1
-
-#ifndef ASIO_HPP
-#error "asio.hpp must be included before including this, see asiolink.h as to why"
-#endif
-
-#include <asiolink/dns_server.h>
-#include <asiolink/simple_callback.h>
-#include <asiolink/dns_lookup.h>
-#include <asiolink/dns_answer.h>
-
-#include <coroutine.h>
-
-namespace asiolink {
-
-//
-// Asynchronous UDP server coroutine
-//
-///
-/// \brief This class implements the coroutine to handle UDP
-///        DNS query event. As such, it is both a \c DNSServer and
-///        a \c coroutine
-///
-class UDPServer : public virtual DNSServer, public virtual coroutine {
-public:
-    /// \brief Constructor
-    /// \param io_service the asio::io_service to work with
-    /// \param addr the IP address to listen for queries on
-    /// \param port the port to listen for queries on
-    /// \param checkin the callbackprovider for non-DNS events
-    /// \param lookup the callbackprovider for DNS lookup events
-    /// \param answer the callbackprovider for DNS answer events
-    explicit UDPServer(asio::io_service& io_service,
-                       const asio::ip::address& addr, const uint16_t port,
-                       SimpleCallback* checkin = NULL,
-                       DNSLookup* lookup = NULL,
-                       DNSAnswer* answer = NULL);
-
-    /// \brief The function operator
-    void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0);
-
-    /// \brief Calls the lookup callback
-    void asyncLookup();
-
-    /// \brief Stop the running server
-    /// \note once the server stopped, it can't restart
-    void stop();
-
-    /// \brief Resume operation
-    ///
-    /// \param done Set this to true if the lookup action is done and
-    ///        we have an answer
-    void resume(const bool done);
-
-    /// \brief Check if we have an answer
-    ///
-    /// \return true if we have an answer
-    bool hasAnswer();
-
-    /// \brief Returns the coroutine state value
-    ///
-    /// \return the coroutine state value
-    int value() { return (get_value()); }
-
-    /// \brief Clones the object
-    ///
-    /// \return a newly allocated copy of this object
-    DNSServer* clone() {
-        UDPServer* s = new UDPServer(*this);
-        return (s);
-    }
-
-private:
-    enum { MAX_LENGTH = 4096 };
-
-    /**
-     * \brief Internal state and data.
-     *
-     * We use the pimple design pattern, but not because we need to hide
-     * internal data. This class and whole header is for private use anyway.
-     * It turned out that UDPServer is copied a lot, because it is a coroutine.
-     * This way the overhead of copying is lower, we copy only one shared
-     * pointer instead of about 10 of them.
-     */
-    class Data;
-    boost::shared_ptr<Data> data_;
-};
-
-}      // namespace asiolink
-#endif // __UDP_SERVER_H
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
index 35fc7b1..c061fba 100644
--- a/src/lib/asiolink/udp_socket.h
+++ b/src/lib/asiolink/udp_socket.h
@@ -33,6 +33,7 @@
 #include <asiolink/io_service.h>
 #include <asiolink/udp_endpoint.h>
 
+namespace isc {
 namespace asiolink {
 
 /// \brief The \c UDPSocket class is a concrete derived class of \c IOAsioSocket
@@ -141,7 +142,7 @@ public:
     virtual bool processReceivedData(const void* staging, size_t length,
                                      size_t& cumulative, size_t& offset,
                                      size_t& expected,
-                                     isc::dns::OutputBufferPtr& outbuff);
+                                     isc::util::OutputBufferPtr& outbuff);
 
     /// \brief Cancel I/O On Socket
     virtual void cancel();
@@ -283,7 +284,7 @@ template <typename C> bool
 UDPSocket<C>::processReceivedData(const void* staging, size_t length,
                                   size_t& cumulative, size_t& offset,
                                   size_t& expected,
-                                  isc::dns::OutputBufferPtr& outbuff)
+                                  isc::util::OutputBufferPtr& outbuff)
 {
     // Set return values to what we should expect.
     cumulative = length;
@@ -318,5 +319,6 @@ UDPSocket<C>::close() {
 }
 
 } // namespace asiolink
+} // namespace isc
 
 #endif // __UDP_SOCKET_H
diff --git a/src/lib/bench/benchmark_util.cc b/src/lib/bench/benchmark_util.cc
index ca2ca1b..c67a851 100644
--- a/src/lib/bench/benchmark_util.cc
+++ b/src/lib/bench/benchmark_util.cc
@@ -19,7 +19,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/name.h>
 #include <dns/message.h>
@@ -35,6 +35,7 @@
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace isc {
 namespace bench {
diff --git a/src/lib/bench/tests/Makefile.am b/src/lib/bench/tests/Makefile.am
index 63d3c87..4259b0e 100644
--- a/src/lib/bench/tests/Makefile.am
+++ b/src/lib/bench/tests/Makefile.am
@@ -16,6 +16,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 run_unittests_LDADD += $(top_builddir)/src/lib/bench/libbench.la
 run_unittests_LDADD += $(GTEST_LDADD)
 endif
diff --git a/src/lib/bench/tests/loadquery_unittest.cc b/src/lib/bench/tests/loadquery_unittest.cc
index a53e191..93130d2 100644
--- a/src/lib/bench/tests/loadquery_unittest.cc
+++ b/src/lib/bench/tests/loadquery_unittest.cc
@@ -17,7 +17,7 @@
 #include <vector>
 #include <sstream>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/opcode.h>
@@ -32,6 +32,7 @@
 using namespace std;
 using namespace isc::bench;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 typedef pair<string, string> QueryParam;
diff --git a/src/lib/cache/Makefile.am b/src/lib/cache/Makefile.am
index 107fc9a..bfbe24a 100644
--- a/src/lib/cache/Makefile.am
+++ b/src/lib/cache/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache
diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h
index 790ed83..7455f66 100644
--- a/src/lib/cache/message_cache.h
+++ b/src/lib/cache/message_cache.h
@@ -20,7 +20,7 @@
 #include <dns/message.h>
 #include "message_entry.h"
 #include <nsas/hash_table.h>
-#include <nsas/lru_list.h>
+#include <util/lru_list.h>
 #include "rrset_cache.h"
 
 namespace isc {
@@ -92,7 +92,7 @@ protected:
     RRsetCachePtr rrset_cache_;
     RRsetCachePtr negative_soa_cache_;
     isc::nsas::HashTable<MessageEntry> message_table_;
-    isc::nsas::LruList<MessageEntry> message_lru_;
+    isc::util::LruList<MessageEntry> message_lru_;
 };
 
 typedef boost::shared_ptr<MessageCache> MessageCachePtr;
diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h
index 104c2a5..0e1b08f 100644
--- a/src/lib/cache/rrset_cache.h
+++ b/src/lib/cache/rrset_cache.h
@@ -17,7 +17,8 @@
 
 #include <cache/rrset_entry.h>
 #include <nsas/hash_table.h>
-#include <nsas/lru_list.h>
+
+#include <util/lru_list.h>
 
 using namespace isc::nsas;
 
@@ -98,7 +99,7 @@ public:
 protected:
     uint16_t class_; // The class of the rrset cache.
     isc::nsas::HashTable<RRsetEntry> rrset_table_;
-    isc::nsas::LruList<RRsetEntry> rrset_lru_;
+    isc::util::LruList<RRsetEntry> rrset_lru_;
 };
 
 typedef boost::shared_ptr<RRsetCache> RRsetCachePtr;
diff --git a/src/lib/cache/tests/Makefile.am b/src/lib/cache/tests/Makefile.am
index 4763f55..68a8425 100644
--- a/src/lib/cache/tests/Makefile.am
+++ b/src/lib/cache/tests/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = .
 
 AM_CPPFLAGS  = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache
 AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\"
@@ -54,6 +55,7 @@ endif
 run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 endif
diff --git a/src/lib/cache/tests/cache_test_messagefromfile.h b/src/lib/cache/tests/cache_test_messagefromfile.h
index 62e237c..7d55f08 100644
--- a/src/lib/cache/tests/cache_test_messagefromfile.h
+++ b/src/lib/cache/tests/cache_test_messagefromfile.h
@@ -14,7 +14,7 @@
 
 #include <vector>
 #include <dns/tests/unittest_util.h>
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/message.h>
 
 using namespace isc;
@@ -31,7 +31,7 @@ messageFromFile(Message& message, const char* datafile) {
     std::vector<unsigned char> data;
     UnitTestUtil::readWireData(datafile, data);
 
-    InputBuffer buffer(&data[0], data.size());
+    isc::util::InputBuffer buffer(&data[0], data.size());
     message.fromWire(buffer);
 }
 
diff --git a/src/lib/cache/tests/cache_test_sectioncount.h b/src/lib/cache/tests/cache_test_sectioncount.h
index 537ca81..df7cb52 100644
--- a/src/lib/cache/tests/cache_test_sectioncount.h
+++ b/src/lib/cache/tests/cache_test_sectioncount.h
@@ -14,7 +14,7 @@
 
 #include <vector>
 #include <dns/tests/unittest_util.h>
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/message.h>
 
 using namespace isc;
diff --git a/src/lib/cache/tests/message_cache_unittest.cc b/src/lib/cache/tests/message_cache_unittest.cc
index fc62e21..60ae037 100644
--- a/src/lib/cache/tests/message_cache_unittest.cc
+++ b/src/lib/cache/tests/message_cache_unittest.cc
@@ -16,7 +16,7 @@
 #include <string>
 #include <gtest/gtest.h>
 #include <dns/tests/unittest_util.h>
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include "../message_cache.h"
 #include "../rrset_cache.h"
 #include "../resolver_cache.h"
@@ -25,6 +25,7 @@
 using namespace isc::cache;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace std;
 
 namespace {
diff --git a/src/lib/cache/tests/message_entry_unittest.cc b/src/lib/cache/tests/message_entry_unittest.cc
index 2ca33ec..d9709ed 100644
--- a/src/lib/cache/tests/message_entry_unittest.cc
+++ b/src/lib/cache/tests/message_entry_unittest.cc
@@ -15,7 +15,7 @@
 #include <gtest/gtest.h>
 #include <dns/tests/unittest_util.h>
 #include <dns/message.h>
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include "../message_entry.h"
 #include "../rrset_cache.h"
 #include "../resolver_cache.h"
diff --git a/src/lib/cc/Makefile.am b/src/lib/cc/Makefile.am
index 44033e9..9d5b188 100644
--- a/src/lib/cc/Makefile.am
+++ b/src/lib/cc/Makefile.am
@@ -11,6 +11,7 @@ if USE_GXX
 # avoid the error.  As a short term workaround we suppress this warning
 # for the entire this module.  See also src/bin/auth/Makefile.am.
 AM_CXXFLAGS += -Wno-unused-parameter
+AM_CXXFLAGS += -fno-strict-aliasing
 endif
 if USE_CLANGPP
 # Likewise, ASIO header files will trigger various warnings with clang++.
diff --git a/src/lib/cc/tests/Makefile.am b/src/lib/cc/tests/Makefile.am
index 535c464..71e6988 100644
--- a/src/lib/cc/tests/Makefile.am
+++ b/src/lib/cc/tests/Makefile.am
@@ -26,7 +26,6 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD +=  $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/libexceptions.la
 
 endif
diff --git a/src/lib/config/Makefile.am b/src/lib/config/Makefile.am
index 580f240..52337ad 100644
--- a/src/lib/config/Makefile.am
+++ b/src/lib/config/Makefile.am
@@ -2,10 +2,24 @@ SUBDIRS = . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
 AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
+
+# Define rule to build logging source files from message file
+configdef.h configdef.cc: configdef.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/config/configdef.mes
+
+BUILT_SOURCES = configdef.h configdef.cc
 
 lib_LTLIBRARIES = libcfgclient.la
-libcfgclient_la_SOURCES = config_data.h config_data.cc module_spec.h module_spec.cc ccsession.cc ccsession.h
+libcfgclient_la_SOURCES = config_data.h config_data.cc
+libcfgclient_la_SOURCES += module_spec.h module_spec.cc
+libcfgclient_la_SOURCES += ccsession.cc ccsession.h
+libcfgclient_la_SOURCES += config_log.h config_log.cc
+
+nodist_libcfgclient_la_SOURCES  = configdef.h configdef.cc
+
+# The message file should be in the distribution.
+EXTRA_DIST = configdef.mes
 
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda configdef.h configdef.cc
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 69621a4..45710e3 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -12,12 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// 
-// todo: generalize this and make it into a specific API for all modules
-//       to use (i.e. connect to cc, send config and commands, get config,
-//               react on config change announcements)
-//
-
 #include <config.h>
 
 #include <stdexcept>
@@ -38,6 +32,7 @@
 #include <cc/session.h>
 #include <exceptions/exceptions.h>
 
+#include <config/config_log.h>
 #include <config/ccsession.h>
 
 using namespace std;
@@ -164,18 +159,18 @@ ModuleCCSession::readModuleSpecification(const std::string& filename) {
     // this file should be declared in a @something@ directive
     file.open(filename.c_str());
     if (!file) {
-        cout << "error opening " << filename << ": " << strerror(errno) << endl;
-        exit(1);
+        LOG_ERROR(config_logger, CONFIG_FOPEN_ERR).arg(filename).arg(strerror(errno));
+        isc_throw(CCSessionInitError, strerror(errno));
     }
 
     try {
         module_spec = moduleSpecFromFile(file, true);
     } catch (const JSONError& pe) {
-        cout << "Error parsing module specification file: " << pe.what() << endl;
-        exit(1);
+        LOG_ERROR(config_logger, CONFIG_JSON_PARSE).arg(filename).arg(pe.what());
+        isc_throw(CCSessionInitError, pe.what());
     } catch (const ModuleSpecError& dde) {
-        cout << "Error reading module specification file: " << dde.what() << endl;
-        exit(1);
+        LOG_ERROR(config_logger, CONFIG_MODULE_SPEC).arg(filename).arg(dde.what());
+        isc_throw(CCSessionInitError, dde.what());
     }
     file.close();
     return (module_spec);
@@ -223,7 +218,8 @@ ModuleCCSession::ModuleCCSession(
     int rcode;
     ConstElementPtr err = parseAnswer(rcode, answer);
     if (rcode != 0) {
-        std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
+        LOG_ERROR(config_logger, CONFIG_MANAGER_MOD_SPEC).arg(answer->str());
+        isc_throw(CCSessionInitError, answer->str());
     }
     
     setLocalConfig(Element::fromJSON("{}"));
@@ -236,7 +232,8 @@ ModuleCCSession::ModuleCCSession(
         if (rcode == 0) {
             handleConfigUpdate(new_config);
         } else {
-            std::cerr << "[" << module_name_ << "] Error getting config: " << new_config << std::endl;
+            LOG_ERROR(config_logger, CONFIG_MANAGER_CONFIG).arg(new_config->str());
+            isc_throw(CCSessionInitError, answer->str());
         }
     }
 
@@ -348,24 +345,51 @@ ModuleCCSession::checkCommand() {
                 answer = checkModuleCommand(cmd_str, target_module, arg);
             }
         } catch (const CCSessionError& re) {
-            // TODO: Once we have logging and timeouts, we should not
-            // answer here (potential interference)
-            answer = createAnswer(1, re.what());
+            LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG).arg(re.what());
         }
         if (!isNull(answer)) {
             session_.reply(routing, answer);
         }
     }
-    
+
     return (0);
 }
 
 std::string
-ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
-    ModuleSpec rmod_spec = readModuleSpecification(spec_file_name);
-    std::string module_name = rmod_spec.getFullSpec()->get("module_name")->stringValue();
+ModuleCCSession::addRemoteConfig(const std::string& spec_name,
+                                 void (*handler)(const std::string& module,
+                                          ConstElementPtr),
+                                 bool spec_is_filename)
+{
+    std::string module_name;
+    ModuleSpec rmod_spec;
+    if (spec_is_filename) {
+        // It's a file name, so load it
+        rmod_spec = readModuleSpecification(spec_name);
+        module_name =
+            rmod_spec.getFullSpec()->get("module_name")->stringValue();
+    } else {
+        // It's module name, request it from config manager
+        ConstElementPtr cmd = Element::fromJSON("{ \"command\": ["
+                                                "\"get_module_spec\","
+                                                "{\"module_name\": \"" +
+                                                module_name + "\"} ] }");
+        unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
+        ConstElementPtr env, answer;
+        session_.group_recvmsg(env, answer, false, seq);
+        int rcode;
+        ConstElementPtr spec_data = parseAnswer(rcode, answer);
+        if (rcode == 0 && spec_data) {
+            rmod_spec = ModuleSpec(spec_data);
+            module_name = spec_name;
+            if (module_name != rmod_spec.getModuleName()) {
+                isc_throw(CCSessionError, "Module name mismatch");
+            }
+        } else {
+            isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
+        }
+    }
     ConfigData rmod_config = ConfigData(rmod_spec);
-    session_.subscribe(module_name);
 
     // Get the current configuration values for that module
     ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
@@ -375,8 +399,9 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
     session_.group_recvmsg(env, answer, false, seq);
     int rcode;
     ConstElementPtr new_config = parseAnswer(rcode, answer);
+    ElementPtr local_config;
     if (rcode == 0 && new_config) {
-        ElementPtr local_config = rmod_config.getLocalConfig();
+        local_config = rmod_config.getLocalConfig();
         isc::data::merge(local_config, new_config);
         rmod_config.setLocalConfig(local_config);
     } else {
@@ -385,6 +410,11 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
 
     // all ok, add it
     remote_module_configs_[module_name] = rmod_config;
+    if (handler) {
+        remote_module_handlers_[module_name] = handler;
+        handler(module_name, local_config);
+    }
+    session_.subscribe(module_name);
     return (module_name);
 }
 
@@ -395,6 +425,7 @@ ModuleCCSession::removeRemoteConfig(const std::string& module_name) {
     it = remote_module_configs_.find(module_name);
     if (it != remote_module_configs_.end()) {
         remote_module_configs_.erase(it);
+        remote_module_handlers_.erase(module_name);
         session_.unsubscribe(module_name);
     }
 }
@@ -424,6 +455,11 @@ ModuleCCSession::updateRemoteConfig(const std::string& module_name,
     if (it != remote_module_configs_.end()) {
         ElementPtr rconf = (*it).second.getLocalConfig();
         isc::data::merge(rconf, new_config);
+        std::map<std::string, RemoteHandler>::iterator hit =
+            remote_module_handlers_.find(module_name);
+        if (hit != remote_module_handlers_.end()) {
+            hit->second(module_name, new_config);
+        }
     }
 }
 
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index d8d1eeb..c845b8f 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -135,6 +135,15 @@ public:
 };
 
 ///
+/// \brief This exception is thrown if the constructor fails
+///
+class CCSessionInitError : public isc::Exception {
+public:
+    CCSessionInitError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+///
 /// \brief This module keeps a connection to the command channel,
 /// holds configuration information, and handles messages from
 /// the command channel
@@ -154,6 +163,11 @@ public:
      * AbstractSession without establishing the session.
      * Note: the design decision on who is responsible for establishing the
      * session is in flux, and may change in near future.
+     *
+     * \exception CCSessionInitError when the initialization fails,
+     *            either because the file cannot be read or there is
+     *            a communication problem with the config manager.
+     *
      * @param command_handler A callback function pointer to be called when
      * a control command from a remote agent needs to be performed on the
      * local module.
@@ -220,24 +234,43 @@ public:
     /**
      * Gives access to the configuration values of a different module
      * Once this function has been called with the name of the specification
-     * file of the module you want the configuration of, you can use
+     * file or the module you want the configuration of, you can use
      * \c getRemoteConfigValue() to get a specific setting.
-     * Changes are automatically updated, but you cannot specify handlers
-     * for those changes, must use \c getRemoteConfigValue() to get a value
-     * This function will subscribe to the relevant module channel.
+     * Changes are automatically updated, and you can specify handlers
+     * for those changes. This function will subscribe to the relevant module
+     * channel.
      *
-     * \param spec_file_name The path to the specification file of
-     *                       the module we want to have configuration
-     *                       values from
+     * \param spec_name This specifies the module to add. It is either a
+     *                  filename of the spec file to use or a name of module
+     *                  (in case it's a module name, the spec data is
+     *                  downloaded from the configuration manager, therefore
+     *                  the configuration manager must know it). If
+     *                  spec_is_filenabe is true (the default), then a
+     *                  filename is assumed, otherwise a module name.
+     * \param handler The handler function called whenever there's a change.
+     *                Called once initally from this function. May be NULL
+     *                if you don't want any handler to be called and you're
+     *                fine with requesting the data through
+     *                getRemoteConfigValue() each time.
+     *
+     *                The handler should not throw, or it'll fall trough and
+     *                the exception will get into strange places, probably
+     *                aborting the application.
+     * \param spec_is_filename Says if spec_name is filename or module name.
      * \return The name of the module specified in the given specification
      *         file
      */
-    std::string addRemoteConfig(const std::string& spec_file_name);
+    std::string addRemoteConfig(const std::string& spec_name,
+                                void (*handler)(const std::string& module_name,
+                                                isc::data::ConstElementPtr
+                                                update) = NULL,
+                                bool spec_is_filename = true);
 
     /**
      * Removes the module with the given name from the remote config
      * settings. If the module was not added with \c addRemoteConfig(),
-     * nothing happens.
+     * nothing happens. If there was a handler for this config, it is
+     * removed as well.
      */
     void removeRemoteConfig(const std::string& module_name);
 
@@ -282,7 +315,11 @@ private:
         const std::string& command,
         isc::data::ConstElementPtr args);
 
+    typedef void (*RemoteHandler)(const std::string&,
+                                  isc::data::ConstElementPtr);
     std::map<std::string, ConfigData> remote_module_configs_;
+    std::map<std::string, RemoteHandler> remote_module_handlers_;
+
     void updateRemoteConfig(const std::string& module_name,
                             isc::data::ConstElementPtr new_config);
 };
diff --git a/src/lib/config/config_log.cc b/src/lib/config/config_log.cc
new file mode 100644
index 0000000..672b9f1
--- /dev/null
+++ b/src/lib/config/config_log.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// Defines the logger used by the config lib
+
+#include "config/config_log.h"
+
+namespace isc {
+namespace config {
+
+isc::log::Logger config_logger("config");
+
+} // namespace nsas
+} // namespace isc
+
diff --git a/src/lib/config/config_log.h b/src/lib/config/config_log.h
new file mode 100644
index 0000000..22e5a5c
--- /dev/null
+++ b/src/lib/config/config_log.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __CONFIG_LOG__H
+#define __CONFIG_LOG__H
+
+#include <log/macros.h>
+#include "configdef.h"
+
+namespace isc {
+namespace config {
+
+/// \brief Config Logging
+///
+/// Defines logger object for config log messages
+
+/// \brief Config Logger
+///
+/// Define the logger used to log messages.  We could define it in multiple
+/// modules, but defining in a single module and linking to it saves time and
+/// space.
+extern isc::log::Logger config_logger;    // isc::config::config_logger is the CONFIG logger
+
+} // namespace config
+} // namespace isc
+
+#endif // __CONFIG_LOG__H
diff --git a/src/lib/config/configdef.mes b/src/lib/config/configdef.mes
new file mode 100644
index 0000000..4c3c991
--- /dev/null
+++ b/src/lib/config/configdef.mes
@@ -0,0 +1,50 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX CONFIG_
+$NAMESPACE isc::config
+
+% FOPEN_ERR     error opening %1: %2
+There was an error opening the given file.
+
+% JSON_PARSE    JSON parse error in %1: %2
+There was a parse error in the JSON file. The given file does not appear
+to be in valid JSON format. Please verify that the filename is correct
+and that the contents are valid JSON.
+
+% MODULE_SPEC   module specification error in %1: %2
+The given file does not appear to be a valid specification file. Please
+verify that the filename is correct and that its contents are a valid
+BIND10 module specification.
+
+% MANAGER_MOD_SPEC    module specification not accepted by cfgmgr: %1
+The module specification file for this module was rejected by the
+configuration manager. The full error message answer from the
+configuration manager is appended to the log error. The most likely
+cause is that the module is of a different (specification file) version
+than the running configuration manager.
+
+% MANAGER_CONFIG    error getting configuration from cfgmgr: %1
+The configuration manager returned an error when this module requested
+the configuration. The full error message answer from the configuration
+manager is appended to the log error. The most likely cause is that
+the module is of a different (command specification) version than the
+running configuration manager.
+
+% CCSESSION_MSG error in CC session message: %1
+There was a problem with an incoming message on the command and control
+channel. The message does not appear to be a valid command, and is
+missing a required element or contains an unknown data format. This
+most likely means that another BIND10 module is sending a bad message.
+The message itself is ignored by this module.
diff --git a/src/lib/config/tests/Makefile.am b/src/lib/config/tests/Makefile.am
index 0cebdbf..0d2c29b 100644
--- a/src/lib/config/tests/Makefile.am
+++ b/src/lib/config/tests/Makefile.am
@@ -24,6 +24,7 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 43663bd..3564d4b 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -264,10 +264,7 @@ TEST_F(CCSessionTest, checkCommand) {
 
     session.addMessage(el("{ \"command\": \"bad_command\" }"), "Spec29", "*");
     result = mccs.checkCommand();
-    EXPECT_EQ(1, session.getMsgQueue()->size());
-    msg = session.getFirstMessage(group, to);
-    EXPECT_EQ("{ \"result\": [ 1, \"Command part in command message missing, empty, or not a list\" ] }", msg->str());
-    EXPECT_EQ(0, result);
+    EXPECT_EQ(0, session.getMsgQueue()->size());
 
     session.addMessage(el("{ \"command\": [ \"bad_command\" ] }"),
                        "Spec29", "*");
@@ -349,6 +346,18 @@ TEST_F(CCSessionTest, checkCommand2) {
     EXPECT_EQ(2, mccs.getValue("item1")->intValue());
 }
 
+std::string remote_module_name;
+int remote_item1(0);
+ConstElementPtr remote_config;
+ModuleCCSession *remote_mccs(NULL);
+
+void remoteHandler(const std::string& module_name, ConstElementPtr config) {
+    remote_module_name = module_name;
+    remote_item1 = remote_mccs->getRemoteConfigValue("Spec2", "item1")->
+        intValue();
+    remote_config = config;
+}
+
 TEST_F(CCSessionTest, remoteConfig) {
     std::string module_name;
     int item1;
@@ -395,6 +404,91 @@ TEST_F(CCSessionTest, remoteConfig) {
     
     session.getMessages()->add(createAnswer());
     EXPECT_THROW(mccs.addRemoteConfig(ccspecfile("spec2.spec")), CCSessionError);
+
+    {
+        SCOPED_TRACE("With module name");
+        // Try adding it with downloading the spec from config manager
+        ModuleSpec spec(moduleSpecFromFile(ccspecfile("spec2.spec")));
+        session.getMessages()->add(createAnswer(0, spec.getFullSpec()));
+        session.getMessages()->add(createAnswer(0, el("{}")));
+
+        EXPECT_NO_THROW(module_name = mccs.addRemoteConfig("Spec2", NULL,
+                                                           false));
+
+        EXPECT_EQ("Spec2", module_name);
+        EXPECT_NO_THROW(item1 =
+                        mccs.getRemoteConfigValue(module_name,
+                                                  "item1")->intValue());
+        EXPECT_EQ(1, item1);
+
+        mccs.removeRemoteConfig(module_name);
+    }
+
+    {
+        // Try adding it with a handler.
+        // Pass non-default value to see the handler is called after
+        // downloading the configuration, not too soon.
+        SCOPED_TRACE("With handler");
+        session.getMessages()->add(createAnswer(0, el("{ \"item1\": 2 }")));
+        remote_mccs = &mccs;
+        module_name = mccs.addRemoteConfig(ccspecfile("spec2.spec"),
+                                           remoteHandler);
+        {
+            SCOPED_TRACE("Before update");
+            EXPECT_EQ("Spec2", module_name);
+            EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
+            // Now check the parameters the remote handler stored
+            // This also checks it was called
+            EXPECT_EQ("Spec2", remote_module_name);
+            remote_module_name = "";
+            EXPECT_EQ(2, remote_item1);
+            remote_item1 = 0;
+            if (remote_config) {
+                EXPECT_EQ(2, remote_config->get("item1")->intValue());
+            } else {
+                ADD_FAILURE() << "Remote config not set";
+            }
+            remote_config.reset();
+            // Make sure normal way still works
+            item1 = mccs.getRemoteConfigValue(module_name,
+                                              "item1")->intValue();
+            EXPECT_EQ(2, item1);
+        }
+
+        {
+            SCOPED_TRACE("After update");
+            session.addMessage(el("{ \"command\": [ \"config_update\", "
+                                  "{ \"item1\": 3 } ] }"), module_name, "*");
+            mccs.checkCommand();
+            EXPECT_EQ("Spec2", remote_module_name);
+            remote_module_name = "";
+            EXPECT_EQ(3, remote_item1);
+            remote_item1 = 0;
+            if (remote_config) {
+                EXPECT_EQ(3, remote_config->get("item1")->intValue());
+            } else {
+                ADD_FAILURE() << "Remote config not set";
+            }
+            remote_config.reset();
+            // Make sure normal way still works
+            item1 = mccs.getRemoteConfigValue(module_name,
+                                              "item1")->intValue();
+            EXPECT_EQ(3, item1);
+        }
+
+        remote_mccs = NULL;
+        mccs.removeRemoteConfig(module_name);
+
+        {
+            SCOPED_TRACE("When removed");
+            // Make sure nothing is called any more
+            session.addMessage(el("{ \"command\": [ \"config_update\", "
+                                  "{ \"item1\": 4 } ] }"), module_name, "*");
+            EXPECT_EQ("", remote_module_name);
+            EXPECT_EQ(0, remote_item1);
+            EXPECT_FALSE(remote_config);
+        }
+    }
 }
 
 TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
@@ -432,4 +526,24 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
     EXPECT_EQ(0, session.getMsgQueue()->size());
 }
 
+TEST_F(CCSessionTest, initializationFail) {
+    // bad specification
+    EXPECT_THROW(ModuleCCSession(ccspecfile("spec8.spec"), session,
+                                 NULL, NULL), CCSessionInitError);
+
+    // file that does not exist
+    EXPECT_THROW(ModuleCCSession(ccspecfile("does_not_exist_spec"),
+                                 session, NULL, NULL),
+                                 CCSessionInitError);
+
+
+    session.getMessages()->add(createAnswer(1, el("\"just an error\"")));
+
+    EXPECT_FALSE(session.haveSubscription("Spec29", "*"));
+    EXPECT_THROW(ModuleCCSession(ccspecfile("spec29.spec"), session,
+                                 my_config_handler, my_command_handler),
+                                 CCSessionInitError);
+    EXPECT_TRUE(session.haveSubscription("Spec29", "*"));
+}
+
 }
diff --git a/src/lib/config/tests/fake_session.cc b/src/lib/config/tests/fake_session.cc
index 29744c7..5f79d48 100644
--- a/src/lib/config/tests/fake_session.cc
+++ b/src/lib/config/tests/fake_session.cc
@@ -52,16 +52,14 @@ listContains(ConstElementPtr list, ConstElementPtr el) {
 
 void
 listRemove(ElementPtr list, ConstElementPtr el) {
-    int i = -1;
+    int i = 0;
     BOOST_FOREACH(ConstElementPtr s_el, list->listValue()) {
         if (*el == *s_el) {
-            i = 0;
+            list->remove(i);
+            return;
         }
         i++;
     }
-    if (i >= 0) {
-        list->remove(i);
-    }
 }
 // endwant
 
diff --git a/src/lib/config/tests/run_unittests.cc b/src/lib/config/tests/run_unittests.cc
index 0908071..fab90f5 100644
--- a/src/lib/config/tests/run_unittests.cc
+++ b/src/lib/config/tests/run_unittests.cc
@@ -13,9 +13,16 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <gtest/gtest.h>
+#include <log/logger_support.h>
 
 int
 main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
+
+    // TODO: UNCOMMENT ON MERGE
+    // (this is the call we want in master, but branch point does not
+    // have this yet)
+    //isc::log::initLogger();
+
     return (RUN_ALL_TESTS());
 }
diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am
new file mode 100644
index 0000000..93f3443
--- /dev/null
+++ b/src/lib/cryptolink/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(BOTAN_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libcryptolink.la
+
+libcryptolink_la_SOURCES = cryptolink.h cryptolink.cc
+libcryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
+
+libcryptolink_la_LIBADD = ${BOTAN_LDFLAGS} ${BOTAN_RPATH}
diff --git a/src/lib/cryptolink/crypto_hmac.cc b/src/lib/cryptolink/crypto_hmac.cc
new file mode 100644
index 0000000..14b43b3
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.cc
@@ -0,0 +1,281 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/version.h>
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+namespace {
+const char*
+getBotanHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm) {
+    switch (algorithm) {
+    case isc::cryptolink::MD5:
+        return ("MD5");
+        break;
+    case isc::cryptolink::SHA1:
+        return ("SHA-1");
+        break;
+    case isc::cryptolink::SHA256:
+        return ("SHA-256");
+        break;
+    case isc::cryptolink::SHA224:
+        return ("SHA-224");
+        break;
+    case isc::cryptolink::SHA384:
+        return ("SHA-384");
+        break;
+    case isc::cryptolink::SHA512:
+        return ("SHA-512");
+        break;
+    case isc::cryptolink::UNKNOWN_HASH:
+        return ("Unknown");
+        break;
+    }
+    // compiler should have prevented us to reach this, since we have
+    // no default. But we need a return value anyway
+    return ("Unknown");
+}
+
+} // local namespace
+
+
+namespace isc {
+namespace cryptolink {
+
+class HMACImpl {
+public:
+    explicit HMACImpl(const void* secret, size_t secret_len,
+                      const HashAlgorithm hash_algorithm) {
+        Botan::HashFunction* hash;
+        try {
+            hash = Botan::get_hash(
+                getBotanHashAlgorithmName(hash_algorithm));
+        } catch (const Botan::Algorithm_Not_Found&) {
+            isc_throw(isc::cryptolink::UnsupportedAlgorithm,
+                      "Unknown hash algorithm: " <<
+                      static_cast<int>(hash_algorithm));
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+
+        hmac_.reset(new Botan::HMAC(hash));
+
+        // If the key length is larger than the block size, we hash the
+        // key itself first.
+        try {
+            // use a temp var so we don't have blocks spanning
+            // preprocessor directives
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0)
+            size_t block_length = hash->hash_block_size();
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0)
+            size_t block_length = hash->HASH_BLOCK_SIZE;
+#else
+#error "Unsupported Botan version (need 1.8 or higher)"
+            // added to suppress irrelevant compiler errors
+            size_t block_length = 0;
+#endif
+            if (secret_len > block_length) {
+                Botan::SecureVector<Botan::byte> hashed_key =
+                    hash->process(static_cast<const Botan::byte*>(secret),
+                                  secret_len);
+                hmac_->set_key(hashed_key.begin(), hashed_key.size());
+            } else {
+                // Botan 1.8 considers len 0 a bad key. 1.9 does not,
+                // but we won't accept it anyway, and fail early
+                if (secret_len == 0) {
+                    isc_throw(BadKey, "Bad HMAC secret length: 0");
+                }
+                hmac_->set_key(static_cast<const Botan::byte*>(secret),
+                               secret_len);
+            }
+        } catch (const Botan::Invalid_Key_Length& ikl) {
+            isc_throw(BadKey, ikl.what());
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    ~HMACImpl() { }
+
+    size_t getOutputLength() const {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0)
+        return (hmac_->output_length());
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0)
+        return (hmac_->OUTPUT_LENGTH);
+#else
+#error "Unsupported Botan version (need 1.8 or higher)"
+        // added to suppress irrelevant compiler errors
+        return 0;
+#endif
+    }
+
+    void update(const void* data, const size_t len) {
+        try {
+            hmac_->update(static_cast<const Botan::byte*>(data), len);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    void sign(isc::util::OutputBuffer& result, size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+
+            if (len == 0 || len > b_result.size()) {
+                len = b_result.size();
+            }
+            result.writeData(b_result.begin(), len);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    void sign(void* result, size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+            size_t output_size = getOutputLength();
+            if (output_size > len) {
+                output_size = len;
+            }
+            memcpy(result, b_result.begin(), output_size);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    std::vector<uint8_t> sign(size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+            if (len == 0 || len > b_result.size()) {
+                return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
+            } else {
+                return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
+            }
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+
+    bool verify(const void* sig, size_t len) {
+        // Botan's verify_mac checks if len matches the output_length,
+        // which causes it to fail for truncated signatures, so we do
+        // the check ourselves
+        // SEE BELOW FOR TEMPORARY CHANGE
+        try {
+            Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
+            if (len < getOutputLength()) {
+                // Currently we don't support truncated signature.  To avoid
+                // validating too short signature accidently, we enforce the
+                // standard signature size for the moment.
+                // Once we support truncation correctly, this if-clause should
+                // (and the capitalized comment above) be removed.
+                return (false);
+            }
+            if (len == 0 || len > getOutputLength()) {
+                len = getOutputLength();
+            }
+            return (Botan::same_mem(&our_mac[0],
+                                    static_cast<const unsigned char*>(sig),
+                                    len));
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+private:
+    boost::scoped_ptr<Botan::HMAC> hmac_;
+};
+
+HMAC::HMAC(const void* secret, size_t secret_length,
+           const HashAlgorithm hash_algorithm)
+{
+    impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
+}
+
+HMAC::~HMAC() {
+    delete impl_;
+}
+
+size_t
+HMAC::getOutputLength() const {
+    return (impl_->getOutputLength());
+}
+
+void
+HMAC::update(const void* data, const size_t len) {
+    impl_->update(data, len);
+}
+
+void
+HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
+    impl_->sign(result, len);
+}
+
+void
+HMAC::sign(void* result, size_t len) {
+    impl_->sign(result, len);
+}
+
+std::vector<uint8_t>
+HMAC::sign(size_t len) {
+    return impl_->sign(len);
+}
+
+bool
+HMAC::verify(const void* sig, const size_t len) {
+    return (impl_->verify(sig, len));
+}
+
+void
+signHMAC(const void* data, size_t data_len, const void* secret,
+         size_t secret_len, const HashAlgorithm hash_algorithm,
+         isc::util::OutputBuffer& result, size_t len)
+{
+    boost::scoped_ptr<HMAC> hmac(
+        CryptoLink::getCryptoLink().createHMAC(secret,
+                                               secret_len,
+                                               hash_algorithm));
+    hmac->update(data, data_len);
+    hmac->sign(result, len);
+}
+
+
+bool
+verifyHMAC(const void* data, const size_t data_len, const void* secret,
+           size_t secret_len, const HashAlgorithm hash_algorithm,
+           const void* sig, const size_t sig_len)
+{
+    boost::scoped_ptr<HMAC> hmac(
+        CryptoLink::getCryptoLink().createHMAC(secret,
+                                               secret_len,
+                                               hash_algorithm));
+    hmac->update(data, data_len);
+    return (hmac->verify(sig, sig_len));
+}
+
+void
+deleteHMAC(HMAC* hmac) {
+    delete hmac;
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
new file mode 100644
index 0000000..2eb0d0e
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -0,0 +1,209 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/buffer.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/cryptolink.h>
+
+#ifndef _ISC_CRYPTO_HMAC_H
+#define _ISC_CRYPTO_HMAC_H
+
+namespace isc {
+namespace cryptolink {
+
+/// Forward declaration, pimpl style
+class HMACImpl;
+
+/// \brief HMAC support
+///
+/// This class is used to create and verify HMAC signatures. Instances
+/// can be created with CryptoLink::createHMAC()
+///
+class HMAC : private boost::noncopyable {
+private:
+    /// \brief Constructor from a secret and a hash algorithm
+    ///
+    /// \exception UnsupportedAlgorithmException if the given algorithm
+    ///            is unknown or not supported by the underlying library
+    /// \exception InvalidKeyLength if the given key secret_len is bad
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// Notes: if the secret is longer than the block size of its
+    /// algorithm, the constructor will run it through the hash
+    /// algorithm, and use the digest as the secret for this HMAC
+    /// operation
+    ///
+    /// \param secret The secret to sign with
+    /// \param len The length of the secret
+    /// \param hash_algorithm The hash algorithm
+    HMAC(const void* secret, size_t secret_len,
+         const HashAlgorithm hash_algorithm);
+
+    friend HMAC* CryptoLink::createHMAC(const void*, size_t,
+                                        const HashAlgorithm);
+
+public:
+    /// \brief Destructor
+    ~HMAC();
+
+    /// \brief Returns the output size of the digest
+    ///
+    /// \return output size of the digest
+    size_t getOutputLength() const;
+
+    /// \brief Add data to digest
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param data The data to add
+    /// \param len The size of the data
+    void update(const void* data, const size_t len);
+
+    /// \brief Calculate the final signature
+    ///
+    /// The result will be appended to the given outputbuffer
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param result The OutputBuffer to append the result to
+    /// \param len The number of bytes from the result to copy. If this
+    ///        value is smaller than the algorithms output size, the
+    ///        result will be truncated. If this value is larger, or 0
+    ///        (the default), it will be ignored
+    void sign(isc::util::OutputBuffer& result, size_t len = 0);
+
+    /// \brief Calculate the final signature
+    ///
+    /// len bytes of data from the result will be copied to *result
+    /// If len is larger than the output size, only output_size bytes
+    /// will be copied. If it is smaller, the output will be truncated
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// At least len bytes of data must be available for writing at
+    /// result
+    void sign(void* result, size_t len);
+
+    /// \brief Calculate the final signatre
+    ///
+    /// The result will be returned as a std::vector<uint8_t>
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param len The number of bytes from the result to copy. If this
+    ///        value is smaller than the algorithms output size, the
+    ///        result will be truncated. If this value is larger, or 0
+    ///        (the default), it will be ignored
+    /// \return a vector containing the signature
+    std::vector<uint8_t> sign(size_t len = 0);
+
+    /// \brief Verify an existing signature
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param sig The signature to verify
+    /// \param len The length of the signature. If this is non-zero,
+    ///            and smaller than the output length of the algorithm,
+    ///            only len bytes will be checked
+    /// \return true if the signature is correct, false otherwise
+    bool verify(const void* sig, size_t len);
+
+private:
+    HMACImpl* impl_;
+};
+
+/// \brief Create an HMAC signature for the given data
+///
+/// This is a convenience function that calculates the hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and calculating the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+///            or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+///                         in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to sign
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param result The signature will be appended to this buffer
+/// \param len If this is non-zero and less than the output size,
+///            the result will be truncated to len bytes
+void signHMAC(const void* data,
+              const size_t data_len,
+              const void* secret,
+              size_t secret_len,
+              const HashAlgorithm hash_algorithm,
+              isc::util::OutputBuffer& result,
+              size_t len = 0);
+
+/// \brief Verify an HMAC signature for the given data
+///
+/// This is a convenience function that verifies an hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and checking the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+///            or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+///                         in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to verify
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param sig The signature to verify
+/// \param sig_len The length of the signature
+/// \return True if the signature verifies, false if not
+bool verifyHMAC(const void* data,
+                const size_t data_len,
+                const void* secret,
+                size_t secret_len,
+                const HashAlgorithm hash_algorithm,
+                const void* sig,
+                const size_t sig_len);
+
+/// \brief Delete an HMAC object
+void deleteHMAC(HMAC* hmac);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // __ISC_CRYPTO_HMAC
+
diff --git a/src/lib/cryptolink/cryptolink.cc b/src/lib/cryptolink/cryptolink.cc
new file mode 100644
index 0000000..d1c375d
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <botan/botan.h>
+
+namespace isc {
+namespace cryptolink {
+
+// For Botan, we use the CryptoLink class object in RAII style
+class CryptoLinkImpl {
+private:
+    Botan::LibraryInitializer botan_init_;
+};
+
+CryptoLink::~CryptoLink() {
+    delete impl_;
+}
+
+CryptoLink&
+CryptoLink::getCryptoLink() {
+    CryptoLink& c = getCryptoLinkInternal();
+    if (c.impl_ == NULL) {
+        c.initialize();
+    }
+    return (c);
+}
+
+CryptoLink&
+CryptoLink::getCryptoLinkInternal() {
+    static CryptoLink instance;
+    return (instance);
+}
+
+void
+CryptoLink::initialize() {
+    CryptoLink& c = getCryptoLinkInternal();
+    if (c.impl_ == NULL) {
+        try {
+            c.impl_ = new CryptoLinkImpl();
+        } catch (const Botan::Exception& ex) {
+            isc_throw(InitializationError, ex.what());
+        }
+    }
+}
+
+HMAC*
+CryptoLink::createHMAC(const void* secret, size_t secret_len,
+                       const HashAlgorithm hash_algorithm)
+{
+    return (new HMAC(secret, secret_len, hash_algorithm));
+}
+
+} // namespace cryptolink
+} // namespace isc
+
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
new file mode 100644
index 0000000..d0f7d38
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.h
@@ -0,0 +1,208 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef _ISC_CRYPTO_H
+#define _ISC_CRYPTO_H
+
+#include <string>
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <memory>
+
+namespace isc {
+namespace cryptolink {
+
+/// \brief Hash algorithm identifiers
+enum HashAlgorithm {
+    UNKNOWN_HASH = 0,   ///< This value can be used in conversion
+                        ///  functions, to be returned when the
+                        ///  input is unknown (but a value MUST be
+                        ///  returned), for instance when the input
+                        ///  is a Name or a string, and the return
+                        ///  value is a HashAlgorithm.
+    MD5 = 1,            ///< MD5
+    SHA1 = 2,           ///< SHA-1
+    SHA256 = 3,         ///< SHA-256
+    SHA224 = 4,         ///< SHA-224
+    SHA384 = 5,         ///< SHA-384
+    SHA512 = 6          ///< SHA-512
+
+};
+
+// Forward declaration for createHMAC()
+class HMAC;
+
+/// General exception class that is the base for all crypto-related
+/// exceptions
+class CryptoLinkError : public Exception {
+public:
+    CryptoLinkError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// This exception is thrown if there was a problem initializing the
+/// crypto library
+class InitializationError : public CryptoLinkError {
+public:
+    InitializationError(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when a cryptographic action is requested
+/// for an algorithm that is not supported by the underlying library.
+class UnsupportedAlgorithm : public CryptoLinkError {
+public:
+    UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when the underlying library could not
+/// handle the key data.
+class BadKey : public CryptoLinkError {
+public:
+    BadKey(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is raised when a general error that was not
+/// specifically caught is thrown by the underlying library. It
+/// is replaced by this one so as not have 'external' exceptions
+/// bubbling up
+class LibraryError : public CryptoLinkError {
+public:
+    LibraryError(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// Forward declaration for pimpl
+class CryptoLinkImpl;
+
+/// \brief Singleton entry point and factory class
+///
+/// This is a singleton class that serves as the entry point to
+/// the underlying cryptography library, and as a factory for objects
+/// within the cryptolink library.
+///
+/// There is only one way to access it, through getCryptoLink(), which
+/// returns a reference to the initialized library. On the first call,
+/// it will be initialized automatically. You can however initialize it
+/// manually through a call to the initalize(), before your first call
+/// to getCryptoLink. Any subsequent call to initialize() will be a
+/// noop.
+///
+/// In order for the CryptoLink library to be sure that the underlying
+/// library has been initialized, and because we do not want to add
+/// such a check to every class and function within it, we have made
+/// the constructors of all classes within cryptolink private. This way
+/// a caller cannot instantiate an object before the library is
+/// initialized, but must use CryptoLink's create method (e.g.
+/// createHMAC()), which enforces (automatic) initialization.
+///
+/// In order for the CryptoLink class to be able to create objects that
+/// have private constructors, it is declared a friend class of these
+/// classes.
+///
+/// Since these factory functions return bare pointers, we also provide
+/// deleter functions for them (e.g. deleteHMAC()), so that a caller
+/// can use that to make sure it uses the correct delete operator (the
+/// one defined at compilation time of this library). A way to make
+/// sure you do not forget this, is to place the result of the create
+/// functions in a shared_ptr with the corresponding deleter function.
+///
+/// \note All other classes within cryptolink should have private
+/// constructors as well, and should have a factory function from
+/// CryptoLink, and a deleter function.
+///
+// Internal note: we can use this class later to initialize and manage
+// dynamic (PKCS#11) libs
+class CryptoLink : private boost::noncopyable {
+public:
+    /// \brief Returns a reference to the singleton instance
+    ///
+    /// If the library has not been initialized yet, it will be
+    /// initialized with some default values.
+    ///
+    /// Since this class is noncopyable, you must use the return
+    /// value directly, or store it in a reference variable.
+    ///
+    /// \exception InitializationError if initialization fails
+    ///
+    /// \return Reference to the singleton instance
+    static CryptoLink& getCryptoLink();
+
+    /// \brief Initialize the library manually
+    ///
+    /// If the library has already been initialized (either by a call
+    /// to initialize() or automatically in getCryptoLink()), this
+    /// function does nothing.
+    ///
+    /// \note A call to initialize() is not strictly necessary with
+    /// the current implementation.
+    ///
+    /// \exception InitializationError if initialization fails
+    ///
+    static void initialize();
+
+    /// \brief Factory function for HMAC objects
+    ///
+    /// CryptoLink objects cannot be constructed directly. This
+    /// function creates a new HMAC object usable for signing or
+    /// verification.
+    ///
+    /// The caller is responsible for deleting the object, and it is
+    /// therefore highly recommended to place the return value of this
+    /// function in a scoped_ptr or shared_ptr.
+    ///
+    /// Notes: if the secret is longer than the block size of its
+    /// algorithm, the constructor will run it through the hash
+    /// algorithm, and use the digest as the secret for this HMAC
+    /// operation
+    ///
+    /// If you want to safely delete objects created with this method,
+    /// you can use the function deleteHMAC() as defined in
+    /// crypto_hmac.h
+    ///
+    /// \exception UnsupportedAlgorithmException if the given algorithm
+    ///            is unknown or not supported by the underlying library
+    /// \exception InvalidKeyLength if the given key secret_len is bad
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param secret The secret to sign with
+    /// \param secret_len The length of the secret
+    /// \param hash_algorithm The hash algorithm
+    HMAC* createHMAC(const void* secret, size_t secret_len,
+                     const HashAlgorithm hash_algorithm);
+
+private:
+    // To enable us to use an optional explicit initialization call,
+    // the 'real' instance getter is private
+    static CryptoLink& getCryptoLinkInternal();
+
+    // To prevent people constructing their own, we make the constructor
+    // private too.
+    CryptoLink() : impl_(NULL) {}
+    ~CryptoLink();
+
+    CryptoLinkImpl* impl_;
+};
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // _ISC_CRYPTO_H
diff --git a/src/lib/cryptolink/tests/Makefile.am b/src/lib/cryptolink/tests/Makefile.am
new file mode 100644
index 0000000..c8b5e26
--- /dev/null
+++ b/src/lib/cryptolink/tests/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += crypto_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
new file mode 100644
index 0000000..339eb1b
--- /dev/null
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -0,0 +1,756 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+using namespace isc::util;
+using namespace isc::cryptolink;
+
+namespace {
+    void checkData(const uint8_t* data, const uint8_t* expected,
+                   size_t len) {
+        for (size_t i = 0; i < len; ++i) {
+            ASSERT_EQ(expected[i], data[i]);
+        }
+    }
+
+    void checkBuffer(const OutputBuffer& buf, const uint8_t* expected,
+                     size_t len)
+    {
+        ASSERT_EQ(len, buf.getLength());
+        checkData(static_cast<const uint8_t*>(buf.getData()), expected,
+                  len);
+    }
+
+    // Sign and verify with the convenience functions
+    void doHMACTestConv(const std::string& data,
+                        const void* secret,
+                        size_t secret_len,
+                        const HashAlgorithm hash_algorithm,
+                        const uint8_t* expected_hmac,
+                        size_t hmac_len) {
+        OutputBuffer data_buf(data.size());
+        data_buf.writeData(data.c_str(), data.size());
+        OutputBuffer hmac_sig(0);
+
+        // Sign it
+        signHMAC(data_buf.getData(), data_buf.getLength(),
+                 secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
+
+        // Check if the signature is what we expect
+        checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+        // Check whether we can verify it ourselves
+        EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                               secret, secret_len, hash_algorithm,
+                               hmac_sig.getData(),
+                               hmac_sig.getLength()));
+
+        // Change the sig by flipping the first octet, and check
+        // whether verification fails then
+        hmac_sig.writeUint8At(~hmac_sig[0], 0);
+        EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                               secret, secret_len, hash_algorithm,
+                               hmac_sig.getData(),
+                               hmac_sig.getLength()));
+    }
+
+    // Sign and verify with an instantiation of an HMAC object
+    void doHMACTestDirect(const std::string& data,
+                          const void* secret,
+                          size_t secret_len,
+                          const HashAlgorithm hash_algorithm,
+                          const uint8_t* expected_hmac,
+                          size_t hmac_len) {
+        OutputBuffer data_buf(data.size());
+        data_buf.writeData(data.c_str(), data.size());
+        OutputBuffer hmac_sig(1);
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+        // Sign it
+        boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm),
+                                          deleteHMAC);
+        hmac_sign->update(data_buf.getData(), data_buf.getLength());
+        hmac_sign->sign(hmac_sig, hmac_len);
+
+        // Check if the signature is what we expect
+        checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+        // Check whether we can verify it ourselves
+        boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm),
+                                            deleteHMAC);
+        hmac_verify->update(data_buf.getData(), data_buf.getLength());
+        EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
+                                        hmac_sig.getLength()));
+
+        // Change the sig by flipping the first octet, and check
+        // whether verification fails then
+        hmac_sig.writeUint8At(~hmac_sig[0], 0);
+        EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
+                                         hmac_sig.getLength()));
+    }
+
+    void doHMACTestVector(const std::string& data,
+                          const void* secret,
+                          size_t secret_len,
+                          const HashAlgorithm hash_algorithm,
+                          const uint8_t* expected_hmac,
+                          size_t hmac_len) {
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+        boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm),
+                                          deleteHMAC);
+        hmac_sign->update(data.c_str(), data.size());
+        std::vector<uint8_t> sig = hmac_sign->sign(hmac_len);
+        ASSERT_EQ(hmac_len, sig.size());
+        checkData(&sig[0], expected_hmac, hmac_len);
+
+        boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm),
+                                            deleteHMAC);
+        hmac_verify->update(data.c_str(), data.size());
+        EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
+
+        sig[0] = ~sig[0];
+        EXPECT_FALSE(hmac_verify->verify(&sig[0], sig.size()));
+    }
+
+    void doHMACTestArray(const std::string& data,
+                         const void* secret,
+                         size_t secret_len,
+                         const HashAlgorithm hash_algorithm,
+                         const uint8_t* expected_hmac,
+                         size_t hmac_len) {
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+        boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm),
+                                          deleteHMAC);
+        hmac_sign->update(data.c_str(), data.size());
+
+        // note: this is not exception-safe, and can leak, but
+        // if there is an unexpected exception in the code below we
+        // have more important things to fix.
+        uint8_t* sig = new uint8_t[hmac_len];
+
+        hmac_sign->sign(sig, hmac_len);
+        checkData(sig, expected_hmac, hmac_len);
+
+        boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm),
+                                            deleteHMAC);
+        hmac_verify->update(data.c_str(), data.size());
+        EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
+
+        sig[0] = ~sig[0];
+        EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
+
+        delete[] sig;
+    }
+
+    void doHMACTest(const std::string& data,
+                    const void* secret,
+                    size_t secret_len,
+                    const HashAlgorithm hash_algorithm,
+                    const uint8_t* expected_hmac,
+                    size_t hmac_len) {
+        doHMACTestConv(data, secret, secret_len, hash_algorithm,
+                       expected_hmac, hmac_len);
+        doHMACTestDirect(data, secret, secret_len, hash_algorithm,
+                         expected_hmac, hmac_len);
+        doHMACTestVector(data, secret, secret_len, hash_algorithm,
+                         expected_hmac, hmac_len);
+        doHMACTestArray(data, secret, secret_len, hash_algorithm,
+                        expected_hmac, hmac_len);
+    }
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_MD5_RFC2202_SIGN) {
+    const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b };
+    const uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36,
+                                      0x38, 0xbb, 0x1c, 0x13, 0xf4,
+                                      0x8e, 0xf8, 0x15, 0x8b, 0xfc,
+                                      0x9d };
+    doHMACTest("Hi There", secret, 16, MD5, hmac_expected, 16);
+
+    const uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a,
+                                       0xb0, 0xb5, 0x03, 0xea, 0xa8,
+                                       0x6e, 0x31, 0x0a, 0x5d, 0xb7,
+                                       0x38 };
+    doHMACTest("what do ya want for nothing?", "Jefe", 4, MD5,
+               hmac_expected2, 16);
+
+    const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa };
+    const uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d,
+                                       0x14, 0x4c, 0x88, 0xdb, 0xb8,
+                                       0xc7, 0x33, 0xf0, 0xe8, 0xb3,
+                                       0xf6};
+    doHMACTest(std::string(50, 0xdd), secret3, 16, MD5, hmac_expected3, 16);
+
+    const std::string data4(50, 0xcd);
+    const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+                                0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                0x19 };
+    const uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca,
+                                       0x3a, 0x3a, 0xea, 0x3a, 0x75,
+                                       0x16, 0x47, 0x46, 0xff, 0xaa,
+                                       0x79 };
+    doHMACTest(data4, secret4, 25, MD5, hmac_expected4, 16);
+
+    const uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b,
+                                       0xd7, 0xbf, 0x8f, 0x0b, 0x62,
+                                       0xe6, 0xce, 0x61, 0xb9, 0xd0,
+                                       0xcd };
+    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+               std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected6, 16);
+
+    const uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67,
+                                       0xcd, 0xa0, 0xee, 0x1f, 0xb1,
+                                       0xf5, 0x62, 0xdb, 0x3a, 0xa5,
+                                       0x3e };
+    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+               "One Block-Size Data",
+               std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected7, 16);
+}
+
+// Temporarily disabled
+TEST(CryptoLinkTest, DISABLED_HMAC_MD5_RFC2202_SIGN_TRUNCATED) {
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34,
+                                       0x2e, 0xdc, 0x00, 0xf9, 0xba,
+                                       0xb9, 0x95, 0x69, 0x0e, 0xfd,
+                                       0x4c };
+    doHMACTest("Test With Truncation", secret5, 16, MD5,
+               hmac_expected5, 16);
+    doHMACTest("Test With Truncation", secret5, 16, MD5,
+               hmac_expected5, 12);
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_SHA1_RFC2202_SIGN) {
+    const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+    const uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55,
+                                      0x05, 0x72, 0x64, 0xe2, 0x8b,
+                                      0xc0, 0xb6, 0xfb, 0x37, 0x8c,
+                                      0x8e, 0xf1, 0x46, 0xbe, 0x00 };
+    doHMACTest("Hi There", secret, 20, SHA1, hmac_expected, 20);
+
+    const uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5,
+                                       0xeb, 0x2f, 0xa2, 0xd2, 0x74,
+                                       0x16, 0xd5, 0xf1, 0x84, 0xdf,
+                                       0x9c, 0x25, 0x9a, 0x7c, 0x79 };
+    doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA1,
+               hmac_expected2, 20);
+
+    const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa };
+    const uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9,
+                                       0xac, 0x11, 0xcd, 0x91, 0xa3,
+                                       0x9a, 0xf4, 0x8a, 0xa1, 0x7b,
+                                       0x4f, 0x63, 0xf1, 0x75, 0xd3 };
+    doHMACTest(std::string(50, 0xdd), secret3, 20, SHA1, hmac_expected3, 20);
+
+    const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+                                0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                0x19 };
+    const uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02,
+                                       0x62, 0x50, 0xc6, 0xbc, 0x84,
+                                       0x14, 0xf9, 0xbf, 0x50, 0xc8,
+                                       0x6c, 0x2d, 0x72, 0x35, 0xda };
+    doHMACTest(std::string(50, 0xcd), secret4, 25, SHA1, hmac_expected4, 20);
+
+    const uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52,
+                                       0x72, 0xd0, 0x0e, 0x95, 0x70,
+                                       0x56, 0x37, 0xce, 0x8a, 0x3b,
+                                       0x55, 0xed, 0x40, 0x21, 0x12 };
+    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+               std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected6, 20);
+
+    const uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45,
+                                       0x23, 0x7d, 0x78, 0x6d, 0x6b,
+                                       0xba, 0xa7, 0x96, 0x5c, 0x78,
+                                       0x08, 0xbb, 0xff, 0x1a, 0x91 };
+    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+               "One Block-Size Data",
+               std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected7, 20);
+}
+
+// Temporarily disabled
+TEST(CryptoLinkTest, DISABLED_HMAC_SHA1_RFC2202_SIGN_TRUNCATED) {
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b,
+                                       0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+                                       0x7b, 0xe1, 0xd5, 0x8b, 0xb9,
+                                       0x32, 0x4a, 0x9a, 0x5a, 0x04 };
+    doHMACTest("Test With Truncation", secret5, 20, SHA1,
+               hmac_expected5, 20);
+    doHMACTest("Test With Truncation", secret5, 20, SHA1,
+               hmac_expected5, 12);
+}
+
+//
+// Test values taken from RFC 4231
+//
+//
+//  Test data from RFC4231, including secret key
+//  and source data, they are common for sha224/256/384/512
+//  so put them together in seperate space
+namespace {
+    static const uint8_t secret1[] = { 
+        0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 
+        0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+        0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b 
+    };
+
+    static const uint8_t secret2[] = "Jefe";
+    static const uint8_t secret3[] = { 
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+        0xaa, 0xaa 
+    };
+    static  const uint8_t secret4[] = { 
+        0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+        0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+        0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+        0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+        0x19 
+    };
+    static const uint8_t secret5[] = { 
+        0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c 
+    };
+
+    static uint8_t secret6[131]; 
+    static uint8_t secret7[131]; 
+
+    static const std::string data1("Hi There");
+    static const std::string data2("what do ya want for nothing?");
+    static const std::string data3(std::string(50, 0xdd));
+    static const std::string data4(std::string(50, 0xcd));
+    static const std::string data5("Test With Truncation");
+    static const std::string data6("Test Using Larger Than Block-Size Key - Hash Key First");
+    static const std::string data7("This is a test using a larger than block-size key and a"
+            " larger than block-size data. The key needs to be hashe"
+            "d before being used by the HMAC algorithm.");
+#define SECRECT(n) secret##n
+#define DATA(n) data##n
+#define HMAC_EXPECTED(n) hmac_expected##n
+
+#define RUN_NTH_TEST_CASE_FOR_ALG(index, hash_algorithm) do {\
+                doHMACTest(DATA(index), \
+                           SECRECT(index), sizeof(SECRECT(index)), \
+                           (hash_algorithm), HMAC_EXPECTED(index), \
+                           sizeof(HMAC_EXPECTED(index)));\
+            }while(0)
+
+#define RUN_TEST_CASES_FOR_ALG(alg) do {\
+        memcpy(secret6, std::string(131, 0xaa).c_str(), 131); \
+        memcpy(secret7, std::string(131, 0xaa).c_str(), 131); \
+        RUN_NTH_TEST_CASE_FOR_ALG(1, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(2, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(3, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(4, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(5, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(6, alg); \
+        RUN_NTH_TEST_CASE_FOR_ALG(7, alg); \
+    }while(0)
+
+
+};
+
+TEST(CryptoLinkTest, HMAC_SHA256_RFC4231_SIGN) {
+    const uint8_t hmac_expected1[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8,
+                                      0xdb, 0x38, 0x53, 0x5c, 0xa8,
+                                      0xaf, 0xce, 0xaf, 0x0b, 0xf1,
+                                      0x2b, 0x88, 0x1d, 0xc2, 0x00,
+                                      0xc9, 0x83, 0x3d, 0xa7, 0x26,
+                                      0xe9, 0x37, 0x6c, 0x2e, 0x32,
+                                      0xcf, 0xf7 };
+    const uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf,
+                                       0x60, 0x75, 0x4e, 0x6a, 0x04,
+                                       0x24, 0x26, 0x08, 0x95, 0x75,
+                                       0xc7, 0x5a, 0x00, 0x3f, 0x08,
+                                       0x9d, 0x27, 0x39, 0x83, 0x9d,
+                                       0xec, 0x58, 0xb9, 0x64, 0xec,
+                                       0x38, 0x43 };
+    const uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36,
+                                       0x80, 0x0e, 0x46, 0x85, 0x4d,
+                                       0xb8, 0xeb, 0xd0, 0x91, 0x81,
+                                       0xa7, 0x29, 0x59, 0x09, 0x8b,
+                                       0x3e, 0xf8, 0xc1, 0x22, 0xd9,
+                                       0x63, 0x55, 0x14, 0xce, 0xd5,
+                                       0x65, 0xfe };
+    const uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a,
+                                       0x44, 0x3c, 0x0e, 0xa4, 0xcc,
+                                       0x81, 0x98, 0x99, 0xf2, 0x08,
+                                       0x3a, 0x85, 0xf0, 0xfa, 0xa3,
+                                       0xe5, 0x78, 0xf8, 0x07, 0x7a,
+                                       0x2e, 0x3f, 0xf4, 0x67, 0x29,
+                                       0x66, 0x5b };
+//    const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
+//                                       0x10, 0x0e, 0xe0, 0x6e, 0x0c,
+//                                       0x79, 0x6c, 0x29, 0x55, 0x55,
+//                                       0x2b };
+    const uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e,
+                                       0xe0, 0xb6, 0x7f, 0x0d, 0x8a,
+                                       0x26, 0xaa, 0xcb, 0xf5, 0xb7,
+                                       0x7f, 0x8e, 0x0b, 0xc6, 0x21,
+                                       0x37, 0x28, 0xc5, 0x14, 0x05,
+                                       0x46, 0x04, 0x0f, 0x0e, 0xe3,
+                                       0x7f, 0x54 };
+    const uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b,
+                                       0x94, 0x2f, 0xcb, 0x27, 0x63,
+                                       0x5f, 0xbc, 0xd5, 0xb0, 0xe9,
+                                       0x44, 0xbf, 0xdc, 0x63, 0x64,
+                                       0x4f, 0x07, 0x13, 0x93, 0x8a,
+                                       0x7f, 0x51, 0x53, 0x5c, 0x3a,
+                                       0x35, 0xe2 };
+
+    memcpy(secret6, std::string(131, 0xaa).c_str(), 131); 
+    memcpy(secret7, std::string(131, 0xaa).c_str(), 131); 
+    RUN_NTH_TEST_CASE_FOR_ALG(1, SHA256); 
+    RUN_NTH_TEST_CASE_FOR_ALG(2, SHA256); 
+    RUN_NTH_TEST_CASE_FOR_ALG(3, SHA256);
+    RUN_NTH_TEST_CASE_FOR_ALG(4, SHA256); 
+    RUN_NTH_TEST_CASE_FOR_ALG(6, SHA256); 
+    RUN_NTH_TEST_CASE_FOR_ALG(7, SHA256); 
+ 
+}
+
+
+//
+// Test values taken from RFC 4231, test optional algorithm 224,384,512
+//
+TEST(CryptoLinkTest, DISABLED_HMAC_SHA224_RFC4231_SIGN) {
+    const uint8_t hmac_expected1[] = { 
+        0x89,0x6f,0xb1,0x12,0x8a,0xbb,0xdf,0x19,0x68,0x32,0x10,0x7c,
+        0xd4,0x9d,0xf3,0x3f,0x47,0xb4,0xb1,0x16,0x99,0x12,0xba,0x4f,
+        0x53,0x68,0x4b,0x22
+    };
+    const uint8_t hmac_expected2[] = { 
+        0xa3,0x0e,0x01,0x09,0x8b,0xc6,0xdb,0xbf,0x45,0x69,0x0f,0x3a,
+        0x7e,0x9e,0x6d,0x0f,0x8b,0xbe,0xa2,0xa3,0x9e,0x61,0x48,0x00,
+        0x8f,0xd0,0x5e,0x44
+    };
+ 
+    const uint8_t hmac_expected3[] = {
+        0x7f,0xb3,0xcb,0x35,0x88,0xc6,0xc1,0xf6,0xff,0xa9,0x69,0x4d,
+        0x7d,0x6a,0xd2,0x64,0x93,0x65,0xb0,0xc1,0xf6,0x5d,0x69,0xd1,
+        0xec,0x83,0x33,0xea
+    };
+
+    const uint8_t hmac_expected4[] = {
+        0x6c,0x11,0x50,0x68,0x74,0x01,0x3c,0xac,0x6a,0x2a,0xbc,0x1b,
+        0xb3,0x82,0x62,0x7c,0xec,0x6a,0x90,0xd8,0x6e,0xfc,0x01,0x2d,
+        0xe7,0xaf,0xec,0x5a
+    };
+ 
+//    const uint8_t hmac_expected5[] = {
+//        0x0e,0x2a,0xea,0x68,0xa9,0x0c,0x8d,0x37,0xc9,0x88,0xbc,0xdb,0x9f,
+//        0xca,0x6f,0xa8
+//    };
+
+    const uint8_t hmac_expected6[] = {
+        0x95,0xe9,0xa0,0xdb,0x96,0x20,0x95,0xad,0xae,0xbe,0x9b,0x2d,0x6f,
+        0x0d,0xbc,0xe2,0xd4,0x99,0xf1,0x12,0xf2,0xd2,0xb7,0x27,0x3f,0xa6,
+        0x87,0x0e
+    };
+
+    const uint8_t hmac_expected7[] = {
+        0x3a,0x85,0x41,0x66,0xac,0x5d,0x9f,0x02,0x3f,0x54,0xd5,0x17,0xd0,
+        0xb3,0x9d,0xbd,0x94,0x67,0x70,0xdb,0x9c,0x2b,0x95,0xc9,0xf6,0xf5,
+        0x65,0xd1
+    };
+ 
+    memcpy(secret6, std::string(131, 0xaa).c_str(), 131); 
+    memcpy(secret7, std::string(131, 0xaa).c_str(), 131); 
+    RUN_NTH_TEST_CASE_FOR_ALG(1, SHA224); 
+    RUN_NTH_TEST_CASE_FOR_ALG(2, SHA224); 
+    RUN_NTH_TEST_CASE_FOR_ALG(3, SHA224);
+    RUN_NTH_TEST_CASE_FOR_ALG(4, SHA224); 
+    RUN_NTH_TEST_CASE_FOR_ALG(6, SHA224); 
+    RUN_NTH_TEST_CASE_FOR_ALG(7, SHA224); 
+}
+
+        
+TEST(CryptoLinkTest, HMAC_SHA384_RFC4231_SIGN) {
+    const uint8_t hmac_expected1[] = { 
+        0xaf,0xd0,0x39,0x44,0xd8,0x48,0x95,0x62,0x6b,0x08,0x25,0xf4,
+        0xab,0x46,0x90,0x7f,0x15,0xf9,0xda,0xdb,0xe4,0x10,0x1e,0xc6,
+        0x82,0xaa,0x03,0x4c,0x7c,0xeb,0xc5,0x9c,0xfa,0xea,0x9e,0xa9,
+        0x07,0x6e,0xde,0x7f,0x4a,0xf1,0x52,0xe8,0xb2,0xfa,0x9c,0xb6
+    };
+
+    const uint8_t hmac_expected2[] = {
+        0xaf,0x45,0xd2,0xe3,0x76,0x48,0x40,0x31,0x61,0x7f,0x78,0xd2,
+        0xb5,0x8a,0x6b,0x1b,0x9c,0x7e,0xf4,0x64,0xf5,0xa0,0x1b,0x47,
+        0xe4,0x2e,0xc3,0x73,0x63,0x22,0x44,0x5e,0x8e,0x22,0x40,0xca,
+        0x5e,0x69,0xe2,0xc7,0x8b,0x32,0x39,0xec,0xfa,0xb2,0x16,0x49
+    };
+ 
+    const uint8_t hmac_expected3[] = {
+        0x88,0x06,0x26,0x08,0xd3,0xe6,0xad,0x8a,0x0a,0xa2,0xac,0xe0,
+        0x14,0xc8,0xa8,0x6f,0x0a,0xa6,0x35,0xd9,0x47,0xac,0x9f,0xeb,
+        0xe8,0x3e,0xf4,0xe5,0x59,0x66,0x14,0x4b,0x2a,0x5a,0xb3,0x9d,
+        0xc1,0x38,0x14,0xb9,0x4e,0x3a,0xb6,0xe1,0x01,0xa3,0x4f,0x27
+    };
+ 
+    const uint8_t hmac_expected4[] = {
+        0x3e,0x8a,0x69,0xb7,0x78,0x3c,0x25,0x85,0x19,0x33,0xab,0x62,
+        0x90,0xaf,0x6c,0xa7,0x7a,0x99,0x81,0x48,0x08,0x50,0x00,0x9c,
+        0xc5,0x57,0x7c,0x6e,0x1f,0x57,0x3b,0x4e,0x68,0x01,0xdd,0x23,
+        0xc4,0xa7,0xd6,0x79,0xcc,0xf8,0xa3,0x86,0xc6,0x74,0xcf,0xfb,
+    };
+   
+//    const uint8_t hmac_expected5[] = {
+//        0x3a,0xbf,0x34,0xc3,0x50,0x3b,0x2a,0x23,0xa4,0x6e,0xfc,0x61,0x9b,
+//        0xae,0xf8,0x97,
+//   };
+ 
+    const uint8_t hmac_expected6[] = {
+        0x4e,0xce,0x08,0x44,0x85,0x81,0x3e,0x90,0x88,0xd2,0xc6,0x3a,0x04,
+        0x1b,0xc5,0xb4,0x4f,0x9e,0xf1,0x01,0x2a,0x2b,0x58,0x8f,0x3c,0xd1,
+        0x1f,0x05,0x03,0x3a,0xc4,0xc6,0x0c,0x2e,0xf6,0xab,0x40,0x30,0xfe,
+        0x82,0x96,0x24,0x8d,0xf1,0x63,0xf4,0x49,0x52
+    };
+ 
+    const uint8_t hmac_expected7[] = {
+        0x66,0x17,0x17,0x8e,0x94,0x1f,0x02,0x0d,0x35,0x1e,0x2f,0x25,0x4e,
+        0x8f,0xd3,0x2c,0x60,0x24,0x20,0xfe,0xb0,0xb8,0xfb,0x9a,0xdc,0xce,
+        0xbb,0x82,0x46,0x1e,0x99,0xc5,0xa6,0x78,0xcc,0x31,0xe7,0x99,0x17,
+        0x6d,0x38,0x60,0xe6,0x11,0x0c,0x46,0x52,0x3e
+    };
+   
+    memcpy(secret6, std::string(131, 0xaa).c_str(), 131); 
+    memcpy(secret7, std::string(131, 0xaa).c_str(), 131); 
+    RUN_NTH_TEST_CASE_FOR_ALG(1, SHA384); 
+    RUN_NTH_TEST_CASE_FOR_ALG(2, SHA384); 
+    RUN_NTH_TEST_CASE_FOR_ALG(3, SHA384);
+    RUN_NTH_TEST_CASE_FOR_ALG(4, SHA384); 
+    RUN_NTH_TEST_CASE_FOR_ALG(6, SHA384); 
+    RUN_NTH_TEST_CASE_FOR_ALG(7, SHA384); 
+}
+
+TEST(CryptoLinkTest, HMAC_SHA512_RFC4231_SIGN) {
+    const uint8_t hmac_expected1[] = { 
+        0x87,0xaa,0x7c,0xde,0xa5,0xef,0x61,0x9d,0x4f,0xf0,0xb4,0x24,
+        0x1a,0x1d,0x6c,0xb0,0x23,0x79,0xf4,0xe2,0xce,0x4e,0xc2,0x78,
+        0x7a,0xd0,0xb3,0x05,0x45,0xe1,0x7c,0xde,0xda,0xa8,0x33,0xb7,
+        0xd6,0xb8,0xa7,0x02,0x03,0x8b,0x27,0x4e,0xae,0xa3,0xf4,0xe4,
+        0xbe,0x9d,0x91,0x4e,0xeb,0x61,0xf1,0x70,0x2e,0x69,0x6c,0x20,
+        0x3a,0x12,0x68,0x54
+    };
+   const uint8_t hmac_expected2[] = {
+        0x16,0x4b,0x7a,0x7b,0xfc,0xf8,0x19,0xe2,0xe3,0x95,0xfb,0xe7,
+        0x3b,0x56,0xe0,0xa3,0x87,0xbd,0x64,0x22,0x2e,0x83,0x1f,0xd6,
+        0x10,0x27,0x0c,0xd7,0xea,0x25,0x05,0x54,0x97,0x58,0xbf,0x75,
+        0xc0,0x5a,0x99,0x4a,0x6d,0x03,0x4f,0x65,0xf8,0xf0,0xe6,0xfd,
+        0xca,0xea,0xb1,0xa3,0x4d,0x4a,0x6b,0x4b,0x63,0x6e,0x07,0x0a,
+        0x38,0xbc,0xe7,0x37
+    }; 
+ 
+   const uint8_t hmac_expected3[] = {
+        0xfa,0x73,0xb0,0x08,0x9d,0x56,0xa2,0x84,0xef,0xb0,0xf0,0x75,
+        0x6c,0x89,0x0b,0xe9,0xb1,0xb5,0xdb,0xdd,0x8e,0xe8,0x1a,0x36,
+        0x55,0xf8,0x3e,0x33,0xb2,0x27,0x9d,0x39,0xbf,0x3e,0x84,0x82,
+        0x79,0xa7,0x22,0xc8,0x06,0xb4,0x85,0xa4,0x7e,0x67,0xc8,0x07,
+        0xb9,0x46,0xa3,0x37,0xbe,0xe8,0x94,0x26,0x74,0x27,0x88,0x59,
+        0xe1,0x32,0x92,0xfb
+    };
+
+   const uint8_t hmac_expected4[] = {
+        0xb0,0xba,0x46,0x56,0x37,0x45,0x8c,0x69,0x90,0xe5,0xa8,0xc5,
+        0xf6,0x1d,0x4a,0xf7,0xe5,0x76,0xd9,0x7f,0xf9,0x4b,0x87,0x2d,
+        0xe7,0x6f,0x80,0x50,0x36,0x1e,0xe3,0xdb,0xa9,0x1c,0xa5,0xc1,
+        0x1a,0xa2,0x5e,0xb4,0xd6,0x79,0x27,0x5c,0xc5,0x78,0x80,0x63,
+        0xa5,0xf1,0x97,0x41,0x12,0x0c,0x4f,0x2d,0xe2,0xad,0xeb,0xeb,
+        0x10,0xa2,0x98,0xdd
+    };
+ 
+//    const uint8_t hmac_expected5[] = {
+//        0x41,0x5f,0xad,0x62,0x71,0x58,0x0a,0x53,0x1d,0x41,0x79,0xbc,0x89,
+//        0x1d,0x87,0xa6,
+//    };
+ 
+    const uint8_t hmac_expected6[] = {
+        0x80,0xb2,0x42,0x63,0xc7,0xc1,0xa3,0xeb,0xb7,0x14,0x93,0xc1,0xdd,
+        0x7b,0xe8,0xb4,0x9b,0x46,0xd1,0xf4,0x1b,0x4a,0xee,0xc1,0x12,0x1b,
+        0x01,0x37,0x83,0xf8,0xf3,0x52,0x6b,0x56,0xd0,0x37,0xe0,0x5f,0x25,
+        0x98,0xbd,0x0f,0xd2,0x21,0x5d,0x6a,0x1e,0x52,0x95,0xe6,0x4f,0x73,
+        0xf6,0x3f,0x0a,0xec,0x8b,0x91,0x5a,0x98,0x5d,0x78,0x65,0x98
+    };
+
+    const uint8_t hmac_expected7[] = {
+        0xe3,0x7b,0x6a,0x77,0x5d,0xc8,0x7d,0xba,0xa4,0xdf,0xa9,0xf9,0x6e,
+        0x5e,0x3f,0xfd,0xde,0xbd,0x71,0xf8,0x86,0x72,0x89,0x86,0x5d,0xf5,
+        0xa3,0x2d,0x20,0xcd,0xc9,0x44,0xb6,0x02,0x2c,0xac,0x3c,0x49,0x82,
+        0xb1,0x0d,0x5e,0xeb,0x55,0xc3,0xe4,0xde,0x15,0x13,0x46,0x76,0xfb,
+        0x6d,0xe0,0x44,0x60,0x65,0xc9,0x74,0x40,0xfa,0x8c,0x6a,0x58
+    };
+ 
+    memcpy(secret6, std::string(131, 0xaa).c_str(), 131); 
+    memcpy(secret7, std::string(131, 0xaa).c_str(), 131); 
+    RUN_NTH_TEST_CASE_FOR_ALG(1, SHA512); 
+    RUN_NTH_TEST_CASE_FOR_ALG(2, SHA512); 
+    RUN_NTH_TEST_CASE_FOR_ALG(3, SHA512);
+    RUN_NTH_TEST_CASE_FOR_ALG(4, SHA512); 
+    RUN_NTH_TEST_CASE_FOR_ALG(6, SHA512); 
+    RUN_NTH_TEST_CASE_FOR_ALG(7, SHA512); 
+}
+
+TEST(CryptoLinkTest, DISABLED_HMAC_SHA256_RFC2202_SIGN_TRUNCATED) {
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
+                                       0x10, 0x0e, 0xe0, 0x6e, 0x0c,
+                                       0x79, 0x6c, 0x29, 0x55, 0x55,
+                                       0x2b };
+    doHMACTest("Test With Truncation", secret5, 20, SHA256,
+               hmac_expected5, 16);
+}
+
+namespace {
+    size_t
+    sigVectorLength(HashAlgorithm alg, size_t len) {
+        boost::shared_ptr<HMAC> hmac_sign(
+            CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+            deleteHMAC);
+        hmac_sign->update("asdf", 4);
+        const std::vector<uint8_t> sig = hmac_sign->sign(len);
+        return (sig.size());
+    }
+
+    size_t
+    sigBufferLength(HashAlgorithm alg, size_t len) {
+        boost::shared_ptr<HMAC> hmac_sign(
+            CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+            deleteHMAC);
+        hmac_sign->update("asdf", 4);
+        OutputBuffer sig(0);
+        hmac_sign->sign(sig, len);
+        return (sig.getLength());
+    }
+}
+
+TEST(CryptoLinkTest, HMACSigLengthArgument) {
+    std::vector<uint8_t> sig;
+
+    EXPECT_EQ(16, sigVectorLength(MD5, 0));
+    EXPECT_EQ(8, sigVectorLength(MD5, 8));
+    EXPECT_EQ(16, sigVectorLength(MD5, 16));
+    EXPECT_EQ(16, sigVectorLength(MD5, 40));
+    EXPECT_EQ(16, sigVectorLength(MD5, 2000));
+
+    EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+    EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+    EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+    EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+
+    EXPECT_EQ(16, sigBufferLength(MD5, 0));
+    EXPECT_EQ(8, sigBufferLength(MD5, 8));
+    EXPECT_EQ(16, sigBufferLength(MD5, 16));
+    EXPECT_EQ(16, sigBufferLength(MD5, 40));
+    EXPECT_EQ(16, sigBufferLength(MD5, 2000));
+
+    EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+    EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+    EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+    EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+    EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+    EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+}
+
+TEST(CryptoLinkTest, BadKey) {
+    OutputBuffer data_buf(0);
+    OutputBuffer hmac_sig(0);
+    CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+    EXPECT_THROW(crypto.createHMAC(NULL, 0, MD5), BadKey);
+    EXPECT_THROW(crypto.createHMAC(NULL, 0, UNKNOWN_HASH), UnsupportedAlgorithm);
+
+    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+                          NULL, 0, MD5, hmac_sig), BadKey);
+    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+                          NULL, 0, UNKNOWN_HASH, hmac_sig),
+                          UnsupportedAlgorithm);
+
+    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                            NULL, 0, MD5, hmac_sig.getData(),
+                            hmac_sig.getLength()), BadKey);
+    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                            NULL, 0, UNKNOWN_HASH, hmac_sig.getData(),
+                            hmac_sig.getLength()),
+                            UnsupportedAlgorithm);
+}
+
+TEST(CryptoLinkTest, Singleton) {
+    const CryptoLink& c1 = CryptoLink::getCryptoLink();
+    const CryptoLink& c2 = CryptoLink::getCryptoLink();
+    ASSERT_EQ(&c1, &c2);
+}
diff --git a/src/lib/cryptolink/tests/run_unittests.cc b/src/lib/cryptolink/tests/run_unittests.cc
new file mode 100644
index 0000000..d16327e
--- /dev/null
+++ b/src/lib/cryptolink/tests/run_unittests.cc
@@ -0,0 +1,22 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index adb1d41..e028186 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(SQLITE_CFLAGS)
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda messagedef.h messagedef.cc
 
 lib_LTLIBRARIES = libdatasrc.la
 libdatasrc_la_SOURCES = data_source.h data_source.cc
@@ -20,3 +20,16 @@ libdatasrc_la_SOURCES += zonetable.h zonetable.cc
 libdatasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
 libdatasrc_la_SOURCES += zone.h
 libdatasrc_la_SOURCES += result.h
+libdatasrc_la_SOURCES += logger.h logger.cc
+nodist_libdatasrc_la_SOURCES = messagedef.h messagedef.cc
+
+libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
+
+BUILT_SOURCES = messagedef.h messagedef.cc
+messagedef.h messagedef.cc: Makefile messagedef.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/datasrc/messagedef.mes
+
+EXTRA_DIST = messagedef.mes
diff --git a/src/lib/datasrc/cache.cc b/src/lib/datasrc/cache.cc
index 6fff754..8e9487d 100644
--- a/src/lib/datasrc/cache.cc
+++ b/src/lib/datasrc/cache.cc
@@ -24,6 +24,7 @@
 #include <list>
 
 #include <datasrc/cache.h>
+#include <datasrc/logger.h>
 
 using namespace std;
 using namespace isc::dns;
@@ -204,16 +205,21 @@ public:
 // HotCacheImpl constructor
 HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
     enabled_(enabled), slots_(slots), count_(0)
-{}
+{
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
+}
 
 // Insert a cache node into the cache
 inline void
 HotCacheImpl::insert(const CacheNodePtr node) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
+        arg(node->getRRset()->getName());
     std::map<Question, CacheNodePtr>::const_iterator iter;
     iter = map_.find(node->question);
     if (iter != map_.end()) {
         CacheNodePtr old = iter->second;
         if (old && old->isValid()) {
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_OLD_FOUND);
             remove(old);
         }
     }
@@ -225,6 +231,7 @@ HotCacheImpl::insert(const CacheNodePtr node) {
     ++count_;
 
     if (slots_ != 0 && count_ > slots_) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FULL);
         remove(lru_.back());
     }
 }
@@ -245,6 +252,8 @@ HotCacheImpl::promote(CacheNodePtr node) {
 // Remove a node from the LRU list and the map
 void
 HotCacheImpl::remove(ConstCacheNodePtr node) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
+        arg(node->getRRset()->getName());
     lru_.erase(node->lru_entry_);
     map_.erase(node->question);
     --count_;
@@ -257,6 +266,7 @@ HotCache::HotCache(const int slots) {
 
 // HotCache destructor
 HotCache::~HotCache() {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_DESTROY);
     delete impl_;
 }
 
@@ -303,18 +313,21 @@ HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
     std::map<Question, CacheNodePtr>::const_iterator iter;
     iter = impl_->map_.find(Question(n, c, t));
     if (iter == impl_->map_.end()) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
         return (false);
     }
 
     CacheNodePtr node = iter->second;
 
     if (node->isValid()) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
         impl_->promote(node);
         rrset = node->getRRset();
         flags = node->getFlags();
         return (true);
     }
 
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
     impl_->remove(node);
     return (false);
 }
@@ -328,6 +341,9 @@ HotCache::setSlots(const int slots) {
         return;
     }
 
+    logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
+                                                        slots));
+
     while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
         impl_->remove(impl_->lru_.back());
     }
@@ -343,6 +359,11 @@ HotCache::getSlots() const {
 void
 HotCache::setEnabled(const bool e) {
     impl_->enabled_ = e;
+    if (e) {
+        logger.info(DATASRC_CACHE_ENABLE);
+    } else {
+        logger.info(DATASRC_CACHE_DISABLE);
+    }
 }
 
 /// Indicate whether the cache is enabled
diff --git a/src/lib/datasrc/data_source.cc b/src/lib/datasrc/data_source.cc
index c9819bb..4e1fcde 100644
--- a/src/lib/datasrc/data_source.cc
+++ b/src/lib/datasrc/data_source.cc
@@ -25,16 +25,18 @@
 #include <datasrc/cache.h>
 #include <datasrc/data_source.h>
 #include <datasrc/query.h>
+#include <datasrc/logger.h>
+
+#include <util/encode/base32hex.h>
+#include <util/hash/sha1.h>
+#include <util/buffer.h>
 
-#include <dns/util/base32hex.h>
-#include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rcode.h>
 #include <dns/rdataclass.h>
 #include <dns/rrset.h>
 #include <dns/rrsetlist.h>
-#include <dns/util/sha1.h>
 
 #include <cc/data.h>
 
@@ -45,6 +47,9 @@
                       } while (0)
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::util::hash;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
@@ -79,7 +84,7 @@ class ZoneInfo {
 public:
     ZoneInfo(DataSrc* ts,
              const isc::dns::Name& n,
-             const isc::dns::RRClass& c, 
+             const isc::dns::RRClass& c,
              const isc::dns::RRType& t = isc::dns::RRType::ANY()) :
         top_source_(ts),
         dsm_(((t == RRType::DS() && n.getLabelCount() != 1)
@@ -119,6 +124,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
         const Rdata& rd(it->getCurrent());
         if (rrset->getType() == RRType::NS()) {
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL).
+                arg(ns.getNSName()).arg(rrset->getName());
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, ns.getNSName(),
                                              Message::SECTION_ADDITIONAL,
@@ -126,6 +133,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
                                              QueryTask::GETADDITIONAL)));
         } else if (rrset->getType() == RRType::MX()) {
             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL).
+                arg(mx.getMXName()).arg(rrset->getName());
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, mx.getMXName(),
                                              Message::SECTION_ADDITIONAL,
@@ -139,11 +148,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
 // understand DNAME
 void
 synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME).
+        arg(rrset->getName());
     RdataIteratorPtr it = rrset->getRdataIterator();
 
     // More than one DNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     if (it->isLast()) {
+        logger.error(DATASRC_QUERY_EMPTY_DNAME).arg(rrset->getName());
         return;
     }
 
@@ -167,16 +179,20 @@ synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
 // to by a CNAME record
 void
 chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME).
+        arg(rrset->getName());
     RdataIteratorPtr it = rrset->getRdataIterator();
 
     // More than one CNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     if (it->isLast()) {
+        logger.error(DATASRC_QUERY_EMPTY_CNAME).arg(rrset->getName());
         return;
     }
 
     // Stop chasing CNAMES after 16 lookups, to prevent loops
     if (q.tooMany()) {
+        logger.error(DATASRC_QUERY_TOO_MANY_CNAMES).arg(rrset->getName());
         return;
     }
 
@@ -190,6 +206,8 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
 // Check the cache for data which can answer the current query task.
 bool
 checkCache(QueryTask& task, RRsetList& target) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE).
+        arg(task.qname).arg(task.qtype);
     HotCache& cache = task.q.getCache();
     RRsetList rrsets;
     RRsetPtr rrset;
@@ -202,6 +220,9 @@ checkCache(QueryTask& task, RRsetList& target) {
         // ANY queries must be handled by the low-level data source,
         // or the results won't be guaranteed to be complete
         if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
+            LOG_DEBUG(logger, DBG_TRACE_DATA,
+                      DATASRC_QUERY_NO_CACHE_ANY_SIMPLE).arg(task.qname).
+                arg(task.qtype).arg(task.qclass);
             break;
         }
 
@@ -231,6 +252,8 @@ checkCache(QueryTask& task, RRsetList& target) {
 
     case QueryTask::AUTH_QUERY:         // Find exact RRset or CNAME
         if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_NO_CACHE_ANY_AUTH).
+                arg(task.qname).arg(task.qtype).arg(task.qclass);
             break;
         }
 
@@ -349,30 +372,43 @@ DataSrc::Result
 doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
     HotCache& cache = task.q.getCache();
     RRsetPtr rrset;
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_DO_QUERY).arg(task.qname).
+        arg(task.qtype);
+
+    // First off, make sure at least we have a matching zone in some data
+    // source.  We must do this before checking the cache, because it can
+    // happen that the matching zone has been removed after an RRset of that
+    // zone is cached.  Such inconsistency will cause various problems,
+    // including a crash.
+    const DataSrc* ds = zoneinfo.getDataSource();
+    const Name* const zonename = zoneinfo.getEnclosingZone();
+    if (ds == NULL) {
+        task.flags |= DataSrc::NO_SUCH_ZONE;
+        logger.info(DATASRC_QUERY_NO_ZONE).arg(task.qname).arg(task.qclass);
+        return (DataSrc::SUCCESS);
+    }
 
-    // First, check the cache for matching data
+    // Then check the cache for matching data
     if (checkCache(task, target)) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CACHED).
+            arg(task.qname).arg(task.qtype);
         return (DataSrc::SUCCESS);
     }
 
     // Requested data weren't in the cache (or were, but had expired),
     // so now we proceed with the low-level data source lookup, and cache
     // whatever we find.
-    const DataSrc* ds = zoneinfo.getDataSource();
-    const Name* const zonename = zoneinfo.getEnclosingZone();
-
-    if (ds == NULL) {
-        task.flags |= DataSrc::NO_SUCH_ZONE;
-        return (DataSrc::SUCCESS);
-    }
 
     DataSrc::Result result;
     switch (task.op) {
     case QueryTask::SIMPLE_QUERY:
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_SIMPLE).
+            arg(task.qname).arg(task.qtype);
         result = ds->findExactRRset(task.qname, task.qclass, task.qtype,
                                     target, task.flags, zonename);
 
         if (result != DataSrc::SUCCESS) {
+            logger.error(DATASRC_QUERY_SIMPLE_FAIL).arg(result);
             return (result);
         }
 
@@ -394,10 +430,13 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
         return (result);
 
     case QueryTask::AUTH_QUERY:
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_AUTH).
+            arg(task.qname).arg(task.qtype);
         result = ds->findRRset(task.qname, task.qclass, task.qtype,
                                target, task.flags, zonename);
 
         if (result != DataSrc::SUCCESS) {
+            logger.error(DATASRC_QUERY_AUTH_FAIL).arg(result);
             return (result);
         }
 
@@ -430,10 +469,16 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
 
     case QueryTask::GLUE_QUERY:
     case QueryTask::NOGLUE_QUERY:
+        LOG_DEBUG(logger, DBG_TRACE_DATA, task.op == QueryTask::GLUE_QUERY ?
+                     DATASRC_QUERY_IS_GLUE : DATASRC_QUERY_IS_NOGLUE).
+            arg(task.qname).arg(task.qtype);
         result = ds->findAddrs(task.qname, task.qclass, target,
                                task.flags, zonename);
 
         if (result != DataSrc::SUCCESS) {
+            logger.error(task.op == QueryTask::GLUE_QUERY ?
+                         DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL).
+                arg(result);
             return (result);
         }
 
@@ -459,10 +504,13 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
         return (result);
 
     case QueryTask::REF_QUERY:
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_REF).
+            arg(task.qname).arg(task.qtype);
         result = ds->findReferral(task.qname, task.qclass, target,
                                  task.flags, zonename);
 
         if (result != DataSrc::SUCCESS) {
+            logger.error(DATASRC_QUERY_REF_FAIL).arg(result);
             return (result);
         }
 
@@ -496,6 +544,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
     }
 
     // Not reached
+    logger.error(DATASRC_QUERY_INVALID_OP);
     return (DataSrc::ERROR);
 }
 
@@ -507,6 +556,8 @@ inline void
 addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
              bool no_dnssec = false)
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET).
+        arg(rrset->getName()).arg(rrset->getType());
     Message& m = q.message();
     if (no_dnssec) {
         if (rrset->getType() == RRType::RRSIG() ||
@@ -525,6 +576,7 @@ addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
 // Copy referral information into the authority section of a message
 inline void
 copyAuth(Query& q, RRsetList& auth) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_COPY_AUTH);
     BOOST_FOREACH(RRsetPtr rrset, auth) {
         if (rrset->getType() == RRType::DNAME()) {
             continue;
@@ -562,6 +614,9 @@ refQuery(const Query& q, const Name& name, ZoneInfo& zoneinfo,
 // they'll be handled in a normal lookup in the zone.
 inline bool
 hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION).
+        arg(task->qname);
+
     const Name* const zonename = zoneinfo.getEnclosingZone();
     if (zonename == NULL) {
         if (task->state == QueryTask::GETANSWER) {
@@ -627,6 +682,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
     RRsetList soa;
 
     const Name* const zonename = zoneinfo.getEnclosingZone();
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA).arg(*zonename);
     QueryTask newtask(q, *zonename, RRType::SOA(), QueryTask::SIMPLE_QUERY);
     RETERR(doQueryTask(newtask, zoneinfo, soa));
     if (newtask.flags != 0) {
@@ -640,6 +696,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
 
 inline DataSrc::Result
 addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC).arg(name);
     RRsetList nsec;
 
     QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY); 
@@ -656,9 +713,11 @@ inline DataSrc::Result
 getNsec3(Query& q, ZoneInfo& zoneinfo, string& hash, RRsetPtr& target) {
     const DataSrc* ds = zoneinfo.getDataSource();
     const Name* const zonename = zoneinfo.getEnclosingZone();
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3).arg(*zonename);
 
     if (ds == NULL) {
         q.message().setRcode(Rcode::SERVFAIL());
+        logger.error(DATASRC_QUERY_NO_DS_NSEC3).arg(*zonename);
         return (DataSrc::ERROR);
     }
 
@@ -761,6 +820,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
             const DataSrc* ds = zoneinfo.getDataSource();
             if (ds == NULL) {
                 m.setRcode(Rcode::SERVFAIL());
+                logger.error(DATASRC_QUERY_NO_DS_NSEC).arg(*zonename);
                 return (DataSrc::ERROR);
             }
             ds->findPreviousName(task->qname, nsecname, zonename);
@@ -789,6 +849,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
 // Attempt a wildcard lookup
 inline DataSrc::Result
 tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD).arg(task->qname);
     Message& m = q.message();
     DataSrc::Result result;
     found = false;
@@ -842,6 +903,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
             result = proveNX(q, task, zoneinfo, true);
             if (result != DataSrc::SUCCESS) {
                 m.setRcode(Rcode::SERVFAIL());
+                logger.error(DATASRC_QUERY_WILDCARD_PROVENX_FAIL).
+                    arg(task->qname).arg(result);
                 return (DataSrc::ERROR);
             }
         }
@@ -864,6 +927,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
 
             RRsetList auth;
             if (!refQuery(q, *zonename, zoneinfo, auth)) {
+                logger.error(DATASRC_QUERY_WILDCARD_REFERRAL).arg(task->qname).
+                    arg(result);
                 return (DataSrc::ERROR);
             }
 
@@ -879,6 +944,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
 // 
 void
 DataSrc::doQuery(Query& q) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS).arg(q.qname()).
+        arg(q.qclass());
     Message& m = q.message();
     vector<RRsetPtr> additional;
 
@@ -896,6 +963,7 @@ DataSrc::doQuery(Query& q) {
         // Can't query directly for RRSIG.
         if (task->qtype == RRType::RRSIG()) {
             m.setRcode(Rcode::REFUSED());
+            logger.warn(DATASRC_QUERY_RRSIG).arg(task->qname);
             return;
         }
 
@@ -903,6 +971,7 @@ DataSrc::doQuery(Query& q) {
         if (task->op == QueryTask::SIMPLE_QUERY ||
             task->op == QueryTask::REF_QUERY) {
             m.setRcode(Rcode::SERVFAIL());
+            logger.error(DATASRC_QUERY_MISPLACED_TASK);
             return;
         }
 
@@ -922,6 +991,7 @@ DataSrc::doQuery(Query& q) {
         result = doQueryTask(*task, zoneinfo, data);
         if (result != SUCCESS) {
             m.setRcode(Rcode::SERVFAIL());
+            logger.error(DATASRC_QUERY_TASK_FAIL).arg(result);
             return;
         }
 
@@ -931,6 +1001,7 @@ DataSrc::doQuery(Query& q) {
         if (task->flags == NO_SUCH_ZONE) {
             if (task->state == QueryTask::GETANSWER) {
                 m.setRcode(Rcode::REFUSED());
+                // No need to log it here, it was already logged in doQueryTask
                 return;
             }
             continue;
@@ -972,6 +1043,7 @@ DataSrc::doQuery(Query& q) {
                     RRsetList auth;
                     if (!refQuery(q, Name(*zonename), zoneinfo, auth) ||
                         !findRRsetFromList(auth, RRType::NS())) {
+                        logger.error(DATASRC_QUERY_MISSING_NS).arg(*zonename);
                         isc_throw(DataSourceError,
                                   "NS RR not found in " << *zonename << "/" <<
                                   q.qclass());
@@ -996,10 +1068,12 @@ DataSrc::doQuery(Query& q) {
                 continue;
 
             default:
+                logger.error(DATASRC_UNEXPECTED_QUERY_STATE);
                 isc_throw (Unexpected, "unexpected query state");
             }
         } else if (result == ERROR || result == NOT_IMPLEMENTED) {
             m.setRcode(Rcode::SERVFAIL());
+            logger.error(DATASRC_QUERY_FAIL);
             return;
         } else if ((task->flags & CNAME_FOUND) != 0) {
             // The qname node contains a CNAME.  Add a new task to the
@@ -1017,6 +1091,7 @@ DataSrc::doQuery(Query& q) {
                 m.setHeaderFlag(Message::HEADERFLAG_AA, false);
                 if (!refQuery(q, task->qname, zoneinfo, auth)) {
                     m.setRcode(Rcode::SERVFAIL());
+                    logger.error(DATASRC_QUERY_BAD_REFERRAL).arg(task->qname);
                     return;
                 }
                 BOOST_FOREACH (RRsetPtr rrset, auth) {
@@ -1048,6 +1123,7 @@ DataSrc::doQuery(Query& q) {
             result = tryWildcard(q, task, zoneinfo, wildcard_found);
             if (result != SUCCESS) {
                 m.setRcode(Rcode::SERVFAIL());
+                logger.error(DATASRC_QUERY_WILDCARD_FAIL).arg(task->qname);
                 return;
             }
 
@@ -1069,6 +1145,7 @@ DataSrc::doQuery(Query& q) {
 
                 result = addSOA(q, zoneinfo);
                 if (result != SUCCESS) {
+                    logger.error(DATASRC_QUERY_MISSING_SOA).arg(*zonename);
                     isc_throw(DataSourceError,
                               "SOA RR not found in " << *zonename <<
                               "/" << q.qclass());
@@ -1085,6 +1162,7 @@ DataSrc::doQuery(Query& q) {
                 result = proveNX(q, task, zoneinfo, false);
                 if (result != DataSrc::SUCCESS) {
                     m.setRcode(Rcode::SERVFAIL());
+                    logger.error(DATASRC_QUERY_PROVENX_FAIL).arg(task->qname);
                     return;
                 }
             }
@@ -1093,6 +1171,7 @@ DataSrc::doQuery(Query& q) {
         } else {
             // Should never be reached!
             m.setRcode(Rcode::SERVFAIL());
+            logger.error(DATASRC_QUERY_UNKNOWN_RESULT);
             return;
         }
     }
@@ -1188,7 +1267,10 @@ DataSrc::findReferral(const Name& qname, const RRClass& qclass,
 
 void
 MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_ADD);
     if (getClass() != RRClass::ANY() && data_src->getClass() != getClass()) {
+        logger.error(DATASRC_META_ADD_CLASS_MISMATCH).
+            arg(data_src->getClass()).arg(getClass());
         isc_throw(Unexpected, "class mismatch");
     }
 
@@ -1197,6 +1279,7 @@ MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
 
 void
 MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_REMOVE);
     std::vector<ConstDataSrcPtr>::iterator it, itr;
     for (it = data_sources.begin(); it != data_sources.end(); ++it) {
         if (*it == data_src) {
diff --git a/src/lib/datasrc/logger.cc b/src/lib/datasrc/logger.cc
new file mode 100644
index 0000000..846e43b
--- /dev/null
+++ b/src/lib/datasrc/logger.cc
@@ -0,0 +1,23 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/logger.h>
+
+namespace isc {
+namespace datasrc {
+
+isc::log::Logger logger("datasrc");
+
+}
+}
diff --git a/src/lib/datasrc/logger.h b/src/lib/datasrc/logger.h
new file mode 100644
index 0000000..7c2828d
--- /dev/null
+++ b/src/lib/datasrc/logger.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __DATASRC_LOGGER_H
+#define __DATASRC_LOGGER_H
+
+#include <log/macros.h>
+#include <datasrc/messagedef.h>
+
+/// \file logger.h
+/// \brief Data Source library global logger
+///
+/// This holds the logger for the data source library. It is a private header
+/// and should not be included in any publicly used header, only in local
+/// cc files.
+
+namespace isc {
+namespace datasrc {
+
+/// \brief The logger for this library
+extern isc::log::Logger logger;
+
+enum {
+    /// \brief Trace basic operations
+    DBG_TRACE_BASIC = 10,
+    /// \brief Trace data changes and lookups as well
+    DBG_TRACE_DATA = 20,
+    /// \brief Detailed even about how the lookups happen
+    DBG_TRACE_DETAILED = 50
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 5230ced..3c57d1b 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -24,6 +24,7 @@
 
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/rbtree.h>
+#include <datasrc/logger.h>
 
 using namespace std;
 using namespace isc::dns;
@@ -94,6 +95,8 @@ struct MemoryZone::MemoryZoneImpl {
              l > origin_labels;
              --l, wname = wname.split(1)) {
             if (wname.isWildcard()) {
+                LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD).
+                    arg(name);
                 // Ensure a separate level exists for the "wildcarding" name,
                 // and mark the node as "wild".
                 DomainNode* node;
@@ -130,10 +133,13 @@ struct MemoryZone::MemoryZoneImpl {
             // (depending on how we support DNSSEC).  We should revisit it
             // at that point.
             if (!domain->empty()) {
+                LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
+                    arg(rrset->getName());
                 isc_throw(AddError, "CNAME can't be added with other data for "
                           << rrset->getName());
             }
         } else if (domain->find(RRType::CNAME()) != domain->end()) {
+            LOG_ERROR(logger, DATASRC_MEM_CNAME_COEXIST).arg(rrset->getName());
             isc_throw(AddError, "CNAME and " << rrset->getType() <<
                       " can't coexist for " << rrset->getName());
         }
@@ -151,6 +157,7 @@ struct MemoryZone::MemoryZoneImpl {
             (rrset->getType() == RRType::NS() &&
             domain->find(RRType::DNAME()) != domain->end())))
         {
+            LOG_ERROR(logger, DATASRC_MEM_DNAME_NS).arg(rrset->getName());
             isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
                 "domain " << rrset->getName());
         }
@@ -172,6 +179,8 @@ struct MemoryZone::MemoryZoneImpl {
             // XXX: this is not only for CNAME or DNAME. We should generalize
             // this code for all other "singleton RR types" (such as SOA) in a
             // separate task.
+            LOG_ERROR(logger, DATASRC_MEM_SINGLETON).arg(rrset->getName()).
+                arg(rrset->getType());
             isc_throw(AddError, "multiple RRs of singleton type for "
                       << rrset->getName());
         }
@@ -180,6 +189,8 @@ struct MemoryZone::MemoryZoneImpl {
         if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
             compare.getRelation() != NameComparisonResult::EQUAL)
         {
+            LOG_ERROR(logger, DATASRC_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+                arg(origin_);
             isc_throw(OutOfZone, "The name " << rrset->getName() <<
                 " is not contained in zone " << origin_);
         }
@@ -194,10 +205,14 @@ struct MemoryZone::MemoryZoneImpl {
         // behavior.
         if (rrset->getName().isWildcard()) {
             if (rrset->getType() == RRType::NS()) {
+                LOG_ERROR(logger, DATASRC_MEM_WILDCARD_NS).
+                    arg(rrset->getName());
                 isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
                           rrset->getName());
             }
             if (rrset->getType() == RRType::DNAME()) {
+                LOG_ERROR(logger, DATASRC_MEM_WILDCARD_DNAME).
+                    arg(rrset->getName());
                 isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
                           rrset->getName());
             }
@@ -210,6 +225,8 @@ struct MemoryZone::MemoryZoneImpl {
      */
     // Implementation of MemoryZone::add
     result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
+            arg(rrset->getName()).arg(rrset->getType()).arg(origin_);
         // Sanitize input
         addValidation(rrset);
 
@@ -271,6 +288,8 @@ struct MemoryZone::MemoryZoneImpl {
     void addFromLoad(const ConstRRsetPtr& set, DomainTree* domains) {
             switch (add(set, domains)) {
                 case result::EXIST:
+                    LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
+                        arg(set->getName()).arg(set->getType());
                     isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
                         set->toText());
                 case result::SUCCESS:
@@ -307,6 +326,8 @@ struct MemoryZone::MemoryZoneImpl {
         const Domain::const_iterator foundDNAME(node.getData()->find(
             RRType::DNAME()));
         if (foundDNAME != node.getData()->end()) {
+            LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+                      DATASRC_MEM_DNAME_ENCOUNTERED);
             state->dname_node_ = &node;
             state->rrset_ = foundDNAME->second;
             // No more processing below the DNAME (RFC 2672, section 3
@@ -328,6 +349,8 @@ struct MemoryZone::MemoryZoneImpl {
                 return (false);
             }
 
+            LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
+
             // BIND 9 checks if this node is not the origin.  That's probably
             // because it can support multiple versions for dynamic updates
             // and IXFR, and it's possible that the callback is called at
@@ -363,6 +386,8 @@ struct MemoryZone::MemoryZoneImpl {
         rrset, bool rename)
     {
         if (rename) {
+            LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
+                arg(rrset->getName()).arg(name);
             /*
              * We lose a signature here. But it would be wrong anyway, because
              * the name changed. This might turn out to be unimportant in
@@ -385,6 +410,8 @@ struct MemoryZone::MemoryZoneImpl {
     FindResult find(const Name& name, RRType type,
                     RRsetList* target, const FindOptions options) const
     {
+        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
+            arg(type);
         // Get the node
         DomainNode* node(NULL);
         FindState state(options);
@@ -411,12 +438,16 @@ struct MemoryZone::MemoryZoneImpl {
                  * is NULL.
                  */
                 if (state.dname_node_ != NULL) {
+                    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+                        arg(state.rrset_->getName());
                     // We were traversing a DNAME node (and wanted to go
                     // lower below it), so return the DNAME
                     return (FindResult(DNAME, prepareRRset(name, state.rrset_,
                         rename)));
                 }
                 if (state.zonecut_node_ != NULL) {
+                    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+                        arg(state.rrset_->getName());
                     return (FindResult(DELEGATION, prepareRRset(name,
                         state.rrset_, rename)));
                 }
@@ -426,6 +457,8 @@ struct MemoryZone::MemoryZoneImpl {
                 // the zone but is empty.  Treat it as NXRRSET.
                 if (node_path.getLastComparisonResult().getRelation() ==
                     NameComparisonResult::SUPERDOMAIN) {
+                    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).
+                        arg(node_path.getAbsoluteName()).arg(name);
                     return (FindResult(NXRRSET, ConstRRsetPtr()));
                 }
 
@@ -463,6 +496,8 @@ struct MemoryZone::MemoryZoneImpl {
                     if (node_path.getLastComparisonResult().getRelation() ==
                         NameComparisonResult::COMMONANCESTOR && node_path.
                         getLastComparisonResult().getCommonLabels() > 1) {
+                        LOG_DEBUG(logger, DBG_TRACE_DATA,
+                                     DATASRC_MEM_WILDCARD_CANCEL).arg(name);
                         return (FindResult(NXDOMAIN, ConstRRsetPtr()));
                     }
                     Name wildcard(Name("*").concatenate(
@@ -485,6 +520,8 @@ struct MemoryZone::MemoryZoneImpl {
 
                 // fall through
             case DomainTree::NOTFOUND:
+                LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOTFOUND).
+                    arg(name);
                 return (FindResult(NXDOMAIN, ConstRRsetPtr()));
             case DomainTree::EXACTMATCH: // This one is OK, handle it
                 break;
@@ -496,6 +533,8 @@ struct MemoryZone::MemoryZoneImpl {
         // If there is an exact match but the node is empty, it's equivalent
         // to NXRRSET.
         if (node->isEmpty()) {
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
+                arg(name);
             return (FindResult(NXRRSET, ConstRRsetPtr()));
         }
 
@@ -506,6 +545,8 @@ struct MemoryZone::MemoryZoneImpl {
         if (node->getFlag(DomainNode::FLAG_CALLBACK) && node != origin_data_) {
             found = node->getData()->find(RRType::NS());
             if (found != node->getData()->end()) {
+                LOG_DEBUG(logger, DBG_TRACE_DATA,
+                          DATASRC_MEM_EXACT_DELEGATION).arg(name);
                 return (FindResult(DELEGATION, prepareRRset(name,
                     found->second, rename)));
             }
@@ -521,23 +562,30 @@ struct MemoryZone::MemoryZoneImpl {
                     boost::const_pointer_cast<RRset>(prepareRRset(name,
                     found->second, rename)));
             }
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
+                arg(name);
             return (FindResult(SUCCESS, ConstRRsetPtr()));
         }
 
         found = node->getData()->find(type);
         if (found != node->getData()->end()) {
             // Good, it is here
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
+                arg(type);
             return (FindResult(SUCCESS, prepareRRset(name, found->second,
                 rename)));
         } else {
             // Next, try CNAME.
             found = node->getData()->find(RRType::CNAME());
             if (found != node->getData()->end()) {
+                LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
                 return (FindResult(CNAME, prepareRRset(name, found->second,
                     rename)));
             }
         }
         // No exact match or CNAME.  Return NXRRSET.
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NXRRSET).arg(type).
+            arg(name);
         return (FindResult(NXRRSET, ConstRRsetPtr()));
     }
 };
@@ -545,9 +593,13 @@ struct MemoryZone::MemoryZoneImpl {
 MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
     impl_(new MemoryZoneImpl(zone_class, origin))
 {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_CREATE).arg(origin).
+        arg(zone_class);
 }
 
 MemoryZone::~MemoryZone() {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_DESTROY).arg(getOrigin()).
+        arg(getClass());
     delete impl_;
 }
 
@@ -576,6 +628,8 @@ MemoryZone::add(const ConstRRsetPtr& rrset) {
 
 void
 MemoryZone::load(const string& filename) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
+        arg(filename);
     // Load it into a temporary tree
     MemoryZoneImpl::DomainTree tmp;
     masterLoad(filename.c_str(), getOrigin(), getClass(),
@@ -588,6 +642,8 @@ MemoryZone::load(const string& filename) {
 
 void
 MemoryZone::swap(MemoryZone& zone) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
+        arg(zone.getOrigin());
     std::swap(impl_, zone.impl_);
 }
 
@@ -628,6 +684,9 @@ MemoryDataSrc::addZone(ZonePtr zone) {
                   "Null pointer is passed to MemoryDataSrc::addZone()");
     }
 
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
+        arg(zone->getOrigin()).arg(zone->getClass().toText());
+
     const result::Result result = impl_->zone_table.addZone(zone);
     if (result == result::SUCCESS) {
         ++impl_->zone_count;
@@ -637,6 +696,7 @@ MemoryDataSrc::addZone(ZonePtr zone) {
 
 MemoryDataSrc::FindResult
 MemoryDataSrc::findZone(const isc::dns::Name& name) const {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
     return (FindResult(impl_->zone_table.findZone(name).code,
                        impl_->zone_table.findZone(name).zone));
 }
diff --git a/src/lib/datasrc/messagedef.mes b/src/lib/datasrc/messagedef.mes
new file mode 100644
index 0000000..2fc5c6b
--- /dev/null
+++ b/src/lib/datasrc/messagedef.mes
@@ -0,0 +1,498 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX DATASRC_
+$NAMESPACE isc::datasrc
+
+# \brief Messages for the data source library
+
+% CACHE_CREATE creating the hotspot cache
+Debug information that the hotspot cache was created at startup.
+
+% CACHE_DESTROY destroying the hotspot cache
+Debug information. The hotspot cache is being destroyed.
+
+% CACHE_INSERT inserting item '%1' into the cache
+Debug information. It means a new item is being inserted into the hotspot
+cache.
+
+% CACHE_OLD_FOUND older instance of cache item found, replacing
+Debug information. While inserting an item into the hotspot cache, an older
+instance of an item with the same name was found. The old instance will be
+removed. This should be directly followed by CACHE_REMOVE.
+
+% CACHE_FULL cache is full, dropping oldest
+Debug information. After inserting an item into the hotspot cache, the
+maximum number of items was exceeded, so the least recently used item will
+be dropped. This should be directly followed by CACHE_REMOVE.
+
+% CACHE_REMOVE removing '%1' from the cache
+Debug information. An item is being removed from the hotspot cache.
+
+% CACHE_NOT_FOUND the item '%1' was not found
+Debug information. It was attempted to look up an item in the hotspot cache,
+but it is not there.
+
+% CACHE_FOUND the item '%1' was found
+Debug information. An item was successfully looked up in the hotspot cache.
+
+% CACHE_EXPIRED the item '%1' is expired
+Debug information. There was an attempt to look up an item in the hotspot
+cache. And the item was actually there, but it was too old, so it was removed
+instead and nothing is reported (the external behaviour is the same as with
+CACHE_NOT_FOUND).
+
+% CACHE_SLOTS setting the cache size to '%1', dropping '%2' items
+The maximum allowed number of items of the hotspot cache is set to the given
+number. If there are too many, some of them will be dropped. The size of 0
+means no limit.
+
+% CACHE_ENABLE enabling the cache
+The hotspot cache is enabled from now on.
+
+% CACHE_DISABLE disabling the cache
+The hotspot cache is disabled from now on. It is not going to store
+information or return anything.
+
+% QUERY_SYNTH_CNAME synthesizing CNAME from DNAME on '%1'
+Debug information. While answering a query, a DNAME was met. The DNAME itself
+will be returned, but along with it a CNAME for clients which don't understand
+DNAMEs will be synthesized.
+
+% QUERY_EMPTY_DNAME the DNAME on '%1' is empty
+During an attempt to synthesize CNAME from this DNAME it was discovered the
+DNAME is empty (it has no records). This indicates problem with supplied data.
+
+% QUERY_GET_NS_ADDITIONAL addition of A/AAAA for '%1' requested by NS '%2'
+Debug information. While processing a query, a NS record was met. It
+references the mentioned address, so A/AAAA records for it are looked up
+and put it into the additional section.
+
+% QUERY_GET_MX_ADDITIONAL addition of A/AAAA for '%1' requested by MX '%2'
+Debug information. While processing a query, a MX record was met. It
+references the mentioned address, so A/AAAA records for it are looked up
+and put it into the additional section.
+
+% QUERY_FOLLOW_CNAME following CNAME at '%1'
+Debug information. The domain is a CNAME (or a DNAME and we created a CNAME
+for it already), so it's being followed.
+
+% QUERY_EMPTY_CNAME cNAME at '%1' is empty
+There was an CNAME and it was being followed. But it contains no records,
+so there's nowhere to go. There will be no answer. This indicates a problem
+with supplied data.
+We tried to follow
+
+% QUERY_TOO_MANY_CNAMES cNAME chain limit exceeded at '%1'
+A CNAME led to another CNAME and it led to another, and so on. After 16
+CNAMEs, the software gave up. Long CNAME chains are discouraged, and this
+might possibly be a loop as well. Note that some of the CNAMEs might have
+been synthesized from DNAMEs. This indicates problem with supplied data.
+
+% QUERY_CHECK_CACHE checking cache for '%1/%2'
+Debug information. While processing a query, lookup to the hotspot cache
+is being made.
+
+% QUERY_NO_CACHE_ANY_SIMPLE ignoring cache for ANY query (%1/%2 in %3 class)
+Debug information. The hotspot cache is ignored for ANY queries for consistency
+reasons.
+
+% QUERY_NO_CACHE_ANY_AUTH ignoring cache for ANY query (%1/%2 in %3 class)
+Debug information. The hotspot cache is ignored for authoritative ANY queries
+for consistency reasons.
+
+% DO_QUERY handling query for '%1/%2'
+Debug information. We're processing some internal query for given name and
+type.
+
+% QUERY_NO_ZONE no zone containing '%1' in class '%2'
+Lookup of domain failed because the data have no zone that contain the
+domain. Maybe someone sent a query to the wrong server for some reason.
+
+% QUERY_CACHED data for %1/%2 found in cache
+Debug information. The requested data were found in the hotspot cache, so
+no query is sent to the real data source.
+
+% QUERY_IS_SIMPLE simple query (%1/%2)
+Debug information. The last DO_QUERY is a simple query.
+
+% QUERY_IS_AUTH auth query (%1/%2)
+Debug information. The last DO_QUERY is an auth query.
+
+% QUERY_IS_GLUE glue query (%1/%2)
+Debug information. The last DO_QUERY is query for glue addresses.
+
+% QUERY_IS_NOGLUE query for non-glue addresses (%1/%2)
+Debug information. The last DO_QUERY is query for addresses that are not
+glue.
+
+% QUERY_IS_REF query for referral (%1/%2)
+Debug information. The last DO_QUERY is query for referral information.
+
+% QUERY_SIMPLE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the simple query. 1 means some
+error, 2 is not implemented. The data source should have logged the specific
+error already.
+
+% QUERY_AUTH_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the authoritative query. 1 means
+some error, 2 is not implemented. The data source should have logged the
+specific error already.
+
+% QUERY_GLUE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the glue query. 1 means some error,
+2 is not implemented. The data source should have logged the specific error
+already.
+
+% QUERY_NOGLUE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the no-glue query. 1 means some
+error, 2 is not implemented. The data source should have logged the specific
+error already.
+
+% QUERY_REF_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the query for referral information.
+1 means some error, 2 is not implemented. The data source should have logged
+the specific error already.
+
+% QUERY_INVALID_OP invalid query operation requested
+This indicates a programmer error. The DO_QUERY was called with unknown
+operation code.
+
+% QUERY_ADD_RRSET adding RRset '%1/%2' to message
+Debug information. An RRset is being added to the response message.
+
+% QUERY_COPY_AUTH copying authoritative section into message
+Debug information. The whole referral information is being copied into the
+response message.
+
+% QUERY_DELEGATION looking for delegation on the path to '%1'
+Debug information. The software is trying to identify delegation points on the
+way down to the given domain.
+
+% QUERY_ADD_SOA adding SOA of '%1'
+Debug information. A SOA record of the given zone is being added to the
+authority section of the response message.
+
+% QUERY_ADD_NSEC adding NSEC record for '%1'
+Debug information. A NSEC record covering this zone is being added.
+
+% QUERY_ADD_NSEC3 adding NSEC3 record of zone '%1'
+Debug information. A NSEC3 record for the given zone is being added to the
+response message.
+
+% QUERY_NO_DS_NSEC3 there's no DS record in the '%1' zone
+An attempt to add a NSEC3 record into the message failed, because the zone does
+not have any DS record. This indicates problem with the provided data.
+
+% QUERY_NO_DS_NSEC there's no DS record in the '%1' zone
+An attempt to add a NSEC record into the message failed, because the zone does
+not have any DS record. This indicates problem with the provided data.
+
+% QUERY_WILDCARD looking for a wildcard covering '%1'
+Debug information. A direct match wasn't found, so a wildcard covering the
+domain is being looked for now.
+
+% QUERY_WILDCARD_PROVENX_FAIL unable to prove nonexistence of '%1' (%2)
+While processing a wildcard, it wasn't possible to prove nonexistence of the
+given domain or record.  The code is 1 for error and 2 for not implemented.
+
+% QUERY_WILDCARD_REFERRAL unable to find referral info for '%1' (%2)
+While processing a wildcard, a referral was met. But it wasn't possible to get
+enough information for it.  The code is 1 for error, 2 for not implemented.
+
+% QUERY_PROCESS processing query '%1/%2' in the '%3' class
+Debug information. A sure query is being processed now.
+
+% QUERY_RRSIG unable to answer RRSIG query
+The server is unable to answer a direct query for RRSIG type, but was asked
+to do so.
+
+% QUERY_MISPLACED_TASK task of this type should not be here
+This indicates a programming error. A task was found in the internal task
+queue, but this kind of task wasn't designed to be inside the queue (it should
+be handled right away, not queued).
+
+% QUERY_TASK_FAIL task failed with %1
+The query subtask failed. The reason should have been reported by the subtask
+already. The code is 1 for error, 2 for not implemented.
+
+% QUERY_MISSING_NS missing NS records for '%1'
+NS records should have been put into the authority section. However, this zone
+has none. This indicates problem with provided data.
+
+% UNEXPECTED_QUERY_STATE unexpected query state
+This indicates a programming error. An internal task of unknown type was
+generated.
+
+% QUERY_FAIL query failed
+Some subtask of query processing failed. The reason should have been reported
+already. We are returning SERVFAIL.
+
+% QUERY_BAD_REFERRAL bad referral to '%1'
+The domain lives in another zone. But it is not possible to generate referral
+information for it.
+
+% QUERY_WILDCARD_FAIL error processing wildcard for '%1'
+During an attempt to cover the domain by a wildcard an error happened. The
+exact kind was hopefully already reported.
+
+% QUERY_MISSING_SOA the zone '%1' has no SOA
+The answer should have been a negative one (eg. of nonexistence of something).
+To do so, a SOA record should be put into the authority section, but the zone
+does not have one. This indicates problem with provided data.
+
+% QUERY_PROVENX_FAIL unable to prove nonexistence of '%1'
+The user wants DNSSEC and we discovered the entity doesn't exist (either
+domain or the record). But there was an error getting NSEC/NSEC3 record
+to prove the nonexistence.
+
+% QUERY_UNKNOWN_RESULT unknown result of subtask
+This indicates a programmer error. The answer of subtask doesn't look like
+anything known.
+
+% META_ADD adding a data source into meta data source
+Debug information. Yet another data source is being added into the meta data
+source. (probably at startup or reconfiguration)
+
+% META_ADD_CLASS_MISMATCH mismatch between classes '%1' and '%2'
+It was attempted to add a data source into a meta data source. But their
+classes do not match.
+
+% META_REMOVE removing data source from meta data source
+Debug information. A data source is being removed from meta data source.
+
+% MEM_ADD_WILDCARD adding wildcards for '%1'
+Debug information. Some special marks above each * in wildcard name are needed.
+They are being added now for this name.
+
+% MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'
+Someone or something tried to add a CNAME into a domain that already contains
+some other data. But the protocol forbids coexistence of CNAME with anything
+(RFC 1034, section 3.6.2). This indicates a problem with provided data.
+
+% MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'
+This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the
+other way around -- adding some outher data to CNAME.
+
+% MEM_DNAME_NS dNAME and NS can't coexist in non-apex domain '%1'
+It was requested for DNAME and NS records to be put into the same domain
+which is not the apex (the top of the zone). This is forbidden by RFC
+2672, section 3. This indicates a problem with provided data.
+
+% MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'
+Some resource types are singletons -- only one is allowed in a domain
+(for example CNAME or SOA). This indicates a problem with provided data.
+
+% MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'
+It was attempted to add the domain into a zone that shouldn't have it
+(eg. the domain is not subdomain of the zone origin). This indicates a
+problem with provided data.
+
+% MEM_WILDCARD_NS nS record in wildcard domain '%1'
+The software refuses to load NS records into a wildcard domain.  It isn't
+explicitly forbidden, but the protocol is ambiguous about how this should
+behave and BIND 9 refuses that as well. Please describe your intention using
+different tools.
+
+% MEM_WILDCARD_DNAME dNAME record in wildcard domain '%1'
+The software refuses to load DNAME records into a wildcard domain.  It isn't
+explicitly forbidden, but the protocol is ambiguous about how this should
+behave and BIND 9 refuses that as well. Please describe your intention using
+different tools.
+
+% MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
+Debug information. An RRset is being added to the in-memory data source.
+
+% MEM_DUP_RRSET duplicate RRset '%1/%2'
+An RRset is being inserted into in-memory data source for a second time.  The
+original version must be removed first. Note that loading master files where an
+RRset is split into multiple locations is not supported yet.
+
+% MEM_DNAME_ENCOUNTERED encountered a DNAME
+Debug information. While searching for the requested domain, a DNAME was
+encountered on the way.  This may lead to redirection to a different domain and
+stop the search.
+
+% MEM_NS_ENCOUNTERED encountered a NS
+Debug information. While searching for the requested domain, a NS was
+encountered on the way (a delegation). This may lead to stop of the search.
+
+% MEM_RENAME renaming RRset from '%1' to '%2'
+Debug information. A RRset is being generated from a different RRset (most
+probably a wildcard). So it must be renamed to whatever the user asked for. In
+fact, it's impossible to rename RRsets with our libraries, so a new one is
+created and all resource records are copied over.
+
+% MEM_FIND find '%1/%2'
+Debug information. A search for the requested RRset is being started.
+
+% MEM_DNAME_FOUND DNAME found at '%1'
+Debug information. A DNAME was found instead of the requested information.
+
+% MEM_DELEG_FOUND delegation found at '%1'
+Debug information. A delegation point was found above the requested record.
+
+% MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty
+Debug information. The search stopped at a superdomain of the requested
+domain. The domain is a empty nonterminal, therefore it is treated  as NXRRSET
+case (eg. the domain exists, but it doesn't have the requested record type).
+
+% MEM_WILDCARD_CANCEL wildcard match canceled for '%1'
+Debug information. A domain above wildcard was reached, but there's something
+below the requested domain. Therefore the wildcard doesn't apply here.  This
+behaviour is specified by RFC 1034, section 4.3.3
+
+% MEM_NOTFOUND requested domain '%1' not found
+Debug information. The requested domain does not exist.
+
+% MEM_DOMAIN_EMPTY requested domain '%1' is empty
+Debug information. The requested domain exists in the tree of domains, but
+it is empty. Therefore it doesn't contain the requested resource type.
+
+% MEM_EXACT_DELEGATION delegation at the exact domain '%1'
+Debug information. There's a NS record at the requested domain. This means
+this zone is not authoritative for the requested domain, but a delegation
+should be followed. The requested domain is an apex of some zone.
+
+% MEM_ANY_SUCCESS ANY query for '%1' successful
+Debug information. The domain was found and an ANY type query is being answered
+by providing everything found inside the domain.
+
+% MEM_SUCCESS query for '%1/%2' successful
+Debug information. The requested record was found.
+
+% MEM_CNAME CNAME at the domain '%1'
+Debug information. The requested domain is an alias to a different domain,
+returning the CNAME instead.
+
+% MEM_NXRRSET no such type '%1' at '%2'
+Debug information. The domain exists, but it doesn't hold any record of the
+requested type.
+
+% MEM_CREATE creating zone '%1' in '%2' class
+Debug information. A representation of a zone for the in-memory data source is
+being created.
+
+% MEM_DESTROY destroying zone '%1' in '%2' class
+Debug information. A zone from in-memory data source is being destroyed.
+
+% MEM_LOAD loading zone '%1' from file '%2'
+Debug information. The content of master file is being loaded into the memory.
+
+% MEM_SWAP swapping contents of two zone representations ('%1' and '%2')
+Debug information. The contents of two in-memory zones are being exchanged.
+This is usual practice to do some manipulation in exception-safe manner -- the
+new data are prepared in a different zone object and when it works, they are
+swapped. The old one contains the new data and the other one can be safely
+destroyed.
+
+% MEM_ADD_ZONE adding zone '%1/%2'
+Debug information. A zone is being added into the in-memory data source.
+
+% MEM_FIND_ZONE looking for zone '%1'
+Debug information. A zone object for this zone is being searched for in the
+in-memory data source.
+
+% STATIC_CREATE creating the static datasource
+Debug information. The static data source (the one holding stuff like
+version.bind) is being created.
+
+% STATIC_BAD_CLASS static data source can handle CH only
+For some reason, someone asked the static data source a query that is not in
+the CH class.
+
+% STATIC_FIND looking for '%1/%2'
+Debug information. This resource record set is being looked up in the static
+data source.
+
+% SQLITE_FINDREC looking for record '%1/%2'
+Debug information. The SQLite data source is looking up records of given name
+and type in the database.
+
+% SQLITE_ENCLOSURE looking for zone containing '%1'
+Debug information. The SQLite data source is trying to identify, which zone
+should hold this domain.
+
+% SQLITE_ENCLOSURE_BAD_CLASS class mismatch looking for a zone ('%1' and '%2')
+The SQLite data source can handle only one class at a time and it was asked
+to identify which zone is holding data of a different class.
+
+% SQLITE_ENCLOSURE_NOTFOUND no zone contains it
+Debug information. The last SQLITE_ENCLOSURE query was unsuccessful, there's
+no such zone in our data.
+
+% SQLITE_PREVIOUS looking for name previous to '%1'
+Debug information. We're trying to look up name preceding the supplied one.
+
+% SQLITE_PREVIOUS_NO_ZONE no zone containing '%1'
+The SQLite data source tried to identify name preceding this one. But this
+one is not contained in any zone in the data source.
+
+% SQLITE_FIND_NSEC3 looking for NSEC3 in zone '%1' for hash '%2'
+Debug information. We're trying to look up a NSEC3 record in the SQLite data
+source.
+
+% SQLITE_FIND_NSEC3_NO_ZONE no such zone '%1'
+The SQLite data source was asked to provide a NSEC3 record for given zone.
+But it doesn't contain that zone.
+
+% SQLITE_FIND looking for RRset '%1/%2'
+Debug information. The SQLite data source is looking up a resource record
+set.
+
+% SQLITE_FIND_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+The SQLite data source was looking up an RRset, but the data source contains
+different class than the query was for.
+
+% SQLITE_FINDEXACT looking for exact RRset '%1/%2'
+Debug information. The SQLite data source is looking up an exact resource
+record.
+
+% SQLITE_FINDEXACT_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+The SQLite data source was looking up an exact RRset, but the data source
+contains different class than the query was for.
+
+% SQLITE_FINDADDRS looking for A/AAAA addresses for '%1'
+Debug information. The data source is looking up the addresses for given
+domain name.
+
+% SQLITE_FINDADDRS_BAD_CLASS class mismatch looking for addresses ('%1' and '%2')
+The SQLite data source was looking up A/AAAA addresses, but the data source
+contains different class than the query was for.
+
+% SQLITE_FINDREF looking for referral at '%1'
+Debug information. The SQLite data source is identifying if this domain is
+a referral and where it goes.
+
+% SQLITE_FINDREF_BAD_CLASS class mismatch looking for referral ('%1' and '%2')
+The SQLite data source was trying to identify, if there's a referral. But
+it contains different class than the query was for.
+
+% SQLITE_CREATE sQLite data source created
+Debug information. An instance of SQLite data source is being created.
+
+% SQLITE_DESTROY sQLite data source destroyed
+Debug information. An instance of SQLite data source is being destroyed.
+
+% SQLITE_SETUP setting up SQLite database
+The database for SQLite data source was found empty. It is assumed this is the
+first run and it is being initialized with current schema.  It'll still contain
+no data, but it will be ready for use.
+
+% SQLITE_OPEN opening SQLite database '%1'
+Debug information. The SQLite data source is loading an SQLite database in
+the provided file.
+
+% SQLITE_CLOSE closing SQLite database
+Debug information. The SQLite data source is closing the database file.
diff --git a/src/lib/datasrc/query.cc b/src/lib/datasrc/query.cc
index d3de5c7..a8d675a 100644
--- a/src/lib/datasrc/query.cc
+++ b/src/lib/datasrc/query.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/message.h>
diff --git a/src/lib/datasrc/sqlite3_datasrc.cc b/src/lib/datasrc/sqlite3_datasrc.cc
index ab910ba..22f035b 100644
--- a/src/lib/datasrc/sqlite3_datasrc.cc
+++ b/src/lib/datasrc/sqlite3_datasrc.cc
@@ -18,6 +18,7 @@
 #include <sqlite3.h>
 
 #include <datasrc/sqlite3_datasrc.h>
+#include <datasrc/logger.h>
 
 #include <dns/rrttl.h>
 #include <dns/rdata.h>
@@ -227,6 +228,8 @@ Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
                             RRsetList& target, const Name* zonename,
                             const Mode mode, uint32_t& flags) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name).
+        arg(rdtype);
     flags = 0;
     int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
         findClosest(*zonename, NULL);
@@ -345,12 +348,17 @@ Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
 
 void
 Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE).
+        arg(match.getName());
     if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
+        LOG_ERROR(logger, DATASRC_SQLITE_ENCLOSURE_BAD_CLASS).arg(getClass()).
+            arg(match.getClass());
         return;
     }
 
     unsigned int position;
     if (findClosest(match.getName(), &position) == -1) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_NOTFOUND);
         return;
     }
 
@@ -362,9 +370,11 @@ Sqlite3DataSrc::findPreviousName(const Name& qname,
                                  Name& target,
                                  const Name* zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname);
     const int zone_id = (zonename == NULL) ?
         findClosest(qname, NULL) : findClosest(*zonename, NULL);
     if (zone_id < 0) {
+        LOG_ERROR(logger, DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText());
         return (ERROR);
     }
     
@@ -402,8 +412,11 @@ Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
                                   string& hashstr,
                                   RRsetList& target) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3).
+        arg(zonename).arg(hashstr);
     const int zone_id = findClosest(zonename, NULL);
     if (zone_id < 0) {
+        LOG_ERROR(logger, DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename);
         return (ERROR);
     }
 
@@ -484,7 +497,11 @@ Sqlite3DataSrc::findRRset(const Name& qname,
                           uint32_t& flags,
                           const Name* zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname).
+        arg(qtype);
     if (qclass != getClass() && qclass != RRClass::ANY()) {
+        LOG_ERROR(logger, DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()).
+            arg(qclass);
         return (ERROR);
     }
     findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -499,7 +516,11 @@ Sqlite3DataSrc::findExactRRset(const Name& qname,
                                uint32_t& flags,
                                const Name* zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname).
+        arg(qtype);
     if (qclass != getClass() && qclass != RRClass::ANY()) {
+        LOG_ERROR(logger, DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()).
+            arg(qclass);
         return (ERROR);
     }
     findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -523,7 +544,10 @@ Sqlite3DataSrc::findAddrs(const Name& qname,
                           uint32_t& flags,
                           const Name* zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname);
     if (qclass != getClass() && qclass != RRClass::ANY()) {
+        LOG_ERROR(logger, DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()).
+            arg(qclass);
         return (ERROR);
     }
     findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
@@ -537,8 +561,11 @@ Sqlite3DataSrc::findReferral(const Name& qname,
                              uint32_t& flags,
                              const Name* zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname);
     if (qclass != getClass() && qclass != RRClass::ANY()) {
-            return (ERROR);
+        LOG_ERROR(logger, DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()).
+            arg(qclass);
+        return (ERROR);
     }
     findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
     return (SUCCESS);
@@ -546,9 +573,12 @@ Sqlite3DataSrc::findReferral(const Name& qname,
 
 Sqlite3DataSrc::Sqlite3DataSrc() :
     dbparameters(new Sqlite3Parameters)
-{}
+{
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CREATE);
+}
 
 Sqlite3DataSrc::~Sqlite3DataSrc() {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DESTROY);
     if (dbparameters->db_ != NULL) {
         close();
     }
@@ -635,6 +665,7 @@ checkAndSetupSchema(Sqlite3Initializer* initializer) {
         initializer->params_.version_ = sqlite3_column_int(prepared, 0);
         sqlite3_finalize(prepared);
     } else {
+        logger.info(DATASRC_SQLITE_SETUP);
         if (prepared != NULL) {
             sqlite3_finalize(prepared);
         }
@@ -664,6 +695,7 @@ checkAndSetupSchema(Sqlite3Initializer* initializer) {
 //
 void
 Sqlite3DataSrc::open(const string& name) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name);
     if (dbparameters->db_ != NULL) {
         isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
     }
@@ -683,6 +715,7 @@ Sqlite3DataSrc::open(const string& name) {
 //
 DataSrc::Result
 Sqlite3DataSrc::close(void) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CLOSE);
     if (dbparameters->db_ == NULL) {
         isc_throw(DataSourceError,
                   "SQLite data source is being closed before open");
diff --git a/src/lib/datasrc/static_datasrc.cc b/src/lib/datasrc/static_datasrc.cc
index 025078a..dee14b9 100644
--- a/src/lib/datasrc/static_datasrc.cc
+++ b/src/lib/datasrc/static_datasrc.cc
@@ -26,6 +26,7 @@
 
 #include <datasrc/data_source.h>
 #include <datasrc/static_datasrc.h>
+#include <datasrc/logger.h>
 
 using namespace std;
 using namespace isc::dns;
@@ -112,6 +113,7 @@ StaticDataSrcImpl::StaticDataSrcImpl() :
 }
 
 StaticDataSrc::StaticDataSrc() {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_STATIC_CREATE);
     setClass(RRClass::CH());
     impl_ = new StaticDataSrcImpl;
 }
@@ -155,8 +157,11 @@ StaticDataSrc::findRRset(const Name& qname,
                          RRsetList& target, uint32_t& flags,
                          const Name* const zonename) const
 {
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_STATIC_FIND).arg(qname).
+        arg(qtype);
     flags = 0;
     if (qclass != getClass() && qclass != RRClass::ANY()) {
+        LOG_ERROR(logger, DATASRC_STATIC_BAD_CLASS);
         return (ERROR);
     }
 
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index f09b4b7..ad4374a 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -27,15 +27,17 @@ run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += zonetable_unittest.cc
 run_unittests_SOURCES += memory_datasrc_unittest.cc
+run_unittests_SOURCES += logger_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 endif
 
 noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/datasrc/tests/datasrc_unittest.cc b/src/lib/datasrc/tests/datasrc_unittest.cc
index 810aef9..cd1a40c 100644
--- a/src/lib/datasrc/tests/datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/datasrc_unittest.cc
@@ -20,7 +20,8 @@
 
 #include <gtest/gtest.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
 #include <dns/question.h>
@@ -44,6 +45,7 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc;
@@ -1090,6 +1092,22 @@ TEST_F(DataSrcTest, DISABLED_synthesizedCnameTooLong) {
         RRClass::IN(), RRType::A());
 }
 
+TEST_F(DataSrcTest, cacheDataInNonexistentZone) {
+    // This test emulates the situation where an RRset in some zone of some
+    // data source is cached and then the zone is removed from the data source.
+    // When there is such a substantial inconsistency between the cache and
+    // the real data source, we should honor the latter.  More important,
+    // the inconsistency shouldn't cause any disruption such as a crash.
+
+    const Name qname("nosuchzone.example");
+    RRsetPtr rrset(new RRset(qname, RRClass::IN(), RRType::A(), RRTTL(0)));
+    cache.addPositive(rrset, DataSrc::REFERRAL);
+
+    createAndProcessQuery(qname, RRClass::IN(), RRType::A(), false);
+    headerCheck(msg, qid, Rcode::REFUSED(), opcodeval, QR_FLAG | RD_FLAG,
+                1, 0, 0, 0);
+}
+
 // Tests of the DataSrcMatch class start here
 class DataSrcMatchTest : public ::testing::Test {
 protected:
diff --git a/src/lib/datasrc/tests/logger_unittest.cc b/src/lib/datasrc/tests/logger_unittest.cc
new file mode 100644
index 0000000..df5a41c
--- /dev/null
+++ b/src/lib/datasrc/tests/logger_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <datasrc/logger.h>
+
+using namespace isc::datasrc;
+
+namespace {
+
+TEST(CacheLogger, name) {
+    // This does not check the name only, but the fact the logger is created
+    // The dot is because of empty root logger
+    std::string name(logger.getName());
+    EXPECT_EQ(name.size() - 8, name.rfind(".datasrc")) <<
+        "Wrong logger name: " << name;
+}
+
+}
diff --git a/src/lib/datasrc/tests/query_unittest.cc b/src/lib/datasrc/tests/query_unittest.cc
index fa7216b..7a20b86 100644
--- a/src/lib/datasrc/tests/query_unittest.cc
+++ b/src/lib/datasrc/tests/query_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <gtest/gtest.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/opcode.h>
diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc
index dd1b7fe..b26a22b 100644
--- a/src/lib/datasrc/tests/rbtree_unittest.cc
+++ b/src/lib/datasrc/tests/rbtree_unittest.cc
@@ -398,7 +398,7 @@ TEST_F(RBTreeTest, getLastComparedNode) {
     EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
     chain.clear();
 
-    const RBNode<int>* expected_node;
+    const RBNode<int>* expected_node = NULL;
 
     // Exact match case.  The returned node should be last compared.
     EXPECT_EQ(RBTree<int>::EXACTMATCH,
diff --git a/src/lib/datasrc/tests/test_datasrc.cc b/src/lib/datasrc/tests/test_datasrc.cc
index c18f0bd..d78e7db 100644
--- a/src/lib/datasrc/tests/test_datasrc.cc
+++ b/src/lib/datasrc/tests/test_datasrc.cc
@@ -23,7 +23,7 @@
 
 #include <datasrc/data_source.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index c5c5cd1..887ac09 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -1,6 +1,8 @@
-SUBDIRS = . tests python
+SUBDIRS = . tests python benchmarks
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
@@ -15,60 +17,58 @@ EXTRA_DIST += rrtype-placeholder.h
 # NOTE: when an rdata file is added, please also add to this list:
 EXTRA_DIST += rdata/any_255/tsig_250.cc
 EXTRA_DIST += rdata/any_255/tsig_250.h
-EXTRA_DIST += rdata/in_1/aaaa_28.cc
-EXTRA_DIST += rdata/in_1/aaaa_28.h
-EXTRA_DIST += rdata/in_1/a_1.cc
-EXTRA_DIST += rdata/in_1/a_1.h
 EXTRA_DIST += rdata/ch_3/a_1.cc
 EXTRA_DIST += rdata/ch_3/a_1.h
-EXTRA_DIST += rdata/generic/mx_15.h
-EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/cname_5.cc
+EXTRA_DIST += rdata/generic/cname_5.h
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
 EXTRA_DIST += rdata/generic/dname_39.cc
-EXTRA_DIST += rdata/generic/rrsig_46.h
 EXTRA_DIST += rdata/generic/dname_39.h
-EXTRA_DIST += rdata/generic/ns_2.cc
-EXTRA_DIST += rdata/generic/nsec_47.cc
-EXTRA_DIST += rdata/generic/ns_2.h
-EXTRA_DIST += rdata/generic/nsec_47.h
-EXTRA_DIST += rdata/generic/opt_41.cc
-EXTRA_DIST += rdata/generic/soa_6.cc
-EXTRA_DIST += rdata/generic/cname_5.cc
 EXTRA_DIST += rdata/generic/dnskey_48.cc
-EXTRA_DIST += rdata/generic/opt_41.h
-EXTRA_DIST += rdata/generic/soa_6.h
-EXTRA_DIST += rdata/generic/cname_5.h
 EXTRA_DIST += rdata/generic/dnskey_48.h
 EXTRA_DIST += rdata/generic/ds_43.cc
 EXTRA_DIST += rdata/generic/ds_43.h
-EXTRA_DIST += rdata/generic/txt_16.cc
-EXTRA_DIST += rdata/generic/txt_16.h
 EXTRA_DIST += rdata/generic/mx_15.cc
-EXTRA_DIST += rdata/generic/nsec3param_51.h
-EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/mx_15.h
+EXTRA_DIST += rdata/generic/ns_2.cc
+EXTRA_DIST += rdata/generic/ns_2.h
 EXTRA_DIST += rdata/generic/nsec3_50.cc
 EXTRA_DIST += rdata/generic/nsec3_50.h
+EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/nsec3param_51.h
+EXTRA_DIST += rdata/generic/nsec_47.cc
+EXTRA_DIST += rdata/generic/nsec_47.h
+EXTRA_DIST += rdata/generic/opt_41.cc
+EXTRA_DIST += rdata/generic/opt_41.h
 EXTRA_DIST += rdata/generic/ptr_12.cc
 EXTRA_DIST += rdata/generic/ptr_12.h
+EXTRA_DIST += rdata/generic/rp_17.cc
+EXTRA_DIST += rdata/generic/rp_17.h
+EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/rrsig_46.h
+EXTRA_DIST += rdata/generic/soa_6.cc
+EXTRA_DIST += rdata/generic/soa_6.h
+EXTRA_DIST += rdata/generic/txt_16.cc
+EXTRA_DIST += rdata/generic/txt_16.h
 EXTRA_DIST += rdata/hs_4/a_1.cc
 EXTRA_DIST += rdata/hs_4/a_1.h
+EXTRA_DIST += rdata/in_1/a_1.cc
+EXTRA_DIST += rdata/in_1/a_1.h
+EXTRA_DIST += rdata/in_1/aaaa_28.cc
+EXTRA_DIST += rdata/in_1/aaaa_28.h
 #EXTRA_DIST += rdata/template.cc
 #EXTRA_DIST += rdata/template.h
 
 # auto-generate by gen-rdatacode.py:
 BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
-#TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
+BUILT_SOURCES += rdataclass.h rdataclass.cc
 
 lib_LTLIBRARIES = libdns++.la
 
-libdns___la_SOURCES = util/base32hex.h util/base64.h util/base_n.cc
-libdns___la_SOURCES += util/base32hex_from_binary.h
-libdns___la_SOURCES += util/binary_from_base32hex.h
-libdns___la_SOURCES += util/base16_from_binary.h util/binary_from_base16.h
-libdns___la_SOURCES += buffer.h
-libdns___la_SOURCES += dnssectime.h dnssectime.cc
+libdns___la_SOURCES =
 libdns___la_SOURCES += edns.h edns.cc
 libdns___la_SOURCES += exceptions.h exceptions.cc
-libdns___la_SOURCES += util/hex.h
 libdns___la_SOURCES += masterload.h masterload.cc
 libdns___la_SOURCES += message.h message.cc
 libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
@@ -76,6 +76,7 @@ libdns___la_SOURCES += name.h name.cc
 libdns___la_SOURCES += opcode.h opcode.cc
 libdns___la_SOURCES += rcode.h rcode.cc
 libdns___la_SOURCES += rdata.h rdata.cc
+libdns___la_SOURCES += rdatafields.h rdatafields.cc
 libdns___la_SOURCES += rrclass.cc
 libdns___la_SOURCES += rrparamregistry.h
 libdns___la_SOURCES += rrset.h rrset.cc
@@ -83,13 +84,22 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
 libdns___la_SOURCES += rrttl.h rrttl.cc
 libdns___la_SOURCES += rrtype.cc
 libdns___la_SOURCES += question.h question.cc
-libdns___la_SOURCES += util/sha1.h util/sha1.cc
+libdns___la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES += tsigerror.h tsigerror.cc
 libdns___la_SOURCES += tsigkey.h tsigkey.cc
+libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
 libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
 libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
 
-nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
-nodist_libdns___la_SOURCES += rrparamregistry.cc
+libdns___la_CPPFLAGS = $(AM_CPPFLAGS)
+# Most applications of libdns++ will only implicitly rely on libcryptolink,
+# so we add the dependency here so that the applications don't have to link
+# libcryptolink explicitly.
+libdns___la_LIBADD = $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+libdns___la_LIBADD += $(top_builddir)/src/lib/util/libutil.la
+
+nodist_libdns___include_HEADERS = rdataclass.h rrclass.h rrtype.h
+nodist_libdns___la_SOURCES = rdataclass.cc rrparamregistry.cc
 
 rrclass.h: rrclass-placeholder.h
 rrtype.h: rrtype-placeholder.h
@@ -99,8 +109,6 @@ rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 
 libdns___includedir = $(includedir)/dns
 libdns___include_HEADERS = \
-	buffer.h \
-	dnssectime.h \
 	edns.h \
 	exceptions.h \
 	message.h \
@@ -109,13 +117,10 @@ libdns___include_HEADERS = \
 	question.h \
 	rcode.h \
 	rdata.h \
-	rdataclass.h \
-	rrclass.h \
 	rrparamregistry.h \
 	rrset.h \
 	rrsetlist.h \
 	rrttl.h \
-	rrtype.h \
 	tsigkey.h
 # Purposely not installing these headers:
 # util/*.h: used only internally, and not actually DNS specific
diff --git a/src/lib/dns/benchmarks/Makefile.am b/src/lib/dns/benchmarks/Makefile.am
new file mode 100644
index 0000000..8645385
--- /dev/null
+++ b/src/lib/dns/benchmarks/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS = rdatarender_bench
+rdatarender_bench_SOURCES = rdatarender_bench.cc
+
+rdatarender_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
+rdatarender_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+rdatarender_bench_LDADD += $(SQLITE_LIBS)
diff --git a/src/lib/dns/benchmarks/README b/src/lib/dns/benchmarks/README
new file mode 100644
index 0000000..7119c13
--- /dev/null
+++ b/src/lib/dns/benchmarks/README
@@ -0,0 +1,10 @@
+- rdatarender_bench
+
+  This is a benchmark for RDATA rendering performance comparing the basic
+  Rdata objects and RdataField objects.  It takes a command line argument
+  that specifies an input data file.  Each line of the data file should
+  specify a single RDATA with its RR class and type, e.g.
+  IN A 192.0.2.1
+  IN NS ns.example.com.
+  Lines beginning with '#' and empty lines will be ignored.  Sample input
+  files can be found in benchmarkdata/rdatarender_*.
diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com
new file mode 100644
index 0000000..12155a6
--- /dev/null
+++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com
@@ -0,0 +1,32 @@
+# This is sample input data for rdatarender_bench.
+# These are RDATA in the authority and additional sections in a response from
+# a root server for a query domain under COM.
+
+IN	NS	g.gtld-servers.net.
+IN	NS	a.gtld-servers.net.
+IN	NS	k.gtld-servers.net.
+IN	NS	c.gtld-servers.net.
+IN	NS	d.gtld-servers.net.
+IN	NS	m.gtld-servers.net.
+IN	NS	h.gtld-servers.net.
+IN	NS	b.gtld-servers.net.
+IN	NS	j.gtld-servers.net.
+IN	NS	l.gtld-servers.net.
+IN	NS	e.gtld-servers.net.
+IN	NS	f.gtld-servers.net.
+IN	NS	i.gtld-servers.net.
+IN	A	192.5.6.30
+IN	A	192.33.14.30
+IN	A	192.26.92.30
+IN	A	192.31.80.30
+IN	A	192.12.94.30
+IN	A	192.35.51.30
+IN	A	192.42.93.30
+IN	A	192.54.112.30
+IN	A	192.43.172.30
+IN	A	192.48.79.30
+IN	A	192.52.178.30
+IN	A	192.41.162.30
+IN	A	192.55.83.30
+IN	AAAA	2001:503:a83e::2:30
+IN	AAAA	2001:503:231d::2:30
diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain
new file mode 100644
index 0000000..eb14b5f
--- /dev/null
+++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain
@@ -0,0 +1,10 @@
+# This is sample input data for rdatarender_bench.
+# These are RDATA in the authority section in a response from
+# a root server for a non existent query domain (with DNSSEC).
+
+IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2010110301 1800 900 604800 86400
+IN	RRSIG	SOA 8 0 86400 20101110000000 20101102230000 40288 . WtvYyX2nIsaqjWqkIG1WHFE5PnJ6eno0KqF6azU/MFJ/t1JpKWQ1P4rA 61rnoq0p252fg7wT4XzEz9UDxmpB5pvF2VApe2w9LvSWxsWIIOg8ue5u e9NAAYdzjd0rsYObQQ6msf7WchyAUbnmrqKvf8/CK6+s1xFihXp5DpYL 6K0=
+IN	NSEC	ac. NS SOA RRSIG NSEC DNSKEY
+IN	RRSIG	NSEC 8 0 86400 20101110000000 20101102230000 40288 . rWfgg4YUDFAjhiUOT+niJy/qbaIbydqoXg5oB/5j//ZjNFy4hqU8DvdM xJr9UybQpEvu7pvmKQ0jRYO98Fw/UTlY5KiKbhVBJ1t8AE93cbU+s5gX d3Q6+wRcFX5MjZyIe+f30llKrYOZHjRyEFALCkLt4XEmr0xsua+ztAFY 65k=
+IN	NSEC	np. NS RRSIG NSEC
+IN	RRSIG	NSEC 8 1 86400 20101110000000 20101102230000 40288 . G32LGynsGA2fyDnesyeCtBCoM3ERMgGS4touDUuoBYW1NrZub76kz5fc z93p8VZfoYWAW7LuC8vJ1jl2sUgBNns4zN4RsfFeopcYjjFnGbGuoZnO NmTU+NKO53Ub7uIcCSeqV+COAaL8XqDfyk1FmVdQvtrBaOW/PWpRahVq 7E8=
diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org
new file mode 100644
index 0000000..17b80d2
--- /dev/null
+++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org
@@ -0,0 +1,22 @@
+# This is sample input data for rdatarender_bench.
+# These are RDATA in the authority and additional sections in a response from
+# a root server for a query domain under ORG.
+
+IN	NS	b0.org.afilias-nst.org.
+IN	NS	a2.org.afilias-nst.info.
+IN	NS	a0.org.afilias-nst.info.
+IN	NS	c0.org.afilias-nst.info.
+IN	NS	d0.org.afilias-nst.org.
+IN	NS	b2.org.afilias-nst.org.
+IN	A	199.19.56.1
+IN	A	199.249.112.1
+IN	A	199.19.54.1
+IN	A	199.249.120.1
+IN	A	199.19.53.1
+IN	A	199.19.57.1
+IN	AAAA	2001:500:e::1
+IN	AAAA	2001:500:40::1
+IN	AAAA	2001:500:c::1
+IN	AAAA	2001:500:48::1
+IN	AAAA	2001:500:b::1
+IN	AAAA	2001:500:f::1
diff --git a/src/lib/dns/benchmarks/rdatarender_bench.cc b/src/lib/dns/benchmarks/rdatarender_bench.cc
new file mode 100644
index 0000000..d1fb0f2
--- /dev/null
+++ b/src/lib/dns/benchmarks/rdatarender_bench.cc
@@ -0,0 +1,188 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <bench/benchmark.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdatafields.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+using namespace std;
+using namespace isc::bench;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::util::OutputBuffer;
+
+namespace {
+// This templated benchmark class is constructed with a vector of Rdata-like
+// (pointer) objects which should have a "toWire()" method.  In its run(),
+// it calls toWire() for each element of the vector.
+template <typename T>
+class RdataRenderBenchMark {
+public:
+    RdataRenderBenchMark(const vector<T>& dataset) :
+        dataset_(dataset), buffer_(4096), renderer_(buffer_)
+    {}
+    unsigned int run() {
+        typename vector<T>::const_iterator data;
+        typename vector<T>::const_iterator data_end = dataset_.end();
+        for (data = dataset_.begin(); data != data_end; ++data) {
+            renderer_.clear();
+            (*data)->toWire(renderer_);
+        }
+        return (dataset_.size());
+    }
+private:
+    const vector<T>& dataset_;
+    OutputBuffer buffer_;
+    MessageRenderer renderer_;
+};
+
+// This supplemental class emulates an RRset like class that internally
+// uses RdataFields.  On construction it stores RDATA information in the
+// form of RdataFields fields.  Its toWire() method restores the data as
+// an RdataFields object for the rendering.
+class RdataFieldsStore {
+public:
+    RdataFieldsStore(ConstRdataPtr rdata) {
+        const RdataFields fields(*rdata);
+
+        spec_size_ = fields.getFieldSpecDataSize();
+        spec_store_.resize(spec_size_);
+        void* cp_spec = &spec_store_[0];
+        memcpy(cp_spec, fields.getFieldSpecData(), spec_store_.size());
+        spec_ptr_ = cp_spec;
+
+        data_length_ = fields.getDataLength();
+        data_store_.resize(data_length_);
+        void* cp_data = &data_store_[0];
+        memcpy(cp_data, fields.getData(), data_store_.size());
+        // Vector guarantees that the elements are stored in continuous array
+        // in memory, so this is actually correct by the standard
+        data_ptr_ = cp_data;
+    }
+    void toWire(MessageRenderer& renderer) const {
+        RdataFields(spec_ptr_, spec_size_,
+                    data_ptr_, data_length_).toWire(renderer);
+    }
+private:
+    vector<unsigned char> spec_store_;
+    vector<unsigned char> data_store_;
+    const void* spec_ptr_;
+    const void* data_ptr_;
+    unsigned int spec_size_;
+    size_t data_length_;
+};
+
+// We wouldn't necessarily have to use a shared pointer, but it's easier
+// to use pointer-like values to adjust them with the RdataRenderBenchMark
+// template.
+typedef boost::shared_ptr<const RdataFieldsStore> ConstRdataFieldsStorePtr;
+
+void
+readInputFile(const char* const input_file, vector<ConstRdataPtr>& rdata_sets,
+              vector<ConstRdataFieldsStorePtr>& fields_sets)
+{
+    ifstream ifs;
+    ifs.open(input_file, ios_base::in);
+    if ((ifs.rdstate() & istream::failbit) != 0) {
+        cerr << "Failed to read input file: " << input_file << endl;
+        exit (1);
+    }
+    string line;
+    unsigned int linenum = 0;
+    while (getline(ifs, line), !ifs.eof()) {
+        ++linenum;
+        if (ifs.bad() || ifs.fail()) {
+            cerr << "Unexpected input at line " << linenum << endl;
+            exit (1);
+        }
+        if (line.empty() || line[0] == '#') {
+            continue;           // skip comment and blank lines
+        }
+        istringstream iss(line);
+        string rrclass_string, rrtype_string;
+        stringbuf rdatabuf;
+        iss >> rrclass_string >> rrtype_string >> &rdatabuf;
+        if (iss.bad() || iss.fail()) {
+            cerr << "Unexpected input at line " << linenum << endl;
+            exit (1);
+        }
+        ConstRdataPtr rdata = createRdata(RRType(rrtype_string),
+                                          RRClass(rrclass_string),
+                                          rdatabuf.str());
+        rdata_sets.push_back(rdata);
+        fields_sets.push_back(ConstRdataFieldsStorePtr(
+                                  new RdataFieldsStore(rdata)));
+    }
+    ifs.close();
+}
+
+void
+usage() {
+    cerr << "Usage: rdatafields_bench [-n iterations] input_file" << endl;
+    exit (1);
+}
+}
+
+int
+main(int argc, char* argv[]) {
+    int ch;
+    int iteration = 10000;
+    while ((ch = getopt(argc, argv, "n:")) != -1) {
+        switch (ch) {
+        case 'n':
+            iteration = atoi(optarg);
+            break;
+        case '?':
+        default:
+            usage();
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc < 1) {
+        usage();
+    }
+    const char* const input_file = argv[0];
+
+    vector<ConstRdataPtr> rdata_sets;
+    vector<ConstRdataFieldsStorePtr> fields_sets;
+
+    readInputFile(input_file, rdata_sets, fields_sets);
+
+    cout << "Parameters:" << endl;
+    cout << "  Iterations: " << iteration << endl;
+    cout << "  Input File: " << input_file << endl;
+
+    typedef RdataRenderBenchMark<ConstRdataPtr> RdataBenchMark;
+    cout << "Benchmark for rendering with standard Rdata" << endl;
+    BenchMark<RdataBenchMark>(iteration, RdataBenchMark(rdata_sets));
+
+    typedef RdataRenderBenchMark<ConstRdataFieldsStorePtr> FieldsBenchMark;
+    cout << "Benchmark for rendering with RdataFields" << endl;
+    BenchMark<FieldsBenchMark>(iteration, FieldsBenchMark(fields_sets));
+
+    return (0);
+}
diff --git a/src/lib/dns/buffer.h b/src/lib/dns/buffer.h
deleted file mode 100644
index c824154..0000000
--- a/src/lib/dns/buffer.h
+++ /dev/null
@@ -1,446 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __BUFFER_H
-#define __BUFFER_H 1
-
-#include <vector>
-
-#include <string.h>
-
-#include <stdint.h>
-
-#include <exceptions/exceptions.h>
-
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dns {
-
-///
-/// \brief A standard DNS module exception that is thrown if an out-of-range
-/// buffer operation is being performed.
-///
-class InvalidBufferPosition : public Exception {
-public:
-    InvalidBufferPosition(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-///\brief The \c InputBuffer class is a buffer abstraction for manipulating
-/// read-only data.
-///
-/// The main purpose of this class is to provide a safe placeholder for
-/// examining wire-format data received from a network.
-///
-/// Applications normally use this class only in a limited situation: as an
-/// interface between legacy I/O operation (such as receiving data from a BSD
-/// socket) and the rest of the BIND10 DNS library.  One common usage of this
-/// class for an application would therefore be something like this:
-///
-/// \code unsigned char buf[1024];
-/// struct sockaddr addr;
-/// socklen_t addrlen = sizeof(addr);
-/// int cc = recvfrom(s, buf, sizeof(buf), 0, &addr, &addrlen);
-/// InputBuffer buffer(buf, cc);
-/// // pass the buffer to a DNS message object to parse the message \endcode
-///
-/// Other BIND10 DNS classes will then use methods of this class to get access
-/// to the data, but the application normally doesn't have to care about the
-/// details.
-///
-/// An \c InputBuffer object internally holds a reference to the given data,
-/// rather than make a local copy of the data.  Also, it does not have an
-/// ownership of the given data.  It is application's responsibility to ensure
-/// the data remains valid throughout the lifetime of the \c InputBuffer
-/// object.  Likewise, this object generally assumes the data isn't modified
-/// throughout its lifetime; if the application modifies the data while this
-/// object retains a reference to it, the result is undefined.  The application
-/// will also be responsible for releasing the data when it's not needed if it
-/// was dynamically acquired.
-///
-/// This is a deliberate design choice: although it's safer to make a local
-/// copy of the given data on construction, it would cause unacceptable
-/// performance overhead, especially considering that a DNS message can be
-/// as large as a few KB.  Alternatively, we could allow the object to allocate
-/// memory internally and expose it to the application to store network data
-/// in it.  This is also a bad design, however, in that we would effectively
-/// break the abstraction employed in the class, and do so by publishing
-/// "read-only" stuff as a writable memory region.  Since there doesn't seem to
-/// be a perfect solution, we have adopted what we thought a "least bad" one.
-///
-/// Methods for reading data from the buffer generally work like an input
-/// stream: it begins with the head of the data, and once some length of data
-/// is read from the buffer, the next read operation will take place from the
-/// head of the unread data.  An object of this class internally holds (a
-/// notion of) where the next read operation should start.  We call it the
-/// <em>read position</em> in this document.
-class InputBuffer {
-public:
-    ///
-    /// \name Constructors and Destructor
-    //@{
-    /// \brief Constructor from variable length of data.
-    ///
-    /// It is caller's responsibility to ensure that the data is valid as long
-    /// as the buffer exists.
-    /// \param data A pointer to the data stored in the buffer.
-    /// \param len The length of the data in bytes.
-    InputBuffer(const void* data, size_t len) :
-        position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
-    //@}
-
-    ///
-    /// \name Getter Methods
-    //@{
-    /// \brief Return the length of the data stored in the buffer.
-    size_t getLength() const { return (len_); }
-    /// \brief Return the current read position.
-    size_t getPosition() const { return (position_); }
-    //@}
-
-    ///
-    /// \name Setter Methods
-    ///
-    //@{
-    /// \brief Set the read position of the buffer to the given value.
-    ///
-    /// The new position must be in the valid range of the buffer; otherwise
-    /// an exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    /// \param position The new position (offset from the beginning of the
-    /// buffer).
-    void setPosition(size_t position)
-    {
-        if (position > len_)
-            isc_throw(InvalidBufferPosition, "position is too large");
-        position_ = position;
-    }
-    //@}
-
-    ///
-    /// \name Methods for reading data from the buffer.
-    //@{
-    /// \brief Read an unsigned 8-bit integer from the buffer and return it.
-    ///
-    /// If the remaining length of the buffer is smaller than 8-bit, an
-    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint8_t readUint8()
-    {
-        if (position_ + sizeof(uint8_t) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
-        }
-
-        return (data_[position_++]);
-    }
-    /// \brief Read an unsigned 16-bit integer in network byte order from the
-    /// buffer, convert it to host byte order, and return it.
-    ///
-    /// If the remaining length of the buffer is smaller than 16-bit, an
-    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint16_t readUint16()
-    {
-        uint16_t data;
-        const uint8_t* cp;
-
-        if (position_ + sizeof(data) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
-        }
-
-        cp = &data_[position_];
-        data = ((unsigned int)(cp[0])) << 8;
-        data |= ((unsigned int)(cp[1]));
-        position_ += sizeof(data);
-
-        return (data);
-    }
-    /// \brief Read an unsigned 32-bit integer in network byte order from the
-    /// buffer, convert it to host byte order, and return it.
-    ///
-    /// If the remaining length of the buffer is smaller than 32-bit, an
-    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint32_t readUint32()
-    {
-        uint32_t data;
-        const uint8_t* cp;
-
-        if (position_ + sizeof(data) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
-        }
-
-        cp = &data_[position_];
-        data = ((unsigned int)(cp[0])) << 24;
-        data |= ((unsigned int)(cp[1])) << 16;
-        data |= ((unsigned int)(cp[2])) << 8;
-        data |= ((unsigned int)(cp[3]));
-        position_ += sizeof(data);
-
-        return (data);
-    }
-    /// \brief Read data of the specified length from the buffer and copy it to
-    /// the caller supplied buffer.
-    ///
-    /// The data is copied as stored in the buffer; no conversion is performed.
-    /// If the remaining length of the buffer is smaller than the specified
-    /// length, an exception of class \c isc::dns::InvalidBufferPosition will
-    /// be thrown.
-    void readData(void* data, size_t len)
-    {
-        if (position_ + len > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
-        }
-
-        memcpy(data, &data_[position_], len);
-        position_ += len;
-    }
-    //@}
-
-private:
-    size_t position_;
-
-    // XXX: The following must be private, but for a short term workaround with
-    // Boost.Python binding, we changed it to protected.  We should soon
-    // revisit it.
-protected:
-    const uint8_t* data_;
-    size_t len_;
-};
-
-///
-///\brief The \c OutputBuffer class is a buffer abstraction for manipulating
-/// mutable data.
-///
-/// The main purpose of this class is to provide a safe workplace for
-/// constructing wire-format data to be sent out to a network.  Here,
-/// <em>safe</em> means that it automatically allocates necessary memory and
-/// avoid buffer overrun.
-///
-/// Like for the \c InputBuffer class, applications normally use this class only
-/// in a limited situation.  One common usage of this class for an application
-/// would be something like this:
-///
-/// \code OutputBuffer buffer(4096); // give a sufficiently large initial size
-/// // pass the buffer to a DNS message object to construct a wire-format
-/// // DNS message.
-/// struct sockaddr to;
-/// sendto(s, buffer.getData(), buffer.getLength(), 0, &to, sizeof(to));
-/// \endcode
-///
-/// where the \c getData() method gives a reference to the internal memory
-/// region stored in the \c buffer object.  This is a suboptimal design in that
-/// it exposes an encapsulated "handle" of an object to its user.
-/// Unfortunately, there is no easy way to avoid this without involving
-/// expensive data copy if we want to use this object with a legacy API such as
-/// a BSD socket interface.  And, indeed, this is one major purpose for this
-/// object.  Applications should use this method only under such a special
-/// circumstance.  It should also be noted that the memory region returned by
-/// \c getData() may be invalidated after a subsequent write operation.
-///
-/// An \c OutputBuffer class object automatically extends its memory region when
-/// data is written beyond the end of the current buffer.  However, it will
-/// involve performance overhead such as reallocating more memory and copying
-/// data.  It is therefore recommended to construct the buffer object with a
-/// sufficiently large initial size.
-/// The \c getCapacity() method provides the current maximum size of data
-/// (including the portion already written) that can be written into the buffer
-/// without causing memory reallocation.
-///
-/// Methods for writing data into the buffer generally work like an output
-/// stream: it begins with the head of the buffer, and once some length of data
-/// is written into the buffer, the next write operation will take place from
-/// the end of the buffer.  Other methods to emulate "random access" are also
-/// provided (e.g., \c writeUint16At()).  The normal write operations are
-/// normally exception-free as this class automatically extends the buffer
-/// when necessary.  However, in extreme cases such as an attempt of writing
-/// multi-GB data, a separate exception (e.g., \c std::bad_alloc) may be thrown
-/// by the system.  This also applies to the constructor with a very large
-/// initial size.
-///
-/// Note to developers: it may make more sense to introduce an abstract base
-/// class for the \c OutputBuffer and define the simple implementation as a
-/// a concrete derived class.  That way we can provide flexibility for future
-/// extension such as more efficient buffer implementation or allowing users
-/// to have their own customized version without modifying the source code.
-/// We in fact considered that option, but at the moment chose the simpler
-/// approach with a single concrete class because it may make the
-/// implementation unnecessarily complicated while we were still not certain
-/// if we really want that flexibility.  We may revisit the class design as
-/// we see more applications of the class.  The same considerations apply to
-/// the \c InputBuffer and \c MessageRenderer classes.
-class OutputBuffer {
-public:
-    ///
-    /// \name Constructors and Destructor
-    ///
-    //@{
-    /// \brief Constructor from the initial size of the buffer.
-    ///
-    /// \param len The initial length of the buffer in bytes.
-    OutputBuffer(size_t len) { data_.reserve(len); }
-    //@}
-
-    ///
-    /// \name Getter Methods
-    ///
-    //@{
-    /// \brief Return the current capacity of the buffer.
-    size_t getCapacity() const { return (data_.capacity()); }
-    /// \brief Return a pointer to the head of the data stored in the buffer.
-    ///
-    /// The caller can assume that the subsequent \c getLength() bytes are
-    /// identical to the stored data of the buffer.
-    ///
-    /// Note: The pointer returned by this method may be invalidated after a
-    /// subsequent write operation.
-    const void* getData() const { return (&data_[0]); }
-    /// \brief Return the length of data written in the buffer.
-    size_t getLength() const { return (data_.size()); }
-    /// \brief Return the value of the buffer at the specified position.
-    ///
-    /// \c pos must specify the valid position of the buffer; otherwise an
-    /// exception class of \c InvalidBufferPosition will be thrown.
-    ///
-    /// \param pos The position in the buffer to be returned.
-    const uint8_t& operator[](size_t pos) const
-    {
-        if (pos >= data_.size()) {
-            isc_throw(InvalidBufferPosition, "read at invalid position");
-        }
-        return (data_[pos]);
-    }
-    //@}
-
-    ///
-    /// \name Methods for writing data into the buffer.
-    ///
-    //@{
-    /// \brief Insert a specified length of gap at the end of the buffer.
-    ///
-    /// The caller should not assume any particular value to be inserted.
-    /// This method is provided as a shortcut to make a hole in the buffer
-    /// that is to be filled in later, e.g, by \ref writeUint16At().
-    /// \param len The length of the gap to be inserted in bytes.
-    void skip(size_t len) { data_.insert(data_.end(), len, 0); }
-
-    /// \brief Trim the specified length of data from the end of the buffer.
-    ///
-    /// The specified length must not exceed the current data size of the
-    /// buffer; otherwise an exception of class \c isc::OutOfRange will
-    /// be thrown.
-    ///
-    /// \param len The length of data that should be trimmed.
-    void trim(size_t len)
-    {
-        if (len > data_.size()) {
-            isc_throw(OutOfRange, "trimming too large from output buffer");
-        }
-        data_.resize(data_.size() - len);
-    }
-    /// \brief Clear buffer content.
-    ///
-    /// This method can be used to re-initialize and reuse the buffer without
-    /// constructing a new one.
-    void clear() { data_.clear(); }
-    /// \brief Write an unsigned 8-bit integer into the buffer.
-    ///
-    /// \param data The 8-bit integer to be written into the buffer.
-    void writeUint8(uint8_t data) { data_.push_back(data); }
-
-    /// \brief Write an unsigned 8-bit integer into the buffer.
-    ///
-    /// The position must be lower than the size of the buffer,
-    /// otherwise an exception of class \c isc::dns::InvalidBufferPosition
-    /// will be thrown.
-    ///
-    /// \param data The 8-bit integer to be written into the buffer.
-    /// \param pos The position in the buffer to write the data.
-    void writeUint8At(uint8_t data, size_t pos) {
-        if (pos + sizeof(data) > data_.size()) {
-            isc_throw(InvalidBufferPosition, "write at invalid position");
-        }
-        data_[pos] = data;
-    }
-
-    /// \brief Write an unsigned 16-bit integer in host byte order into the
-    /// buffer in network byte order.
-    ///
-    /// \param data The 16-bit integer to be written into the buffer.
-    void writeUint16(uint16_t data)
-    {
-        data_.push_back(static_cast<uint8_t>((data & 0xff00U) >> 8));
-        data_.push_back(static_cast<uint8_t>(data & 0x00ffU));
-    }
-    /// \brief Write an unsigned 16-bit integer in host byte order at the
-    /// specified position of the buffer in network byte order.
-    ///
-    /// The buffer must have a sufficient room to store the given data at the
-    /// given position, that is, <code>pos + 2 < getLength()</code>;
-    /// otherwise an exception of class \c isc::dns::InvalidBufferPosition will
-    /// be thrown.
-    /// Note also that this method never extends the buffer.
-    ///
-    /// \param data The 16-bit integer to be written into the buffer.
-    /// \param pos The beginning position in the buffer to write the data.
-    void writeUint16At(uint16_t data, size_t pos)
-    {
-        if (pos + sizeof(data) > data_.size()) {
-            isc_throw(InvalidBufferPosition, "write at invalid position");
-        }
-
-        data_[pos] = static_cast<uint8_t>((data & 0xff00U) >> 8);
-        data_[pos + 1] = static_cast<uint8_t>(data & 0x00ffU);
-    }
-    /// \brief Write an unsigned 32-bit integer in host byte order
-    /// into the buffer in network byte order.
-    ///
-    /// \param data The 32-bit integer to be written into the buffer.
-    void writeUint32(uint32_t data)
-    {
-        data_.push_back(static_cast<uint8_t>((data & 0xff000000) >> 24));
-        data_.push_back(static_cast<uint8_t>((data & 0x00ff0000) >> 16));
-        data_.push_back(static_cast<uint8_t>((data & 0x0000ff00) >> 8));
-        data_.push_back(static_cast<uint8_t>(data & 0x000000ff));
-    }
-    /// \brief Copy an arbitrary length of data into the buffer.
-    ///
-    /// No conversion on the copied data is performed.
-    ///
-    /// \param data A pointer to the data to be copied into the buffer.
-    /// \param len The length of the data in bytes.
-    void writeData(const void *data, size_t len)
-    {
-        const uint8_t* cp = static_cast<const uint8_t*>(data);
-        data_.insert(data_.end(), cp, cp + len);
-    }
-    //@}
-    
-private:
-    std::vector<uint8_t> data_;
-};
-
-/// \brief Pointer-like types pointing to \c InputBuffer or \c OutputBuffer
-///
-/// These types are expected to be used as an argument in asynchronous
-/// callback functions.  The internal reference-counting will ensure that
-/// that ongoing state information will not be lost if the object
-/// that originated the asynchronous call falls out of scope.
-typedef boost::shared_ptr<InputBuffer> InputBufferPtr;
-typedef boost::shared_ptr<OutputBuffer> OutputBufferPtr;
-
-}
-}
-#endif  // __BUFFER_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/dnssectime.cc b/src/lib/dns/dnssectime.cc
deleted file mode 100644
index c889178..0000000
--- a/src/lib/dns/dnssectime.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <stdint.h>
-
-#include <sys/time.h>
-
-#include <string>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-
-#include <stdio.h>
-#include <time.h>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/dnssectime.h>
-
-using namespace std;
-
-namespace {
-int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-inline bool
-isLeap(const int y) {
-    return ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0);
-}
-
-unsigned int
-yearSecs(const int year) {
-    return ((isLeap(year) ? 366 : 365 ) * 86400);
-}
-
-unsigned int
-monthSecs(const int month, const int year) {
-    return ((days[month] + ((month == 1 && isLeap(year)) ? 1 : 0 )) * 86400);
-}
-}
-
-namespace isc {
-namespace dns {
-
-string
-timeToText64(uint64_t value) {
-    struct tm tm;
-    unsigned int secs;
-
-    // We cannot rely on gmtime() because time_t may not be of 64 bit
-    // integer.  The following conversion logic is borrowed from BIND 9.
-    tm.tm_year = 70;
-    while ((secs = yearSecs(tm.tm_year + 1900)) <= value) {
-        value -= secs;
-        ++tm.tm_year;
-        if (tm.tm_year + 1900 > 9999) {
-            isc_throw(InvalidTime,
-                      "Time value out of range (year > 9999): " <<
-                      tm.tm_year + 1900);
-        }
-    }
-    tm.tm_mon = 0;
-    while ((secs = monthSecs(tm.tm_mon, tm.tm_year + 1900)) <= value) {
-        value -= secs;
-        tm.tm_mon++;
-    }
-    tm.tm_mday = 1;
-    while (86400 <= value) {
-        value -= 86400;
-        ++tm.tm_mday;
-    }
-    tm.tm_hour = 0;
-    while (3600 <= value) {
-        value -= 3600;
-        ++tm.tm_hour;
-    }
-    tm.tm_min = 0;
-    while (60 <= value) {
-        value -= 60;
-        ++tm.tm_min;
-    }
-    tm.tm_sec = value;    // now t < 60, so this substitution is safe.
-
-    ostringstream oss;
-    oss << setfill('0')
-        << setw(4) << tm.tm_year + 1900
-        << setw(2) << tm.tm_mon + 1
-        << setw(2) << tm.tm_mday
-        << setw(2) << tm.tm_hour
-        << setw(2) << tm.tm_min
-        << setw(2) << tm.tm_sec;
-    return (oss.str());
-}
-
-// timeToText32() below uses the current system time.  To test it with
-// unusual current time values we introduce the following function pointer;
-// when it's non NULL, we call it to get the (normally faked) current time.
-// Otherwise we use the standard gettimeofday(2).  This hook is specifically
-// intended for testing purposes, so, even if it's visible outside of this
-// library, it's not even declared in a header file.
-namespace dnssectime {
-namespace detail {
-int64_t (*gettimeFunction)() = NULL;
-}
-}
-
-namespace {
-int64_t
-gettimeofdayWrapper() {
-    using namespace dnssectime::detail;
-    if (gettimeFunction != NULL) {
-        return (gettimeFunction());
-    }
-
-    struct timeval now;
-    gettimeofday(&now, NULL);
-
-    return (static_cast<int64_t>(now.tv_sec));
-}
-}
-
-string
-timeToText32(const uint32_t value) {
-    // We first adjust the time to the closest epoch based on the current time.
-    // Note that the following variables must be signed in order to handle
-    // time until year 2038 correctly.
-    const int64_t start = gettimeofdayWrapper() - 0x7fffffff;
-    int64_t base = 0;
-    int64_t t;
-    while ((t = (base + value)) < start) {
-        base += 0x100000000LL;
-    }
-
-    // Then convert it to text.
-    return (timeToText64(t));
-}
-
-namespace {
-const size_t DATE_LEN = 14;      // YYYYMMDDHHmmSS
-
-inline void
-checkRange(const int min, const int max, const int value,
-           const string& valname)
-{
-    if ((value >= min) && (value <= max)) {
-        return;
-    }
-    isc_throw(InvalidTime, "Invalid " << valname << "value: " << value);
-}
-}
-
-uint64_t
-timeFromText64(const string& time_txt) {
-    // Confirm the source only consists digits.  sscanf() allows some
-    // minor exceptions.
-    for (int i = 0; i < time_txt.length(); ++i) {
-        if (!isdigit(time_txt.at(i))) {
-            isc_throw(InvalidTime, "Couldn't convert non-numeric time value: "
-                      << time_txt);
-        }
-    }
-
-    int year, month, day, hour, minute, second;
-    if (time_txt.length() != DATE_LEN ||
-        sscanf(time_txt.c_str(), "%4d%2d%2d%2d%2d%2d",
-               &year, &month, &day, &hour, &minute, &second) != 6)
-    {
-        isc_throw(InvalidTime, "Couldn't convert time value: " << time_txt);
-    }
-
-    checkRange(1970, 9999, year, "year");
-    checkRange(1, 12, month, "month");
-    checkRange(1, days[month - 1] + ((month == 2 && isLeap(year)) ? 1 : 0),
-            day, "day");
-    checkRange(0, 23, hour, "hour");
-    checkRange(0, 59, minute, "minute");
-    checkRange(0, 60, second, "second"); // 60 == leap second.
-
-    uint64_t timeval = second + (60 * minute) + (3600 * hour) +
-        ((day - 1) * 86400);
-    for (int m = 0; m < (month - 1); ++m) {
-            timeval += days[m] * 86400;
-    }
-    if (isLeap(year) && month > 2) {
-            timeval += 86400;
-    }
-    for (int y = 1970; y < year; ++y) {
-        timeval += ((isLeap(y) ? 366 : 365 ) * 86400);
-    }
-
-    return (timeval);
-}
-
-uint32_t
-timeFromText32(const string& time_txt) {
-    // The implicit conversion from uint64_t to uint32_t should just work here,
-    // because we only need to drop higher 32 bits.
-    return (timeFromText64(time_txt));
-}
-}
-}
diff --git a/src/lib/dns/dnssectime.h b/src/lib/dns/dnssectime.h
deleted file mode 100644
index baf866f..0000000
--- a/src/lib/dns/dnssectime.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __DNSSECTIME_H
-#define __DNSSECTIME_H 1
-
-#include <sys/types.h>
-#include <stdint.h>
-
-#include <exceptions/exceptions.h>
-
-//
-// Note: this helper module isn't specific to the DNS protocol per se.
-// We should probably move this to somewhere else, possibly in some common
-// utility area.
-//
-
-namespace isc {
-namespace dns {
-
-///
-/// \brief A standard DNS (or ISC) module exception that is thrown if 
-/// a time conversion function encounters bad input
-///
-class InvalidTime : public Exception {
-public:
-    InvalidTime(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-///
-/// \name DNSSEC time conversion functions.
-///
-/// These functions convert between times represented in seconds (in integer)
-/// since epoch and those in the textual form used in the RRSIG records.
-/// For integers we provide both 32-bit and 64-bit versions.
-/// The RRSIG expiration and inception fields are both 32-bit unsigned
-/// integers, so 32-bit versions would be more useful for protocol operations.
-/// However, with 32-bit integers we need to take into account wrap-around
-/// points and compare values using the serial number arithmetic as specified
-/// in RFC4034, which would be more error prone.  We therefore provide 64-bit
-/// versions, too.
-///
-/// The timezone is always UTC for these functions.
-//@{
-/// Convert textual DNSSEC time to integer, 64-bit version.
-///
-/// The textual form must only consist of digits and be in the form of
-/// YYYYMMDDHHmmSS, where:
-/// - YYYY must be between 1970 and 9999
-/// - MM must be between 01 and 12
-/// - DD must be between 01 and 31 and must be a valid day for the month
-///   represented in 'MM'.  For example, if MM is 04, DD cannot be 31.
-///   DD can be 29 when MM is 02 only when YYYY is a leap year.
-/// - HH must be between 00 and 23
-/// - mm must be between 00 and 59
-/// - SS must be between 00 and 60
-///
-/// For all fields the range includes the begin and end values.  Note that
-/// 60 is allowed for 'SS', intending a leap second, although in real operation
-/// it's unlikely to be specified.
-///
-/// If the given text is valid, this function converts it to an unsigned
-/// 64-bit number of seconds since epoch (1 January 1970 00:00:00) and returns
-/// the converted value.  64 bits are sufficient to represent all possible
-/// values for the valid format uniquely, so there is no overflow.
-///
-/// \note RFC4034 also defines the textual form of an unsigned decimal integer
-/// for the corresponding time in seconds.  This function doesn't support
-/// this form, and if given it throws an exception of class \c InvalidTime.
-///
-/// \exception InvalidTime The given textual representation is invalid.
-///
-/// \param time_txt Textual time in the form of YYYYMMDDHHmmSS
-/// \return Seconds since epoch corresponding to \c time_txt
-uint64_t
-timeFromText64(const std::string& time_txt);
-
-/// Convert textual DNSSEC time to integer, 32-bit version.
-///
-/// This version is the same as \c timeFromText64() except that the return
-/// value is wrapped around to an unsigned 32-bit integer, simply dropping
-/// the upper 32 bits.
-uint32_t
-timeFromText32(const std::string& time_txt);
-
-/// Convert integral DNSSEC time to textual form, 64-bit version.
-///
-/// This function takes an integer that would be seconds since epoch and
-/// converts it in the form of YYYYMMDDHHmmSS.  For example, if \c value is
-/// 0, it returns "19700101000000".  If the value corresponds to a point
-/// of time on and after year 10,000, which cannot be represented in the
-/// YYYY... form, an exception of class \c InvalidTime will be thrown.
-///
-/// \exception InvalidTime The given time specifies on or after year 10,000.
-/// \exception Other A standard exception, if resource allocation for the
-/// returned text fails.
-///
-/// \param value Seconds since epoch to be converted.
-/// \return Textual representation of \c value in the form of YYYYMMDDHHmmSS.
-std::string
-timeToText64(uint64_t value);
-
-/// Convert integral DNSSEC time to textual form, 32-bit version.
-///
-/// This version is the same as \c timeToText64(), but the time value
-/// is expected to be the lower 32 bits of the full 64-bit value.
-/// These two will be different on and after a certain point of time
-/// in year 2106, so this function internally resolves the ambiguity
-/// using the current system time at the time of function call;
-/// it first identifies the range of [N*2^32 - 2^31, N*2^32 + 2^31)
-/// that contains the current time, and interprets \c value in the context
-/// of that range.  It then applies the same process as \c timeToText64().
-///
-/// There is one important exception in this processing, however.
-/// Until 19 Jan 2038 03:14:08 (2^31 seconds since epoch), this range
-/// would contain time before epoch.  In order to ensure the returned
-/// value is also a valid input to \c timeFromText, this function uses
-/// a special range [0, 2^32) until that time.  As a result, all upper
-/// half of the 32-bit values are treated as a future time.  For example,
-/// 2^32-1 (the highest value in 32-bit unsigned integers) will be converted
-/// to "21060207062815", instead of "19691231235959".
-std::string
-timeToText32(const uint32_t value);
-
-//@}
-}
-}
-
-#endif  // __DNSSECTIME_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/edns.cc b/src/lib/dns/edns.cc
index 6e25624..447b479 100644
--- a/src/lib/dns/edns.cc
+++ b/src/lib/dns/edns.cc
@@ -36,6 +36,7 @@
 using namespace std;
 using namespace boost;
 using namespace isc::dns::rdata;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -109,19 +110,25 @@ EDNS::toText() const {
     return (ret);
 }
 
+namespace {
+/// Helper function to define unified implementation for the public versions
+/// of toWire().
 template <typename Output>
 int
-EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
+toWireCommon(Output& output, const uint8_t version,
+             const uint16_t udp_size, const bool dnssec_aware,
+             const uint8_t extended_rcode)
+{
     // Render EDNS OPT RR
     uint32_t extrcode_flags = extended_rcode << EXTRCODE_SHIFT;
-    extrcode_flags |= (version_ << VERSION_SHIFT) & VERSION_MASK;
-    if (dnssec_aware_) {
+    extrcode_flags |= (version << VERSION_SHIFT) & VERSION_MASK;
+    if (dnssec_aware) {
         extrcode_flags |= EXTFLAG_DO;
     }
 
     // Construct an RRset corresponding to the EDNS.
     // We don't support any options for now, so the OPT RR can be empty.
-    RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size_),
+    RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size),
                                   RRType::OPT(), RRTTL(extrcode_flags)));
     edns_rrset->addRdata(ConstRdataPtr(new generic::OPT()));
 
@@ -129,9 +136,12 @@ EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
 
     return (1);
 }
+}
 
 unsigned int
-EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
+EDNS::toWire(AbstractMessageRenderer& renderer,
+             const uint8_t extended_rcode) const
+{
     // If adding the OPT RR would exceed the size limit, don't do it.
     // 11 = len(".") + type(2byte) + class(2byte) + TTL(4byte) + RDLEN(2byte)
     // (RDATA is empty in this simple implementation)
@@ -139,12 +149,16 @@ EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
         return (0);
     }
 
-    return (toWire<MessageRenderer>(renderer, extended_rcode));
+    return (toWireCommon(renderer, version_, udp_size_, dnssec_aware_,
+                         extended_rcode));
 }
 
 unsigned int
-EDNS::toWire(OutputBuffer& buffer, const uint8_t extended_rcode) const {
-    return (toWire<OutputBuffer>(buffer, extended_rcode));
+EDNS::toWire(isc::util::OutputBuffer& buffer,
+             const uint8_t extended_rcode) const
+{
+    return (toWireCommon(buffer, version_, udp_size_, dnssec_aware_,
+                         extended_rcode));
 }
 
 EDNS*
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index ca3db47..a7bc4c4 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -24,11 +24,15 @@
 #include <dns/rdata.h>
 
 namespace isc {
+namespace util {
+class OutputBuffer;
+}
+
 namespace dns {
 
 class EDNS;
 class Name;
-class MessageRenderer;
+class AbstractMessageRenderer;
 class RRClass;
 class RRTTL;
 class RRType;
@@ -310,7 +314,7 @@ public:
     /// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
     /// part of the EDNS OPT RR.
     /// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
-    unsigned int toWire(MessageRenderer& renderer,
+    unsigned int toWire(AbstractMessageRenderer& renderer,
                         const uint8_t extended_rcode) const;
 
     /// \brief Render the \c EDNS in the wire format.
@@ -319,7 +323,7 @@ public:
     /// except it renders the OPT RR in an \c OutputBuffer and therefore
     /// does not care about message size limit.
     /// As a consequence it always returns 1.
-    unsigned int toWire(OutputBuffer& buffer,
+    unsigned int toWire(isc::util::OutputBuffer& buffer,
                         const uint8_t extended_rcode) const;
 
     /// \brief Convert the EDNS to a string.
@@ -350,12 +354,6 @@ public:
     // something like this.
     //void addOption();
 
-private:
-    /// Helper method to define unified implementation for the public versions
-    /// of toWire().
-    template <typename Output>
-    int toWire(Output& output, const uint8_t extended_rcode) const;
-
 public:
     /// \brief The highest EDNS version this implementation supports.
     static const uint8_t SUPPORTED_VERSION = 0;
@@ -382,7 +380,7 @@ private:
 ///
 /// The intended usage of this function is to parse an OPT RR of an incoming
 /// DNS message, while updating the RCODE of the message.
-/// One common usage patter is as follows:
+/// One common usage pattern is as follows:
 ///
 /// \code Message msg;
 /// ...
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index 04e5c6a..b3c8da2 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -86,6 +86,11 @@ def import_classheader(class_txt, type_txt, type_code, file):
             continue
         if re.match('// BEGIN_ISC_NAMESPACE', line):
             content += 'namespace isc {\n'
+            content += 'namespace util {\n'
+            content += '''
+class InputBuffer;
+class OutputBuffer;\n'''
+            content += '}\n\n'
             content += 'namespace dns {\n'
             continue
         if re.match('// BEGIN_RDATA_NAMESPACE', line):
@@ -105,17 +110,15 @@ def import_classheader(class_txt, type_txt, type_code, file):
         content += line
         if re.match('// BEGIN_COMMON_DECLARATIONS', line):
             content += '''
-class InputBuffer;
-class OutputBuffer;
-class MessageRenderer;\n\n'''
+class AbstractMessageRenderer;\n\n'''
         if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
             content += '''
     explicit ''' + type_utxt + '''(const std::string& type_str);
-    ''' + type_utxt + '''(InputBuffer& buffer, size_t rdata_len);
+    ''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len);
     ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
     virtual std::string toText() const;
-    virtual void toWire(OutputBuffer& buffer) const;
-    virtual void toWire(MessageRenderer& renderer) const;
+    virtual void toWire(isc::util::OutputBuffer& buffer) const;
+    virtual void toWire(AbstractMessageRenderer& renderer) const;
     virtual int compare(const Rdata& other) const;\n\n'''
     rdata_header.close()
     return content
diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc
index 9eae605..bf7ccd5 100644
--- a/src/lib/dns/message.cc
+++ b/src/lib/dns/message.cc
@@ -15,6 +15,7 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <cassert>
 #include <string>
 #include <sstream>
 #include <vector>
@@ -25,7 +26,8 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/message.h>
@@ -39,10 +41,12 @@
 #include <dns/rrtype.h>
 #include <dns/rrttl.h>
 #include <dns/rrset.h>
+#include <dns/tsig.h>
 
 using namespace std;
 using namespace boost;
 using namespace isc::dns::rdata;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -79,7 +83,7 @@ const unsigned int HEADERFLAG_MASK = 0x87b0;
 const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
                                         Message::HEADERFLAG_CD);
 
-const char *sectiontext[] = {
+const char* const sectiontext[] = {
     "QUESTION",
     "ANSWER",
     "AUTHORITY",
@@ -112,8 +116,8 @@ public:
     vector<QuestionPtr> questions_;
     vector<RRsetPtr> rrsets_[NUM_SECTIONS];
     ConstEDNSPtr edns_;
+    ConstTSIGRecordPtr tsig_rr_;
 
-    // tsig/sig0: TODO
     // RRsetsSorter* sorter_; : TODO
 
     void init();
@@ -121,6 +125,17 @@ public:
     void setRcode(const Rcode& rcode);
     int parseQuestion(InputBuffer& buffer);
     int parseSection(const Message::Section section, InputBuffer& buffer);
+    void addRR(Message::Section section, const Name& name,
+               const RRClass& rrclass, const RRType& rrtype,
+               const RRTTL& ttl, ConstRdataPtr rdata);
+    void addEDNS(Message::Section section, const Name& name,
+                 const RRClass& rrclass, const RRType& rrtype,
+                 const RRTTL& ttl, const Rdata& rdata);
+    void addTSIG(Message::Section section, unsigned int count,
+                 const InputBuffer& buffer, size_t start_position,
+                 const Name& name, const RRClass& rrclass,
+                 const RRTTL& ttl, const Rdata& rdata);
+    void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
 };
 
 MessageImpl::MessageImpl(Message::Mode mode) :
@@ -138,6 +153,7 @@ MessageImpl::init() {
     rcode_ = NULL;
     opcode_ = NULL;
     edns_ = EDNSPtr();
+    tsig_rr_ = ConstTSIGRecordPtr();
 
     for (int i = 0; i < NUM_SECTIONS; ++i) {
         counts_[i] = 0;
@@ -162,6 +178,154 @@ MessageImpl::setRcode(const Rcode& rcode) {
     rcode_ = &rcode_placeholder_;
 }
 
+namespace {
+// This helper class is used by MessageImpl::toWire() to render a set of
+// RRsets of a specific section of message to a given MessageRenderer.
+//
+// A RenderSection object is expected to be used with a QuestionIterator or
+// SectionIterator.  Its operator() is called for each RRset as the iterator
+// iterates over the corresponding section, and it renders the RRset to
+// the given MessageRenderer, while counting the number of RRs (note: not
+// RRsets) successfully rendered.  If the MessageRenderer reports the need
+// for truncation (via its isTruncated() method), the RenderSection object
+// stops rendering further RRsets.  In addition, unless partial_ok (given on
+// construction) is true, it removes any RRs that are partially rendered
+// from the MessageRenderer.
+//
+// On the completion of rendering the entire section, the owner of the
+// RenderSection object can get the number of rendered RRs via the
+// getTotalCount() method.
+template <typename T>
+struct RenderSection {
+    RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
+        counter_(0), renderer_(renderer), partial_ok_(partial_ok),
+        truncated_(false)
+    {}
+    void operator()(const T& entry) {
+        // If it's already truncated, ignore the rest of the section.
+        if (truncated_) {
+            return;
+        }
+        const size_t pos0 = renderer_.getLength();
+        counter_ += entry->toWire(renderer_);
+        if (renderer_.isTruncated()) {
+            truncated_ = true;
+            if (!partial_ok_) {
+                // roll back to the end of the previous RRset.
+                renderer_.trim(renderer_.getLength() - pos0);
+            }
+        }
+    }
+    unsigned int getTotalCount() { return (counter_); }
+    unsigned int counter_;
+    AbstractMessageRenderer& renderer_;
+    const bool partial_ok_;
+    bool truncated_;
+};
+}
+
+void
+MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
+    if (mode_ != Message::RENDER) {
+        isc_throw(InvalidMessageOperation,
+                  "Message rendering attempted in non render mode");
+    }
+    if (rcode_ == NULL) {
+        isc_throw(InvalidMessageOperation,
+                  "Message rendering attempted without Rcode set");
+    }
+    if (opcode_ == NULL) {
+        isc_throw(InvalidMessageOperation,
+                  "Message rendering attempted without Opcode set");
+    }
+
+    // reserve room for the header
+    renderer.skip(HEADERLEN);
+
+    uint16_t qdcount =
+        for_each(questions_.begin(), questions_.end(),
+                 RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
+
+    // TODO: sort RRsets in each section based on configuration policy.
+    uint16_t ancount = 0;
+    if (!renderer.isTruncated()) {
+        ancount =
+            for_each(rrsets_[Message::SECTION_ANSWER].begin(),
+                     rrsets_[Message::SECTION_ANSWER].end(),
+                     RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+    }
+    uint16_t nscount = 0;
+    if (!renderer.isTruncated()) {
+        nscount =
+            for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
+                     rrsets_[Message::SECTION_AUTHORITY].end(),
+                     RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+    }
+    uint16_t arcount = 0;
+    if (renderer.isTruncated()) {
+        flags_ |= Message::HEADERFLAG_TC;
+    } else {
+        arcount =
+            for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
+                     rrsets_[Message::SECTION_ADDITIONAL].end(),
+                     RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
+    }
+
+    // Add EDNS OPT RR if necessary.  Basically, we add it only when EDNS
+    // has been explicitly set.  However, if the RCODE would require it and
+    // no EDNS has been set we generate a temporary local EDNS and use it.
+    if (!renderer.isTruncated()) {
+        ConstEDNSPtr local_edns = edns_;
+        if (!local_edns && rcode_->getExtendedCode() != 0) {
+            local_edns = ConstEDNSPtr(new EDNS());
+        }
+        if (local_edns) {
+            arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
+        }
+    }
+
+    // Adjust the counter buffer.
+    // XXX: these may not be equal to the number of corresponding entries
+    // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
+    // was inserted.  This is not good, and we should revisit the entire
+    // design.
+    counts_[Message::SECTION_QUESTION] = qdcount;
+    counts_[Message::SECTION_ANSWER] = ancount;
+    counts_[Message::SECTION_AUTHORITY] = nscount;
+    counts_[Message::SECTION_ADDITIONAL] = arcount;
+
+    // fill in the header
+    size_t header_pos = 0;
+    renderer.writeUint16At(qid_, header_pos);
+    header_pos += sizeof(uint16_t);
+
+    uint16_t codes_and_flags =
+        (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
+    codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
+    codes_and_flags |= (flags_ & HEADERFLAG_MASK);
+    renderer.writeUint16At(codes_and_flags, header_pos);
+    header_pos += sizeof(uint16_t);
+    // TODO: should avoid repeated pattern
+    renderer.writeUint16At(qdcount, header_pos);
+    header_pos += sizeof(uint16_t);
+    renderer.writeUint16At(ancount, header_pos);
+    header_pos += sizeof(uint16_t);
+    renderer.writeUint16At(nscount, header_pos);
+    header_pos += sizeof(uint16_t);
+    renderer.writeUint16At(arcount, header_pos);
+
+    // Add TSIG, if necessary, at the end of the message.
+    // TODO: truncate case consideration
+    if (tsig_ctx != NULL) {
+        tsig_ctx->sign(qid_, renderer.getData(),
+                       renderer.getLength())->toWire(renderer);
+
+        // update the ARCOUNT for the TSIG RR.  Note that for a sane DNS
+        // message arcount should never overflow to 0.
+        renderer.writeUint16At(++arcount, header_pos);
+    }
+}
+
 Message::Message(Mode mode) :
     impl_(new MessageImpl(mode))
 {}
@@ -260,6 +424,16 @@ Message::setEDNS(ConstEDNSPtr edns) {
     impl_->edns_ = edns;
 }
 
+const TSIGRecord*
+Message::getTSIGRecord() const {
+    if (impl_->mode_ != Message::PARSE) {
+        isc_throw(InvalidMessageOperation,
+                  "getTSIGRecord performed in non-parse mode");
+    }
+
+    return (impl_->tsig_rr_.get());
+}
+
 unsigned int
 Message::getRRCount(const Section section) const {
     if (section >= MessageImpl::NUM_SECTIONS) {
@@ -361,129 +535,14 @@ Message::addQuestion(const Question& question) {
     addQuestion(QuestionPtr(new Question(question)));
 }
 
-namespace {
-template <typename T>
-struct RenderSection {
-    RenderSection(MessageRenderer& renderer, const bool partial_ok) :
-        counter_(0), renderer_(renderer), partial_ok_(partial_ok),
-        truncated_(false)
-    {}
-    void operator()(const T& entry) {
-        // If it's already truncated, ignore the rest of the section.
-        if (truncated_) {
-            return;
-        }
-        const size_t pos0 = renderer_.getLength();
-        counter_ += entry->toWire(renderer_);
-        if (renderer_.isTruncated()) {
-            truncated_ = true;
-            if (!partial_ok_) {
-                // roll back to the end of the previous RRset.
-                renderer_.trim(renderer_.getLength() - pos0);
-            }
-        }
-    }
-    unsigned int getTotalCount() { return (counter_); }
-    unsigned int counter_;
-    MessageRenderer& renderer_;
-    const bool partial_ok_;
-    bool truncated_;
-};
+void
+Message::toWire(AbstractMessageRenderer& renderer) {
+    impl_->toWire(renderer, NULL);
 }
 
 void
-Message::toWire(MessageRenderer& renderer) {
-    if (impl_->mode_ != Message::RENDER) {
-        isc_throw(InvalidMessageOperation,
-                  "Message rendering attempted in non render mode");
-    }
-    if (impl_->rcode_ == NULL) {
-        isc_throw(InvalidMessageOperation,
-                  "Message rendering attempted without Rcode set");
-    }
-    if (impl_->opcode_ == NULL) {
-        isc_throw(InvalidMessageOperation,
-                  "Message rendering attempted without Opcode set");
-    }
-
-    // reserve room for the header
-    renderer.skip(HEADERLEN);
-
-    uint16_t qdcount =
-        for_each(impl_->questions_.begin(), impl_->questions_.end(),
-                 RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
-
-    // TBD: sort RRsets in each section based on configuration policy.
-    uint16_t ancount = 0;
-    if (!renderer.isTruncated()) {
-        ancount =
-            for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
-                     impl_->rrsets_[SECTION_ANSWER].end(),
-                     RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
-    }
-    uint16_t nscount = 0;
-    if (!renderer.isTruncated()) {
-        nscount =
-            for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
-                     impl_->rrsets_[SECTION_AUTHORITY].end(),
-                     RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
-    }
-    uint16_t arcount = 0;
-    if (renderer.isTruncated()) {
-        setHeaderFlag(HEADERFLAG_TC, true);
-    } else {
-        arcount =
-            for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
-                     impl_->rrsets_[SECTION_ADDITIONAL].end(),
-                     RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
-    }
-
-    // Add EDNS OPT RR if necessary.  Basically, we add it only when EDNS
-    // has been explicitly set.  However, if the RCODE would require it and
-    // no EDNS has been set we generate a temporary local EDNS and use it.
-    if (!renderer.isTruncated()) {
-        ConstEDNSPtr local_edns = impl_->edns_;
-        if (!local_edns && impl_->rcode_->getExtendedCode() != 0) {
-            local_edns = ConstEDNSPtr(new EDNS());
-        }
-        if (local_edns) {
-            arcount += local_edns->toWire(renderer,
-                                          impl_->rcode_->getExtendedCode());
-        }
-    }
- 
-    // Adjust the counter buffer.
-    // XXX: these may not be equal to the number of corresponding entries
-    // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
-    // was inserted.  This is not good, and we should revisit the entire
-    // design.
-    impl_->counts_[SECTION_QUESTION] = qdcount;
-    impl_->counts_[SECTION_ANSWER] = ancount;
-    impl_->counts_[SECTION_AUTHORITY] = nscount;
-    impl_->counts_[SECTION_ADDITIONAL] = arcount;
-
-    // TBD: TSIG, SIG(0) etc.
-
-    // fill in the header
-    size_t header_pos = 0;
-    renderer.writeUint16At(impl_->qid_, header_pos);
-    header_pos += sizeof(uint16_t);
-
-    uint16_t codes_and_flags =
-        (impl_->opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
-    codes_and_flags |= (impl_->rcode_->getCode() & RCODE_MASK);
-    codes_and_flags |= (impl_->flags_ & HEADERFLAG_MASK);
-    renderer.writeUint16At(codes_and_flags, header_pos);
-    header_pos += sizeof(uint16_t);
-    // XXX: should avoid repeated pattern (TODO)
-    renderer.writeUint16At(qdcount, header_pos);
-    header_pos += sizeof(uint16_t);
-    renderer.writeUint16At(ancount, header_pos);
-    header_pos += sizeof(uint16_t);
-    renderer.writeUint16At(nscount, header_pos);
-    header_pos += sizeof(uint16_t);
-    renderer.writeUint16At(arcount, header_pos);
-    header_pos += sizeof(uint16_t);
+Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) {
+    impl_->toWire(renderer, &tsig_ctx);
 }
 
 void
@@ -611,6 +670,9 @@ MessageImpl::parseSection(const Message::Section section,
     unsigned int added = 0;
 
     for (unsigned int count = 0; count < counts_[section]; ++count) {
+        // We need to remember the start position for TSIG processing
+        const size_t start_position = buffer.getPosition();
+
         const Name name(buffer);
 
         // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
@@ -628,32 +690,12 @@ MessageImpl::parseSection(const Message::Section section,
         ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
 
         if (rrtype == RRType::OPT()) {
-            if (section != Message::SECTION_ADDITIONAL) {
-                isc_throw(DNSMessageFORMERR,
-                          "EDNS OPT RR found in an invalid section");
-            }
-            if (edns_) {
-                isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
-            }
-
-            uint8_t extended_rcode;
-            edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl,
-                                                  *rdata, extended_rcode));
-            setRcode(Rcode(rcode_->getCode(), extended_rcode));
-            continue;
+            addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
+        } else if (rrtype == RRType::TSIG()) {
+            addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
+                    *rdata);
         } else {
-            vector<RRsetPtr>::iterator it =
-                find_if(rrsets_[section].begin(), rrsets_[section].end(),
-                        MatchRR(name, rrtype, rrclass));
-            if (it != rrsets_[section].end()) {
-                (*it)->setTTL(min((*it)->getTTL(), ttl));
-                (*it)->addRdata(rdata);
-            } else {
-                RRsetPtr rrset =
-                    RRsetPtr(new RRset(name, rrclass, rrtype, ttl)); 
-                rrset->addRdata(rdata);
-                rrsets_[section].push_back(rrset);
-            }
+            addRR(section, name, rrclass, rrtype, ttl, rdata);
             ++added;
         }
     }
@@ -661,6 +703,65 @@ MessageImpl::parseSection(const Message::Section section,
     return (added);
 }
 
+void
+MessageImpl::addRR(Message::Section section, const Name& name,
+                   const RRClass& rrclass, const RRType& rrtype,
+                   const RRTTL& ttl, ConstRdataPtr rdata)
+{
+    vector<RRsetPtr>::iterator it =
+        find_if(rrsets_[section].begin(), rrsets_[section].end(),
+                MatchRR(name, rrtype, rrclass));
+    if (it != rrsets_[section].end()) {
+        (*it)->setTTL(min((*it)->getTTL(), ttl));
+        (*it)->addRdata(rdata);
+    } else {
+        RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
+        rrset->addRdata(rdata);
+        rrsets_[section].push_back(rrset);
+    }
+}
+
+void
+MessageImpl::addEDNS(Message::Section section,  const Name& name,
+                     const RRClass& rrclass, const RRType& rrtype,
+                     const RRTTL& ttl, const Rdata& rdata)
+{
+    if (section != Message::SECTION_ADDITIONAL) {
+        isc_throw(DNSMessageFORMERR,
+                  "EDNS OPT RR found in an invalid section");
+    }
+    if (edns_) {
+        isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
+    }
+
+    uint8_t extended_rcode;
+    edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
+                                          extended_rcode));
+    setRcode(Rcode(rcode_->getCode(), extended_rcode));
+}
+
+void
+MessageImpl::addTSIG(Message::Section section, unsigned int count,
+                     const InputBuffer& buffer, size_t start_position,
+                     const Name& name, const RRClass& rrclass,
+                     const RRTTL& ttl, const Rdata& rdata)
+{
+    if (section != Message::SECTION_ADDITIONAL) {
+        isc_throw(DNSMessageFORMERR,
+                  "TSIG RR found in an invalid section");
+    }
+    if (count != counts_[section] - 1) {
+        isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
+    }
+    if (tsig_rr_) {
+        isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
+    }
+    tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
+                                                 ttl, rdata,
+                                                 buffer.getPosition() -
+                                                 start_position));
+}
+
 namespace {
 template <typename T>
 struct SectionFormatter {
@@ -694,31 +795,31 @@ Message::toText() const {
     // for simplicity we don't consider extended rcode (unlike BIND9)
     s += ", status: " + impl_->rcode_->toText();
     s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
-    s += "\n;; flags: ";
+    s += "\n;; flags:";
     if (getHeaderFlag(HEADERFLAG_QR)) {
-        s += "qr ";
+        s += " qr";
     }
     if (getHeaderFlag(HEADERFLAG_AA)) {
-        s += "aa ";
+        s += " aa";
     }
     if (getHeaderFlag(HEADERFLAG_TC)) {
-        s += "tc ";
+        s += " tc";
     }
     if (getHeaderFlag(HEADERFLAG_RD)) {
-        s += "rd ";
+        s += " rd";
     }
     if (getHeaderFlag(HEADERFLAG_RA)) {
-        s += "ra ";
+        s += " ra";
     }
     if (getHeaderFlag(HEADERFLAG_AD)) {
-        s += "ad ";
+        s += " ad";
     }
     if (getHeaderFlag(HEADERFLAG_CD)) {
-        s += "cd ";
+        s += " cd";
     }
 
     // for simplicity, don't consider the update case for now
-    s += "; QUESTION: " +
+    s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
         lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
     s += ", ANSWER: " +
         lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
@@ -729,6 +830,9 @@ Message::toText() const {
     if (impl_->edns_ != NULL) {
         ++arcount;
     }
+    if (impl_->tsig_rr_ != NULL) {
+        ++arcount;
+    }
     s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
 
     if (impl_->edns_ != NULL) {
@@ -765,6 +869,11 @@ Message::toText() const {
                  SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
     }
 
+    if (impl_->tsig_rr_ != NULL) {
+        s += "\n;; TSIG PSEUDOSECTION:\n";
+        s += impl_->tsig_rr_->toText();
+    }
+
     return (s);
 }
 
diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h
index 0bbb9ea..fcc53e9 100644
--- a/src/lib/dns/message.h
+++ b/src/lib/dns/message.h
@@ -28,7 +28,13 @@
 #include <dns/rrset.h>
 
 namespace isc {
+namespace util {
+class InputBuffer;
+}
+
 namespace dns {
+class TSIGContext;
+class TSIGRecord;
 
 ///
 /// \brief A standard DNS module exception that is thrown if a wire format
@@ -76,8 +82,7 @@ public:
 
 typedef uint16_t qid_t;
 
-class InputBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 class Message;
 class MessageImpl;
 class Opcode;
@@ -365,6 +370,25 @@ public:
     /// \c Message.
     void setEDNS(ConstEDNSPtr edns);
 
+    /// \brief Return, if any, the TSIG record contained in the received
+    /// message.
+    ///
+    /// Currently, this method is only intended to return a TSIG record
+    /// for an incoming message built via the \c fromWire() method in the
+    /// PARSE mode.  A call to this method in the RENDER mode is invalid and
+    /// result in an exception.  Also, calling this method is meaningless
+    /// unless \c fromWire() is performed.
+    ///
+    /// The returned pointer is valid only during the lifetime of the
+    /// \c Message object and until \c clear() is called.  The \c Message
+    /// object retains the ownership of \c TSIGRecord; the caller must not
+    /// try to delete it.
+    ///
+    /// \exception InvalidMessageOperation Message is not in the PARSE mode.
+    ///
+    /// \return A pointer to the stored \c TSIGRecord or \c NULL.
+    const TSIGRecord* getTSIGRecord() const;
+
     /// \brief Returns the number of RRs contained in the given section.
     ///
     /// In the \c PARSE mode, the returned value may not be identical to
@@ -520,19 +544,37 @@ public:
     /// class \c InvalidMessageOperation will be thrown.
     std::string toText() const;
 
-    /// \brief Render the message in wire formant into a \c MessageRenderer
+    /// \brief Render the message in wire formant into a message renderer
     /// object.
     ///
     /// This \c Message must be in the \c RENDER mode and both \c Opcode and
     /// \c Rcode must have been set beforehand; otherwise, an exception of
     /// class \c InvalidMessageOperation will be thrown.
-    void toWire(MessageRenderer& renderer);
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer and name compression information.
+    void toWire(AbstractMessageRenderer& renderer);
+
+    /// \brief Render the message in wire formant into a message renderer
+    /// object with TSIG.
+    ///
+    /// This method is similar to the other version of \c toWire(), but
+    /// it will also add a TSIG RR with (in many cases) the TSIG MAC for
+    /// the message along with the given TSIG context (\c tsig_ctx).
+    /// The TSIG RR will be placed at the end of \c renderer.
+    /// \c tsig_ctx will be updated based on the fact it was used for signing
+    /// and with the latest MAC.
+    ///
+    /// \param renderer See the other version
+    /// \param tsig_ctx A TSIG context that is to be used for signing the
+    /// message
+    void toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx);
 
     /// \brief Parse the header section of the \c Message.
-    void parseHeader(InputBuffer& buffer);
+    void parseHeader(isc::util::InputBuffer& buffer);
 
     /// \brief Parse the \c Message.
-    void fromWire(InputBuffer& buffer);
+    void fromWire(isc::util::InputBuffer& buffer);
 
     ///
     /// \name Protocol constants
@@ -559,7 +601,18 @@ private:
 /// that ongoing state information will not be lost if the object
 /// that originated the asynchronous call falls out of scope.
 typedef boost::shared_ptr<Message> MessagePtr;
+typedef boost::shared_ptr<const Message> ConstMessagePtr;
 
+/// Insert the \c Message as a string into stream.
+///
+/// This method convert \c message into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param record A \c Message object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
 std::ostream& operator<<(std::ostream& os, const Message& message);
 }
 }
diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc
index 212411a..767aca9 100644
--- a/src/lib/dns/messagerenderer.cc
+++ b/src/lib/dns/messagerenderer.cc
@@ -16,10 +16,12 @@
 #include <cassert>
 #include <set>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 
+using namespace isc::util;
+
 namespace isc {
 namespace dns {
 
@@ -150,12 +152,10 @@ struct MessageRenderer::MessageRendererImpl {
     ///
     /// \param buffer An \c OutputBuffer object to which wire format data is
     /// written.
-    MessageRendererImpl(OutputBuffer& buffer) :
-        buffer_(buffer), nbuffer_(Name::MAX_WIRE), msglength_limit_(512),
+    MessageRendererImpl() :
+        nbuffer_(Name::MAX_WIRE), msglength_limit_(512),
         truncated_(false), compress_mode_(MessageRenderer::CASE_INSENSITIVE)
     {}
-    /// The buffer that holds the entire DNS message.
-    OutputBuffer& buffer_;
     /// A local working buffer to convert each given name into wire format.
     /// This could be a local variable of the \c writeName() method, but
     /// we keep it in the class so that we can reuse it and avoid construction
@@ -174,7 +174,8 @@ struct MessageRenderer::MessageRendererImpl {
 };
 
 MessageRenderer::MessageRenderer(OutputBuffer& buffer) :
-    impl_(new MessageRendererImpl(buffer))
+    AbstractMessageRenderer(buffer),
+    impl_(new MessageRendererImpl)
 {}
 
 MessageRenderer::~MessageRenderer() {
@@ -182,18 +183,8 @@ MessageRenderer::~MessageRenderer() {
 }
 
 void
-MessageRenderer::skip(const size_t len) {
-    impl_->buffer_.skip(len);
-}
-
-void
-MessageRenderer::trim(const size_t len) {
-    impl_->buffer_.trim(len);
-}
-
-void
 MessageRenderer::clear() {
-    impl_->buffer_.clear();
+    AbstractMessageRenderer::clear();
     impl_->nbuffer_.clear();
     impl_->nodeset_.clear();
     impl_->msglength_limit_ = 512;
@@ -201,41 +192,6 @@ MessageRenderer::clear() {
     impl_->compress_mode_ = CASE_INSENSITIVE;
 }
 
-void
-MessageRenderer::writeUint8(const uint8_t data) {
-    impl_->buffer_.writeUint8(data);
-}
-
-void
-MessageRenderer::writeUint16(const uint16_t data) {
-    impl_->buffer_.writeUint16(data);
-}
-
-void
-MessageRenderer::writeUint16At(const uint16_t data, const size_t pos) {
-    impl_->buffer_.writeUint16At(data, pos);
-}
-
-void
-MessageRenderer::writeUint32(const uint32_t data) {
-    impl_->buffer_.writeUint32(data);
-}
-
-void
-MessageRenderer::writeData(const void* const data, const size_t len) {
-    impl_->buffer_.writeData(data, len);
-}
-
-const void*
-MessageRenderer::getData() const {
-    return (impl_->buffer_.getData());
-}
-
-size_t
-MessageRenderer::getLength() const {
-    return (impl_->buffer_.getLength());
-}
-
 size_t
 MessageRenderer::getLengthLimit() const {
     return (impl_->msglength_limit_);
@@ -272,8 +228,9 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     name.toWire(impl_->nbuffer_);
 
     unsigned int i;
-    std::set<NameCompressNode>::const_iterator notfound = impl_->nodeset_.end();
-    std::set<NameCompressNode>::const_iterator n = notfound;
+    std::set<NameCompressNode, NameCompare>::const_iterator notfound =
+        impl_->nodeset_.end();
+    std::set<NameCompressNode, NameCompare>::const_iterator n = notfound;
 
     // Find the longest ancestor name in the rendered set that matches the
     // given name.
@@ -291,15 +248,15 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     }
 
     // Record the current offset before extending the buffer.
-    const size_t offset = impl_->buffer_.getLength();
+    const size_t offset = getLength();
     // Write uncompress part...
-    impl_->buffer_.writeData(impl_->nbuffer_.getData(),
-                             compress ? i : impl_->nbuffer_.getLength());
+    writeData(impl_->nbuffer_.getData(),
+              compress ? i : impl_->nbuffer_.getLength());
     if (compress && n != notfound) {
         // ...and compression pointer if available.
         uint16_t pointer = (*n).pos_;
         pointer |= Name::COMPRESS_POINTER_MARK16;
-        impl_->buffer_.writeUint16(pointer);
+        writeUint16(pointer);
     }
 
     // Finally, add to the set the newly rendered name and its ancestors that
@@ -311,11 +268,17 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
         if (offset + j > Name::MAX_COMPRESS_POINTER) {
             break;
         }
-        impl_->nodeset_.insert(NameCompressNode(*this, impl_->buffer_,
+        impl_->nodeset_.insert(NameCompressNode(*this, getBuffer(),
                                                 offset + j,
                                                 impl_->nbuffer_.getLength() -
                                                 j));
     }
 }
+
+void
+AbstractMessageRenderer::clear() {
+    buffer_.clear();
+}
+
 }
 }
diff --git a/src/lib/dns/messagerenderer.h b/src/lib/dns/messagerenderer.h
index 9a7f149..52d9245 100644
--- a/src/lib/dns/messagerenderer.h
+++ b/src/lib/dns/messagerenderer.h
@@ -15,64 +15,64 @@
 #ifndef __MESSAGERENDERER_H
 #define __MESSAGERENDERER_H 1
 
+#include <util/buffer.h>
+
 namespace isc {
+
 namespace dns {
 // forward declarations
-class OutputBuffer;
 class Name;
 
+/// \brief The \c AbstractMessageRenderer class is an abstract base class
+/// that provides common interfaces for rendering a DNS message into a buffer
+/// in wire format.
 ///
-/// \brief The \c MessageRenderer class encapsulates implementation details
-/// of rendering a DNS message into a buffer in wire format.
+/// A specific derived class of \c AbstractMessageRenderer (we call it
+/// a renderer class hereafter) is simply responsible for name compression at
+/// least in the current design.  A renderer class object (conceptually)
+/// manages the positions of names rendered in some sort of buffer and uses
+/// that information to render subsequent names with compression.
 ///
-/// In effect, it's simply responsible for name compression at least in the
-/// current implementation.  A \c MessageRenderer class object manages the
-/// positions of names rendered in a buffer and uses that information to render
-/// subsequent names with compression.
-///
-/// This class is mainly intended to be used as a helper for a more
+/// A renderer class is mainly intended to be used as a helper for a more
 /// comprehensive \c Message class internally; normal applications won't have
-/// to care about this class.
-///
-/// A \c MessageRenderer class object is constructed with a \c OutputBuffer
-/// object, which is the buffer into which the rendered %data will be written.
-/// Normally the buffer is expected to be empty on construction, but it doesn't
-/// have to be so; the \c MessageRenderer object will start rendering from the
-/// end of the buffer at the time of construction.  However, if the
-/// pre-existing portion of the buffer contains DNS names, these names won't
-/// be considered for name compression.
+/// to care about details of this class.
 ///
-/// Once a \c MessageRenderer object is constructed with a buffer, it is
-/// generally expected that all rendering operations are performed via the
-/// \c MessageRenderer object.  If the application modifies the buffer in
-/// parallel with the \c MessageRenderer, the result will be undefined.
+/// Once a renderer class object is constructed with a buffer, it is
+/// generally expected that all rendering operations are performed via that
+/// object.  If the application modifies the buffer in
+/// parallel with the renderer, the result will be undefined.
 ///
 /// Note to developers: we introduced a separate class for name compression
 /// because previous benchmark with BIND9 showed compression affects overall
 /// response performance very much.  By having a separate class dedicated for
 /// this purpose, we'll be able to change the internal implementation of name
 /// compression in the future without affecting other part of the API and
-/// implementation.  For the same reason, we adopt the "pimpl" idiom in the
-/// class definition (i.e., using a pointer to a \c MessageRendererImpl class,
-/// which is defined with the class implementation, not in the header file):
-/// we may want to modify the compression implementation without modifying the
-/// header file thereby requesting rebuild the package.
+/// implementation.
 ///
-/// Furthermore, we may eventually want to allow other developers to develop
-/// and use their own compression implementation.  Should such a case become
-/// realistic, we may want to make the \c MessageRendererImpl class an abstract
-/// base class and let concrete derived classes have their own implementations.
-/// At the moment we don't the strong need for it, so we rather avoid over
-/// abstraction and keep the definition simpler.
-class MessageRenderer {
+/// In addition, by introducing a class hierarchy from
+/// \c AbstractMessageRenderer, we allow an application to use a customized
+/// renderer class for specific purposes.  For example, a high performance
+/// DNS server may want to use an optimized renderer class assuming some
+/// specific underlying data representation.
+///
+/// \note Some functions (like writeUint8) are not virtual. It is because
+///     it is hard to imagine any version of message renderer that would
+///     do anything else than just putting the data into a buffer, so we
+///     provide a default implementation and having them virtual would only
+///     hurt the performance with no real gain. If it would happen a different
+///     implementation is really needed, we can make them virtual in future.
+///     The only one that is virtual is writeName and it's because this
+///     function is much more complicated, therefore there's a lot of space
+///     for different implementations or behaviours.
+class AbstractMessageRenderer {
 public:
     /// \brief Compression mode constants.
     ///
     /// The \c CompressMode enum type represents the name compression mode
-    /// for the \c MessageRenderer.
+    /// for renderer classes.
     /// \c CASE_INSENSITIVE means compress names in case-insensitive manner;
     /// \c CASE_SENSITIVE means compress names in case-sensitive manner.
-    /// By default, \c MessageRenderer compresses names in case-insensitive
+    /// By default, a renderer compresses names in case-insensitive
     /// manner.
     /// Compression mode can be dynamically modified by the
     /// \c setCompressMode() method.
@@ -80,7 +80,7 @@ public:
     /// is not an intended usage.  In this case the names already compressed
     /// are intact; only names being compressed after the mode change are
     /// affected by the change.
-    /// If the internal \c MessageRenderer is reinitialized by the \c clear()
+    /// If a renderer class object is reinitialized by the \c clear()
     /// method, the compression mode will be reset to the default, which is
     /// \c CASE_INSENSITIVE
     ///
@@ -93,25 +93,39 @@ public:
         CASE_INSENSITIVE,  //!< Compress names case-insensitive manner (default)
         CASE_SENSITIVE     //!< Compress names case-sensitive manner
     };
-public:
+protected:
     ///
     /// \name Constructors and Destructor
     //@{
-    /// \brief Constructor from an output buffer.
-    ///
-    /// \param buffer An \c OutputBuffer object to which wire format data is
-    /// written.
-    MessageRenderer(OutputBuffer& buffer);
+    /// \brief The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).
+    /// \param buffer The buffer where the data should be rendered into.
+    /// \todo We might want to revisit this API at some point and remove the
+    ///     buffer parameter. In that case it would create it's own buffer and
+    ///     a function to extract the data would be available instead. It seems
+    ///     like a cleaner design, but it's left undone until we would actually
+    ///     benefit from the change.
+    AbstractMessageRenderer(isc::util::OutputBuffer& buffer) :
+        buffer_(buffer)
+    {}
+public:
     /// \brief The destructor.
-    ///
-    /// The destructor does nothing on the given \c buffer on construction;
-    /// in fact, it is expected that the user will use the resulting buffer
-    /// for some post rendering purposes (e.g., send the data to the network).
-    /// It's the user's responsibility to do any necessary cleanup for the
-    /// \c buffer.
-    ~MessageRenderer();
+    virtual ~AbstractMessageRenderer() {}
     //@}
-
+protected:
+    /// \brief Return the output buffer we render into.
+    const isc::util::OutputBuffer& getBuffer() const { return (buffer_); }
+    isc::util::OutputBuffer& getBuffer() { return (buffer_); }
+private:
+    /// \short Buffer to store data
+    ///
+    /// It was decided that there's no need to have this in every subclass,
+    /// at least not now, and this reduces code size and gives compiler a better
+    /// chance to optimise.
+    isc::util::OutputBuffer& buffer_;
+public:
     ///
     /// \name Getter Methods
     ///
@@ -121,9 +135,15 @@ public:
     ///
     /// This method works exactly same as the same method of the \c OutputBuffer
     /// class; all notes for \c OutputBuffer apply.
-    const void* getData() const;
+    const void* getData() const {
+        return (buffer_.getData());
+    }
+
     /// \brief Return the length of data written in the internal buffer.
-    size_t getLength() const;
+    size_t getLength() const {
+        return (buffer_.getLength());
+    }
+
     /// \brief Return whether truncation has occurred while rendering.
     ///
     /// Once the return value of this method is \c true, it doesn't make sense
@@ -133,20 +153,22 @@ public:
     /// This method never throws an exception.
     ///
     /// \return true if truncation has occurred; otherwise \c false.
-    bool isTruncated() const;
+    virtual bool isTruncated() const = 0;
+
     /// \brief Return the maximum length of rendered data that can fit in the
     /// corresponding DNS message without truncation.
     ///
     /// This method never throws an exception.
     ///
     /// \return The maximum length in bytes.
-    size_t getLengthLimit() const;
-    /// \brief Return the compression mode of the \c MessageRenderer.
+    virtual size_t getLengthLimit() const = 0;
+
+    /// \brief Return the compression mode of the renderer class object.
     ///
     /// This method never throws an exception.
     ///
     /// \return The current compression mode.
-    CompressMode getCompressMode() const;
+    virtual CompressMode getCompressMode() const = 0;
     //@}
 
     ///
@@ -157,20 +179,22 @@ public:
     /// rendering.
     ///
     /// This method never throws an exception.
-    void setTruncated();
+    virtual void setTruncated() = 0;
+
     /// \brief Set the maximum length of rendered data that can fit in the
     /// corresponding DNS message without truncation.
     ///
     /// This method never throws an exception.
     ///
     /// \param len The maximum length in bytes.
-    void setLengthLimit(size_t len);
-    /// \brief Set the compression mode of the \c MessageRenderer.
+    virtual void setLengthLimit(size_t len) = 0;
+
+    /// \brief Set the compression mode of the renderer class object.
     ///
     /// This method never throws an exception.
     ///
     /// \param mode A \c CompressMode value representing the compression mode.
-    void setCompressMode(CompressMode mode);
+    virtual void setCompressMode(CompressMode mode) = 0;
     //@}
 
     ///
@@ -184,7 +208,10 @@ public:
     /// that is to be filled in later, e.g, by \ref writeUint16At().
     ///
     /// \param len The length of the gap to be inserted in bytes.
-    void skip(size_t len);
+    void skip(size_t len) {
+        buffer_.skip(len);
+    }
+
     /// \brief Trim the specified length of data from the end of the internal
     /// buffer.
     ///
@@ -195,21 +222,31 @@ public:
     /// be thrown.
     ///
     /// \param len The length of data that should be trimmed.
-    void trim(size_t len);
+    void trim(size_t len) {
+        buffer_.trim(len);
+    }
+
     /// \brief Clear the internal buffer and other internal resources.
     ///
     /// This method can be used to re-initialize and reuse the renderer
     /// without constructing a new one.
-    void clear();
+    virtual void clear();
+
     /// \brief Write an unsigned 8-bit integer into the internal buffer.
     ///
     /// \param data The 8-bit integer to be written into the internal buffer.
-    void writeUint8(uint8_t data);
+    void writeUint8(const uint8_t data) {
+        buffer_.writeUint8(data);
+    }
+
     /// \brief Write an unsigned 16-bit integer in host byte order into the
     /// internal buffer in network byte order.
     ///
     /// \param data The 16-bit integer to be written into the buffer.
-    void writeUint16(uint16_t data);
+    void writeUint16(uint16_t data) {
+        buffer_.writeUint16(data);
+    }
+
     /// \brief Write an unsigned 16-bit integer in host byte order at the
     /// specified position of the internal buffer in network byte order.
     ///
@@ -221,26 +258,29 @@ public:
     ///
     /// \param data The 16-bit integer to be written into the internal buffer.
     /// \param pos The beginning position in the buffer to write the data.
-    void writeUint16At(uint16_t data, size_t pos);
+    void writeUint16At(uint16_t data, size_t pos) {
+        buffer_.writeUint16At(data, pos);
+    }
+
     /// \brief Write an unsigned 32-bit integer in host byte order into the
     /// internal buffer in network byte order.
     ///
     /// \param data The 32-bit integer to be written into the buffer.
-    void writeUint32(uint32_t data);
+    void writeUint32(uint32_t data) {
+        buffer_.writeUint32(data);
+    }
+
     /// \brief Copy an arbitrary length of data into the internal buffer
-    /// of the \c MessageRenderer.
+    /// of the renderer object.
     ///
     /// No conversion on the copied data is performed.
     ///
     /// \param data A pointer to the data to be copied into the internal buffer.
     /// \param len The length of the data in bytes.
-    void writeData(const void *data, size_t len);
-    //@}
+    void writeData(const void *data, size_t len) {
+        buffer_.writeData(data, len);
+    }
 
-    ///
-    /// \name Rendering Methods
-    ///
-    //@{
     /// \brief Write a \c Name object into the internal buffer in wire format,
     /// with or without name compression.
     ///
@@ -255,8 +295,41 @@ public:
     ///
     /// \param name A \c Name object to be written.
     /// \param compress A boolean indicating whether to enable name compression.
-    void writeName(const Name& name, bool compress = true);
+    virtual void writeName(const Name& name, bool compress = true) = 0;
     //@}
+};
+
+/// The \c MessageRenderer is a concrete derived class of
+/// \c AbstractMessageRenderer as a general purpose implementation of the
+/// renderer interfaces.
+///
+/// A \c MessageRenderer object is constructed with a \c OutputBuffer
+/// object, which is the buffer into which the rendered %data will be written.
+/// Normally the buffer is expected to be empty on construction, but it doesn't
+/// have to be so; the renderer object will start rendering from the
+/// end of the buffer at the time of construction.  However, if the
+/// pre-existing portion of the buffer contains DNS names, these names won't
+/// be considered for name compression.
+class MessageRenderer : public AbstractMessageRenderer {
+public:
+    using AbstractMessageRenderer::CASE_INSENSITIVE;
+    using AbstractMessageRenderer::CASE_SENSITIVE;
+
+    /// \brief Constructor from an output buffer.
+    ///
+    /// \param buffer An \c OutputBuffer object to which wire format data is
+    /// written.
+    MessageRenderer(isc::util::OutputBuffer& buffer);
+
+    virtual ~MessageRenderer();
+    virtual bool isTruncated() const;
+    virtual size_t getLengthLimit() const;
+    virtual CompressMode getCompressMode() const;
+    virtual void setTruncated();
+    virtual void setLengthLimit(size_t len);
+    virtual void setCompressMode(CompressMode mode);
+    virtual void clear();
+    virtual void writeName(const Name& name, bool compress = true);
 private:
     struct MessageRendererImpl;
     MessageRendererImpl* impl_;
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index 8786bcf..4cd0b2b 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -20,14 +20,14 @@
 #include <iostream>
 #include <algorithm>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 
 using namespace std;
+using namespace isc::util;
 using isc::dns::NameComparisonResult;
-using isc::dns::MessageRenderer;
 
 namespace isc {
 namespace dns {
@@ -403,7 +403,7 @@ Name::toWire(OutputBuffer& buffer) const {
 }
 
 void
-Name::toWire(MessageRenderer& renderer) const {
+Name::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(*this);
 }
 
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h
index dc1b5b3..4ff7fe5 100644
--- a/src/lib/dns/name.h
+++ b/src/lib/dns/name.h
@@ -23,10 +23,13 @@
 #include <exceptions/exceptions.h>
 
 namespace isc {
-namespace dns {
+namespace util {
 class InputBuffer;
 class OutputBuffer;
-class MessageRenderer;
+}
+
+namespace dns {
+class AbstractMessageRenderer;
 
 ///
 /// \brief A standard DNS module exception that is thrown if the name parser
@@ -247,7 +250,7 @@ public:
     ///
     /// \param buffer A buffer storing the wire format %data.
     /// \param downcase Whether to convert upper case alphabets to lower case.
-    explicit Name(InputBuffer& buffer, bool downcase = false);
+    explicit Name(isc::util::InputBuffer& buffer, bool downcase = false);
     ///
     /// We use the default copy constructor intentionally.
     //@}
@@ -347,7 +350,7 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer and name compression information.
-    void toWire(MessageRenderer& renderer) const;
+    void toWire(AbstractMessageRenderer& renderer) const;
 
     /// \brief Render the <code>Name</code> in the wire format without
     /// compression.
@@ -359,7 +362,7 @@ public:
     /// then this method should not throw an exception.
     ///
     /// \param buffer An output buffer to store the wire %data.
-    void toWire(OutputBuffer& buffer) const;
+    void toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/python/Makefile.am b/src/lib/dns/python/Makefile.am
index 9d171cd..aa9d062 100644
--- a/src/lib/dns/python/Makefile.am
+++ b/src/lib/dns/python/Makefile.am
@@ -5,7 +5,16 @@ AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 pyexec_LTLIBRARIES = pydnspp.la
-pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc
+pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc pydnspp_towire.h
+pydnspp_la_SOURCES += name_python.cc name_python.h
+pydnspp_la_SOURCES += messagerenderer_python.cc messagerenderer_python.h
+pydnspp_la_SOURCES += rcode_python.cc rcode_python.h
+pydnspp_la_SOURCES += tsigkey_python.cc tsigkey_python.h
+pydnspp_la_SOURCES += tsigerror_python.cc tsigerror_python.h
+pydnspp_la_SOURCES += tsig_rdata_python.cc tsig_rdata_python.h
+pydnspp_la_SOURCES += tsigrecord_python.cc tsigrecord_python.h
+pydnspp_la_SOURCES += tsig_python.cc tsig_python.h
+
 pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
 pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
 
@@ -13,18 +22,15 @@ pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
 # rules
 EXTRA_DIST = pydnspp_common.h
 EXTRA_DIST += edns_python.cc
-EXTRA_DIST += messagerenderer_python.cc
 EXTRA_DIST += message_python.cc
 EXTRA_DIST += rrclass_python.cc
-EXTRA_DIST += name_python.cc
 EXTRA_DIST += opcode_python.cc
-EXTRA_DIST += rcode_python.cc
 EXTRA_DIST += rrset_python.cc
 EXTRA_DIST += question_python.cc
 EXTRA_DIST += rrttl_python.cc
 EXTRA_DIST += rdata_python.cc
 EXTRA_DIST += rrtype_python.cc
-EXTRA_DIST += tsigkey_python.cc
+EXTRA_DIST += tsigerror_python_inc.cc
 
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
diff --git a/src/lib/dns/python/edns_python.cc b/src/lib/dns/python/edns_python.cc
index e54dba0..83c3bfa 100644
--- a/src/lib/dns/python/edns_python.cc
+++ b/src/lib/dns/python/edns_python.cc
@@ -17,6 +17,7 @@
 #include <dns/edns.h>
 
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 //
@@ -107,7 +108,7 @@ PyMethodDef EDNS_methods[] = {
 // Most of the functions are not actually implemented and NULL here.
 PyTypeObject edns_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.EDNS",
+    "pydnspp.EDNS",
     sizeof(s_EDNS),                     // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)EDNS_destroy,           // tp_dealloc
@@ -202,7 +203,7 @@ EDNS_init(s_EDNS* self, PyObject* args) {
         // in this context so that we can share the try-catch logic with
         // EDNS_createFromRR() (see below).
         uint8_t extended_rcode;
-        self->edns = createFromRR(*name->name, *rrclass->rrclass,
+        self->edns = createFromRR(*name->cppobj, *rrclass->rrclass,
                                   *rrtype->rrtype, *rrttl->rrttl,
                                   *rdata->rdata, extended_rcode);
         return (self->edns != NULL ? 0 : -1);
@@ -297,12 +298,15 @@ EDNS_getUDPSize(const s_EDNS* const self) {
 
 PyObject*
 EDNS_setUDPSize(s_EDNS* self, PyObject* args) {
-    unsigned int size;
-    if (!PyArg_ParseTuple(args, "I", &size)) {
+    long size;
+    if (!PyArg_ParseTuple(args, "l", &size)) {
+        PyErr_Clear();
+        PyErr_SetString(PyExc_TypeError,
+                        "No valid type in set_udp_size argument");
         return (NULL);
     }
-    if (size > 65535) {
-        PyErr_SetString(PyExc_OverflowError,
+    if (size < 0 || size > 0xffff) {
+        PyErr_SetString(PyExc_ValueError,
                         "UDP size is not an unsigned 16-bit integer");
         return (NULL);
     }
@@ -330,7 +334,7 @@ EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
             return (NULL);
         }
 
-        edns_obj->edns = createFromRR(*name->name, *rrclass->rrclass,
+        edns_obj->edns = createFromRR(*name->cppobj, *rrclass->rrclass,
                                       *rrtype->rrtype, *rrttl->rrttl,
                                       *rdata->rdata, extended_rcode);
         if (edns_obj->edns != NULL) {
diff --git a/src/lib/dns/python/message_python.cc b/src/lib/dns/python/message_python.cc
index e19547e..2842588 100644
--- a/src/lib/dns/python/message_python.cc
+++ b/src/lib/dns/python/message_python.cc
@@ -14,17 +14,22 @@
 
 #include <exceptions/exceptions.h>
 #include <dns/message.h>
+#include <dns/rcode.h>
+#include <dns/tsig.h>
+
 using namespace isc::dns;
+using namespace isc::util;
 
+namespace {
 //
 // Declaration of the custom exceptions
 // Initialization and addition of these go in the initModulePart
 // function at the end of this file
 //
-static PyObject* po_MessageTooShort;
-static PyObject* po_InvalidMessageSection;
-static PyObject* po_InvalidMessageOperation;
-static PyObject* po_InvalidMessageUDPSize;
+PyObject* po_MessageTooShort;
+PyObject* po_InvalidMessageSection;
+PyObject* po_InvalidMessageOperation;
+PyObject* po_InvalidMessageUDPSize;
 
 //
 // Definition of the classes
@@ -35,10 +40,6 @@ static PyObject* po_InvalidMessageUDPSize;
 // and a type description
 
 //
-// Section
-//
-
-//
 // Message
 //
 
@@ -54,36 +55,37 @@ public:
 //
 
 // General creation and destruction
-static int Message_init(s_Message* self, PyObject* args);
-static void Message_destroy(s_Message* self);
-
-static PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
-static PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
-static PyObject* Message_getQid(s_Message* self);
-static PyObject* Message_setQid(s_Message* self, PyObject* args);
-static PyObject* Message_getRcode(s_Message* self);
-static PyObject* Message_setRcode(s_Message* self, PyObject* args);
-static PyObject* Message_getOpcode(s_Message* self);
-static PyObject* Message_setOpcode(s_Message* self, PyObject* args);
-static PyObject* Message_getEDNS(s_Message* self);
-static PyObject* Message_setEDNS(s_Message* self, PyObject* args);
-static PyObject* Message_getRRCount(s_Message* self, PyObject* args);
+int Message_init(s_Message* self, PyObject* args);
+void Message_destroy(s_Message* self);
+
+PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
+PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
+PyObject* Message_getQid(s_Message* self);
+PyObject* Message_setQid(s_Message* self, PyObject* args);
+PyObject* Message_getRcode(s_Message* self);
+PyObject* Message_setRcode(s_Message* self, PyObject* args);
+PyObject* Message_getOpcode(s_Message* self);
+PyObject* Message_setOpcode(s_Message* self, PyObject* args);
+PyObject* Message_getEDNS(s_Message* self);
+PyObject* Message_setEDNS(s_Message* self, PyObject* args);
+PyObject* Message_getTSIGRecord(s_Message* self);
+PyObject* Message_getRRCount(s_Message* self, PyObject* args);
 // use direct iterators for these? (or simply lists for now?)
-static PyObject* Message_getQuestion(s_Message* self);
-static PyObject* Message_getSection(s_Message* self, PyObject* args);
+PyObject* Message_getQuestion(s_Message* self);
+PyObject* Message_getSection(s_Message* self, PyObject* args);
 //static PyObject* Message_beginQuestion(s_Message* self, PyObject* args);
 //static PyObject* Message_endQuestion(s_Message* self, PyObject* args);
 //static PyObject* Message_beginSection(s_Message* self, PyObject* args);
 //static PyObject* Message_endSection(s_Message* self, PyObject* args);
 
-static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
-static PyObject* Message_addRRset(s_Message* self, PyObject* args);
-static PyObject* Message_clear(s_Message* self, PyObject* args);
-static PyObject* Message_makeResponse(s_Message* self);
-static PyObject* Message_toText(s_Message* self);
-static PyObject* Message_str(PyObject* self);
-static PyObject* Message_toWire(s_Message* self, PyObject* args);
-static PyObject* Message_fromWire(s_Message* self, PyObject* args);
+PyObject* Message_addQuestion(s_Message* self, PyObject* args);
+PyObject* Message_addRRset(s_Message* self, PyObject* args);
+PyObject* Message_clear(s_Message* self, PyObject* args);
+PyObject* Message_makeResponse(s_Message* self);
+PyObject* Message_toText(s_Message* self);
+PyObject* Message_str(PyObject* self);
+PyObject* Message_toWire(s_Message* self, PyObject* args);
+PyObject* Message_fromWire(s_Message* self, PyObject* args);
 
 // This list contains the actual set of functions we have in
 // python. Each entry has
@@ -91,7 +93,7 @@ static PyObject* Message_fromWire(s_Message* self, PyObject* args);
 // 2. Our static function here
 // 3. Argument type
 // 4. Documentation
-static PyMethodDef Message_methods[] = {
+PyMethodDef Message_methods[] = {
     { "get_header_flag", reinterpret_cast<PyCFunction>(Message_getHeaderFlag),
       METH_VARARGS,
       "Return whether the specified header flag bit is set in the "
@@ -125,6 +127,11 @@ static PyMethodDef Message_methods[] = {
     { "set_edns", reinterpret_cast<PyCFunction>(Message_setEDNS), METH_VARARGS,
       "Set EDNS for the message."
     },
+    { "get_tsig_record",
+      reinterpret_cast<PyCFunction>(Message_getTSIGRecord), METH_NOARGS,
+      "Return, if any, the TSIG record contained in the received message. "
+      "If no TSIG RR is set in the message, None will be returned."
+    },
     { "get_rr_count", reinterpret_cast<PyCFunction>(Message_getRRCount), METH_VARARGS,
       "Returns the number of RRs contained in the given section." },
     { "get_question", reinterpret_cast<PyCFunction>(Message_getQuestion), METH_NOARGS,
@@ -174,7 +181,7 @@ static PyMethodDef Message_methods[] = {
 // This defines the complete type for reflection in python and
 // parsing of PyObject* to s_Message
 // Most of the functions are not actually implemented and NULL here.
-static PyTypeObject message_type = {
+PyTypeObject message_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "pydnspp.Message",
     sizeof(s_Message),                  // tp_basicsize
@@ -224,11 +231,11 @@ static PyTypeObject message_type = {
     0                                   // tp_version_tag
 };
 
-static int
+int
 Message_init(s_Message* self, PyObject* args) {
-    unsigned int i;
-    
-    if (PyArg_ParseTuple(args, "I", &i)) {
+    int i;
+
+    if (PyArg_ParseTuple(args, "i", &i)) {
         PyErr_Clear();
         if (i == Message::PARSE) {
             self->message = new Message(Message::PARSE);
@@ -247,14 +254,14 @@ Message_init(s_Message* self, PyObject* args) {
     return (-1);
 }
 
-static void
+void
 Message_destroy(s_Message* self) {
     delete self->message;
     self->message = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
-static PyObject*
+PyObject*
 Message_getHeaderFlag(s_Message* self, PyObject* args) {
     unsigned int messageflag;
     if (!PyArg_ParseTuple(args, "I", &messageflag)) {
@@ -272,19 +279,19 @@ Message_getHeaderFlag(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_setHeaderFlag(s_Message* self, PyObject* args) {
-    int messageflag;
+    long messageflag;
     PyObject *on = Py_True;
 
-    if (!PyArg_ParseTuple(args, "i|O!", &messageflag, &PyBool_Type, &on)) {
+    if (!PyArg_ParseTuple(args, "l|O!", &messageflag, &PyBool_Type, &on)) {
         PyErr_Clear();
         PyErr_SetString(PyExc_TypeError,
                         "no valid type in set_header_flag argument");
         return (NULL);
     }
-    if (messageflag < 0) {
-        PyErr_SetString(PyExc_TypeError, "invalid Message header flag");
+    if (messageflag < 0 || messageflag > 0xffff) {
+        PyErr_SetString(PyExc_ValueError, "Message header flag out of range");
         return (NULL);
     }
 
@@ -303,17 +310,26 @@ Message_setHeaderFlag(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_getQid(s_Message* self) {
     return (Py_BuildValue("I", self->message->getQid()));
 }
 
-static PyObject*
+PyObject*
 Message_setQid(s_Message* self, PyObject* args) {
-    uint16_t id;
-    if (!PyArg_ParseTuple(args, "H", &id)) {
+    long id;
+    if (!PyArg_ParseTuple(args, "l", &id)) {
+        PyErr_Clear();
+        PyErr_SetString(PyExc_TypeError,
+                        "no valid type in set_qid argument");
         return (NULL);
     }
+    if (id < 0 || id > 0xffff) {
+        PyErr_SetString(PyExc_ValueError,
+                        "Message id out of range");
+        return (NULL);
+    }
+
     try {
         self->message->setQid(id);
         Py_RETURN_NONE;
@@ -323,21 +339,21 @@ Message_setQid(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_getRcode(s_Message* self) {
     s_Rcode* rcode;
 
     rcode = static_cast<s_Rcode*>(rcode_type.tp_alloc(&rcode_type, 0));
     if (rcode != NULL) {
-        rcode->rcode = NULL;
+        rcode->cppobj = NULL;
         try {
-            rcode->rcode = new Rcode(self->message->getRcode());
+            rcode->cppobj = new Rcode(self->message->getRcode());
         } catch (const InvalidMessageOperation& imo) {
             PyErr_SetString(po_InvalidMessageOperation, imo.what());
         } catch (...) {
             PyErr_SetString(po_IscException, "Unexpected exception");
         }
-        if (rcode->rcode == NULL) {
+        if (rcode->cppobj == NULL) {
             Py_DECREF(rcode);
             return (NULL);
         }
@@ -346,14 +362,14 @@ Message_getRcode(s_Message* self) {
     return (rcode);
 }
 
-static PyObject*
+PyObject*
 Message_setRcode(s_Message* self, PyObject* args) {
     s_Rcode* rcode;
     if (!PyArg_ParseTuple(args, "O!", &rcode_type, &rcode)) {
         return (NULL);
     }
     try {
-        self->message->setRcode(*rcode->rcode);
+        self->message->setRcode(*rcode->cppobj);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -361,7 +377,7 @@ Message_setRcode(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_getOpcode(s_Message* self) {
     s_Opcode* opcode;
 
@@ -384,7 +400,7 @@ Message_getOpcode(s_Message* self) {
     return (opcode);
 }
 
-static PyObject*
+PyObject*
 Message_setOpcode(s_Message* self, PyObject* args) {
     s_Opcode* opcode;
     if (!PyArg_ParseTuple(args, "O!", &opcode_type, &opcode)) {
@@ -399,7 +415,7 @@ Message_setOpcode(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_getEDNS(s_Message* self) {
     s_EDNS* edns;
     EDNS* edns_body;
@@ -419,7 +435,7 @@ Message_getEDNS(s_Message* self) {
     return (edns);
 }
 
-static PyObject*
+PyObject*
 Message_setEDNS(s_Message* self, PyObject* args) {
     s_EDNS* edns;
     if (!PyArg_ParseTuple(args, "O!", &edns_type, &edns)) {
@@ -434,7 +450,30 @@ Message_setEDNS(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
+Message_getTSIGRecord(s_Message* self) {
+    try {
+        const TSIGRecord* tsig_record = self->message->getTSIGRecord();
+
+        if (tsig_record == NULL) {
+            Py_RETURN_NONE;
+        }
+        return (createTSIGRecordObject(*tsig_record));
+    } catch (const InvalidMessageOperation& ex) {
+        PyErr_SetString(po_InvalidMessageOperation, ex.what());
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in getting TSIGRecord from message: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting TSIGRecord from message");
+    }
+    return (NULL);
+}
+
+PyObject*
 Message_getRRCount(s_Message* self, PyObject* args) {
     unsigned int section;
     if (!PyArg_ParseTuple(args, "I", &section)) {
@@ -453,7 +492,7 @@ Message_getRRCount(s_Message* self, PyObject* args) {
 }
 
 // TODO use direct iterators for these? (or simply lists for now?)
-static PyObject*
+PyObject*
 Message_getQuestion(s_Message* self) {
     QuestionIterator qi, qi_end;
     try {
@@ -492,7 +531,7 @@ Message_getQuestion(s_Message* self) {
     return (list);
 }
 
-static PyObject*
+PyObject*
 Message_getSection(s_Message* self, PyObject* args) {
     unsigned int section;
     if (!PyArg_ParseTuple(args, "I", &section)) {
@@ -549,7 +588,7 @@ Message_getSection(s_Message* self, PyObject* args) {
 //static PyObject* Message_beginSection(s_Message* self, PyObject* args);
 //static PyObject* Message_endSection(s_Message* self, PyObject* args);
 //static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
-static PyObject*
+PyObject*
 Message_addQuestion(s_Message* self, PyObject* args) {
     s_Question *question;
 
@@ -562,12 +601,12 @@ Message_addQuestion(s_Message* self, PyObject* args) {
     Py_RETURN_NONE;
 }
 
-static PyObject*
+PyObject*
 Message_addRRset(s_Message* self, PyObject* args) {
     PyObject *sign = Py_False;
-    unsigned int section;
+    int section;
     s_RRset* rrset;
-    if (!PyArg_ParseTuple(args, "IO!|O!", &section, &rrset_type, &rrset,
+    if (!PyArg_ParseTuple(args, "iO!|O!", &section, &rrset_type, &rrset,
                           &PyBool_Type, &sign)) {
         return (NULL);
     }
@@ -589,10 +628,10 @@ Message_addRRset(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_clear(s_Message* self, PyObject* args) {
-    unsigned int i;
-    if (PyArg_ParseTuple(args, "I", &i)) {
+    int i;
+    if (PyArg_ParseTuple(args, "i", &i)) {
         PyErr_Clear();
         if (i == Message::PARSE) {
             self->message->clear(Message::PARSE);
@@ -610,13 +649,13 @@ Message_clear(s_Message* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_makeResponse(s_Message* self) {
     self->message->makeResponse();
     Py_RETURN_NONE;
 }
 
-static PyObject*
+PyObject*
 Message_toText(s_Message* self) {
     // Py_BuildValue makes python objects from native data
     try {
@@ -631,7 +670,7 @@ Message_toText(s_Message* self) {
     }
 }
 
-static PyObject*
+PyObject*
 Message_str(PyObject* self) {
     // Simply call the to_text method we already defined
     return (PyObject_CallMethod(self,
@@ -639,13 +678,19 @@ Message_str(PyObject* self) {
                                 const_cast<char*>("")));
 }
 
-static PyObject*
+PyObject*
 Message_toWire(s_Message* self, PyObject* args) {
     s_MessageRenderer* mr;
+    s_TSIGContext* tsig_ctx = NULL;
     
-    if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
+    if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr,
+                         &tsigcontext_type, &tsig_ctx)) {
         try {
-            self->message->toWire(*mr->messagerenderer);
+            if (tsig_ctx == NULL) {
+                self->message->toWire(*mr->messagerenderer);
+            } else {
+                self->message->toWire(*mr->messagerenderer, *tsig_ctx->cppobj);
+            }
             // If we return NULL it is seen as an error, so use this for
             // None returns
             Py_RETURN_NONE;
@@ -653,6 +698,11 @@ Message_toWire(s_Message* self, PyObject* args) {
             PyErr_Clear();
             PyErr_SetString(po_InvalidMessageOperation, imo.what());
             return (NULL);
+        } catch (const TSIGContextError& ex) {
+            // toWire() with a TSIG context can fail due to this if the
+            // python program has a bug.
+            PyErr_SetString(po_TSIGContextError, ex.what());
+            return (NULL);
         }
     }
     PyErr_Clear();
@@ -661,7 +711,7 @@ Message_toWire(s_Message* self, PyObject* args) {
     return (NULL);
 }
 
-static PyObject*
+PyObject*
 Message_fromWire(s_Message* self, PyObject* args) {
     const char* b;
     Py_ssize_t len;
@@ -755,3 +805,4 @@ initModulePart_Message(PyObject* mod) {
 
     return (true);
 }
+} // end of unnamed namespace
diff --git a/src/lib/dns/python/messagerenderer_python.cc b/src/lib/dns/python/messagerenderer_python.cc
index a00d8d4..e6f5d3e 100644
--- a/src/lib/dns/python/messagerenderer_python.cc
+++ b/src/lib/dns/python/messagerenderer_python.cc
@@ -12,38 +12,41 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <Python.h>
+
+#include <util/buffer.h>
+
 #include <dns/messagerenderer.h>
 
-// For each class, we need a struct, a helper functions (init, destroy,
-// and static wrappers around the methods we export), a list of methods,
-// and a type description
+#include "pydnspp_common.h"
+#include "messagerenderer_python.h"
+
 using namespace isc::dns;
+using namespace isc::dns::python;
+using namespace isc::util;
 
 // MessageRenderer
 
-// since we don't use *Buffer in the python version (but work with
-// the already existing bytearray type where we use these custom buffers
-// in c++, we need to keep track of one here.
-class s_MessageRenderer : public PyObject {
-public:
-    OutputBuffer* outputbuffer;
-    MessageRenderer* messagerenderer;
-};
+s_MessageRenderer::s_MessageRenderer() : outputbuffer(NULL),
+                                         messagerenderer(NULL)
+{
+}
 
-static int MessageRenderer_init(s_MessageRenderer* self);
-static void MessageRenderer_destroy(s_MessageRenderer* self);
+namespace {
+int MessageRenderer_init(s_MessageRenderer* self);
+void MessageRenderer_destroy(s_MessageRenderer* self);
 
-static PyObject* MessageRenderer_getData(s_MessageRenderer* self);
-static PyObject* MessageRenderer_getLength(s_MessageRenderer* self);
-static PyObject* MessageRenderer_isTruncated(s_MessageRenderer* self);
-static PyObject* MessageRenderer_getLengthLimit(s_MessageRenderer* self);
-static PyObject* MessageRenderer_getCompressMode(s_MessageRenderer* self);
-static PyObject* MessageRenderer_setTruncated(s_MessageRenderer* self);
-static PyObject* MessageRenderer_setLengthLimit(s_MessageRenderer* self, PyObject* args);
-static PyObject* MessageRenderer_setCompressMode(s_MessageRenderer* self, PyObject* args);
-static PyObject* MessageRenderer_clear(s_MessageRenderer* self);
+PyObject* MessageRenderer_getData(s_MessageRenderer* self);
+PyObject* MessageRenderer_getLength(s_MessageRenderer* self);
+PyObject* MessageRenderer_isTruncated(s_MessageRenderer* self);
+PyObject* MessageRenderer_getLengthLimit(s_MessageRenderer* self);
+PyObject* MessageRenderer_getCompressMode(s_MessageRenderer* self);
+PyObject* MessageRenderer_setTruncated(s_MessageRenderer* self);
+PyObject* MessageRenderer_setLengthLimit(s_MessageRenderer* self, PyObject* args);
+PyObject* MessageRenderer_setCompressMode(s_MessageRenderer* self, PyObject* args);
+PyObject* MessageRenderer_clear(s_MessageRenderer* self);
 
-static PyMethodDef MessageRenderer_methods[] = {
+PyMethodDef MessageRenderer_methods[] = {
     { "get_data", reinterpret_cast<PyCFunction>(MessageRenderer_getData), METH_NOARGS,
       "Returns the data as a bytes() object" },
     { "get_length", reinterpret_cast<PyCFunction>(MessageRenderer_getLength), METH_NOARGS,
@@ -66,69 +69,14 @@ static PyMethodDef MessageRenderer_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-static PyTypeObject messagerenderer_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "pydnspp.MessageRenderer",
-    sizeof(s_MessageRenderer),          // tp_basicsize
-    0,                                  // tp_itemsize
-    (destructor)MessageRenderer_destroy,// tp_dealloc
-    NULL,                               // tp_print
-    NULL,                               // tp_getattr
-    NULL,                               // tp_setattr
-    NULL,                               // tp_reserved
-    NULL,                               // tp_repr
-    NULL,                               // tp_as_number
-    NULL,                               // tp_as_sequence
-    NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
-    NULL,                               // tp_call
-    NULL,                               // tp_str
-    NULL,                               // tp_getattro
-    NULL,                               // tp_setattro
-    NULL,                               // tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                 // tp_flags
-    "The MessageRenderer class encapsulates implementation details "
-    "of rendering a DNS message into a buffer in wire format. "
-    "In effect, it's simply responsible for name compression at least in the "
-    "current implementation. A MessageRenderer class object manages the "
-    "positions of names rendered in a buffer and uses that information to render "
-    "subsequent names with compression.",
-    NULL,                               // tp_traverse
-    NULL,                               // tp_clear
-    NULL,                               // tp_richcompare
-    0,                                  // tp_weaklistoffset
-    NULL,                               // tp_iter
-    NULL,                               // tp_iternext
-    MessageRenderer_methods,            // tp_methods
-    NULL,                               // tp_members
-    NULL,                               // tp_getset
-    NULL,                               // tp_base
-    NULL,                               // tp_dict
-    NULL,                               // tp_descr_get
-    NULL,                               // tp_descr_set
-    0,                                  // tp_dictoffset
-    (initproc)MessageRenderer_init,     // tp_init
-    NULL,                               // tp_alloc
-    PyType_GenericNew,                  // tp_new
-    NULL,                               // tp_free
-    NULL,                               // tp_is_gc
-    NULL,                               // tp_bases
-    NULL,                               // tp_mro
-    NULL,                               // tp_cache
-    NULL,                               // tp_subclasses
-    NULL,                               // tp_weaklist
-    NULL,                               // tp_del
-    0                                   // tp_version_tag
-};
-
-static int
+int
 MessageRenderer_init(s_MessageRenderer* self) {
     self->outputbuffer = new OutputBuffer(4096);
     self->messagerenderer = new MessageRenderer(*self->outputbuffer);
     return (0);
 }
 
-static void
+void
 MessageRenderer_destroy(s_MessageRenderer* self) {
     delete self->messagerenderer;
     delete self->outputbuffer;
@@ -137,19 +85,19 @@ MessageRenderer_destroy(s_MessageRenderer* self) {
     Py_TYPE(self)->tp_free(self);
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_getData(s_MessageRenderer* self) {
     return (Py_BuildValue("y#",
                          self->messagerenderer->getData(),
                           self->messagerenderer->getLength()));
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_getLength(s_MessageRenderer* self) {
     return (Py_BuildValue("I", self->messagerenderer->getLength()));
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_isTruncated(s_MessageRenderer* self) {
     if (self->messagerenderer->isTruncated()) {
         Py_RETURN_TRUE;
@@ -158,40 +106,48 @@ MessageRenderer_isTruncated(s_MessageRenderer* self) {
     }
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_getLengthLimit(s_MessageRenderer* self) {
     return (Py_BuildValue("I", self->messagerenderer->getLengthLimit()));
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_getCompressMode(s_MessageRenderer* self) {
     return (Py_BuildValue("I", self->messagerenderer->getCompressMode()));
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_setTruncated(s_MessageRenderer* self) {
     self->messagerenderer->setTruncated();
     Py_RETURN_NONE;
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_setLengthLimit(s_MessageRenderer* self,
                                PyObject* args)
 {
-    unsigned int lengthlimit;
-    if (!PyArg_ParseTuple(args, "I", &lengthlimit)) {
+    long lengthlimit;
+    if (!PyArg_ParseTuple(args, "l", &lengthlimit)) {
+        PyErr_Clear();
+        PyErr_SetString(PyExc_TypeError,
+                        "No valid type in set_length_limit argument");
+        return (NULL);
+    }
+    if (lengthlimit < 0) {
+        PyErr_SetString(PyExc_ValueError,
+                        "MessageRenderer length limit out of range");
         return (NULL);
     }
     self->messagerenderer->setLengthLimit(lengthlimit);
     Py_RETURN_NONE;
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_setCompressMode(s_MessageRenderer* self,
                                PyObject* args)
 {
-    unsigned int mode;
-    if (!PyArg_ParseTuple(args, "I", &mode)) {
+    int mode;
+    if (!PyArg_ParseTuple(args, "i", &mode)) {
         return (NULL);
     }
 
@@ -211,14 +167,71 @@ MessageRenderer_setCompressMode(s_MessageRenderer* self,
     }
 }
 
-static PyObject*
+PyObject*
 MessageRenderer_clear(s_MessageRenderer* self) {
     self->messagerenderer->clear();
     Py_RETURN_NONE;
 }
+} // end of unnamed namespace
 
 // end of MessageRenderer
-
+namespace isc {
+namespace dns {
+namespace python {
+PyTypeObject messagerenderer_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.MessageRenderer",
+    sizeof(s_MessageRenderer),          // tp_basicsize
+    0,                                  // tp_itemsize
+    (destructor)MessageRenderer_destroy,// tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The MessageRenderer class encapsulates implementation details "
+    "of rendering a DNS message into a buffer in wire format. "
+    "In effect, it's simply responsible for name compression at least in the "
+    "current implementation. A MessageRenderer class object manages the "
+    "positions of names rendered in a buffer and uses that information to render "
+    "subsequent names with compression.",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    MessageRenderer_methods,            // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    (initproc)MessageRenderer_init,     // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
 
 // Module Initialization, all statics are initialized here
 bool
@@ -251,5 +264,6 @@ initModulePart_MessageRenderer(PyObject* mod) {
     
     return (true);
 }
-
-
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/messagerenderer_python.h b/src/lib/dns/python/messagerenderer_python.h
new file mode 100644
index 0000000..3bb096e
--- /dev/null
+++ b/src/lib/dns/python/messagerenderer_python.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_MESSAGERENDERER_H
+#define __PYTHON_MESSAGERENDERER_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace util {
+class OutputBuffer;
+}
+namespace dns {
+class MessageRenderer;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object.
+//
+// since we don't use *Buffer in the python version (but work with
+// the already existing bytearray type where we use these custom buffers
+// in C++, we need to keep track of one here.
+class s_MessageRenderer : public PyObject {
+public:
+    s_MessageRenderer();
+    isc::util::OutputBuffer* outputbuffer;
+    MessageRenderer* messagerenderer;
+};
+
+extern PyTypeObject messagerenderer_type;
+
+bool initModulePart_MessageRenderer(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_MESSAGERENDERER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc
index 3d7a196..d00c6f7 100644
--- a/src/lib/dns/python/name_python.cc
+++ b/src/lib/dns/python/name_python.cc
@@ -12,26 +12,18 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-static PyObject* po_EmptyLabel;
-static PyObject* po_TooLongName;
-static PyObject* po_TooLongLabel;
-static PyObject* po_BadLabelType;
-static PyObject* po_BadEscape;
-static PyObject* po_IncompleteName;
-static PyObject* po_InvalidBufferPosition;
-static PyObject* po_DNSMessageFORMERR;
+#include <Python.h>
 
-//
-// Declaration of enums
-// Initialization and addition of these go in the module init at the
-// end
-//
-static PyObject* po_NameRelation;
+#include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+
+#include "pydnspp_common.h"
+#include "messagerenderer_python.h"
+#include "name_python.h"
 
 //
 // Definition of the classes
@@ -41,20 +33,20 @@ static PyObject* po_NameRelation;
 // and static wrappers around the methods we export), a list of methods,
 // and a type description
 using namespace isc::dns;
+using namespace isc::dns::python;
+using namespace isc::util;
+using namespace isc::util::python;
 
+namespace {
 // NameComparisonResult
-class s_NameComparisonResult : public PyObject {
-public:
-    isc::dns::NameComparisonResult* ncr;
-};
 
-static int NameComparisonResult_init(s_NameComparisonResult*, PyObject*);
-static void NameComparisonResult_destroy(s_NameComparisonResult* self);
-static PyObject* NameComparisonResult_getOrder(s_NameComparisonResult* self);
-static PyObject* NameComparisonResult_getCommonLabels(s_NameComparisonResult* self);
-static PyObject* NameComparisonResult_getRelation(s_NameComparisonResult* self);
+int NameComparisonResult_init(s_NameComparisonResult*, PyObject*);
+void NameComparisonResult_destroy(s_NameComparisonResult* self);
+PyObject* NameComparisonResult_getOrder(s_NameComparisonResult* self);
+PyObject* NameComparisonResult_getCommonLabels(s_NameComparisonResult* self);
+PyObject* NameComparisonResult_getRelation(s_NameComparisonResult* self);
 
-static PyMethodDef NameComparisonResult_methods[] = {
+PyMethodDef NameComparisonResult_methods[] = {
     { "get_order", reinterpret_cast<PyCFunction>(NameComparisonResult_getOrder), METH_NOARGS,
       "Returns the order" },
     { "get_common_labels", reinterpret_cast<PyCFunction>(NameComparisonResult_getCommonLabels), METH_NOARGS,
@@ -64,122 +56,61 @@ static PyMethodDef NameComparisonResult_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-static PyTypeObject name_comparison_result_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "pydnspp.NameComparisonResult",
-    sizeof(s_NameComparisonResult),           // tp_basicsize
-    0,                                        // tp_itemsize
-    (destructor)NameComparisonResult_destroy, // tp_dealloc
-    NULL,                                     // tp_print
-    NULL,                                     // tp_getattr
-    NULL,                                     // tp_setattr
-    NULL,                                     // tp_reserved
-    NULL,                                     // tp_repr
-    NULL,                                     // tp_as_number
-    NULL,                                     // tp_as_sequence
-    NULL,                                     // tp_as_mapping
-    NULL,                                     // tp_hash 
-    NULL,                                     // tp_call
-    NULL,                                     // tp_str
-    NULL,                                     // tp_getattro
-    NULL,                                     // tp_setattro
-    NULL,                                     // tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                       // tp_flags
-    "This is a supplemental class used only as a return value of Name.compare(). "
-    "It encapsulate a tuple of the comparison: ordering, number of common labels, "
-    "and relationship as follows:\n"
-    "- ordering: relative ordering under the DNSSEC order relation\n"
-    "- labels: the number of common significant labels of the two names being"
-    "  compared\n"
-    "- relationship: see NameComparisonResult.NameRelation\n",
-    NULL,                                     // tp_traverse
-    NULL,                                     // tp_clear
-    NULL,                                     // tp_richcompare
-    0,                                        // tp_weaklistoffset
-    NULL,                                     // tp_iter
-    NULL,                                     // tp_iternext
-    NameComparisonResult_methods,             // tp_methods
-    NULL,                                     // tp_members
-    NULL,                                     // tp_getset
-    NULL,                                     // tp_base
-    NULL,                                     // tp_dict
-    NULL,                                     // tp_descr_get
-    NULL,                                     // tp_descr_set
-    0,                                        // tp_dictoffset
-    (initproc)NameComparisonResult_init,      // tp_init
-    NULL,                                     // tp_alloc
-    PyType_GenericNew,                        // tp_new
-    NULL,                                     // tp_free
-    NULL,                                     // tp_is_gc
-    NULL,                                     // tp_bases
-    NULL,                                     // tp_mro
-    NULL,                                     // tp_cache
-    NULL,                                     // tp_subclasses
-    NULL,                                     // tp_weaklist
-    NULL,                                     // tp_del
-    0                                         // tp_version_tag
-};
-
-static int
+int
 NameComparisonResult_init(s_NameComparisonResult*, PyObject*) {
     PyErr_SetString(PyExc_NotImplementedError,
                     "NameComparisonResult can't be built directly");
     return (-1);
 }
 
-static void
+void
 NameComparisonResult_destroy(s_NameComparisonResult* self) {
-    delete self->ncr;
-    self->ncr = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
-static PyObject* 
+PyObject*
 NameComparisonResult_getOrder(s_NameComparisonResult* self) {
-    return (Py_BuildValue("i", self->ncr->getOrder()));
+    return (Py_BuildValue("i", self->cppobj->getOrder()));
 }
 
-static PyObject* 
+PyObject*
 NameComparisonResult_getCommonLabels(s_NameComparisonResult* self) {
-    return (Py_BuildValue("I", self->ncr->getCommonLabels()));
+    return (Py_BuildValue("I", self->cppobj->getCommonLabels()));
 }
 
-static PyObject* 
+PyObject*
 NameComparisonResult_getRelation(s_NameComparisonResult* self) {
-    return (Py_BuildValue("I", self->ncr->getRelation()));
+    return (Py_BuildValue("I", self->cppobj->getRelation()));
 }
-
 // end of NameComparisonResult
 
 // Name
-
-class s_Name : public PyObject {
-public:
-    isc::dns::Name* name;
-    size_t position;
-};
-
-static int Name_init(s_Name* self, PyObject* args);
-static void Name_destroy(s_Name* self);
-
-static PyObject* Name_toWire(s_Name* self, PyObject* args);
-static PyObject* Name_toText(s_Name* self);
-static PyObject* Name_str(PyObject* self);
-static PyObject* Name_getLabelCount(s_Name* self);
-static PyObject* Name_at(s_Name* self, PyObject* args);
-static PyObject* Name_getLength(s_Name* self);
-
-static PyObject* Name_compare(s_Name* self, PyObject* args);
-static PyObject* Name_equals(s_Name* self, PyObject* args);
-
-static PyObject* Name_richcmp(s_Name* self, s_Name* other, int op);
-static PyObject* Name_split(s_Name* self, PyObject* args);
-static PyObject* Name_reverse(s_Name* self);
-static PyObject* Name_concatenate(s_Name* self, PyObject* args);
-static PyObject* Name_downcase(s_Name* self);
-static PyObject* Name_isWildCard(s_Name* self);
-
-static PyMethodDef Name_methods[] = {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_Name, Name> NameContainer;
+
+int Name_init(s_Name* self, PyObject* args);
+void Name_destroy(s_Name* self);
+
+PyObject* Name_toWire(s_Name* self, PyObject* args);
+PyObject* Name_toText(s_Name* self);
+PyObject* Name_str(PyObject* self);
+PyObject* Name_getLabelCount(s_Name* self);
+PyObject* Name_at(s_Name* self, PyObject* args);
+PyObject* Name_getLength(s_Name* self);
+
+PyObject* Name_compare(s_Name* self, PyObject* args);
+PyObject* Name_equals(s_Name* self, PyObject* args);
+
+PyObject* Name_richcmp(s_Name* self, s_Name* other, int op);
+PyObject* Name_split(s_Name* self, PyObject* args);
+PyObject* Name_reverse(s_Name* self);
+PyObject* Name_concatenate(s_Name* self, PyObject* args);
+PyObject* Name_downcase(s_Name* self);
+PyObject* Name_isWildCard(s_Name* self);
+
+PyMethodDef Name_methods[] = {
     { "at", reinterpret_cast<PyCFunction>(Name_at), METH_VARARGS,
       "Returns the integer value of the name data at the specified position" },
     { "get_length", reinterpret_cast<PyCFunction>(Name_getLength), METH_NOARGS,
@@ -216,63 +147,7 @@ static PyMethodDef Name_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-static PyTypeObject name_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "pydnspp.Name",
-    sizeof(s_Name),                     // tp_basicsize
-    0,                                  // tp_itemsize
-    (destructor)Name_destroy,           // tp_dealloc
-    NULL,                               // tp_print
-    NULL,                               // tp_getattr
-    NULL,                               // tp_setattr
-    NULL,                               // tp_reserved
-    NULL,                               // tp_repr
-    NULL,                               // tp_as_number
-    NULL,                               // tp_as_sequence
-    NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
-    NULL,                               // tp_call
-    Name_str,                           // tp_str
-    NULL,                               // tp_getattro
-    NULL,                               // tp_setattro
-    NULL,                               // tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                 // tp_flags
-    "The Name class encapsulates DNS names.\n"
-    "It provides interfaces to construct a name from string or wire-format data, "
-    "transform a name into a string or wire-format data, compare two names, get "
-    "access to various properties of a name, etc.",
-    NULL,                               // tp_traverse
-    NULL,                               // tp_clear
-    (richcmpfunc)Name_richcmp,          // tp_richcompare
-    0,                                  // tp_weaklistoffset
-    NULL,                               // tp_iter
-    NULL,                               // tp_iternext
-    Name_methods,                       // tp_methods
-    NULL,                               // tp_members
-    NULL,                               // tp_getset
-    NULL,                               // tp_base
-    NULL,                               // tp_dict
-    NULL,                               // tp_descr_get
-    NULL,                               // tp_descr_set
-    0,                                  // tp_dictoffset
-    (initproc)Name_init,                // tp_init
-    NULL,                               // tp_alloc
-    PyType_GenericNew,                  // tp_new
-    NULL,                               // tp_free
-    NULL,                               // tp_is_gc
-    NULL,                               // tp_bases
-    NULL,                               // tp_mro
-    NULL,                               // tp_cache
-    NULL,                               // tp_subclasses
-    NULL,                               // tp_weaklist
-    // Note: not sure if the following are correct.  Added them just to
-    // make the compiler happy.
-    NULL,                               // tp_del
-    0                                   // tp_version_tag
-};
-
-
-static int
+int
 Name_init(s_Name* self, PyObject* args) {
     const char* s;
     PyObject* downcase = Py_False;
@@ -285,7 +160,7 @@ Name_init(s_Name* self, PyObject* args) {
         try {
             const std::string n(s);
 
-            self->name = new Name(n, downcase == Py_True);
+            self->cppobj = new Name(n, downcase == Py_True);
             self->position = 0;
         } catch (const EmptyLabel&) {
             PyErr_SetString(po_EmptyLabel, "EmptyLabel");
@@ -321,18 +196,24 @@ Name_init(s_Name* self, PyObject* args) {
     PyObject* bytes_obj;
     const char* bytes;
     Py_ssize_t len;
-    unsigned int position = 0;
+    long position = 0;
 
     // It was not a string (see comment above), so try bytes, and
     // create with buffer object
-    if (PyArg_ParseTuple(args, "O|IO!", &bytes_obj, &position,
+    if (PyArg_ParseTuple(args, "O|lO!", &bytes_obj, &position,
                          &PyBool_Type, &downcase) &&
                          PyObject_AsCharBuffer(bytes_obj, &bytes, &len) != -1) {
         try {
+            if (position < 0) {
+                // Throw IndexError here since name index should be unsigned
+                PyErr_SetString(PyExc_IndexError,
+                                "Name index shouldn't be negative");
+                return (-1);
+            }
             InputBuffer buffer(bytes, len);
 
             buffer.setPosition(position);
-            self->name = new Name(buffer, downcase == Py_True);
+            self->cppobj = new Name(buffer, downcase == Py_True);
             self->position = buffer.getPosition();
         } catch (const InvalidBufferPosition&) {
             PyErr_SetString(po_InvalidBufferPosition,
@@ -354,21 +235,28 @@ Name_init(s_Name* self, PyObject* args) {
     return (-1);
 }
 
-static void
+void
 Name_destroy(s_Name* self) {
-    delete self->name;
-    self->name = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
-static PyObject*
+PyObject*
 Name_at(s_Name* self, PyObject* args) {
-    unsigned int pos;
-    if (!PyArg_ParseTuple(args, "I", &pos)) {
+    int pos;
+    if (!PyArg_ParseTuple(args, "i", &pos)) {
         return (NULL);
     }
+    if (pos < 0) {
+        // Throw IndexError here since name index should be unsigned
+        PyErr_SetString(PyExc_IndexError,
+                        "name index shouldn't be negative");
+        return (NULL);
+    }
+
     try {
-        return (Py_BuildValue("I", self->name->at(pos)));
+        return (Py_BuildValue("I", self->cppobj->at(pos)));
     } catch (const isc::OutOfRange&) {
         PyErr_SetString(PyExc_IndexError,
                         "name index out of range");
@@ -376,22 +264,22 @@ Name_at(s_Name* self, PyObject* args) {
     }
 }
 
-static PyObject*
+PyObject*
 Name_getLength(s_Name* self) {
-    return (Py_BuildValue("i", self->name->getLength()));
+    return (Py_BuildValue("i", self->cppobj->getLength()));
 }
 
-static PyObject*
+PyObject*
 Name_getLabelCount(s_Name* self) {
-    return (Py_BuildValue("i", self->name->getLabelCount()));
+    return (Py_BuildValue("i", self->cppobj->getLabelCount()));
 }
 
-static PyObject*
+PyObject*
 Name_toText(s_Name* self) {
-    return (Py_BuildValue("s", self->name->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
-static PyObject*
+PyObject*
 Name_str(PyObject* self) {
     // Simply call the to_text method we already defined
     // str() is not defined in the c++ version, only to_text
@@ -401,16 +289,16 @@ Name_str(PyObject* self) {
                                 const_cast<char*>("")));
 }
 
-static PyObject*
+PyObject*
 Name_toWire(s_Name* self, PyObject* args) {
     PyObject* bytes;
     s_MessageRenderer* mr;
-    
+
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
-        
+
         OutputBuffer buffer(Name::MAX_WIRE);
-        self->name->toWire(buffer);
+        self->cppobj->toWire(buffer);
         PyObject* name_bytes = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()), buffer.getLength());
         PyObject* result = PySequence_InPlaceConcat(bytes_o, name_bytes);
         // We need to release the object we temporarily created here
@@ -418,7 +306,7 @@ Name_toWire(s_Name* self, PyObject* args) {
         Py_DECREF(name_bytes);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->name->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(*mr->messagerenderer);
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -429,7 +317,7 @@ Name_toWire(s_Name* self, PyObject* args) {
     return (NULL);
 }
 
-static PyObject*
+PyObject*
 Name_compare(s_Name* self, PyObject* args) {
     s_Name* other;
 
@@ -438,71 +326,87 @@ Name_compare(s_Name* self, PyObject* args) {
 
     s_NameComparisonResult* ret = PyObject_New(s_NameComparisonResult, &name_comparison_result_type);
     if (ret != NULL) {
-        ret->ncr = new NameComparisonResult(
-            self->name->compare(*other->name));
+        ret->cppobj = new NameComparisonResult(
+            self->cppobj->compare(*other->cppobj));
     }
     return (ret);
 }
 
-static PyObject* 
+PyObject*
 Name_equals(s_Name* self, PyObject* args) {
     s_Name* other;
 
     if (!PyArg_ParseTuple(args, "O!", &name_type, &other))
         return (NULL);
 
-    if (self->name->equals(*other->name))
+    if (self->cppobj->equals(*other->cppobj))
         Py_RETURN_TRUE;
     else
         Py_RETURN_FALSE;
 }
 
-static PyObject* 
+PyObject*
 Name_split(s_Name* self, PyObject* args) {
-    unsigned int first, n;
+    int first, n;
     s_Name* ret = NULL;
-    
-    if (PyArg_ParseTuple(args, "II", &first, &n)) {
+
+    if (PyArg_ParseTuple(args, "ii", &first, &n)) {
+        if (first < 0 || n < 0) {
+            // Throw IndexError here since name index should be unsigned
+            PyErr_SetString(PyExc_IndexError,
+                            "name index shouldn't be negative");
+            return (NULL);
+        }
         ret = PyObject_New(s_Name, &name_type);
         if (ret != NULL) {
-            ret->name = NULL;
+            ret->cppobj = NULL;
             try {
-                ret->name = new Name(self->name->split(first, n));
+                ret->cppobj = new Name(self->cppobj->split(first, n));
             } catch(const isc::OutOfRange& oor) {
                 PyErr_SetString(PyExc_IndexError, oor.what());
-                ret->name = NULL;
+                ret->cppobj = NULL;
             }
-            if (ret->name == NULL) {
+            if (ret->cppobj == NULL) {
                 Py_DECREF(ret);
                 return (NULL);
             }
         }
-    } else if (PyArg_ParseTuple(args, "I", &n)) {
+    } else if (PyArg_ParseTuple(args, "i", &n)) {
+        PyErr_Clear();
+        if (n < 0) {
+            // Throw IndexError here since name index should be unsigned
+            PyErr_SetString(PyExc_IndexError,
+                            "name index shouldn't be negative");
+            return (NULL);
+        }
         ret = PyObject_New(s_Name, &name_type);
         if (ret != NULL) {
-            ret->name = NULL;
+            ret->cppobj = NULL;
             try {
-                ret->name = new Name(self->name->split(n));
+                ret->cppobj = new Name(self->cppobj->split(n));
             } catch(const isc::OutOfRange& oor) {
                 PyErr_SetString(PyExc_IndexError, oor.what());
-                ret->name = NULL;
+                ret->cppobj = NULL;
             }
-            if (ret->name == NULL) {
+            if (ret->cppobj == NULL) {
                 Py_DECREF(ret);
                 return (NULL);
             }
         }
     }
+
+    PyErr_Clear();
+    PyErr_SetString(PyExc_TypeError,
+                    "No valid type in split argument");
     return (ret);
 }
-#include <iostream>
 
 //
 // richcmp defines the ==, !=, >, <, >= and <= operators in python
 // It is translated to a function that gets 3 arguments, an object,
 // an object to compare to, and an operator.
 //
-static PyObject* 
+PyObject*
 Name_richcmp(s_Name* self, s_Name* other, int op) {
     bool c;
 
@@ -514,22 +418,22 @@ Name_richcmp(s_Name* self, s_Name* other, int op) {
 
     switch (op) {
     case Py_LT:
-        c = *self->name < *other->name;
+        c = *self->cppobj < *other->cppobj;
         break;
     case Py_LE:
-        c = *self->name <= *other->name;
+        c = *self->cppobj <= *other->cppobj;
         break;
     case Py_EQ:
-        c = *self->name == *other->name;
+        c = *self->cppobj == *other->cppobj;
         break;
     case Py_NE:
-        c = *self->name != *other->name;
+        c = *self->cppobj != *other->cppobj;
         break;
     case Py_GT:
-        c = *self->name > *other->name;
+        c = *self->cppobj > *other->cppobj;
         break;
     case Py_GE:
-        c = *self->name >= *other->name;
+        c = *self->cppobj >= *other->cppobj;
         break;
     default:
         PyErr_SetString(PyExc_IndexError,
@@ -543,13 +447,13 @@ Name_richcmp(s_Name* self, s_Name* other, int op) {
     }
 }
 
-static PyObject*
+PyObject*
 Name_reverse(s_Name* self) {
     s_Name* ret = PyObject_New(s_Name, &name_type);
 
     if (ret != NULL) {
-        ret->name = new Name(self->name->reverse());
-        if (ret->name == NULL) {
+        ret->cppobj = new Name(self->cppobj->reverse());
+        if (ret->cppobj == NULL) {
             Py_DECREF(ret);
             return (NULL);
         }
@@ -557,7 +461,7 @@ Name_reverse(s_Name* self) {
     return (ret);
 }
 
-static PyObject*
+PyObject*
 Name_concatenate(s_Name* self, PyObject* args) {
     s_Name* other;
 
@@ -567,7 +471,7 @@ Name_concatenate(s_Name* self, PyObject* args) {
     s_Name* ret = PyObject_New(s_Name, &name_type);
     if (ret != NULL) {
         try {
-            ret->name = new Name(self->name->concatenate(*other->name));
+            ret->cppobj = new Name(self->cppobj->concatenate(*other->cppobj));
         } catch (const TooLongName& tln) {
             PyErr_SetString(po_TooLongName, tln.what());
             return (NULL);
@@ -576,23 +480,159 @@ Name_concatenate(s_Name* self, PyObject* args) {
     return (ret);
 }
 
-static PyObject*
+PyObject*
 Name_downcase(s_Name* self) {
-    self->name->downcase();
+    self->cppobj->downcase();
     Py_INCREF(self);
     return (self);
 }
 
-static PyObject*
+PyObject*
 Name_isWildCard(s_Name* self) {
-    if (self->name->isWildcard()) {
+    if (self->cppobj->isWildcard()) {
         Py_RETURN_TRUE;
     } else {
         Py_RETURN_FALSE;
     }
 }
 // end of Name
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
 
+//
+// Definition of the custom exceptions
+// Initialization and addition of these go in the module init at the
+// end
+//
+PyObject* po_EmptyLabel;
+PyObject* po_TooLongName;
+PyObject* po_TooLongLabel;
+PyObject* po_BadLabelType;
+PyObject* po_BadEscape;
+PyObject* po_IncompleteName;
+PyObject* po_InvalidBufferPosition;
+PyObject* po_DNSMessageFORMERR;
+
+//
+// Definition of enums
+// Initialization and addition of these go in the module init at the
+// end
+//
+PyObject* po_NameRelation;
+
+PyTypeObject name_comparison_result_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.NameComparisonResult",
+    sizeof(s_NameComparisonResult),           // tp_basicsize
+    0,                                        // tp_itemsize
+    (destructor)NameComparisonResult_destroy, // tp_dealloc
+    NULL,                                     // tp_print
+    NULL,                                     // tp_getattr
+    NULL,                                     // tp_setattr
+    NULL,                                     // tp_reserved
+    NULL,                                     // tp_repr
+    NULL,                                     // tp_as_number
+    NULL,                                     // tp_as_sequence
+    NULL,                                     // tp_as_mapping
+    NULL,                                     // tp_hash
+    NULL,                                     // tp_call
+    NULL,                                     // tp_str
+    NULL,                                     // tp_getattro
+    NULL,                                     // tp_setattro
+    NULL,                                     // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                       // tp_flags
+    "This is a supplemental class used only as a return value of Name.compare(). "
+    "It encapsulate a tuple of the comparison: ordering, number of common labels, "
+    "and relationship as follows:\n"
+    "- ordering: relative ordering under the DNSSEC order relation\n"
+    "- labels: the number of common significant labels of the two names being"
+    "  compared\n"
+    "- relationship: see NameComparisonResult.NameRelation\n",
+    NULL,                                     // tp_traverse
+    NULL,                                     // tp_clear
+    NULL,                                     // tp_richcompare
+    0,                                        // tp_weaklistoffset
+    NULL,                                     // tp_iter
+    NULL,                                     // tp_iternext
+    NameComparisonResult_methods,             // tp_methods
+    NULL,                                     // tp_members
+    NULL,                                     // tp_getset
+    NULL,                                     // tp_base
+    NULL,                                     // tp_dict
+    NULL,                                     // tp_descr_get
+    NULL,                                     // tp_descr_set
+    0,                                        // tp_dictoffset
+    (initproc)NameComparisonResult_init,      // tp_init
+    NULL,                                     // tp_alloc
+    PyType_GenericNew,                        // tp_new
+    NULL,                                     // tp_free
+    NULL,                                     // tp_is_gc
+    NULL,                                     // tp_bases
+    NULL,                                     // tp_mro
+    NULL,                                     // tp_cache
+    NULL,                                     // tp_subclasses
+    NULL,                                     // tp_weaklist
+    NULL,                                     // tp_del
+    0                                         // tp_version_tag
+};
+
+PyTypeObject name_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.Name",
+    sizeof(s_Name),                     // tp_basicsize
+    0,                                  // tp_itemsize
+    (destructor)Name_destroy,           // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    Name_str,                           // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The Name class encapsulates DNS names.\n"
+    "It provides interfaces to construct a name from string or wire-format data, "
+    "transform a name into a string or wire-format data, compare two names, get "
+    "access to various properties of a name, etc.",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    (richcmpfunc)Name_richcmp,          // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    Name_methods,                       // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    (initproc)Name_init,                // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    // Note: not sure if the following are correct.  Added them just to
+    // make the compiler happy.
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
 
 // Module Initialization, all statics are initialized here
 bool
@@ -638,7 +678,7 @@ initModulePart_Name(PyObject* mod) {
     addClassVariable(name_type, "COMPRESS_POINTER_MARK16", Py_BuildValue("I", Name::COMPRESS_POINTER_MARK16));
 
     s_Name* root_name = PyObject_New(s_Name, &name_type);
-    root_name->name = new Name(Name::ROOT_NAME());
+    root_name->cppobj = new Name(Name::ROOT_NAME());
     PyObject* po_ROOT_NAME = root_name;
     addClassVariable(name_type, "ROOT_NAME", po_ROOT_NAME);
 
@@ -675,3 +715,13 @@ initModulePart_Name(PyObject* mod) {
 
     return (true);
 }
+
+PyObject*
+createNameObject(const Name& source) {
+    NameContainer container = PyObject_New(s_Name, &name_type);
+    container.set(new Name(source));
+    return (container.release());
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/name_python.h b/src/lib/dns/python/name_python.h
new file mode 100644
index 0000000..f8e793d
--- /dev/null
+++ b/src/lib/dns/python/name_python.h
@@ -0,0 +1,84 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_NAME_H
+#define __PYTHON_NAME_H 1
+
+#include <Python.h>
+
+#include <util/python/pycppwrapper_util.h>
+
+namespace isc {
+namespace dns {
+class NameComparisonResult;
+class Name;
+
+namespace python {
+
+//
+// Declaration of the custom exceptions
+// Initialization and addition of these go in the module init at the
+// end
+//
+extern PyObject* po_EmptyLabel;
+extern PyObject* po_TooLongName;
+extern PyObject* po_TooLongLabel;
+extern PyObject* po_BadLabelType;
+extern PyObject* po_BadEscape;
+extern PyObject* po_IncompleteName;
+extern PyObject* po_InvalidBufferPosition;
+extern PyObject* po_DNSMessageFORMERR;
+
+//
+// Declaration of enums
+// Initialization and addition of these go in the module init at the
+// end
+//
+extern PyObject* po_NameRelation;
+
+// The s_* Class simply covers one instantiation of the object.
+class s_NameComparisonResult : public PyObject {
+public:
+    s_NameComparisonResult() : cppobj(NULL) {}
+    NameComparisonResult* cppobj;
+};
+
+class s_Name : public PyObject {
+public:
+    s_Name() : cppobj(NULL), position(0) {}
+    Name* cppobj;
+    size_t position;
+};
+
+extern PyTypeObject name_comparison_result_type;
+extern PyTypeObject name_type;
+
+bool initModulePart_Name(PyObject* mod);
+
+/// This is A simple shortcut to create a python Name object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called with in a try block
+/// followed by necessary setup for python exception.
+PyObject* createNameObject(const Name& source);
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_NAME_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 7b41598..07abf71 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -31,23 +31,38 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+
 #include <dns/exceptions.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 
-#include <dns/python/pydnspp_common.h>
-
+#include "pydnspp_common.h"
+#include "messagerenderer_python.h"
+#include "name_python.h"
+#include "rcode_python.h"
+#include "tsigkey_python.h"
+#include "tsig_rdata_python.h"
+#include "tsigerror_python.h"
+#include "tsigrecord_python.h"
+#include "tsig_python.h"
+
+namespace isc {
+namespace dns {
+namespace python {
 // For our 'general' isc::Exceptions
-static PyObject* po_IscException;
-static PyObject* po_InvalidParameter;
+PyObject* po_IscException;
+PyObject* po_InvalidParameter;
 
 // For our own isc::dns::Exception
-static PyObject* po_DNSMessageBADVERS;
+PyObject* po_DNSMessageBADVERS;
+}
+}
+}
 
 // order is important here!
-#include <dns/python/messagerenderer_python.cc>
-#include <dns/python/name_python.cc>           // needs Messagerenderer
+using namespace isc::dns::python;
+
 #include <dns/python/rrclass_python.cc>        // needs Messagerenderer
 #include <dns/python/rrtype_python.cc>         // needs Messagerenderer
 #include <dns/python/rrttl_python.cc>          // needs Messagerenderer
@@ -55,16 +70,15 @@ static PyObject* po_DNSMessageBADVERS;
 #include <dns/python/rrset_python.cc>          // needs Rdata, RRTTL
 #include <dns/python/question_python.cc>       // needs RRClass, RRType, RRTTL,
                                                // Name
-#include <dns/python/tsigkey_python.cc>        // needs Name
 #include <dns/python/opcode_python.cc>
-#include <dns/python/rcode_python.cc>
 #include <dns/python/edns_python.cc>           // needs Messagerenderer, Rcode
 #include <dns/python/message_python.cc>        // needs RRset, Question
 
 //
 // Definition of the module
 //
-static PyModuleDef pydnspp = {
+namespace {
+PyModuleDef pydnspp = {
     { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
     "pydnspp",
     "Python bindings for the classes in the isc::dns namespace.\n\n"
@@ -79,10 +93,11 @@ static PyModuleDef pydnspp = {
     NULL,
     NULL
 };
+}
 
 PyMODINIT_FUNC
 PyInit_pydnspp(void) {
-    PyObject *mod = PyModule_Create(&pydnspp);
+    PyObject* mod = PyModule_Create(&pydnspp);
     if (mod == NULL) {
         return (NULL);
     }
@@ -153,6 +168,21 @@ PyInit_pydnspp(void) {
         return (NULL);
     }
 
+    if (!initModulePart_TSIG(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_TSIGError(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_TSIGRecord(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_TSIGContext(mod)) {
+        return (NULL);
+    }
+
     return (mod);
 }
-
diff --git a/src/lib/dns/python/pydnspp_common.cc b/src/lib/dns/python/pydnspp_common.cc
index 6c26367..8ca763a 100644
--- a/src/lib/dns/python/pydnspp_common.cc
+++ b/src/lib/dns/python/pydnspp_common.cc
@@ -15,6 +15,9 @@
 #include <Python.h>
 #include <pydnspp_common.h>
 
+namespace isc {
+namespace dns {
+namespace python {
 int
 readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
     PyObject* el = NULL;
@@ -44,8 +47,15 @@ readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
 }
 
 
-void addClassVariable(PyTypeObject& c, const char* name,
-                      PyObject* obj)
-{
-    PyDict_SetItemString(c.tp_dict, name, obj);
+int
+addClassVariable(PyTypeObject& c, const char* name, PyObject* obj) {
+    if (obj == NULL) {
+        PyErr_SetString(PyExc_ValueError,
+                        "NULL object is specified for a class variable");
+        return (-1);
+    }
+    return (PyDict_SetItemString(c.tp_dict, name, obj));
+}
+}
+}
 }
diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h
index 32e2b78..ed90998 100644
--- a/src/lib/dns/python/pydnspp_common.h
+++ b/src/lib/dns/python/pydnspp_common.h
@@ -15,9 +15,22 @@
 #ifndef __LIBDNS_PYTHON_COMMON_H
 #define __LIBDNS_PYTHON_COMMON_H 1
 
-//
-// Shared functions for python/c API
-//
+#include <Python.h>
+
+#include <stdexcept>
+#include <string>
+
+#include <util/python/pycppwrapper_util.h>
+
+namespace isc {
+namespace dns {
+namespace python {
+// For our 'general' isc::Exceptions
+extern PyObject* po_IscException;
+extern PyObject* po_InvalidParameter;
+
+// For our own isc::dns::Exception
+extern PyObject* po_DNSMessageBADVERS;
 
 // This function reads 'bytes' from a sequence
 // This sequence can be anything that implements the Sequence interface,
@@ -31,6 +44,12 @@
 // case nothing is removed
 int readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence);
 
-void addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
-
+int addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
+} // namespace python
+} // namespace dns
+} // namespace isc
 #endif // __LIBDNS_PYTHON_COMMON_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/pydnspp_towire.h b/src/lib/dns/python/pydnspp_towire.h
new file mode 100644
index 0000000..66362a0
--- /dev/null
+++ b/src/lib/dns/python/pydnspp_towire.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LIBDNS_PYTHON_TOWIRE_H
+#define __LIBDNS_PYTHON_TOWIRE_H 1
+
+#include <Python.h>
+
+#include <stdexcept>
+#include <string>
+
+#include <dns/messagerenderer.h>
+
+#include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
+
+#include "messagerenderer_python.h"
+
+namespace isc {
+namespace dns {
+namespace python {
+
+// The following two templated structures are a helper to use the same
+// toWire() template implementation for two types of toWire() methods:
+// return an integer or have no return value.
+template <typename CPPCLASS>
+struct ToWireCallVoid {
+    ToWireCallVoid(CPPCLASS& cppobj) : cppobj_(cppobj) {}
+    int operator()(AbstractMessageRenderer& renderer) const {
+        cppobj_.toWire(renderer);
+        return (0);
+    }
+    const CPPCLASS& cppobj_;
+};
+
+template <typename CPPCLASS>
+struct ToWireCallInt {
+    ToWireCallInt(CPPCLASS& cppobj) : cppobj_(cppobj) {}
+    int operator()(AbstractMessageRenderer& renderer) const {
+        return (cppobj_.toWire(renderer));
+    }
+    const CPPCLASS& cppobj_;
+};
+
+// This templated function gives a common implementation of the toWire()
+// wrapper for various libdns++ classes.  PYSTRUCT and CPPCLASS are
+// (C++ binding of) python and (pure) C++ classes (e.g., s_Name and Name),
+// and TOWIRECALLER is either ToWireCallVoid<CPPCLASS> or
+// ToWireCallInt<CPPCLASS>, depending on the toWire() method of the class
+// returns a value or not.
+//
+// See, e.g., tsigrecord_python.cc for how to use it.
+//
+// This should be able to be used without modification for most classes that
+// have toWire().  But if the underlying toWire() has an extra argument, the
+// definition will need to be adjusted accordingly.
+template <typename PYSTRUCT, typename CPPCLASS, typename TOWIRECALLER>
+PyObject*
+toWireWrapper(const PYSTRUCT* const self, PyObject* args) {
+    try {
+        // To OutputBuffer version
+        PyObject* bytes; // this won't have own reference, no risk of leak.
+        if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
+            // render the object into a buffer (this can throw)
+            isc::util::OutputBuffer buffer(0);
+            self->cppobj->toWire(buffer);
+
+            // convert the rendered data into PyObject.  This could leak later,
+            // so we need to store it in a container.
+            PyObject* rd_bytes = PyBytes_FromStringAndSize(
+                static_cast<const char*>(buffer.getData()),
+                buffer.getLength());
+            isc::util::python::PyObjectContainer rd_bytes_container(rd_bytes);
+
+            // concat the latest data to the given existing sequence.  concat
+            // operation could fail, so we use a container to clean it up
+            // safely should that happen.
+            PyObject* result = PySequence_InPlaceConcat(bytes, rd_bytes);
+            isc::util::python::PyObjectContainer result_container(result);
+
+            return (result_container.release());
+        }
+
+        // To MessageRenderer version
+        s_MessageRenderer* renderer;
+        if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &renderer)) {
+            const unsigned int n = TOWIRECALLER(*self->cppobj)(
+                *renderer->messagerenderer);
+
+            return (Py_BuildValue("I", n));
+        }
+    } catch (const std::exception& ex) {
+        const std::string ex_what =
+            "Failed to render an libdns++ object wire-format: "
+            + std::string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpectedly failed to render an "
+                        "libdns++ object wire-format.");
+        return (NULL);
+    }
+
+    PyErr_Clear();
+    PyErr_SetString(PyExc_TypeError,
+                    "Incorrect arguments for a to_wire() method");
+    return (NULL);
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __LIBDNS_PYTHON_TOWIRE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/question_python.cc b/src/lib/dns/python/question_python.cc
index a039284..c702f85 100644
--- a/src/lib/dns/python/question_python.cc
+++ b/src/lib/dns/python/question_python.cc
@@ -144,7 +144,7 @@ Question_init(s_Question* self, PyObject* args) {
                                                &rrclass_type, &rrclass,
                                                &rrtype_type, &rrtype
            )) {
-            self->question = QuestionPtr(new Question(*name->name, *rrclass->rrclass,
+            self->question = QuestionPtr(new Question(*name->cppobj, *rrclass->rrclass,
                                           *rrtype->rrtype));
             return (0);
         } else if (PyArg_ParseTuple(args, "y#|I", &b, &len, &position)) {
@@ -169,7 +169,7 @@ Question_init(s_Question* self, PyObject* args) {
     }
 
     self->question = QuestionPtr();
-    
+
     PyErr_Clear();
     PyErr_SetString(PyExc_TypeError,
                     "no valid type in constructor argument");
@@ -189,7 +189,7 @@ Question_getName(s_Question* self) {
     // is this the best way to do this?
     name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
     if (name != NULL) {
-        name->name = new Name(self->question->getName());
+        name->cppobj = new Name(self->question->getName());
     }
 
     return (name);
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
index fce8eef..b594ad3 100644
--- a/src/lib/dns/python/rcode_python.cc
+++ b/src/lib/dns/python/rcode_python.cc
@@ -12,9 +12,17 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <Python.h>
+
+#include <exceptions/exceptions.h>
+
 #include <dns/rcode.h>
 
+#include "pydnspp_common.h"
+#include "rcode_python.h"
+
 using namespace isc::dns;
+using namespace isc::dns::python;
 
 //
 // Declaration of the custom exceptions (None for this class)
@@ -27,25 +35,14 @@ using namespace isc::dns;
 // and static wrappers around the methods we export), a list of methods,
 // and a type description
 
-namespace {
 //
 // Rcode
 //
 
-// We added a helper variable static_code here
-// Since we can create Rcodes dynamically with Rcode(int), but also
-// use the static globals (Rcode::NOERROR() etc), we use this
-// variable to see if the code came from one of the latter, in which
-// case Rcode_destroy should not free it (the other option is to
-// allocate new Rcodes for every use of the static ones, but this
-// seems more efficient).
-class s_Rcode : public PyObject {
-public:
-    s_Rcode() : rcode(NULL), static_code(false) {}
-    const Rcode* rcode;
-    bool static_code;
-};
+// Trivial constructor.
+s_Rcode::s_Rcode() : cppobj(NULL), static_code(false) {}
 
+namespace {
 int Rcode_init(s_Rcode* const self, PyObject* args);
 void Rcode_destroy(s_Rcode* const self);
 
@@ -118,71 +115,20 @@ PyMethodDef Rcode_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-PyTypeObject rcode_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "pydnspp.Rcode",
-    sizeof(s_Rcode),                    // tp_basicsize
-    0,                                  // tp_itemsize
-    (destructor)Rcode_destroy,          // tp_dealloc
-    NULL,                               // tp_print
-    NULL,                               // tp_getattr
-    NULL,                               // tp_setattr
-    NULL,                               // tp_reserved
-    NULL,                               // tp_repr
-    NULL,                               // tp_as_number
-    NULL,                               // tp_as_sequence
-    NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
-    NULL,                               // tp_call
-    Rcode_str,                          // tp_str
-    NULL,                               // tp_getattro
-    NULL,                               // tp_setattro
-    NULL,                               // tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                 // tp_flags
-    "The Rcode class objects represent standard RCODEs"
-    "of the header section of DNS messages.",
-    NULL,                               // tp_traverse
-    NULL,                               // tp_clear
-    (richcmpfunc)Rcode_richcmp,         // tp_richcompare
-    0,                                  // tp_weaklistoffset
-    NULL,                               // tp_iter
-    NULL,                               // tp_iternext
-    Rcode_methods,                      // tp_methods
-    NULL,                               // tp_members
-    NULL,                               // tp_getset
-    NULL,                               // tp_base
-    NULL,                               // tp_dict
-    NULL,                               // tp_descr_get
-    NULL,                               // tp_descr_set
-    0,                                  // tp_dictoffset
-    (initproc)Rcode_init,               // tp_init
-    NULL,                               // tp_alloc
-    PyType_GenericNew,                  // tp_new
-    NULL,                               // tp_free
-    NULL,                               // tp_is_gc
-    NULL,                               // tp_bases
-    NULL,                               // tp_mro
-    NULL,                               // tp_cache
-    NULL,                               // tp_subclasses
-    NULL,                               // tp_weaklist
-    NULL,                               // tp_del
-    0                                   // tp_version_tag
-};
-
 int
 Rcode_init(s_Rcode* const self, PyObject* args) {
-    int code = 0;
+    long code = 0;
     int ext_code = 0;
 
-    if (PyArg_ParseTuple(args, "i", &code)) {
+    if (PyArg_ParseTuple(args, "l", &code)) {
         if (code < 0 || code > 0xffff) {
-            PyErr_SetString(PyExc_OverflowError, "Rcode out of range");
+            PyErr_SetString(PyExc_ValueError, "Rcode out of range");
             return (-1);
         }
         ext_code = -1;
-    } else if (PyArg_ParseTuple(args, "ii", &code, &ext_code)) {
+    } else if (PyArg_ParseTuple(args, "li", &code, &ext_code)) {
         if (code < 0 || code > 0xff || ext_code < 0 || ext_code > 0xff) {
-            PyErr_SetString(PyExc_OverflowError, "Rcode out of range");
+            PyErr_SetString(PyExc_ValueError, "Rcode out of range");
             return (-1);
         }
     } else {
@@ -193,9 +139,9 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
     }
     try {
         if (ext_code == -1) {
-            self->rcode = new Rcode(code);
+            self->cppobj = new Rcode(code);
         } else {
-            self->rcode = new Rcode(code, ext_code);
+            self->cppobj = new Rcode(code, ext_code);
         }
         self->static_code = false;
     } catch (const isc::OutOfRange& ex) {
@@ -211,27 +157,27 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
 void
 Rcode_destroy(s_Rcode* const self) {
     // Depending on whether we created the rcode or are referring
-    // to a global one, we do or do not delete self->rcode here
+    // to a global one, we do or do not delete self->cppobj here
     if (!self->static_code) {
-        delete self->rcode;
+        delete self->cppobj;
     }
-    self->rcode = NULL;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 Rcode_getCode(const s_Rcode* const self) {
-    return (Py_BuildValue("I", self->rcode->getCode()));
+    return (Py_BuildValue("I", self->cppobj->getCode()));
 }
 
 PyObject*
 Rcode_getExtendedCode(const s_Rcode* const self) {
-    return (Py_BuildValue("I", self->rcode->getExtendedCode()));
+    return (Py_BuildValue("I", self->cppobj->getExtendedCode()));
 }
 
 PyObject*
 Rcode_toText(const s_Rcode* const self) {
-    return (Py_BuildValue("s", self->rcode->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 PyObject*
@@ -245,7 +191,7 @@ PyObject*
 Rcode_createStatic(const Rcode& rcode) {
     s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
     if (ret != NULL) {
-        ret->rcode = &rcode;
+        ret->cppobj = &rcode;
         ret->static_code = true;
     }
     return (ret);
@@ -357,10 +303,10 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
         PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
         return (NULL);
     case Py_EQ:
-        c = (*self->rcode == *other->rcode);
+        c = (*self->cppobj == *other->cppobj);
         break;
     case Py_NE:
-        c = (*self->rcode != *other->rcode);
+        c = (*self->cppobj != *other->cppobj);
         break;
     case Py_GT:
         PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
@@ -374,6 +320,61 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
     else
         Py_RETURN_FALSE;
 }
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+PyTypeObject rcode_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.Rcode",
+    sizeof(s_Rcode),                    // tp_basicsize
+    0,                                  // tp_itemsize
+    (destructor)Rcode_destroy,          // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    Rcode_str,                          // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The Rcode class objects represent standard RCODEs"
+    "of the header section of DNS messages.",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    reinterpret_cast<richcmpfunc>(Rcode_richcmp),         // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    Rcode_methods,                      // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    (initproc)Rcode_init,               // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
 
 // Module Initialization, all statics are initialized here
 bool
@@ -428,4 +429,6 @@ initModulePart_Rcode(PyObject* mod) {
 
     return (true);
 }
-} // end of unnamed namespace
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/rcode_python.h b/src/lib/dns/python/rcode_python.h
new file mode 100644
index 0000000..9b5e699
--- /dev/null
+++ b/src/lib/dns/python/rcode_python.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_RCODE_H
+#define __PYTHON_RCODE_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class Rcode;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object.
+//
+// We added a helper variable static_code here
+// Since we can create Rcodes dynamically with Rcode(int), but also
+// use the static globals (Rcode::NOERROR() etc), we use this
+// variable to see if the code came from one of the latter, in which
+// case Rcode_destroy should not free it (the other option is to
+// allocate new Rcodes for every use of the static ones, but this
+// seems more efficient).
+//
+// Follow-up note: we don't have to use the proxy function in the python lib;
+// we can just define class specific constants directly (see TSIGError).
+// We should make this cleanup later.
+class s_Rcode : public PyObject {
+public:
+    s_Rcode();
+    const Rcode* cppobj;
+    bool static_code;
+};
+
+extern PyTypeObject rcode_type;
+
+bool initModulePart_Rcode(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_RCODE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/rdata_python.cc b/src/lib/dns/python/rdata_python.cc
index 8579b7e..faa4f4c 100644
--- a/src/lib/dns/python/rdata_python.cc
+++ b/src/lib/dns/python/rdata_python.cc
@@ -14,6 +14,7 @@
 
 #include <dns/rdata.h>
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 //
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index 3cfed4c..6d150c2 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -14,6 +14,7 @@
 
 #include <dns/rrclass.h>
 using namespace isc::dns;
+using namespace isc::util;
 
 //
 // Declaration of the custom exceptions
@@ -152,7 +153,7 @@ static PyTypeObject rrclass_type = {
 static int
 RRClass_init(s_RRClass* self, PyObject* args) {
     const char* s;
-    unsigned int i;
+    long i;
     PyObject* bytes = NULL;
     // The constructor argument can be a string ("IN"), an integer (1),
     // or a sequence of numbers between 0 and 65535 (wire code)
@@ -165,10 +166,11 @@ RRClass_init(s_RRClass* self, PyObject* args) {
         if (PyArg_ParseTuple(args, "s", &s)) {
             self->rrclass = new RRClass(s);
             return (0);
-        } else if (PyArg_ParseTuple(args, "I", &i)) {
-            PyErr_Clear();
-            if (i > 65535) {
-                PyErr_SetString(po_InvalidRRClass, "RR class number too high");
+        } else if (PyArg_ParseTuple(args, "l", &i)) {
+            if (i < 0 || i > 0xffff) {
+                PyErr_Clear();
+                PyErr_SetString(PyExc_ValueError,
+                                "RR class number out of range");
                 return (-1);
             }
             self->rrclass = new RRClass(i);
diff --git a/src/lib/dns/python/rrset_python.cc b/src/lib/dns/python/rrset_python.cc
index 2292784..71a0710 100644
--- a/src/lib/dns/python/rrset_python.cc
+++ b/src/lib/dns/python/rrset_python.cc
@@ -29,6 +29,7 @@ static PyObject* po_EmptyRRset;
 // and static wrappers around the methods we export), a list of methods,
 // and a type description
 using namespace isc::dns;
+using namespace isc::util;
 
 // RRset
 
@@ -167,7 +168,7 @@ RRset_init(s_RRset* self, PyObject* args) {
                                            &rrtype_type, &rrtype,
                                            &rrttl_type, &rrttl
        )) {
-        self->rrset = RRsetPtr(new RRset(*name->name, *rrclass->rrclass,
+        self->rrset = RRsetPtr(new RRset(*name->cppobj, *rrclass->rrclass,
                                 *rrtype->rrtype, *rrttl->rrttl));
         return (0);
     }
@@ -196,8 +197,8 @@ RRset_getName(s_RRset* self) {
     // is this the best way to do this?
     name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
     if (name != NULL) {
-        name->name = new Name(self->rrset->getName());
-        if (name->name == NULL)
+        name->cppobj = new Name(self->rrset->getName());
+        if (name->cppobj == NULL)
           {
             Py_DECREF(name);
             return (NULL);
@@ -264,7 +265,7 @@ RRset_setName(s_RRset* self, PyObject* args) {
     if (!PyArg_ParseTuple(args, "O!", &name_type, &name)) {
         return (NULL);
     }
-    self->rrset->setName(*name->name);
+    self->rrset->setName(*name->cppobj);
     Py_RETURN_NONE;
 }
 
diff --git a/src/lib/dns/python/rrttl_python.cc b/src/lib/dns/python/rrttl_python.cc
index e7391d0..c4b25bf 100644
--- a/src/lib/dns/python/rrttl_python.cc
+++ b/src/lib/dns/python/rrttl_python.cc
@@ -18,6 +18,7 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 //
 // Declaration of the custom exceptions
@@ -145,7 +146,7 @@ static PyTypeObject rrttl_type = {
 static int
 RRTTL_init(s_RRTTL* self, PyObject* args) {
     const char* s;
-    unsigned long i;
+    long long i;
     PyObject* bytes = NULL;
     // The constructor argument can be a string ("1234"), an integer (1),
     // or a sequence of numbers between 0 and 255 (wire code)
@@ -158,8 +159,12 @@ RRTTL_init(s_RRTTL* self, PyObject* args) {
         if (PyArg_ParseTuple(args, "s", &s)) {
             self->rrttl = new RRTTL(s);
             return (0);
-        } else if (PyArg_ParseTuple(args, "I", &i)) {
+        } else if (PyArg_ParseTuple(args, "L", &i)) {
             PyErr_Clear();
+            if (i < 0 || i > 0xffffffff) {
+                PyErr_SetString(PyExc_ValueError, "RR TTL number out of range");
+                return (-1);
+            }
             self->rrttl = new RRTTL(i);
             return (0);
         } else if (PyArg_ParseTuple(args, "O", &bytes) &&
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index 012f251..00e0acd 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -18,6 +18,7 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 //
 // Declaration of the custom exceptions
@@ -182,7 +183,7 @@ static PyTypeObject rrtype_type = {
 static int
 RRType_init(s_RRType* self, PyObject* args) {
     const char* s;
-    unsigned int i;
+    long i;
     PyObject* bytes = NULL;
     // The constructor argument can be a string ("A"), an integer (1),
     // or a sequence of numbers between 0 and 65535 (wire code)
@@ -195,10 +196,10 @@ RRType_init(s_RRType* self, PyObject* args) {
         if (PyArg_ParseTuple(args, "s", &s)) {
             self->rrtype = new RRType(s);
             return (0);
-        } else if (PyArg_ParseTuple(args, "I", &i)) {
+        } else if (PyArg_ParseTuple(args, "l", &i)) {
             PyErr_Clear();
-            if (i > 65535) {
-                PyErr_SetString(po_InvalidRRType, "RR Type number too high");
+            if (i < 0 || i > 0xffff) {
+                PyErr_SetString(PyExc_ValueError, "RR Type number out of range");
                 return (-1);
             }
             self->rrtype = new RRType(i);
@@ -259,10 +260,10 @@ static PyObject*
 RRType_toWire(s_RRType* self, PyObject* args) {
     PyObject* bytes;
     s_MessageRenderer* mr;
-    
+
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
-        
+
         OutputBuffer buffer(2);
         self->rrtype->toWire(buffer);
         PyObject* n = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()), buffer.getLength());
diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am
index 7f3c213..eb0c136 100644
--- a/src/lib/dns/python/tests/Makefile.am
+++ b/src/lib/dns/python/tests/Makefile.am
@@ -11,7 +11,11 @@ PYTESTS += rrclass_python_test.py
 PYTESTS += rrset_python_test.py
 PYTESTS += rrttl_python_test.py
 PYTESTS += rrtype_python_test.py
+PYTESTS += tsig_python_test.py
+PYTESTS += tsig_rdata_python_test.py
+PYTESTS += tsigerror_python_test.py
 PYTESTS += tsigkey_python_test.py
+PYTESTS += tsigrecord_python_test.py
 
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST += testutil.py
@@ -20,7 +24,7 @@ EXTRA_DIST += testutil.py
 # required by loadable python modules.
 LIBRARY_PATH_PLACEHOLDER =
 if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
 # test using command-line arguments, so use check-local target instead of TESTS
@@ -32,7 +36,7 @@ if ENABLE_PYTHON_COVERAGE
 endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/dns/.libs:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
+	env PYTHONPATH=$(abs_top_builddir)/src/lib/util/pyunittests/.libs:$(abs_top_srcdir)/src/lib/dns/.libs:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	TESTDATA_PATH=$(abs_top_srcdir)/src/lib/dns/tests/testdata:$(abs_top_builddir)/src/lib/dns/tests/testdata \
 	$(LIBRARY_PATH_PLACEHOLDER) \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
diff --git a/src/lib/dns/python/tests/edns_python_test.py b/src/lib/dns/python/tests/edns_python_test.py
index 3f03c90..b249213 100644
--- a/src/lib/dns/python/tests/edns_python_test.py
+++ b/src/lib/dns/python/tests/edns_python_test.py
@@ -62,17 +62,16 @@ class EDNSTest(unittest.TestCase):
         edns = EDNS()
         edns.set_udp_size(511)
         self.assertEqual(511, edns.get_udp_size())
-        edns.set_udp_size(0)
-        self.assertEqual(0, edns.get_udp_size())
-        edns.set_udp_size(65535)
-        self.assertEqual(65535, edns.get_udp_size())
-
         self.assertRaises(TypeError, edns.set_udp_size, "wrong")
 
         # Range check.  We need to do this at the binding level, so we need
         # explicit tests for it.
-        self.assertRaises(OverflowError, edns.set_udp_size, 65536)
-        self.assertRaises(OverflowError, edns.set_udp_size, -1)
+        edns.set_udp_size(0)
+        self.assertEqual(0, edns.get_udp_size())
+        edns.set_udp_size(65535)
+        self.assertEqual(65535, edns.get_udp_size())
+        self.assertRaises(ValueError, edns.set_udp_size, 0x10000)
+        self.assertRaises(ValueError, edns.set_udp_size, -1)
 
     def test_get_version(self):
         self.assertEqual(EDNS.SUPPORTED_VERSION, EDNS().get_version())
diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py
index 6ef42d4..41b9a67 100644
--- a/src/lib/dns/python/tests/message_python_test.py
+++ b/src/lib/dns/python/tests/message_python_test.py
@@ -62,6 +62,12 @@ def create_message():
     message_render.add_rrset(Message.SECTION_ANSWER, rrset)
     return message_render
 
+def strip_mutable_tsig_data(data):
+    # Unfortunately we cannot easily compare TSIG RR because we can't tweak
+    # current time.  As a work around this helper function strips off the time
+    # dependent part of TSIG RDATA, i.e., the MAC (assuming HMAC-MD5) and
+    # Time Signed.
+    return data[0:-32] + data[-26:-22] + data[-6:]
 
 class MessageTest(unittest.TestCase):
 
@@ -80,8 +86,12 @@ class MessageTest(unittest.TestCase):
                                         "2001:db8::134"))
 
         self.bogus_section = Message.SECTION_ADDITIONAL + 1
+        self.bogus_below_section = Message.SECTION_QUESTION - 1
+        self.tsig_key = TSIGKey("www.example.com:SFuWd/q99SzF8Yzd1QbB9g==")
+        self.tsig_ctx = TSIGContext(self.tsig_key)
 
     def test_init(self):
+        self.assertRaises(TypeError, Message, -1)
         self.assertRaises(TypeError, Message, 3)
         self.assertRaises(TypeError, Message, "wrong")
 
@@ -109,22 +119,28 @@ class MessageTest(unittest.TestCase):
         self.assertRaises(InvalidParameter, self.r.set_header_flag, 0)
         self.assertRaises(InvalidParameter, self.r.set_header_flag, 0x7000)
         self.assertRaises(InvalidParameter, self.r.set_header_flag, 0x0800)
-        self.assertRaises(InvalidParameter, self.r.set_header_flag, 0x10000)
-        self.assertRaises(TypeError, self.r.set_header_flag, 0x80000000)
-        # this would cause overflow and result in a "valid" flag
-        self.assertRaises(TypeError, self.r.set_header_flag,
-                          Message.HEADERFLAG_AA | 0x100000000)
-        self.assertRaises(TypeError, self.r.set_header_flag, -1)
-
         self.assertRaises(InvalidMessageOperation,
                           self.p.set_header_flag, Message.HEADERFLAG_AA)
 
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertRaises(ValueError, self.r.set_header_flag, 0x10000)
+        self.assertRaises(ValueError, self.r.set_header_flag, -1)
+
     def test_set_qid(self):
         self.assertRaises(TypeError, self.r.set_qid, "wrong")
         self.assertRaises(InvalidMessageOperation,
                           self.p.set_qid, 123)
         self.r.set_qid(1234)
         self.assertEqual(1234, self.r.get_qid())
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.r.set_qid(0)
+        self.assertEqual(0, self.r.get_qid())
+        self.r.set_qid(0xffff)
+        self.assertEqual(0xffff, self.r.get_qid())
+        self.assertRaises(ValueError, self.r.set_qid, -1)
+        self.assertRaises(ValueError, self.r.set_qid, 0x10000)
 
     def test_set_rcode(self):
         self.assertRaises(TypeError, self.r.set_rcode, "wrong")
@@ -135,7 +151,7 @@ class MessageTest(unittest.TestCase):
 
         self.assertRaises(InvalidMessageOperation,
                           self.p.set_rcode, rcode)
-        
+
         self.assertRaises(InvalidMessageOperation, self.p.get_rcode)
 
     def test_set_opcode(self):
@@ -197,7 +213,7 @@ class MessageTest(unittest.TestCase):
 
         self.assertRaises(InvalidMessageOperation, self.p.add_rrset,
                           Message.SECTION_ANSWER, self.rrset_a)
-        
+
         self.assertFalse(compare_rrset_list(section_rrset, self.r.get_section(Message.SECTION_ANSWER)))
         self.assertEqual(0, self.r.get_rr_count(Message.SECTION_ANSWER))
         self.r.add_rrset(Message.SECTION_ANSWER, self.rrset_a)
@@ -239,6 +255,8 @@ class MessageTest(unittest.TestCase):
                           Message.SECTION_ANSWER, self.rrset_a)
         self.assertRaises(OverflowError, self.r.add_rrset,
                           self.bogus_section, self.rrset_a)
+        self.assertRaises(OverflowError, self.r.add_rrset,
+                          self.bogus_below_section, self.rrset_a)
 
     def test_clear(self):
         self.assertEqual(None, self.r.clear(Message.PARSE))
@@ -267,12 +285,39 @@ class MessageTest(unittest.TestCase):
         self.assertRaises(InvalidMessageOperation, self.r.to_wire,
                           MessageRenderer())
 
+    def __common_tsigquery_setup(self):
+        self.r.set_opcode(Opcode.QUERY())
+        self.r.set_rcode(Rcode.NOERROR())
+        self.r.set_header_flag(Message.HEADERFLAG_RD)
+        self.r.add_question(Question(Name("www.example.com"),
+                                     RRClass("IN"), RRType("A")))
+
+    def __common_tsig_checks(self, expected_file):
+        renderer = MessageRenderer()
+        self.r.to_wire(renderer, self.tsig_ctx)
+        actual_wire = strip_mutable_tsig_data(renderer.get_data())
+        expected_wire = strip_mutable_tsig_data(read_wire_data(expected_file))
+        self.assertEqual(expected_wire, actual_wire)
+
+    def test_to_wire_with_tsig(self):
+        self.r.set_qid(0x2d65)
+        self.__common_tsigquery_setup()
+        self.__common_tsig_checks("message_toWire2.wire")
+
+    def test_to_wire_with_edns_tsig(self):
+        self.r.set_qid(0x6cd)
+        self.__common_tsigquery_setup()
+        edns = EDNS()
+        edns.set_udp_size(4096)
+        self.r.set_edns(edns)
+        self.__common_tsig_checks("message_toWire3.wire")
+
     def test_to_text(self):
         message_render = create_message()
         
         msg_str =\
 """;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4149
-;; flags: qr aa rd ; QUESTION: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
+;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
 
 ;; QUESTION SECTION:
 ;test.example.com. IN A
@@ -377,7 +422,54 @@ test.example.com. 3600 IN A 192.0.2.2
                           factoryFromFile,
                           message_parse,
                           "message_fromWire9")
-    
+
+    def test_from_wire_with_tsig(self):
+        # Initially there should be no TSIG
+        self.assertEqual(None, self.p.get_tsig_record())
+
+        # getTSIGRecord() is only valid in the parse mode.
+        self.assertRaises(InvalidMessageOperation, self.r.get_tsig_record)
+
+        factoryFromFile(self.p, "message_toWire2.wire")
+        tsig_rr = self.p.get_tsig_record()
+        self.assertEqual(Name("www.example.com"), tsig_rr.get_name())
+        self.assertEqual(85, tsig_rr.get_length())
+        self.assertEqual(TSIGKey.HMACMD5_NAME,
+                         tsig_rr.get_rdata().get_algorithm())
+
+        # If we clear the message for reuse, the recorded TSIG will be cleared.
+        self.p.clear(Message.PARSE)
+        self.assertEqual(None, self.p.get_tsig_record())
+
+    def test_from_wire_with_tsigcompressed(self):
+        # Mostly same as fromWireWithTSIG, but the TSIG owner name is
+        # compressed.
+        factoryFromFile(self.p, "message_fromWire12.wire");
+        tsig_rr = self.p.get_tsig_record()
+        self.assertEqual(Name("www.example.com"), tsig_rr.get_name())
+        # len(www.example.com) = 17, but when fully compressed, the length is
+        # 2 bytes.  So the length of the record should be 15 bytes shorter.
+        self.assertEqual(70, tsig_rr.get_length())
+
+    def test_from_wire_with_badtsig(self):
+        # Multiple TSIG RRs
+        self.assertRaises(DNSMessageFORMERR, factoryFromFile,
+                          self.p, "message_fromWire13.wire")
+        self.p.clear(Message.PARSE)
+
+        # TSIG in the answer section (must be in additional)
+        self.assertRaises(DNSMessageFORMERR, factoryFromFile,
+                          self.p, "message_fromWire14.wire")
+        self.p.clear(Message.PARSE)
+
+        # TSIG is not the last record.
+        self.assertRaises(DNSMessageFORMERR, factoryFromFile,
+                          self.p, "message_fromWire15.wire")
+        self.p.clear(Message.PARSE)
+
+        # Unexpected RR Class (this will fail in constructing TSIGRecord)
+        self.assertRaises(DNSMessageFORMERR, factoryFromFile,
+                          self.p, "message_fromWire16.wire")
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/messagerenderer_python_test.py b/src/lib/dns/python/tests/messagerenderer_python_test.py
index 544ad23..5362496 100644
--- a/src/lib/dns/python/tests/messagerenderer_python_test.py
+++ b/src/lib/dns/python/tests/messagerenderer_python_test.py
@@ -98,6 +98,11 @@ class MessageRendererTest(unittest.TestCase):
         renderer.set_length_limit(1024)
         self.assertEqual(1024, renderer.get_length_limit())
         self.assertRaises(TypeError, renderer.set_length_limit, "wrong")
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        renderer.set_length_limit(0)
+        self.assertEqual(0, renderer.get_length_limit())
+        self.assertRaises(ValueError, renderer.set_length_limit, -1)
 
     def test_messagerenderer_set_compress_mode(self):
         renderer = MessageRenderer()
diff --git a/src/lib/dns/python/tests/name_python_test.py b/src/lib/dns/python/tests/name_python_test.py
index 81060e9..b8e625a 100644
--- a/src/lib/dns/python/tests/name_python_test.py
+++ b/src/lib/dns/python/tests/name_python_test.py
@@ -95,11 +95,14 @@ class NameTest(unittest.TestCase):
         b = bytearray()
         b += b'\x07example'*32 + b'\x03com\x00'
         self.assertRaises(DNSMessageFORMERR, Name, b, 0)
+        self.assertRaises(IndexError, Name, b, -1)
 
     def test_at(self):
         self.assertEqual(7, self.name1.at(0))
         self.assertEqual(101, self.name1.at(1))
         self.assertRaises(IndexError, self.name1.at, 100)
+        self.assertRaises(IndexError, self.name1.at, 0x10000)
+        self.assertRaises(IndexError, self.name1.at, -1)
         self.assertRaises(TypeError, self.name1.at, "wrong")
 
     def test_get_length(self):
@@ -151,14 +154,25 @@ class NameTest(unittest.TestCase):
         self.assertEqual("completely.different.", s.to_text())
         self.assertRaises(TypeError, self.name1.split, "wrong", 1)
         self.assertRaises(TypeError, self.name1.split, 1, "wrong")
-        self.assertRaises(IndexError, self.name1.split, 123, 1)
-        self.assertRaises(IndexError, self.name1.split, 1, 123)
 
         s = self.name1.split(1)
         self.assertEqual("com.", s.to_text())
+
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertRaises(IndexError, self.name1.split, 123, 1)
+        self.assertRaises(IndexError, self.name1.split, 1, 123)
+        self.assertRaises(IndexError, self.name1.split, 0x10000, 5)
+        self.assertRaises(IndexError, self.name1.split, -1, -1)
+        self.assertRaises(IndexError, self.name1.split, 0, -1)
+        self.assertRaises(IndexError, self.name1.split, -1, 0x10000)
+
         s = self.name1.split(0)
         self.assertEqual("example.com.", s.to_text())
         self.assertRaises(IndexError, self.name1.split, 123)
+        self.assertRaises(IndexError, self.name1.split, 0x10000)
+        self.assertRaises(IndexError, self.name1.split, -123)
+        self.assertRaises(TypeError, self.name1.split, -1)
 
     def test_reverse(self):
         self.assertEqual("com.example.", self.name1.reverse().to_text())
@@ -169,7 +183,6 @@ class NameTest(unittest.TestCase):
         self.assertEqual("example.com.example.com.", self.name1.concatenate(self.name1).to_text())
         self.assertRaises(TypeError, self.name1.concatenate, "wrong")
         self.assertRaises(TooLongName, self.name1.concatenate, Name("example."*31))
-        
 
     def test_downcase(self):
         self.assertEqual("EXAMPLE.com.", self.name4.to_text())
diff --git a/src/lib/dns/python/tests/question_python_test.py b/src/lib/dns/python/tests/question_python_test.py
index 6c4db4b..69e3051 100644
--- a/src/lib/dns/python/tests/question_python_test.py
+++ b/src/lib/dns/python/tests/question_python_test.py
@@ -45,7 +45,7 @@ class QuestionTest(unittest.TestCase):
     # tests below based on cpp unit tests
     # also tests get_name, get_class and get_type
     def test_from_wire(self):
-        
+
         q = question_from_wire("question_fromWire")
 
         self.assertEqual(self.example_name1, q.get_name())
diff --git a/src/lib/dns/python/tests/rcode_python_test.py b/src/lib/dns/python/tests/rcode_python_test.py
index 3577f84..77fed3a 100644
--- a/src/lib/dns/python/tests/rcode_python_test.py
+++ b/src/lib/dns/python/tests/rcode_python_test.py
@@ -23,12 +23,8 @@ from pydnspp import *
 class RcodeTest(unittest.TestCase):
     def test_init(self):
         self.assertRaises(TypeError, Rcode, "wrong")
-        self.assertRaises(OverflowError, Rcode, 65536)
-        self.assertEqual(Rcode(0).get_code(), 0)
-    
-        self.assertEqual(0, Rcode(0).get_code())
         self.assertEqual(0xfff, Rcode(0xfff).get_code()) # possible max code
-    
+
         # should fail on attempt of construction with an out of range code
         self.assertRaises(OverflowError, Rcode, 0x1000)
         self.assertRaises(OverflowError, Rcode, 0xffff)
@@ -38,7 +34,18 @@ class RcodeTest(unittest.TestCase):
         self.assertEqual(Rcode.BADVERS_CODE, Rcode(0, 1).get_code())
         self.assertEqual(0xfff, Rcode(0xf, 0xff).get_code())
         self.assertRaises(OverflowError, Rcode, 0x10, 0xff)
-        
+
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertEqual(Rcode(0).get_code(), 0)
+        self.assertEqual(Rcode(4095).get_code(), 4095)
+        self.assertEqual(Rcode(0, 0).get_code(), 0)
+        self.assertEqual(Rcode(0, 0).get_extended_code(), 0)
+        self.assertEqual(Rcode(15, 255).get_code(), 4095)
+        self.assertRaises(ValueError, Rcode, 65536)
+        self.assertRaises(ValueError, Rcode, 0x10, 0x100)
+        self.assertRaises(ValueError, Rcode, 0x100, 0x10)
+
     def test_constants(self):
         self.assertEqual(Rcode.NOERROR_CODE, Rcode(0).get_code())
         self.assertEqual(Rcode.FORMERR_CODE, Rcode(1).get_code())
diff --git a/src/lib/dns/python/tests/rrclass_python_test.py b/src/lib/dns/python/tests/rrclass_python_test.py
index b5e8b5e..38d8c8c 100644
--- a/src/lib/dns/python/tests/rrclass_python_test.py
+++ b/src/lib/dns/python/tests/rrclass_python_test.py
@@ -32,12 +32,17 @@ class RRClassTest(unittest.TestCase):
         b = bytearray(1)
         b[0] = 123
         self.assertRaises(TypeError, RRClass, b)
-        self.assertRaises(InvalidRRClass, RRClass, 65536)
         self.assertEqual(self.c1, RRClass(1))
         b = bytearray()
         self.c1.to_wire(b)
         self.assertEqual(self.c1, RRClass(b))
-        
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertRaises(ValueError, RRClass, 65536)
+        self.assertRaises(TypeError, RRClass, -1)
+        self.assertEqual(RRClass(65535).get_code(), 65535)
+        self.assertEqual(RRClass(0).get_code(), 0)
+
     def test_rrclass_to_text(self):
         self.assertEqual("IN", self.c1.to_text())
         self.assertEqual("IN", str(self.c1))
diff --git a/src/lib/dns/python/tests/rrttl_python_test.py b/src/lib/dns/python/tests/rrttl_python_test.py
index 095a0b1..aa4a34d 100644
--- a/src/lib/dns/python/tests/rrttl_python_test.py
+++ b/src/lib/dns/python/tests/rrttl_python_test.py
@@ -25,7 +25,7 @@ class RRTTLTest(unittest.TestCase):
     def setUp(self):
         self.t1 = RRTTL(1)
         self.t2 = RRTTL(3600)
-        
+
     def test_init(self):
         self.assertRaises(InvalidRRTTL, RRTTL, "wrong")
         self.assertRaises(TypeError, RRTTL, Exception())
@@ -39,7 +39,13 @@ class RRTTLTest(unittest.TestCase):
         b[2] = 0
         b[3] = 15
         self.assertEqual(15, RRTTL(b).get_value())
-        
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertRaises(TypeError, RRTTL, -1)
+        self.assertRaises(ValueError, RRTTL, 4294967296)
+        self.assertEqual(0, RRTTL(0).get_value())
+        self.assertEqual(4294967295, RRTTL(4294967295).get_value())
+
     def test_rrttl_to_text(self):
         self.assertEqual("1", self.t1.to_text())
         self.assertEqual("1", str(self.t1))
diff --git a/src/lib/dns/python/tests/rrtype_python_test.py b/src/lib/dns/python/tests/rrtype_python_test.py
index c35e1e7..7135426 100644
--- a/src/lib/dns/python/tests/rrtype_python_test.py
+++ b/src/lib/dns/python/tests/rrtype_python_test.py
@@ -22,7 +22,7 @@ import os
 from pydnspp import *
 
 class TestModuleSpec(unittest.TestCase):
-    
+
     rrtype_1 = RRType(1)
     rrtype_0x80 = RRType(0x80);
     rrtype_0x800 = RRType(0x800);
@@ -32,24 +32,28 @@ class TestModuleSpec(unittest.TestCase):
 
 
     def test_init(self):
-        self.assertRaises(InvalidRRType, RRType, 65537)
         b = bytearray(b'\x00\x01')
         self.assertEqual(RRType("A"), RRType(b))
         b = bytearray(b'\x01')
         self.assertRaises(IncompleteRRType, RRType, b)
         self.assertRaises(TypeError, RRType, Exception)
-    
+        # Range check.  We need to do this at the binding level, so we need
+        # explicit tests for it.
+        self.assertRaises(ValueError, RRType, 65536)
+        self.assertRaises(TypeError, RRType, -1)
+        self.assertEqual("TYPE65535", RRType(65535).to_text());
+        self.assertEqual("TYPE0", RRType(0).to_text());
+
     def test_init_from_text(self):
         self.assertEqual("A", RRType("A").to_text())
         self.assertEqual("NS", RRType("NS").to_text());
         self.assertEqual("NS", str(RRType("NS")));
-    
         self.assertEqual("TYPE65535", RRType("TYPE65535").to_text());
-    
+
         self.assertEqual(53, RRType("TYPE00053").get_code());
 
         self.assertRaises(InvalidRRType, RRType, "TYPE000053");
-    
+
         self.assertRaises(InvalidRRType, RRType, "TYPE");
         self.assertRaises(InvalidRRType, RRType, "TYPE-1");
         self.assertRaises(InvalidRRType, RRType, "TYPExxx");
diff --git a/src/lib/dns/python/tests/tsig_python_test.py b/src/lib/dns/python/tests/tsig_python_test.py
new file mode 100644
index 0000000..7e5515d
--- /dev/null
+++ b/src/lib/dns/python/tests/tsig_python_test.py
@@ -0,0 +1,554 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import base64, sys, time, unittest
+from pydnspp import *
+from testutil import *
+from pyunittests_util import fix_current_time
+
+# bit-wise constant flags to configure DNS header flags for test
+# messages.
+QR_FLAG = 0x1
+AA_FLAG = 0x2
+RD_FLAG = 0x4
+
+COMMON_EXPECTED_MAC = b"\x22\x70\x26\xad\x29\x7b\xee\xe7\x21\xce\x6c\x6f\xff\x1e\x9e\xf3"
+DUMMY_DATA = b"\xdd" * 100
+
+class TSIGContextTest(unittest.TestCase):
+    tsig_key = TSIGKey('www.example.com:SFuWd/q99SzF8Yzd1QbB9g==')
+
+    def setUp(self):
+        # make sure we don't use faked time unless explicitly do so in tests
+        fix_current_time(None)
+        self.qid = 0x2d65
+        self.test_name = Name("www.example.com")
+        self.tsig_ctx = TSIGContext(self.tsig_key)
+        self.tsig_verify_ctx = TSIGContext(self.tsig_key)
+        self.keyring = TSIGKeyRing()
+        self.message = Message(Message.RENDER)
+        self.renderer = MessageRenderer()
+        self.test_class = RRClass.IN()
+        self.test_ttl = RRTTL(86400)
+        self.secret = base64.b64decode(b"SFuWd/q99SzF8Yzd1QbB9g==")
+        self.tsig_ctx = TSIGContext(TSIGKey(self.test_name,
+                                            TSIGKey.HMACMD5_NAME,
+                                            self.secret))
+        self.badkey_name = Name("badkey.example.com")
+        self.dummy_record = TSIGRecord(self.badkey_name,
+                                       TSIG("hmac-md5.sig-alg.reg.int. " + \
+                                                "1302890362 300 0 11621 " + \
+                                                "0 0"))
+
+    def tearDown(self):
+        # reset any faked current time setting (it would affect other tests)
+        fix_current_time(None)
+
+    # Note: intentionally use camelCase so that we can easily copy-paste
+    # corresponding C++ tests.
+    def createMessageAndSign(self, id, qname, ctx, message_flags=RD_FLAG,
+                             qtype=RRType.A(), answer_data=None,
+                             answer_type=None, add_question=True,
+                             rcode=Rcode.NOERROR()):
+        self.message.clear(Message.RENDER)
+        self.message.set_qid(id)
+        self.message.set_opcode(Opcode.QUERY())
+        self.message.set_rcode(rcode)
+        if (message_flags & QR_FLAG) != 0:
+            self.message.set_header_flag(Message.HEADERFLAG_QR)
+        if (message_flags & AA_FLAG) != 0:
+            self.message.set_header_flag(Message.HEADERFLAG_AA)
+        if (message_flags & RD_FLAG) != 0:
+            self.message.set_header_flag(Message.HEADERFLAG_RD)
+        if add_question:
+            self.message.add_question(Question(qname, self.test_class, qtype))
+        if answer_data is not None:
+            if answer_type is None:
+                answer_type = qtype
+            answer_rrset = RRset(qname, self.test_class, answer_type,
+                                 self.test_ttl)
+            answer_rrset.add_rdata(Rdata(answer_type, self.test_class,
+                                         answer_data))
+            self.message.add_rrset(Message.SECTION_ANSWER, answer_rrset)
+        self.renderer.clear()
+        self.message.to_wire(self.renderer)
+
+        if ctx.get_state() == TSIGContext.STATE_INIT:
+            expected_new_state = TSIGContext.STATE_SENT_REQUEST
+        else:
+            expected_new_state = TSIGContext.STATE_SENT_RESPONSE
+        tsig = ctx.sign(id, self.renderer.get_data())
+
+        return tsig
+
+    # Note: intentionally use camelCase so that we can easily copy-paste
+    # corresponding C++ tests.
+    def createMessageFromFile(self, file):
+        self.message.clear(Message.PARSE)
+        self.received_data = read_wire_data(file)
+        self.message.from_wire(self.received_data)
+
+    # Note: intentionally use camelCase so that we can easily copy-paste
+    # corresponding C++ tests.
+    def commonSignChecks(self, tsig, expected_qid, expected_timesigned,
+                         expected_mac, expected_error=0,
+                         expected_otherdata=None,
+                         expected_algorithm=TSIGKey.HMACMD5_NAME):
+        tsig_rdata = tsig.get_rdata()
+        self.assertEqual(expected_algorithm, tsig_rdata.get_algorithm())
+        self.assertEqual(expected_timesigned, tsig_rdata.get_timesigned())
+        self.assertEqual(300, tsig_rdata.get_fudge())
+        self.assertEqual(expected_mac, tsig_rdata.get_mac())
+        self.assertEqual(expected_qid, tsig_rdata.get_original_id())
+        self.assertEqual(expected_error, tsig_rdata.get_error())
+        self.assertEqual(expected_otherdata, tsig_rdata.get_other_data())
+
+    def test_initial_state(self):
+        # Until signing or verifying, the state should be INIT
+        self.assertEqual(TSIGContext.STATE_INIT, self.tsig_ctx.get_state())
+
+        # And there should be no error code.
+        self.assertEqual(TSIGError(Rcode.NOERROR()), self.tsig_ctx.get_error())
+
+    # Note: intentionally use camelCase so that we can easily copy-paste
+    # corresponding C++ tests.
+    def commonVerifyChecks(self, ctx, record, data, expected_error,
+                           expected_new_state=\
+                               TSIGContext.STATE_VERIFIED_RESPONSE):
+        self.assertEqual(expected_error, ctx.verify(record, data))
+        self.assertEqual(expected_error, ctx.get_error())
+        self.assertEqual(expected_new_state, ctx.get_state())
+
+    def test_from_keyring(self):
+        # Construct a TSIG context with an empty key ring.  Key shouldn't be
+        # found, and the BAD_KEY error should be recorded.
+        ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
+        self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
+        self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
+        # check get_error() doesn't cause ref leak.  Note: we can't
+        # realiably do this check for get_state(), as it returns an integer
+        # object, which could have many references
+        self.assertEqual(1, sys.getrefcount(ctx.get_error()))
+
+        # Add a matching key (we don't use the secret so leave it empty), and
+        # construct it again.  This time it should be constructed with a valid
+        # key.
+        self.keyring.add(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME, b""))
+        ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
+        self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
+        self.assertEqual(TSIGError.NOERROR, ctx.get_error())
+
+        # Similar to the first case except that the key ring isn't empty but
+        # it doesn't contain a matching key.
+        ctx = TSIGContext(self.test_name, TSIGKey.HMACSHA1_NAME, self.keyring)
+        self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
+        self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
+
+        ctx = TSIGContext(Name("different-key.example"),
+                          TSIGKey.HMACMD5_NAME, self.keyring)
+        self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
+        self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
+
+        # "Unknown" algorithm name will result in BADKEY, too.
+        ctx = TSIGContext(self.test_name, Name("unknown.algorithm"),
+                          self.keyring)
+        self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
+        self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
+
+    def test_sign(self):
+        fix_current_time(0x4da8877a)
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx)
+        self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
+
+    # Same test as sign, but specifying the key name with upper-case (i.e.
+    # non canonical) characters.  The digest must be the same.  It should
+    # actually be ensured at the level of TSIGKey, but we confirm that at
+    # this level, too.
+    def test_sign_using_uppercase_keyname(self):
+        fix_current_time(0x4da8877a)
+        cap_ctx = TSIGContext(TSIGKey(Name("WWW.EXAMPLE.COM"),
+                                      TSIGKey.HMACMD5_NAME, self.secret))
+        tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
+        self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
+
+    # Same as the previous test, but for the algorithm name.
+    def test_sign_using_uppercase_algorithm_name(self):
+        fix_current_time(0x4da8877a)
+        cap_ctx = TSIGContext(TSIGKey(self.test_name,
+                                      Name("HMAC-md5.SIG-alg.REG.int"),
+                                      self.secret))
+        tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
+        self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
+
+    # Sign the message using the actual time, and check the accuracy of it.
+    # We cannot reasonably predict the expected MAC, so don't bother to
+    # check it.
+    def test_sign_at_actual_time(self):
+        now = int(time.time())
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx)
+        tsig_rdata = tsig.get_rdata()
+
+        # Check the resulted time signed is in the range of [now, now + 5]
+        self.assertTrue(now <= tsig_rdata.get_timesigned())
+        self.assertTrue(now + 5 >= tsig_rdata.get_timesigned())
+
+    def test_bad_data(self):
+        self.assertRaises(TypeError, self.tsig_ctx.sign, None, 10)
+
+    def test_verify_bad_data(self):
+        # the data must at least hold the DNS message header and the specified
+        # TSIG.
+        bad_len = 12 + self.dummy_record.get_length() - 1
+        self.assertRaises(InvalidParameter, self.tsig_ctx.verify,
+                          self.dummy_record, DUMMY_DATA[:bad_len])
+
+    def test_sign_using_hmacsha1(self):
+        fix_current_time(0x4dae7d5f)
+
+        secret = base64.b64decode(b"MA+QDhXbyqUak+qnMFyTyEirzng=")
+        sha1_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACSHA1_NAME,
+                                       secret))
+        qid = 0x0967
+        expected_mac = b"\x41\x53\x40\xc7\xda\xf8\x24\xed\x68\x4e\xe5\x86" + \
+            b"\xf7\xb5\xa6\x7a\x2f\xeb\xc0\xd3"
+        tsig = self.createMessageAndSign(qid, self.test_name, sha1_ctx)
+        self.commonSignChecks(tsig, qid, 0x4dae7d5f, expected_mac,
+                              0, None, TSIGKey.HMACSHA1_NAME)
+
+    def test_verify_then_sign_response(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageFromFile("message_toWire2.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_verify_ctx,
+                                         QR_FLAG|AA_FLAG|RD_FLAG,
+                                         RRType.A(), "192.0.2.1")
+
+        expected_mac = b"\x8f\xcd\xa6\x6a\x7c\xd1\xa3\xb9\x94\x8e\xb1\x86" + \
+            b"\x9d\x38\x4a\x9f"
+        self.commonSignChecks(tsig, self.qid, 0x4da8877a, expected_mac)
+
+    def test_verify_uppercase_names(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageFromFile("tsig_verify9.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+    def test_verify_forward_message(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageFromFile("tsig_verify6.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+    def test_sign_continuation(self):
+        fix_current_time(0x4da8e951)
+
+        axfr_qid = 0x3410
+        zone_name = Name("example.com")
+
+        tsig = self.createMessageAndSign(axfr_qid, zone_name, self.tsig_ctx,
+                                         0, RRType.AXFR())
+
+        received_data = read_wire_data("tsig_verify1.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx, tsig, received_data,
+                                TSIGError.NOERROR,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        tsig = self.createMessageAndSign(axfr_qid, zone_name,
+                                         self.tsig_verify_ctx,
+                                         AA_FLAG|QR_FLAG, RRType.AXFR(),
+                                         "ns.example.com. root.example.com." +\
+                                         " 2011041503 7200 3600 2592000 1200",
+                                         RRType.SOA())
+
+        received_data = read_wire_data("tsig_verify2.wire")
+        self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
+                                TSIGError.NOERROR)
+
+        expected_mac = b"\x10\x24\x58\xf7\xf6\x2d\xdd\x7d\x63\x8d\x74" +\
+            b"\x60\x34\x13\x09\x68"
+        tsig = self.createMessageAndSign(axfr_qid, zone_name,
+                                         self.tsig_verify_ctx,
+                                         AA_FLAG|QR_FLAG, RRType.AXFR(),
+                                         "ns.example.com.", RRType.NS(),
+                                         False)
+        self.commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac)
+
+        received_data = read_wire_data("tsig_verify3.wire")
+        self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
+                                TSIGError.NOERROR)
+
+    def test_badtime_response(self):
+        fix_current_time(0x4da8b9d6)
+
+        test_qid = 0x7fc4
+        tsig = self.createMessageAndSign(test_qid, self.test_name,
+                                         self.tsig_ctx, 0, RRType.SOA())
+
+        # "advance the clock" and try validating, which should fail due to
+        # BADTIME
+        fix_current_time(0x4da8be86)
+        self.commonVerifyChecks(self.tsig_verify_ctx, tsig, DUMMY_DATA,
+                                TSIGError.BAD_TIME,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        # make and sign a response in the context of TSIG error.
+        tsig = self.createMessageAndSign(test_qid, self.test_name,
+                                         self.tsig_verify_ctx,
+                                         QR_FLAG, RRType.SOA(), None, None,
+                                         True, Rcode.NOTAUTH())
+
+        expected_otherdata = b"\x00\x00\x4d\xa8\xbe\x86"
+        expected_mac = b"\xd4\xb0\x43\xf6\xf4\x44\x95\xec\x8a\x01\x26" +\
+            b"\x0e\x39\x15\x9d\x76"
+
+        self.commonSignChecks(tsig, self.message.get_qid(), 0x4da8b9d6,
+                              expected_mac,
+                              18,     # error: BADTIME
+                              expected_otherdata)
+
+    def test_badtime_response2(self):
+        fix_current_time(0x4da8b9d6)
+
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx, 0, RRType.SOA())
+
+        # "rewind the clock" and try validating, which should fail due to
+        # BADTIME
+        fix_current_time(0x4da8b9d6 - 600)
+        self.commonVerifyChecks(self.tsig_verify_ctx, tsig, DUMMY_DATA,
+                           TSIGError.BAD_TIME,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+    # Test various boundary conditions.  We intentionally use the magic
+    # number of 300 instead of the constant variable for testing.
+    # In the okay cases, signature is not correct, but it's sufficient to
+    # check the error code isn't BADTIME for the purpose of this test.
+    def test_badtime_boundaries(self):
+        fix_current_time(0x4da8b9d6)
+
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx, 0, RRType.SOA())
+                                         
+        fix_current_time(0x4da8b9d6 + 301)
+        self.assertEqual(TSIGError.BAD_TIME,
+                         self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
+
+        fix_current_time(0x4da8b9d6 + 300)
+        self.assertNotEqual(TSIGError.BAD_TIME,
+                            self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
+
+        fix_current_time(0x4da8b9d6 - 301)
+        self.assertEqual(TSIGError.BAD_TIME,
+                         self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
+
+        fix_current_time(0x4da8b9d6 - 300)
+        self.assertNotEqual(TSIGError.BAD_TIME,
+                            self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
+
+    def test_badtime_overflow(self):
+        fix_current_time(200)
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx, 0, RRType.SOA())
+
+        # This should be in the okay range, but since "200 - fudge" overflows
+        # and we compare them as 64-bit unsigned integers, it results in a
+        # false positive (we intentionally accept that).
+        fix_current_time(100)
+        self.assertEqual(TSIGError.BAD_TIME,
+                         self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
+
+    def test_badsig_response(self):
+        fix_current_time(0x4da8877a)
+
+        # Try to sign a simple message with bogus secret.  It should fail
+        # with BADSIG.
+        self.createMessageFromFile("message_toWire2.wire")
+        bad_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME,
+                                      DUMMY_DATA))
+        self.commonVerifyChecks(bad_ctx, self.message.get_tsig_record(),
+                                self.received_data, TSIGError.BAD_SIG,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        # Sign the same message (which doesn't matter for this test) with the
+        # context of "checked state".
+        tsig = self.createMessageAndSign(self.qid, self.test_name, bad_ctx)
+        self.commonSignChecks(tsig, self.message.get_qid(), 0x4da8877a, None,
+                              16)   # 16: BADSIG
+
+    def test_badkey_response(self):
+        # A similar test as badsigResponse but for BADKEY
+        fix_current_time(0x4da8877a)
+        tsig_ctx = TSIGContext(self.badkey_name, TSIGKey.HMACMD5_NAME,
+                               self.keyring)
+        self.commonVerifyChecks(tsig_ctx, self.dummy_record, DUMMY_DATA,
+                                TSIGError.BAD_KEY,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        sig = self.createMessageAndSign(self.qid, self.test_name, tsig_ctx)
+        self.assertEqual(self.badkey_name, sig.get_name())
+        self.commonSignChecks(sig, self.qid, 0x4da8877a, None, 17) # 17: BADKEY
+
+    def test_badkey_for_response(self):
+        # "BADKEY" case for a response to a signed message
+        self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
+        self.commonVerifyChecks(self.tsig_ctx, self.dummy_record, DUMMY_DATA,
+                                TSIGError.BAD_KEY,
+                                TSIGContext.STATE_SENT_REQUEST)
+
+        # A similar case with a different algorithm
+        dummy_record = TSIGRecord(self.test_name,
+                                  TSIG("hmac-sha1. 1302890362 300 0 "
+                                       "11621 0 0"))
+        self.commonVerifyChecks(self.tsig_ctx, dummy_record, DUMMY_DATA,
+                                TSIGError.BAD_KEY,
+                                TSIGContext.STATE_SENT_REQUEST)
+
+    # According to RFC2845 4.6, if TSIG verification fails the client
+    # should discard that message and wait for another signed response.
+    # This test emulates that situation.
+    def test_badsig_then_validate(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
+        self.createMessageFromFile("tsig_verify4.wire")
+
+        self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+                                self.received_data, TSIGError.BAD_SIG,
+                                TSIGContext.STATE_SENT_REQUEST)
+
+        self.createMessageFromFile("tsig_verify5.wire")
+        self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_VERIFIED_RESPONSE)
+
+    # Similar to the previous test, but the first response doesn't contain
+    # TSIG.
+    def test_nosig_then_validate(self):
+        fix_current_time(0x4da8877a)
+        self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
+
+        self.commonVerifyChecks(self.tsig_ctx, None, DUMMY_DATA,
+                           TSIGError.FORMERR, TSIGContext.STATE_SENT_REQUEST)
+
+        self.createMessageFromFile("tsig_verify5.wire")
+        self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_VERIFIED_RESPONSE)
+
+    # Similar to the previous test, but the first response results in BADTIME.
+    def test_badtime_then_validate(self):
+        fix_current_time(0x4da8877a)
+        tsig = self.createMessageAndSign(self.qid, self.test_name,
+                                         self.tsig_ctx)
+
+        # "advance the clock" and try validating, which should fail due to
+        # BADTIME
+        fix_current_time(0x4da8877a + 600)
+        self.commonVerifyChecks(self.tsig_ctx, tsig, DUMMY_DATA,
+                           TSIGError.BAD_TIME, TSIGContext.STATE_SENT_REQUEST)
+
+        # revert the clock again.
+        fix_current_time(0x4da8877a)
+        self.createMessageFromFile("tsig_verify5.wire")
+        self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+                                self.received_data, TSIGError.NOERROR,
+                                TSIGContext.STATE_VERIFIED_RESPONSE)
+
+    # We don't allow empty MAC unless the TSIG error is BADSIG or BADKEY.
+    def test_empty_mac(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageFromFile("tsig_verify7.wire")
+
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data,
+                                TSIGError.BAD_SIG,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+        # If the empty MAC comes with a BADKEY error, the error is passed
+        # transparently.
+        self.createMessageFromFile("tsig_verify8.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data,
+                                TSIGError.BAD_KEY,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+    # Once the context is used for sending a signed response, it shouldn't
+    # be used for further verification.
+    def test_verify_after_sendresponse(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageFromFile("message_toWire2.wire")
+        self.tsig_verify_ctx.verify(self.message.get_tsig_record(),
+                                    self.received_data)
+        self.assertEqual(TSIGContext.STATE_RECEIVED_REQUEST,
+                         self.tsig_verify_ctx.get_state())
+        self.createMessageAndSign(self.qid, self.test_name,
+                                  self.tsig_verify_ctx,
+                                  QR_FLAG|AA_FLAG|RD_FLAG, RRType.A(),
+                                  "192.0.2.1")
+        self.assertEqual(TSIGContext.STATE_SENT_RESPONSE,
+                         self.tsig_verify_ctx.get_state())
+
+        # Now trying further verification.
+        self.createMessageFromFile("message_toWire2.wire")
+        self.assertRaises(TSIGContextError, self.tsig_verify_ctx.verify,
+                          self.message.get_tsig_record(), self.received_data)
+
+    # Likewise, once the context verifies a response, it shouldn't for
+    # signing any more.
+    def test_sign_after_verified(self):
+        fix_current_time(0x4da8877a)
+
+        self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
+        self.createMessageFromFile("tsig_verify5.wire")
+        self.tsig_ctx.verify(self.message.get_tsig_record(),
+                             self.received_data)
+        self.assertEqual(TSIGContext.STATE_VERIFIED_RESPONSE,
+                         self.tsig_ctx.get_state())
+
+        # Now trying further signing.
+        self.assertRaises(TSIGContextError, self.createMessageAndSign,
+                          self.qid, self.test_name, self.tsig_ctx)
+
+    # Too short MAC should be rejected.
+    # Note: when we implement RFC4635-based checks, the error code will
+    # (probably) be FORMERR.
+    def test_too_short_mac(self):
+        fix_current_time(0x4da8877a)
+        self.createMessageFromFile("tsig_verify10.wire")
+        self.commonVerifyChecks(self.tsig_verify_ctx,
+                                self.message.get_tsig_record(),
+                                self.received_data, TSIGError.BAD_SIG,
+                                TSIGContext.STATE_RECEIVED_REQUEST)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/lib/dns/python/tests/tsig_rdata_python_test.py b/src/lib/dns/python/tests/tsig_rdata_python_test.py
new file mode 100644
index 0000000..7b861d6
--- /dev/null
+++ b/src/lib/dns/python/tests/tsig_rdata_python_test.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import sys
+from pydnspp import *
+
+class TSIGRdataTest(unittest.TestCase):
+    VALID_TEXT1 = "hmac-md5.sig-alg.reg.int. 1286779327 300 0 16020 BADKEY 0"
+    def test_from_string(self):
+        tsig = TSIG(self.VALID_TEXT1)
+        self.assertEqual(Name("hmac-md5.sig-alg.reg.int"),
+                         tsig.get_algorithm())
+        # check there's no leak in creating the name object:
+        self.assertEqual(1, sys.getrefcount(tsig.get_algorithm()))
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/lib/dns/python/tests/tsigerror_python_test.py b/src/lib/dns/python/tests/tsigerror_python_test.py
new file mode 100644
index 0000000..a968b6b
--- /dev/null
+++ b/src/lib/dns/python/tests/tsigerror_python_test.py
@@ -0,0 +1,97 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import sys
+from pydnspp import *
+
+class TSIGErrorTest(unittest.TestCase):
+    def test_from_code(self):
+        self.assertEqual(0, TSIGError(0).get_code())
+        self.assertEqual(18, TSIGError(18).get_code())
+        self.assertEqual(65535, TSIGError(65535).get_code())
+        self.assertRaises(ValueError, TSIGError, 65536)
+        self.assertRaises(ValueError, TSIGError, -1)
+        self.assertRaises(TypeError, TSIGError, "not yet supported")
+
+    def test_from_rcode(self):
+        # We use RCODE for code values from 0-15.
+        self.assertEqual(0, TSIGError(Rcode.NOERROR()).get_code())
+        self.assertEqual(15, TSIGError(Rcode(15)).get_code())
+
+        # From error code 16 TSIG errors define a separate space, so passing
+        # corresponding RCODE for such code values should be prohibited.
+        self.assertRaises(ValueError, TSIGError, Rcode(16))
+
+    def test_constants(self):
+        # We'll only test arbitrarily chosen subsets of the codes.
+        # This class is quite simple, so it should be suffice.
+        self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError(16).get_code())
+        self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError(17).get_code())
+        self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError(18).get_code())
+
+        self.assertEqual(0, TSIGError.NOERROR.get_code())
+        self.assertEqual(9, TSIGError.NOTAUTH.get_code())
+        self.assertEqual(14, TSIGError.RESERVED14.get_code())
+        self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError.BAD_SIG.get_code())
+        self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError.BAD_KEY.get_code())
+        self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError.BAD_TIME.get_code())
+
+    def test_equal(self):
+        self.assertTrue(TSIGError.NOERROR == TSIGError(Rcode.NOERROR()))
+        self.assertTrue(TSIGError(Rcode.NOERROR()) == TSIGError.NOERROR)
+
+        self.assertTrue(TSIGError.BAD_SIG == TSIGError(16))
+        self.assertTrue(TSIGError(16) == TSIGError.BAD_SIG)
+
+    def test_nequal(self):
+        self.assertTrue(TSIGError.BAD_KEY != TSIGError(Rcode.NOERROR()))
+        self.assertTrue(TSIGError(Rcode.NOERROR()) != TSIGError.BAD_KEY)
+
+    def test_to_text(self):
+        # TSIGError derived from the standard Rcode
+        self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR()).to_text())
+
+        # Well known TSIG errors
+        self.assertEqual("BADSIG", TSIGError.BAD_SIG.to_text())
+        self.assertEqual("BADKEY", TSIGError.BAD_KEY.to_text())
+        self.assertEqual("BADTIME", TSIGError.BAD_TIME.to_text())
+
+        # Unknown (or not yet supported) codes.  Simply converted as numeric.
+        self.assertEqual("19", TSIGError(19).to_text());
+        self.assertEqual("65535", TSIGError(65535).to_text());
+
+        # also check str() works same way
+        self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR())))
+        self.assertEqual("BADSIG", str(TSIGError.BAD_SIG))
+
+    def test_to_rcode(self):
+        # TSIGError derived from the standard Rcode
+        self.assertEqual(Rcode.NOERROR(), TSIGError(Rcode.NOERROR()).to_rcode())
+
+        # Well known TSIG errors
+        self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_SIG.to_rcode())
+        self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_KEY.to_rcode())
+        self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_TIME.to_rcode())
+
+        # Unknown (or not yet supported) codes are treated as SERVFAIL.
+        self.assertEqual(Rcode.SERVFAIL(), TSIGError(19).to_rcode())
+        self.assertEqual(Rcode.SERVFAIL(), TSIGError(65535).to_rcode())
+
+        # Check there's no redundant refcount (which would cause leak)
+        self.assertEqual(1, sys.getrefcount(TSIGError.BAD_SIG.to_rcode()))
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/lib/dns/python/tests/tsigkey_python_test.py b/src/lib/dns/python/tests/tsigkey_python_test.py
index 06e6868..516bea4 100644
--- a/src/lib/dns/python/tests/tsigkey_python_test.py
+++ b/src/lib/dns/python/tests/tsigkey_python_test.py
@@ -25,6 +25,9 @@ class TSIGKeyTest(unittest.TestCase):
                          TSIGKey.HMACMD5_NAME)
         self.assertEqual(Name('hmac-sha1'), TSIGKey.HMACSHA1_NAME)
         self.assertEqual(Name('hmac-sha256'), TSIGKey.HMACSHA256_NAME)
+        self.assertEqual(Name('hmac-sha224'), TSIGKey.HMACSHA224_NAME)
+        self.assertEqual(Name('hmac-sha384'), TSIGKey.HMACSHA384_NAME)
+        self.assertEqual(Name('hmac-sha512'), TSIGKey.HMACSHA512_NAME)
 
     def test_init(self):
         key = TSIGKey(self.key_name, TSIGKey.HMACMD5_NAME, self.secret)
@@ -44,8 +47,33 @@ class TSIGKeyTest(unittest.TestCase):
                           TSIGKey.HMACMD5_NAME,
                           'should be binary') # signature mismatch
 
+    def test_str(self):
+        k1 = TSIGKey('test.example:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int')
+        self.assertEqual(Name('test.example.'), k1.get_key_name())
+        self.assertEqual(Name('hmac-md5.sig-alg.reg.int.'), k1.get_algorithm_name())
+        self.assertEqual(b'\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b',
+                         k1.get_secret())
+        self.assertEqual('test.example.:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int.',
+                         k1.to_text())
+
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          'test.example:CwsLCwsLCwsLCwsLCwsLCw==:unsupported')
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          '::')
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          'test.example:')
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          'test.example:%bad_base_64%')
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          'test.example:CwsLCwsLCwsLCwsLCwsLCw==:')
+        self.assertRaises(InvalidParameter, TSIGKey,
+                          'test.:example:CwsLCwsLCwsLCwsLCwsLCw==')
+
 class TSIGKeyRingTest(unittest.TestCase):
     key_name = Name('example.com')
+    md5_name = Name('hmac-md5.sig-alg.reg.int')
+    sha1_name = Name('hmac-sha1')
+    sha256_name = Name('hmac-sha256')
     secret = b'someRandomData'
 
     def setUp(self):
@@ -130,18 +158,26 @@ class TSIGKeyRingTest(unittest.TestCase):
 
     def test_find(self):
         self.assertEqual((TSIGKeyRing.NOTFOUND, None),
-                         self.keyring.find(self.key_name))
+                         self.keyring.find(self.key_name, self.md5_name))
 
         self.assertEqual(TSIGKeyRing.SUCCESS,
                          self.keyring.add(TSIGKey(self.key_name,
-                                                  TSIGKey.HMACSHA256_NAME,
+                                                  self.sha256_name,
                                                   self.secret)))
-        (code, key) = self.keyring.find(self.key_name)
+        (code, key) = self.keyring.find(self.key_name, self.sha256_name)
         self.assertEqual(TSIGKeyRing.SUCCESS, code)
         self.assertEqual(self.key_name, key.get_key_name())
         self.assertEqual(TSIGKey.HMACSHA256_NAME, key.get_algorithm_name())
         self.assertEqual(self.secret, key.get_secret())
 
+        (code, key) = self.keyring.find(Name('different-key.example'),
+                                        self.sha256_name)
+        self.assertEqual(TSIGKeyRing.NOTFOUND, code)
+        self.assertEqual(None, key)
+        (code, key) = self.keyring.find(self.key_name, self.md5_name)
+        self.assertEqual(TSIGKeyRing.NOTFOUND, code)
+        self.assertEqual(None, key)
+
         self.assertRaises(TypeError, self.keyring.find, 1)
         self.assertRaises(TypeError, self.keyring.find, 'should be a name')
         self.assertRaises(TypeError, self.keyring.find, self.key_name, 0)
@@ -149,24 +185,28 @@ class TSIGKeyRingTest(unittest.TestCase):
     def test_find_from_some(self):
         self.assertEqual(TSIGKeyRing.SUCCESS,
                          self.keyring.add(TSIGKey(self.key_name,
-                                                  TSIGKey.HMACSHA256_NAME,
+                                                  self.sha256_name,
                                                   self.secret)))
         self.assertEqual(TSIGKeyRing.SUCCESS,
                          self.keyring.add(TSIGKey(Name('another.example'),
-                                                  TSIGKey.HMACMD5_NAME,
+                                                  self.md5_name,
                                                   self.secret)))
         self.assertEqual(TSIGKeyRing.SUCCESS,
                          self.keyring.add(TSIGKey(Name('more.example'),
-                                                  TSIGKey.HMACSHA1_NAME,
+                                                  self.sha1_name,
                                                   self.secret)))
 
-        (code, key) = self.keyring.find(Name('another.example'))
+        (code, key) = self.keyring.find(Name('another.example'), self.md5_name)
         self.assertEqual(TSIGKeyRing.SUCCESS, code)
         self.assertEqual(Name('another.example'), key.get_key_name())
         self.assertEqual(TSIGKey.HMACMD5_NAME, key.get_algorithm_name())
 
         self.assertEqual((TSIGKeyRing.NOTFOUND, None),
-                         self.keyring.find(Name('noexist.example')))
+                         self.keyring.find(Name('noexist.example'),
+                                           self.sha1_name))
+        self.assertEqual((TSIGKeyRing.NOTFOUND, None),
+                         self.keyring.find(Name('another.example'),
+                                           self.sha1_name))
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/tsigrecord_python_test.py b/src/lib/dns/python/tests/tsigrecord_python_test.py
new file mode 100644
index 0000000..813a23b
--- /dev/null
+++ b/src/lib/dns/python/tests/tsigrecord_python_test.py
@@ -0,0 +1,44 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import sys
+from pydnspp import *
+
+class TSIGRecordTest(unittest.TestCase):
+    def setUp(self):
+        self.test_name = Name("www.example.com")
+        self.test_rdata = TSIG("hmac-md5.sig-alg.reg.int. 1302890362 " + \
+                                   "300 16 2tra2tra2tra2tra2tra2g== " + \
+                                   "11621 0 0")
+        self.test_record = TSIGRecord(self.test_name, self.test_rdata)
+
+    def test_getname(self):
+        self.assertEqual(self.test_name, self.test_record.get_name())
+        self.assertEqual(1, sys.getrefcount(self.test_record.get_name()))
+
+    def test_get_length(self):
+        # see the C++ test for the magic number
+        self.assertEqual(85, self.test_record.get_length())
+
+    def test_to_text(self):
+        expected_text = "www.example.com. 0 ANY TSIG " + \
+            "hmac-md5.sig-alg.reg.int. 1302890362 300 16 " + \
+            "2tra2tra2tra2tra2tra2g== 11621 NOERROR 0\n"
+        self.assertEqual(expected_text, self.test_record.to_text())
+        self.assertEqual(expected_text, str(self.test_record))
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/lib/dns/python/tsig_python.cc b/src/lib/dns/python/tsig_python.cc
new file mode 100644
index 0000000..db93a08
--- /dev/null
+++ b/src/lib/dns/python/tsig_python.cc
@@ -0,0 +1,364 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#define PY_SSIZE_T_CLEAN        // need for "y#" below
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <exceptions/exceptions.h>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/tsig.h>
+
+#include "pydnspp_common.h"
+#include "name_python.h"
+#include "tsigkey_python.h"
+#include "tsigerror_python.h"
+#include "tsigrecord_python.h"
+#include "tsig_python.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// TSIGContext
+//
+
+// Trivial constructor.
+s_TSIGContext::s_TSIGContext() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_TSIGContext, TSIGContext> TSIGContextContainer;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIGContext_init(s_TSIGContext* self, PyObject* args);
+void TSIGContext_destroy(s_TSIGContext* self);
+
+// Class specific methods
+PyObject* TSIGContext_getState(s_TSIGContext* self);
+PyObject* TSIGContext_getError(s_TSIGContext* self);
+PyObject* TSIGContext_sign(s_TSIGContext* self, PyObject* args);
+PyObject* TSIGContext_verify(s_TSIGContext* self, PyObject* args);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIGContext_methods[] = {
+    { "get_state", reinterpret_cast<PyCFunction>(TSIGContext_getState),
+      METH_NOARGS,
+      "Return the current state of the context (mainly for tests)" },
+    { "get_error", reinterpret_cast<PyCFunction>(TSIGContext_getError),
+      METH_NOARGS,
+      "Return the TSIG error as a result of the latest verification" },
+    { "sign",
+      reinterpret_cast<PyCFunction>(TSIGContext_sign), METH_VARARGS,
+      "Sign a DNS message." },
+    { "verify",
+      reinterpret_cast<PyCFunction>(TSIGContext_verify), METH_VARARGS,
+      "Verify a DNS message." },
+    { NULL, NULL, 0, NULL }
+};
+
+int
+TSIGContext_init(s_TSIGContext* self, PyObject* args) {
+    try {
+        // "From key" constructor
+        const s_TSIGKey* tsigkey_obj;
+        if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
+            self->cppobj = new TSIGContext(*tsigkey_obj->cppobj);
+            return (0);
+        }
+
+        // "From key param + keyring" constructor
+        PyErr_Clear();
+        const s_Name* keyname_obj;
+        const s_Name* algname_obj;
+        const s_TSIGKeyRing* keyring_obj;
+        if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &keyname_obj,
+                             &name_type, &algname_obj, &tsigkeyring_type,
+                             &keyring_obj)) {
+            self->cppobj = new TSIGContext(*keyname_obj->cppobj,
+                                           *algname_obj->cppobj,
+                                           *keyring_obj->cppobj);
+            return (0);
+        }
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct TSIGContext object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in constructing TSIGContext");
+        return (-1);
+    }
+
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to TSIGContext constructor");
+
+    return (-1);
+}
+
+void
+TSIGContext_destroy(s_TSIGContext* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+TSIGContext_getState(s_TSIGContext* self) {
+    return (Py_BuildValue("I", self->cppobj->getState()));
+}
+
+PyObject*
+TSIGContext_getError(s_TSIGContext* self) {
+    try {
+        PyObjectContainer container(createTSIGErrorObject(
+                                        self->cppobj->getError()));
+        return (Py_BuildValue("O", container.get()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpectedly failed to get TSIGContext error: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in TSIGContext.get_error");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGContext_sign(s_TSIGContext* self, PyObject* args) {
+    long qid = 0;
+    const char* mac;
+    Py_ssize_t mac_size;
+
+    if (PyArg_ParseTuple(args, "ly#", &qid, &mac, &mac_size)) {
+        if (qid < 0 || qid > 0xffff) {
+            PyErr_SetString(PyExc_ValueError,
+                            "TSIGContext.sign: QID out of range");
+            return (NULL);
+        }
+
+        try {
+            ConstTSIGRecordPtr record = self->cppobj->sign(qid, mac, mac_size);
+            return (createTSIGRecordObject(*record));
+        } catch (const TSIGContextError& ex) {
+            PyErr_SetString(po_TSIGContextError, ex.what());
+        } catch (const exception& ex) {
+            const string ex_what = "Unexpected failure in TSIG sign: " +
+                string(ex.what());
+            PyErr_SetString(po_IscException, ex_what.c_str());
+        } catch (...) {
+            PyErr_SetString(PyExc_SystemError,
+                            "Unexpected failure in TSIG sign");
+        }
+    } else {
+        PyErr_SetString(PyExc_TypeError,
+                        "Invalid arguments to TSIGContext.sign");
+    }
+
+    return (NULL);
+}
+
+PyObject*
+TSIGContext_verify(s_TSIGContext* self, PyObject* args) {
+    const char* data;
+    Py_ssize_t data_len;
+    s_TSIGRecord* py_record;
+    PyObject* py_maybe_none;
+    TSIGRecord* record;
+
+    if (PyArg_ParseTuple(args, "O!y#", &tsigrecord_type, &py_record,
+                         &data, &data_len)) {
+        record = py_record->cppobj;
+    } else if (PyArg_ParseTuple(args, "Oy#", &py_maybe_none, &data,
+                                &data_len)) {
+        record = NULL;
+    } else {
+        PyErr_SetString(PyExc_TypeError,
+                        "Invalid arguments to TSIGContext.verify");
+        return (NULL);
+    }
+    PyErr_Clear();
+
+    try {
+        const TSIGError error = self->cppobj->verify(record, data, data_len);
+        return (createTSIGErrorObject(error));
+    } catch (const TSIGContextError& ex) {
+        PyErr_SetString(po_TSIGContextError, ex.what());
+    } catch (const InvalidParameter& ex) {
+        PyErr_SetString(po_InvalidParameter, ex.what());
+    } catch (const exception& ex) {
+        const string ex_what = "Unexpected failure in TSIG verify: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in TSIG verify");
+    }
+
+    return (NULL);
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// Definition of class specific exception(s)
+PyObject* po_TSIGContextError;
+
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_TSIGContext
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsigcontext_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.TSIGContext",
+    sizeof(s_TSIGContext),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(TSIGContext_destroy),       // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+
+    // We allow the python version of TSIGContext to act as a base class.
+    // From pure design point of view, this is wrong because it's not intended
+    // to be inherited.  However, cryptographic operations are generally
+    // difficult to test, so it would be very advantageous if we can define
+    // a mock context class.
+    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // tp_flags
+
+    "The TSIGContext class objects is...(COMPLETE THIS)",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL, // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    TSIGContext_methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(TSIGContext_init),            // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIGContext(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&tsigcontext_type) < 0) {
+        return (false);
+    }
+    void* p = &tsigcontext_type;
+    if (PyModule_AddObject(mod, "TSIGContext",
+                           static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&tsigcontext_type);
+
+    try {
+        // Class specific exceptions
+        po_TSIGContextError = PyErr_NewException("pydnspp.TSIGContextError",
+                                                 po_IscException, NULL);
+        PyObjectContainer(po_TSIGContextError).installToModule(
+            mod, "TSIGContextError");
+
+        // Constant class variables
+        installClassVariable(tsigcontext_type, "STATE_INIT",
+                             Py_BuildValue("I", TSIGContext::INIT));
+        installClassVariable(tsigcontext_type, "STATE_SENT_REQUEST",
+                             Py_BuildValue("I", TSIGContext::SENT_REQUEST));
+        installClassVariable(tsigcontext_type, "STATE_RECEIVED_REQUEST",
+                             Py_BuildValue("I", TSIGContext::RECEIVED_REQUEST));
+        installClassVariable(tsigcontext_type, "STATE_SENT_RESPONSE",
+                             Py_BuildValue("I", TSIGContext::SENT_RESPONSE));
+        installClassVariable(tsigcontext_type, "STATE_VERIFIED_RESPONSE",
+                             Py_BuildValue("I",
+                                           TSIGContext::VERIFIED_RESPONSE));
+
+        installClassVariable(tsigcontext_type, "DEFAULT_FUDGE",
+                             Py_BuildValue("H", TSIGContext::DEFAULT_FUDGE));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in TSIGContext initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in TSIGContext initialization");
+        return (false);
+    }
+
+    return (true);
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsig_python.h b/src/lib/dns/python/tsig_python.h
new file mode 100644
index 0000000..f9b4f7b
--- /dev/null
+++ b/src/lib/dns/python/tsig_python.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIGCONTEXT_H
+#define __PYTHON_TSIGCONTEXT_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class TSIGContext;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGContext : public PyObject {
+public:
+    s_TSIGContext();
+    TSIGContext* cppobj;
+};
+
+extern PyTypeObject tsigcontext_type;
+
+// Class specific exceptions
+extern PyObject* po_TSIGContextError;
+
+bool initModulePart_TSIGContext(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIGCONTEXT_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tsig_rdata_python.cc b/src/lib/dns/python/tsig_rdata_python.cc
new file mode 100644
index 0000000..4e4f287
--- /dev/null
+++ b/src/lib/dns/python/tsig_rdata_python.cc
@@ -0,0 +1,369 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/rdataclass.h>
+
+#include "pydnspp_common.h"
+#include "pydnspp_towire.h"
+#include "name_python.h"
+#include "tsig_rdata_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::dns::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// TSIG RDATA
+//
+
+// Trivial constructor.
+s_TSIG::s_TSIG() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_TSIG, any::TSIG> TSIGContainer;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIG_init(s_TSIG* self, PyObject* args);
+void TSIG_destroy(s_TSIG* self);
+
+// These are the functions we export
+// ADD/REMOVE/MODIFY THE FOLLOWING AS APPROPRIATE FOR THE ACTUAL CLASS.
+//
+PyObject* TSIG_toText(const s_TSIG* const self);
+PyObject* TSIG_getAlgorithm(const s_TSIG* const self);
+PyObject* TSIG_getTimeSigned(const s_TSIG* const self);
+PyObject* TSIG_getFudge(const s_TSIG* const self);
+PyObject* TSIG_getOriginalID(const s_TSIG* const self);
+PyObject* TSIG_getError(const s_TSIG* const self);
+PyObject* TSIG_getMAC(const s_TSIG* const self);
+PyObject* TSIG_getOtherData(const s_TSIG* const self);
+PyObject* TSIG_str(PyObject* self);
+PyObject* TSIG_richcmp(const s_TSIG* const self,
+                       const s_TSIG* const other, int op);
+PyObject* TSIG_toWire(const s_TSIG* self, PyObject* args);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIG_methods[] = {
+    { "get_algorithm", reinterpret_cast<PyCFunction>(TSIG_getAlgorithm),
+      METH_NOARGS,
+      "Return the algorithm name." },
+    { "get_timesigned", reinterpret_cast<PyCFunction>(TSIG_getTimeSigned),
+      METH_NOARGS,
+      "Return the value of the Time Signed field. "
+      "The returned value does not exceed 2^48-1."
+    },
+    { "get_fudge", reinterpret_cast<PyCFunction>(TSIG_getFudge),
+      METH_NOARGS,
+      "Return the value of the Fudge field." },
+    { "get_original_id", reinterpret_cast<PyCFunction>(TSIG_getOriginalID),
+      METH_NOARGS,
+      "Return the value of the Original ID field." },
+    { "get_error", reinterpret_cast<PyCFunction>(TSIG_getError),
+      METH_NOARGS,
+      "Return the value of the Error field." },
+    { "get_mac", reinterpret_cast<PyCFunction>(TSIG_getMAC),
+      METH_NOARGS,
+      "Return the value of the MAC field."
+      "If it's empty, return None." },
+    { "get_other_data", reinterpret_cast<PyCFunction>(TSIG_getOtherData),
+      METH_NOARGS,
+      "Return the value of the Other Data field."
+      "If it's empty, return None." },
+    { "to_text", reinterpret_cast<PyCFunction>(TSIG_toText), METH_NOARGS,
+      "Returns the text representation" },
+    { "to_wire", reinterpret_cast<PyCFunction>(TSIG_toWire), METH_VARARGS,
+      "Converts the TSIG object to wire format.\n"
+      "The argument can be either a MessageRenderer or an object that "
+      "implements the sequence interface. If the object is mutable "
+      "(for instance a bytearray()), the wire data is added in-place.\n"
+      "If it is not (for instance a bytes() object), a new object is "
+      "returned" },
+    { NULL, NULL, 0, NULL }
+};
+
+int
+TSIG_init(s_TSIG* self, PyObject* args) {
+    try {
+        // constructor from string
+        const char* rdata_str;
+        if (PyArg_ParseTuple(args, "s", &rdata_str)) {
+            self->cppobj = new any::TSIG(string(rdata_str));
+            return (0);
+        }
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct TSIG object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in constructing TSIG");
+        return (-1);
+    }
+
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to TSIG constructor");
+
+    return (-1);
+}
+
+void
+TSIG_destroy(s_TSIG* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+TSIG_getAlgorithm(const s_TSIG* const self) {
+    try {
+        return (createNameObject(self->cppobj->getAlgorithm()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to get TSIG algorithm: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting TSIG algorithm");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIG_getTimeSigned(const s_TSIG* const self) {
+    return (Py_BuildValue("K", self->cppobj->getTimeSigned()));
+}
+
+PyObject*
+TSIG_getFudge(const s_TSIG* const self) {
+    return (Py_BuildValue("H", self->cppobj->getFudge()));
+}
+
+PyObject*
+TSIG_getOriginalID(const s_TSIG* const self) {
+    return (Py_BuildValue("H", self->cppobj->getOriginalID()));
+}
+
+PyObject*
+TSIG_getError(const s_TSIG* const self) {
+    return (Py_BuildValue("H", self->cppobj->getError()));
+}
+
+PyObject*
+TSIG_getMAC(const s_TSIG* const self) {
+    return (Py_BuildValue("y#", self->cppobj->getMAC(),
+                          self->cppobj->getMACSize()));
+}
+
+PyObject*
+TSIG_getOtherData(const s_TSIG* const self) {
+    return (Py_BuildValue("y#", self->cppobj->getOtherData(),
+                          self->cppobj->getOtherLen()));
+}
+
+PyObject*
+TSIG_toText(const s_TSIG* const self) {
+    try {
+        // toText() could throw, so we need to catch any exceptions below.
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to convert TSIG object to text: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "converting TSIG object to text");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIG_str(PyObject* self) {
+    // Simply call the to_text method we already defined
+    return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+                                const_cast<char*>("")));
+}
+
+PyObject*
+TSIG_toWire(const s_TSIG* const self, PyObject* args) {
+    typedef any::TSIG TSIGRdata;
+    return (toWireWrapper<s_TSIG, TSIGRdata, ToWireCallVoid<const TSIGRdata> >(
+                self, args));
+}
+
+PyObject* 
+TSIG_richcmp(const s_TSIG* const self,
+                   const s_TSIG* const other,
+                   const int op)
+{
+    bool c = false;
+
+    // Check for null and if the types match. If different type,
+    // simply return False
+    if (other == NULL || (self->ob_type != other->ob_type)) {
+        Py_RETURN_FALSE;
+    }
+
+    // Only equals and not equals here, unorderable type
+    const int cmp = self->cppobj->compare(*other->cppobj);
+    switch (op) {
+    case Py_EQ:
+        c = (cmp == 0);
+        break;
+    case Py_NE:
+        c = (cmp != 0);
+        break;
+    case Py_GT:
+        c = (cmp > 0);
+        break;
+    case Py_GE:
+        c = (cmp >= 0);
+        break;
+    case Py_LT:
+        c = (cmp < 0);
+        break;
+    case Py_LE:
+        c = (cmp <= 0);
+        break;
+    default:
+        PyErr_SetString(PyExc_IndexError,
+                        "Unhandled rich comparison operator for TSIG");
+        return (NULL);
+    }
+    if (c) {
+        Py_RETURN_TRUE;
+    } else {
+        Py_RETURN_FALSE;
+    }
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_TSIG
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsig_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.TSIG",
+    sizeof(s_TSIG),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(TSIG_destroy),       // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    TSIG_str,                       // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The TSIG class objects represents the TSIG RDATA as defined in RFC2845.",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    reinterpret_cast<richcmpfunc>(TSIG_richcmp), // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    TSIG_methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    // At the moment, we leave tp_base NULL as we won't use this class
+    // in a polymorphic way for our immediate need.
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(TSIG_init),            // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIG(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&tsig_type) < 0) {
+        return (false);
+    }
+    void* p = &tsig_type;
+    if (PyModule_AddObject(mod, "TSIG", static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&tsig_type);
+
+    return (true);
+}
+
+PyObject*
+createTSIGObject(const any::TSIG& source) {
+    TSIGContainer container = PyObject_New(s_TSIG, &tsig_type);
+    container.set(new any::TSIG(source));
+    return (container.release());
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsig_rdata_python.h b/src/lib/dns/python/tsig_rdata_python.h
new file mode 100644
index 0000000..e5e0c6c
--- /dev/null
+++ b/src/lib/dns/python/tsig_rdata_python.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIG_H
+#define __PYTHON_TSIG_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace any {
+class TSIG;
+}
+}
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIG : public PyObject {
+public:
+    s_TSIG();
+    const rdata::any::TSIG* cppobj;
+};
+
+extern PyTypeObject tsig_type;
+
+bool initModulePart_TSIG(PyObject* mod);
+
+/// This is A simple shortcut to create a python TSIG object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called with in a try block
+/// followed by necessary setup for python exception.
+PyObject* createTSIGObject(const rdata::any::TSIG& source);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIG_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tsigerror_python.cc b/src/lib/dns/python/tsigerror_python.cc
new file mode 100644
index 0000000..0ad4716
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python.cc
@@ -0,0 +1,370 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/tsigerror.h>
+
+#include "pydnspp_common.h"
+#include "rcode_python.h"
+#include "tsigerror_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// TSIGError
+//
+
+// Trivial constructor.
+s_TSIGError::s_TSIGError() : cppobj(NULL) {
+}
+
+// Import pydoc text
+#include "tsigerror_python_inc.cc"
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_TSIGError, TSIGError> TSIGErrorContainer;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIGError_init(s_TSIGError* self, PyObject* args);
+void TSIGError_destroy(s_TSIGError* self);
+
+// These are the functions we export
+PyObject* TSIGError_getCode(const s_TSIGError* const self);
+PyObject* TSIGError_toText(const s_TSIGError* const self);
+PyObject* TSIGError_toRcode(const s_TSIGError* const self);
+PyObject* TSIGError_str(PyObject* self);
+PyObject* TSIGError_richcmp(const s_TSIGError* const self,
+                            const s_TSIGError* const other, int op);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIGError_methods[] = {
+    { "get_code", reinterpret_cast<PyCFunction>(TSIGError_getCode),
+      METH_NOARGS,
+      TSIGError_getCode_doc },
+    { "to_text", reinterpret_cast<PyCFunction>(TSIGError_toText), METH_NOARGS,
+      TSIGError_toText_doc },
+    { "to_rcode", reinterpret_cast<PyCFunction>(TSIGError_toRcode),
+      METH_NOARGS,
+      TSIGError_toRcode_doc },
+    { NULL, NULL, 0, NULL }
+};
+
+int
+TSIGError_init(s_TSIGError* self, PyObject* args) {
+    try {
+        // Constructor from the code value
+        long code = 0;
+        if (PyArg_ParseTuple(args, "l", &code)) {
+            if (code < 0 || code > 0xffff) {
+                PyErr_SetString(PyExc_ValueError, "TSIG error out of range");
+                return (-1);
+            }
+            self->cppobj = new TSIGError(code);
+            return (0);
+        }
+
+        // Constructor from Rcode
+        PyErr_Clear();
+        s_Rcode* py_rcode;
+        if (PyArg_ParseTuple(args, "O!", &rcode_type, &py_rcode)) {
+            self->cppobj = new TSIGError(*py_rcode->cppobj);
+            return (0);
+        }
+    } catch (const isc::OutOfRange& ex) {
+        const string ex_what = "Failed to construct TSIGError object: " +
+            string(ex.what());
+        PyErr_SetString(PyExc_ValueError, ex_what.c_str());
+        return (-1);
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct TSIGError object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in constructing TSIGError");
+        return (-1);
+    }
+
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to TSIGError constructor");
+
+    return (-1);
+}
+
+void
+TSIGError_destroy(s_TSIGError* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+TSIGError_getCode(const s_TSIGError* const self) {
+    return (Py_BuildValue("I", self->cppobj->getCode()));
+}
+
+PyObject*
+TSIGError_toText(const s_TSIGError* const self) {
+    try {
+        // toText() could throw, so we need to catch any exceptions below.
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to convert TSIGError object to text: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "converting TSIGError object to text");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGError_str(PyObject* self) {
+    // Simply call the to_text method we already defined
+    return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+                                const_cast<char*>("")));
+}
+
+PyObject*
+TSIGError_toRcode(const s_TSIGError* const self) {
+    typedef CPPPyObjectContainer<s_Rcode, Rcode> RcodePyObjectContainer;
+
+    try {
+        RcodePyObjectContainer rcode_container(PyObject_New(s_Rcode,
+                                                            &rcode_type));
+        rcode_container.set(new Rcode(self->cppobj->toRcode()));
+        return (rcode_container.release());
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to convert TSIGError to Rcode: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "converting TSIGError to Rcode");
+    }
+    return (NULL);
+}
+
+PyObject* 
+TSIGError_richcmp(const s_TSIGError* const self,
+                   const s_TSIGError* const other,
+                   const int op)
+{
+    bool c = false;
+
+    // Check for null and if the types match. If different type,
+    // simply return False
+    if (other == NULL || (self->ob_type != other->ob_type)) {
+        Py_RETURN_FALSE;
+    }
+
+    // Only equals and not equals here, unorderable type
+    switch (op) {
+    case Py_LT:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+        return (NULL);
+    case Py_LE:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+        return (NULL);
+    case Py_EQ:
+        c = (*self->cppobj == *other->cppobj);
+        break;
+    case Py_NE:
+        c = (*self->cppobj != *other->cppobj);
+        break;
+    case Py_GT:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+        return (NULL);
+    case Py_GE:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+        return (NULL);
+    }
+    if (c) {
+        Py_RETURN_TRUE;
+    } else {
+        Py_RETURN_FALSE;
+    }
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_TSIGError
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsigerror_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.TSIGError",
+    sizeof(s_TSIGError),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(TSIGError_destroy),       // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    // THIS MAY HAVE TO BE CHANGED TO NULL:
+    TSIGError_str,                       // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    TSIGError_doc,
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    // THIS MAY HAVE TO BE CHANGED TO NULL:
+    reinterpret_cast<richcmpfunc>(TSIGError_richcmp), // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    TSIGError_methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(TSIGError_init),            // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+namespace {
+// Trivial shortcut to create and install TSIGError constants.
+inline void
+installTSIGErrorConstant(const char* name, const TSIGError& val) {
+    TSIGErrorContainer container(PyObject_New(s_TSIGError, &tsigerror_type));
+    container.installAsClassVariable(tsigerror_type, name, new TSIGError(val));
+}
+}
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIGError(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&tsigerror_type) < 0) {
+        return (false);
+    }
+    void* p = &tsigerror_type;
+    if (PyModule_AddObject(mod, "TSIGError", static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&tsigerror_type);
+
+    try {
+        // Constant class variables
+        // Error codes (bare values)
+        installClassVariable(tsigerror_type, "BAD_SIG_CODE",
+                             Py_BuildValue("H", TSIGError::BAD_SIG_CODE));
+        installClassVariable(tsigerror_type, "BAD_KEY_CODE",
+                             Py_BuildValue("H", TSIGError::BAD_KEY_CODE));
+        installClassVariable(tsigerror_type, "BAD_TIME_CODE",
+                             Py_BuildValue("H", TSIGError::BAD_TIME_CODE));
+
+        // Error codes (constant objects)
+        installTSIGErrorConstant("NOERROR", TSIGError::NOERROR());
+        installTSIGErrorConstant("FORMERR", TSIGError::FORMERR());
+        installTSIGErrorConstant("SERVFAIL", TSIGError::SERVFAIL());
+        installTSIGErrorConstant("NXDOMAIN", TSIGError::NXDOMAIN());
+        installTSIGErrorConstant("NOTIMP", TSIGError::NOTIMP());
+        installTSIGErrorConstant("REFUSED", TSIGError::REFUSED());
+        installTSIGErrorConstant("YXDOMAIN", TSIGError::YXDOMAIN());
+        installTSIGErrorConstant("YXRRSET", TSIGError::YXRRSET());
+        installTSIGErrorConstant("NXRRSET", TSIGError::NXRRSET());
+        installTSIGErrorConstant("NOTAUTH", TSIGError::NOTAUTH());
+        installTSIGErrorConstant("NOTZONE", TSIGError::NOTZONE());
+        installTSIGErrorConstant("RESERVED11", TSIGError::RESERVED11());
+        installTSIGErrorConstant("RESERVED12", TSIGError::RESERVED12());
+        installTSIGErrorConstant("RESERVED13", TSIGError::RESERVED13());
+        installTSIGErrorConstant("RESERVED14", TSIGError::RESERVED14());
+        installTSIGErrorConstant("RESERVED15", TSIGError::RESERVED15());
+        installTSIGErrorConstant("BAD_SIG", TSIGError::BAD_SIG());
+        installTSIGErrorConstant("BAD_KEY", TSIGError::BAD_KEY());
+        installTSIGErrorConstant("BAD_TIME", TSIGError::BAD_TIME());
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in TSIGError initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in TSIGError initialization");
+        return (false);
+    }
+
+    return (true);
+}
+
+PyObject*
+createTSIGErrorObject(const TSIGError& source) {
+    TSIGErrorContainer container = PyObject_New(s_TSIGError, &tsigerror_type);
+    container.set(new TSIGError(source));
+    return (container.release());
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsigerror_python.h b/src/lib/dns/python/tsigerror_python.h
new file mode 100644
index 0000000..735a480
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIGERROR_H
+#define __PYTHON_TSIGERROR_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class TSIGError;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGError : public PyObject {
+public:
+    s_TSIGError();
+    const TSIGError* cppobj;
+};
+
+extern PyTypeObject tsigerror_type;
+
+bool initModulePart_TSIGError(PyObject* mod);
+
+/// This is A simple shortcut to create a python TSIGError object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called with in a try block
+/// followed by necessary setup for python exception.
+PyObject* createTSIGErrorObject(const TSIGError& source);
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIGERROR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tsigerror_python_inc.cc b/src/lib/dns/python/tsigerror_python_inc.cc
new file mode 100644
index 0000000..ed3b605
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python_inc.cc
@@ -0,0 +1,83 @@
+namespace {
+const char* const TSIGError_doc = "\n\
+TSIG errors.\n\
+\n\
+\n\
+The TSIGError class objects represent standard errors related to TSIG\n\
+protocol operations as defined in related specifications, mainly in\n\
+RFC2845.\n\
+\n\
+TSIGError(error_code)\n\
+\n\
+Constructor from the code value.\n\
+\n\
+Exceptions:\n\
+  None: \n\
+\n\
+Parameters:\n\
+  error_code: The underlying 16-bit error code value of the TSIGError.\n\
+\n\
+TSIGError(rcode)\n\
+\n\
+Constructor from Rcode.\n\
+\n\
+As defined in RFC2845, error code values from 0 to 15 (inclusive) are\n\
+derived from the DNS RCODEs, which are represented via the Rcode class\n\
+in this library. This constructor works as a converter from these\n\
+RCODEs to corresponding TSIGError objects.\n\
+\n\
+Exceptions:\n\
+  ValueError: Given rcode is not convertible to TSIGErrors.\n\
+\n\
+Parameters:\n\
+  rcode: the Rcode from which the TSIGError should be derived.\n\
+\n\
+";
+const char* const TSIGError_getCode_doc = "get_code() -> integer\n\
+\n\
+Returns the TSIGCode error code value.\n\
+\n\
+Exceptions:\n\
+  None: \n\
+\n\
+Return Value(s):\n\
+  The underlying code value corresponding to the TSIGError.\n\
+";
+const char* const TSIGError_toText_doc = "to_text() -> string\n\
+\n\
+Convert the TSIGError to a string.\n\
+\n\
+For codes derived from RCODEs up to 15, this method returns the same\n\
+string as Rcode.to_text() for the corresponding code. For other pre-\n\
+defined code values (see TSIGError.CodeValue), this method returns a\n\
+string representation of the \"mnemonic' used for the enum and\n\
+constant objects as defined in RFC2845. For example, the string for\n\
+code value 16 is \"BADSIG\", etc. For other code values it returns a\n\
+string representation of the decimal number of the value, e.g. \"32\",\n\
+\"100\", etc.\n\
+\n\
+Exceptions:\n\
+  None\n\
+\n\
+Return Value(s):\n\
+  A string representation of the TSIGError.\n\
+";
+const char* const TSIGError_toRcode_doc = "to_rcode() -> Rcode\n\
+\n\
+Convert the TSIGError to a Rcode.\n\
+\n\
+This method returns an Rcode object that is corresponding to the TSIG\n\
+error. The returned Rcode is expected to be used by a verifying server\n\
+to specify the RCODE of a response when TSIG verification fails.\n\
+\n\
+Specifically, this method returns Rcode.NOTAUTH() for the TSIG\n\
+specific errors, BADSIG, BADKEY, BADTIME, as described in RFC2845. For\n\
+errors derived from the standard Rcode (code 0-15), it returns the\n\
+corresponding Rcode. For others, this method returns Rcode.SERVFAIL()\n\
+as a last resort.\n\
+\n\
+Exceptions:\n\
+  None: \n\
+\n\
+";
+}
diff --git a/src/lib/dns/python/tsigkey_python.cc b/src/lib/dns/python/tsigkey_python.cc
index aa87909..f0906cb 100644
--- a/src/lib/dns/python/tsigkey_python.cc
+++ b/src/lib/dns/python/tsigkey_python.cc
@@ -12,12 +12,24 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <new>
+#include <Python.h>
 
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/name.h>
 #include <dns/tsigkey.h>
+#include <dns/rdata.h>
 
+#include "pydnspp_common.h"
+#include "name_python.h"
+#include "tsigkey_python.h"
+
+using namespace std;
+using namespace isc::util::python;
 using namespace isc::dns;
-using namespace isc::dns::rdata;
+using namespace isc::dns::python;
 
 //
 // Definition of the classes
@@ -27,19 +39,15 @@ using namespace isc::dns::rdata;
 // and static wrappers around the methods we export), a list of methods,
 // and a type description
 
-namespace {
 //
 // TSIGKey
 //
 
 // The s_* Class simply covers one instantiation of the object
 
-class s_TSIGKey : public PyObject {
-public:
-    s_TSIGKey() : tsigkey(NULL) {}
-    TSIGKey* tsigkey;
-};
+s_TSIGKey::s_TSIGKey() : cppobj(NULL) {}
 
+namespace {
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -55,6 +63,7 @@ void TSIGKey_destroy(s_TSIGKey* self);
 PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
 PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
 PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
+PyObject* TSIGKey_toText(const s_TSIGKey* self);
 
 // This list contains the actual set of functions we have in
 // python. Each entry has
@@ -72,15 +81,110 @@ PyMethodDef TSIGKey_methods[] = {
     { "get_secret",
       reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
       "Return the value of the TSIG secret." },
+    { "to_text", reinterpret_cast<PyCFunction>(TSIGKey_toText), METH_NOARGS,
+      "Returns the string representation (name:secret:algorithm)" },
     { NULL, NULL, 0, NULL }
 };
 
+int
+TSIGKey_init(s_TSIGKey* self, PyObject* args) {
+    try {
+        const char* str;
+        if (PyArg_ParseTuple(args, "s", &str)) {
+            self->cppobj = new TSIGKey(str);
+            return (0);
+        }
+
+        PyErr_Clear();
+        const s_Name* key_name;
+        const s_Name* algorithm_name;
+        PyObject* bytes_obj;
+        const char* secret;
+        Py_ssize_t secret_len;
+        if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
+                             &name_type, &algorithm_name, &bytes_obj) &&
+            PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) == 0) {
+            if (secret_len == 0) {
+                secret = NULL;
+            }
+            self->cppobj = new TSIGKey(*key_name->cppobj,
+                                       *algorithm_name->cppobj,
+                                       secret, secret_len);
+            return (0);
+        }
+    } catch (const isc::InvalidParameter& ex) {
+        PyErr_SetString(po_InvalidParameter, ex.what());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpected exception");
+        return (-1);
+    }
+
+    PyErr_Clear();
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to TSIGKey constructor");
+
+    return (-1);
+}
+
+void
+TSIGKey_destroy(s_TSIGKey* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+TSIGKey_getKeyName(const s_TSIGKey* const self) {
+    try {
+        return (createNameObject(self->cppobj->getKeyName()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to get key name of TSIGKey: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting key name of TSIGKey");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGKey_getAlgorithmName(const s_TSIGKey* const self) {
+    try {
+        return (createNameObject(self->cppobj->getAlgorithmName()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to get algorithm name of TSIGKey: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting algorithm name of TSIGKey");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGKey_getSecret(const s_TSIGKey* const self) {
+    return (Py_BuildValue("y#", self->cppobj->getSecret(),
+                          self->cppobj->getSecretLength()));
+}
+
+PyObject*
+TSIGKey_toText(const s_TSIGKey* self) {
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
 // This defines the complete type for reflection in python and
 // parsing of PyObject* to s_EDNS
 // Most of the functions are not actually implemented and NULL here.
 PyTypeObject tsigkey_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.TSIGKey",
+    "pydnspp.TSIGKey",
     sizeof(s_TSIGKey),                  // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)TSIGKey_destroy,        // tp_dealloc
@@ -129,78 +233,6 @@ PyTypeObject tsigkey_type = {
     0                                   // tp_version_tag
 };
 
-// A helper function to build a python "Name" object with error handling
-// encapsulated.
-s_Name*
-createNameObject(const Name& source) {
-    s_Name* name = PyObject_New(s_Name, &name_type);
-    if (name == NULL) {
-        return (NULL);
-    }
-    name->name = new(nothrow) Name(source);
-    if (name->name == NULL) {
-        Py_DECREF(name);
-        PyErr_SetString(po_IscException, "Allocating Name object failed");
-        return (NULL);
-    }
-    return (name);
-}
-
-int
-TSIGKey_init(s_TSIGKey* self, PyObject* args) {
-    const s_Name* key_name;
-    const s_Name* algorithm_name;
-    PyObject* bytes_obj;
-    const char* secret;
-    Py_ssize_t secret_len;
-
-    if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
-                         &name_type, &algorithm_name, &bytes_obj) &&
-        PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
-        try {
-            self->tsigkey = new TSIGKey(*key_name->name,
-                                        *algorithm_name->name,
-                                        secret, secret_len);
-        } catch (const isc::InvalidParameter& ex) {
-            PyErr_SetString(po_InvalidParameter, ex.what());
-            return (-1);
-        } catch (...) {
-            PyErr_SetString(po_IscException, "Unexpected exception");
-            return (-1);
-        }
-        return (0);
-    }
-
-    PyErr_Clear();
-    PyErr_SetString(PyExc_TypeError,
-                    "Invalid arguments to TSIGKey constructor");
-
-    return (-1);
-}
-
-void
-TSIGKey_destroy(s_TSIGKey* const self) {
-    delete self->tsigkey;
-    self->tsigkey = NULL;
-    Py_TYPE(self)->tp_free(self);
-}
-
-PyObject*
-TSIGKey_getKeyName(const s_TSIGKey* const self) {
-    return (createNameObject(self->tsigkey->getKeyName()));
-}
-
-PyObject*
-TSIGKey_getAlgorithmName(const s_TSIGKey* const self) {
-    return (createNameObject(self->tsigkey->getAlgorithmName()));
-}
-
-PyObject*
-TSIGKey_getSecret(const s_TSIGKey* const self) {
-    return (Py_BuildValue("y#", self->tsigkey->getSecret(),
-                          self->tsigkey->getSecretLength()));
-}
-
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_TSIGKey(PyObject* mod) {
@@ -210,33 +242,43 @@ initModulePart_TSIGKey(PyObject* mod) {
     if (PyType_Ready(&tsigkey_type) < 0) {
         return (false);
     }
-    Py_INCREF(&tsigkey_type);
     void* p = &tsigkey_type;
     if (PyModule_AddObject(mod, "TSIGKey", static_cast<PyObject*>(p)) != 0) {
-        Py_DECREF(&tsigkey_type);
         return (false);
     }
+    Py_INCREF(&tsigkey_type);
 
-    s_Name* name;
-    if ((name = createNameObject(TSIGKey::HMACMD5_NAME())) == NULL) {
-        goto cleanup;
-    }
-    addClassVariable(tsigkey_type, "HMACMD5_NAME", name);
-    if ((name = createNameObject(TSIGKey::HMACSHA1_NAME())) == NULL) {
-        goto cleanup;
-    }
-    addClassVariable(tsigkey_type, "HMACSHA1_NAME", name);
-    if ((name = createNameObject(TSIGKey::HMACSHA256_NAME())) == NULL) {
-        goto cleanup;
+    try {
+        // Constant class variables
+        installClassVariable(tsigkey_type, "HMACMD5_NAME",
+                             createNameObject(TSIGKey::HMACMD5_NAME()));
+        installClassVariable(tsigkey_type, "HMACSHA1_NAME",
+                             createNameObject(TSIGKey::HMACSHA1_NAME()));
+        installClassVariable(tsigkey_type, "HMACSHA256_NAME",
+                             createNameObject(TSIGKey::HMACSHA256_NAME()));
+        installClassVariable(tsigkey_type, "HMACSHA224_NAME",
+                             createNameObject(TSIGKey::HMACSHA224_NAME()));
+        installClassVariable(tsigkey_type, "HMACSHA384_NAME",
+                             createNameObject(TSIGKey::HMACSHA384_NAME()));
+        installClassVariable(tsigkey_type, "HMACSHA512_NAME",
+                             createNameObject(TSIGKey::HMACSHA512_NAME()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in TSIGKey initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in TSIGKey initialization");
+        return (false);
     }
-    addClassVariable(tsigkey_type, "HMACSHA256_NAME", name);
 
     return (true);
-
-  cleanup:
-    Py_DECREF(&tsigkey_type);
-    return (false);
 }
+} // namespace python
+} // namespace dns
+} // namespace isc
 //
 // End of TSIGKey
 //
@@ -249,12 +291,9 @@ initModulePart_TSIGKey(PyObject* mod) {
 
 // The s_* Class simply covers one instantiation of the object
 
-class s_TSIGKeyRing : public PyObject {
-public:
-    s_TSIGKeyRing() : keyring(NULL) {}
-    TSIGKeyRing* keyring;
-};
+s_TSIGKeyRing::s_TSIGKeyRing() : cppobj(NULL) {}
 
+namespace {
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -282,56 +321,6 @@ PyMethodDef TSIGKeyRing_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-PyTypeObject tsigkeyring_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.TSIGKeyRing",
-    sizeof(s_TSIGKeyRing),              // tp_basicsize
-    0,                                  // tp_itemsize
-    (destructor)TSIGKeyRing_destroy,    // tp_dealloc
-    NULL,                               // tp_print
-    NULL,                               // tp_getattr
-    NULL,                               // tp_setattr
-    NULL,                               // tp_reserved
-    NULL,                               // tp_repr
-    NULL,                               // tp_as_number
-    NULL,                               // tp_as_sequence
-    NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
-    NULL,                               // tp_call
-    NULL,                               // tp_str
-    NULL,                               // tp_getattro
-    NULL,                               // tp_setattro
-    NULL,                               // tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                 // tp_flags
-    "A simple repository of a set of TSIGKey objects.",
-    NULL,                               // tp_traverse
-    NULL,                               // tp_clear
-    NULL,                               // tp_richcompare
-    0,                                  // tp_weaklistoffset
-    NULL,                               // tp_iter
-    NULL,                               // tp_iternext
-    TSIGKeyRing_methods,                // tp_methods
-    NULL,                               // tp_members
-    NULL,                               // tp_getset
-    NULL,                               // tp_base
-    NULL,                               // tp_dict
-    NULL,                               // tp_descr_get
-    NULL,                               // tp_descr_set
-    0,                                  // tp_dictoffset
-    (initproc)TSIGKeyRing_init,         // tp_init
-    NULL,                               // tp_alloc
-    PyType_GenericNew,                  // tp_new
-    NULL,                               // tp_free
-    NULL,                               // tp_is_gc
-    NULL,                               // tp_bases
-    NULL,                               // tp_mro
-    NULL,                               // tp_cache
-    NULL,                               // tp_subclasses
-    NULL,                               // tp_weaklist
-    NULL,                               // tp_del
-    0                                   // tp_version_tag
-};
-
 int
 TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
     if (!PyArg_ParseTuple(args, "")) {
@@ -341,8 +330,8 @@ TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
         return (-1);
     }
     
-    self->keyring = new(nothrow) TSIGKeyRing();
-    if (self->keyring == NULL) {
+    self->cppobj = new(nothrow) TSIGKeyRing();
+    if (self->cppobj == NULL) {
         PyErr_SetString(po_IscException, "Allocating TSIGKeyRing failed");
         return (-1);
     }
@@ -352,14 +341,14 @@ TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
 
 void
 TSIGKeyRing_destroy(s_TSIGKeyRing* self) {
-    delete self->keyring;
-    self->keyring = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 TSIGKeyRing_size(const s_TSIGKeyRing* const self) {
-    return (Py_BuildValue("I", self->keyring->size()));
+    return (Py_BuildValue("I", self->cppobj->size()));
 }
 
 PyObject*
@@ -369,7 +358,7 @@ TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {
     if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey)) {
         try {
             const TSIGKeyRing::Result result =
-                self->keyring->add(*tsigkey->tsigkey);
+                self->cppobj->add(*tsigkey->cppobj);
             return (Py_BuildValue("I", result));
         } catch (...) {
             PyErr_SetString(po_IscException, "Unexpected exception");
@@ -389,7 +378,7 @@ TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
 
     if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
         const TSIGKeyRing::Result result =
-            self->keyring->remove(*key_name->name);
+            self->cppobj->remove(*key_name->cppobj);
         return (Py_BuildValue("I", result));
     }
 
@@ -402,17 +391,19 @@ TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
 PyObject*
 TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
     s_Name* key_name;
+    s_Name* algorithm_name;
 
-    if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
+    if (PyArg_ParseTuple(args, "O!O!", &name_type, &key_name,
+                         &name_type, &algorithm_name)) {
         const TSIGKeyRing::FindResult result =
-            self->keyring->find(*key_name->name);
+            self->cppobj->find(*key_name->cppobj, *algorithm_name->cppobj);
         if (result.key != NULL) {
             s_TSIGKey* key = PyObject_New(s_TSIGKey, &tsigkey_type);
             if (key == NULL) {
                 return (NULL);
             }
-            key->tsigkey = new(nothrow) TSIGKey(*result.key);
-            if (key->tsigkey == NULL) {
+            key->cppobj = new(nothrow) TSIGKey(*result.key);
+            if (key->cppobj == NULL) {
                 Py_DECREF(key);
                 PyErr_SetString(po_IscException,
                                 "Allocating TSIGKey object failed");
@@ -426,6 +417,60 @@ TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
 
     return (NULL);
 }
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+PyTypeObject tsigkeyring_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.TSIGKeyRing",
+    sizeof(s_TSIGKeyRing),              // tp_basicsize
+    0,                                  // tp_itemsize
+    (destructor)TSIGKeyRing_destroy,    // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "A simple repository of a set of TSIGKey objects.",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    TSIGKeyRing_methods,                // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    (initproc)TSIGKeyRing_init,         // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
 
 bool
 initModulePart_TSIGKeyRing(PyObject* mod) {
@@ -449,5 +494,6 @@ initModulePart_TSIGKeyRing(PyObject* mod) {
 
     return (true);
 }
-
-} // end of unnamed namespace
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsigkey_python.h b/src/lib/dns/python/tsigkey_python.h
new file mode 100644
index 0000000..51b3ae7
--- /dev/null
+++ b/src/lib/dns/python/tsigkey_python.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIGKEY_H
+#define __PYTHON_TSIGKEY_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class TSIGKey;
+class TSIGKeyRing;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGKey : public PyObject {
+public:
+    s_TSIGKey();
+    TSIGKey* cppobj;
+};
+
+class s_TSIGKeyRing : public PyObject {
+public:
+    s_TSIGKeyRing();
+    TSIGKeyRing* cppobj;
+};
+
+extern PyTypeObject tsigkey_type;
+extern PyTypeObject tsigkeyring_type;
+
+bool initModulePart_TSIGKey(PyObject* mod);
+bool initModulePart_TSIGKeyRing(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIGKEY_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tsigrecord_python.cc b/src/lib/dns/python/tsigrecord_python.cc
new file mode 100644
index 0000000..8a78b5e
--- /dev/null
+++ b/src/lib/dns/python/tsigrecord_python.cc
@@ -0,0 +1,311 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/tsigrecord.h>
+
+#include "pydnspp_common.h"
+#include "pydnspp_towire.h"
+#include "name_python.h"
+#include "tsig_rdata_python.h"
+#include "tsigrecord_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// TSIGRecord
+//
+
+// Trivial constructor.
+s_TSIGRecord::s_TSIGRecord() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_TSIGRecord, TSIGRecord> TSIGRecordContainer;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIGRecord_init(s_TSIGRecord* self, PyObject* args);
+void TSIGRecord_destroy(s_TSIGRecord* self);
+PyObject* TSIGRecord_toText(const s_TSIGRecord* const self);
+PyObject* TSIGRecord_str(PyObject* self);
+PyObject* TSIGRecord_toWire(const s_TSIGRecord* self, PyObject* args);
+PyObject* TSIGRecord_getName(const s_TSIGRecord* self);
+PyObject* TSIGRecord_getLength(const s_TSIGRecord* self);
+PyObject* TSIGRecord_getRdata(const s_TSIGRecord* self);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIGRecord_methods[] = {
+    { "get_name", reinterpret_cast<PyCFunction>(TSIGRecord_getName),
+      METH_NOARGS,
+      "Return the owner name of the TSIG RR, which is the TSIG key name" },
+    { "get_length", reinterpret_cast<PyCFunction>(TSIGRecord_getLength),
+      METH_NOARGS,
+      "Return the length of the TSIG record" },
+    { "get_rdata", reinterpret_cast<PyCFunction>(TSIGRecord_getRdata),
+      METH_NOARGS,
+      "Return the RDATA of the TSIG RR" },
+    { "to_text", reinterpret_cast<PyCFunction>(TSIGRecord_toText), METH_NOARGS,
+      "Returns the text representation" },
+    { "to_wire", reinterpret_cast<PyCFunction>(TSIGRecord_toWire),
+      METH_VARARGS,
+      "Converts the TSIGRecord object to wire format.\n"
+      "The argument can be either a MessageRenderer or an object that "
+      "implements the sequence interface. If the object is mutable "
+      "(for instance a bytearray()), the wire data is added in-place.\n"
+      "If it is not (for instance a bytes() object), a new object is "
+      "returned" },
+    { NULL, NULL, 0, NULL }
+};
+
+int
+TSIGRecord_init(s_TSIGRecord* self, PyObject* args) {
+    try {
+        const s_Name* py_name;
+        const s_TSIG* py_tsig;
+        if (PyArg_ParseTuple(args, "O!O!", &name_type, &py_name,
+                             &tsig_type, &py_tsig)) {
+            self->cppobj = new TSIGRecord(*py_name->cppobj, *py_tsig->cppobj);
+            return (0);
+        }
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct TSIGRecord object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in constructing TSIGRecord");
+        return (-1);
+    }
+
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to TSIGRecord constructor");
+
+    return (-1);
+}
+
+// This is a template of typical code logic of python object destructor.
+// In many cases you can use it without modification, but check that carefully.
+void
+TSIGRecord_destroy(s_TSIGRecord* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+// This should be able to be used without modification as long as the
+// underlying C++ class has toText().
+PyObject*
+TSIGRecord_toText(const s_TSIGRecord* const self) {
+    try {
+        // toText() could throw, so we need to catch any exceptions below.
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to convert TSIGRecord object to text: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "converting TSIGRecord object to text");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGRecord_str(PyObject* self) {
+    // Simply call the to_text method we already defined
+    return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+                                const_cast<char*>("")));
+}
+
+PyObject*
+TSIGRecord_toWire(const s_TSIGRecord* const self, PyObject* args) {
+    typedef ToWireCallInt<const TSIGRecord> ToWireCall;
+    PyObject* (*towire_fn)(const s_TSIGRecord* const, PyObject*) =
+        toWireWrapper<s_TSIGRecord, TSIGRecord, ToWireCall>;
+    return (towire_fn(self, args));
+}
+
+PyObject*
+TSIGRecord_getName(const s_TSIGRecord* const self) {
+    try {
+        return (createNameObject(self->cppobj->getName()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to get TSIGRecord name: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting TSIGRecord name");
+    }
+    return (NULL);
+}
+
+PyObject*
+TSIGRecord_getLength(const s_TSIGRecord* const self) {
+    return (Py_BuildValue("H", self->cppobj->getLength()));
+}
+
+PyObject*
+TSIGRecord_getRdata(const s_TSIGRecord* const self) {
+    try {
+        return (createTSIGObject(self->cppobj->getRdata()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to get TSIGRecord RDATA: " + string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "getting TSIGRecord RDATA");
+    }
+    return (NULL);
+}
+
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_TSIGRecord
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsigrecord_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp.TSIGRecord",
+    sizeof(s_TSIGRecord),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(TSIGRecord_destroy),       // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    TSIGRecord_str,                       // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The TSIGRecord class objects is...(COMPLETE THIS)",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    TSIGRecord_methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(TSIGRecord_init),            // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIGRecord(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&tsigrecord_type) < 0) {
+        return (false);
+    }
+    void* p = &tsigrecord_type;
+    if (PyModule_AddObject(mod, "TSIGRecord", static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&tsigrecord_type);
+
+    // The following template is the typical procedure for installing class
+    // variables.  If the class doesn't have a class variable, remove the
+    // entire try-catch clauses.
+    try {
+        // Constant class variables
+        installClassVariable(tsigrecord_type, "TSIG_TTL",
+                             Py_BuildValue("I", 0));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in TSIGRecord initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in TSIGRecord initialization");
+        return (false);
+    }
+
+    return (true);
+}
+
+PyObject*
+createTSIGRecordObject(const TSIGRecord& source) {
+    TSIGRecordContainer container = PyObject_New(s_TSIGRecord,
+                                                 &tsigrecord_type);
+    container.set(new TSIGRecord(source));
+    return (container.release());
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsigrecord_python.h b/src/lib/dns/python/tsigrecord_python.h
new file mode 100644
index 0000000..e0a3526
--- /dev/null
+++ b/src/lib/dns/python/tsigrecord_python.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIGRECORD_H
+#define __PYTHON_TSIGRECORD_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class TSIGRecord;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGRecord : public PyObject {
+public:
+    s_TSIGRecord();
+    TSIGRecord* cppobj;
+};
+
+extern PyTypeObject tsigrecord_type;
+
+bool initModulePart_TSIGRecord(PyObject* mod);
+
+/// This is A simple shortcut to create a python TSIGRecord object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called with in a try block
+/// followed by necessary setup for python exception.
+PyObject* createTSIGRecordObject(const TSIGRecord& source);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIGRECORD_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/question.cc b/src/lib/dns/question.cc
index 3e14c78..96e2a9c 100644
--- a/src/lib/dns/question.cc
+++ b/src/lib/dns/question.cc
@@ -15,7 +15,7 @@
 #include <iostream>
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/question.h>
@@ -23,6 +23,7 @@
 #include <dns/rrtype.h>
 
 using namespace std;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -55,7 +56,7 @@ Question::toWire(OutputBuffer& buffer) const {
 }
 
 unsigned int
-Question::toWire(MessageRenderer& renderer) const {
+Question::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(name_);
     rrtype_.toWire(renderer);
     rrclass_.toWire(renderer);
diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h
index 520207b..b3f3d98 100644
--- a/src/lib/dns/question.h
+++ b/src/lib/dns/question.h
@@ -25,10 +25,14 @@
 #include <dns/rrtype.h>
 
 namespace isc {
+namespace util {
+class InputBuffer;
+class OutputBuffer;
+}
+
 namespace dns {
 
-class InputBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 class Question;
 
 /// \brief A pointer-like type pointing to an \c Question object.
@@ -118,7 +122,7 @@ public:
     /// classes fails.
     ///
     /// \param buffer A buffer storing the wire format data.
-    Question(InputBuffer& buffer);
+    Question(isc::util::InputBuffer& buffer);
 
     /// \brief Constructor from fixed parameters of the \c Question.
     ///
@@ -214,17 +218,17 @@ public:
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer and name compression information.
     /// \return 1
-    unsigned int toWire(MessageRenderer& renderer) const;
+    unsigned int toWire(AbstractMessageRenderer& renderer) const;
 
     /// \brief Render the Question in the wire format without name compression.
     ///
     /// This method behaves like the render version except it doesn't compress
     /// the owner name.
-    /// See \c toWire(MessageRenderer& renderer)const.
+    /// See \c toWire(AbstractMessageRenderer& renderer)const.
     ///
     /// \param buffer An output buffer to store the wire data.
     /// \return 1
-    unsigned int toWire(OutputBuffer& buffer) const;
+    unsigned int toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc
index 17fee25..27496a2 100644
--- a/src/lib/dns/rdata.cc
+++ b/src/lib/dns/rdata.cc
@@ -27,7 +27,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -36,6 +36,7 @@
 
 using namespace std;
 using namespace boost;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -53,7 +54,7 @@ createRdata(const RRType& rrtype, const RRClass& rrclass,
 
 RdataPtr
 createRdata(const RRType& rrtype, const RRClass& rrclass,
-            InputBuffer& buffer, size_t len)
+            isc::util::InputBuffer& buffer, size_t len)
 {
     if (len > MAX_RDLENGTH) {
         isc_throw(InvalidRdataLength, "RDLENGTH too large");
@@ -66,7 +67,8 @@ createRdata(const RRType& rrtype, const RRClass& rrclass,
                                                    len);
                                                    
     if (buffer.getPosition() - old_pos != len) {
-        isc_throw(InvalidRdataLength, "RDLENGTH mismatch");
+        isc_throw(InvalidRdataLength, "RDLENGTH mismatch: " <<
+                  buffer.getPosition() - old_pos << " != " << len);
     }
 
     return (rdata);
@@ -104,7 +106,7 @@ struct GenericImpl {
     vector<uint8_t> data_;
 };
 
-Generic::Generic(InputBuffer& buffer, size_t rdata_len) {
+Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) {
     if (rdata_len > MAX_RDLENGTH) {
         isc_throw(InvalidRdataLength, "RDLENGTH too large");
     }
@@ -223,12 +225,12 @@ Generic::toText() const {
 }
 
 void
-Generic::toWire(OutputBuffer& buffer) const {
+Generic::toWire(isc::util::OutputBuffer& buffer) const {
     buffer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
 void
-Generic::toWire(MessageRenderer& renderer) const {
+Generic::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h
index 8eaedd3..afcf4b3 100644
--- a/src/lib/dns/rdata.h
+++ b/src/lib/dns/rdata.h
@@ -22,10 +22,12 @@
 #include <exceptions/exceptions.h>
 
 namespace isc {
-namespace dns {
+namespace util {
 class InputBuffer;
 class OutputBuffer;
-class MessageRenderer;
+}
+namespace dns {
+class AbstractMessageRenderer;
 class RRType;
 class RRClass;
 class Name;
@@ -161,6 +163,7 @@ public:
     ///
     /// \return A string representation of \c Rdata.
     virtual std::string toText() const = 0;
+
     /// \brief Render the \c Rdata in the wire format into a buffer.
     ///
     /// This is a pure virtual method without the definition; the actual
@@ -168,7 +171,8 @@ public:
     /// should be explicitly defined in the derived class.
     ///
     /// \param buffer An output buffer to store the wire data.
-    virtual void toWire(OutputBuffer& buffer) const = 0;
+    virtual void toWire(isc::util::OutputBuffer& buffer) const = 0;
+
     /// \brief Render the \c Rdata in the wire format into a
     /// \c MessageRenderer object.
     ///
@@ -178,7 +182,7 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer in which the \c Rdata is to be stored.
-    virtual void toWire(MessageRenderer& renderer) const = 0;
+    virtual void toWire(AbstractMessageRenderer& renderer) const = 0;
     //@}
 
     ///
@@ -251,6 +255,7 @@ public:
     /// \param rdata_string A string of textual representation of generic
     /// RDATA.
     explicit Generic(const std::string& rdata_string);
+
     ///
     /// \brief Constructor from wire-format data.
     ///
@@ -272,7 +277,8 @@ public:
     /// \param buffer A reference to an \c InputBuffer object storing the
     /// \c Rdata to parse.
     /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
-    Generic(InputBuffer& buffer, size_t rdata_len);
+    Generic(isc::util::InputBuffer& buffer, size_t rdata_len);
+
     ///
     /// \brief The destructor.
     virtual ~Generic();
@@ -284,6 +290,7 @@ public:
     ///
     /// \param source A reference to a \c generic::Generic object to copy from.
     Generic(const Generic& source);
+
     ///
     /// \brief The assignment operator.
     ///
@@ -293,6 +300,7 @@ public:
     /// \param source A reference to a \c generic::Generic object to copy from.
     Generic& operator=(const Generic& source);
     //@}
+
     ///
     /// \name Converter methods
     ///
@@ -307,6 +315,7 @@ public:
     ///
     /// \return A string representation of \c generic::Generic.
     virtual std::string toText() const;
+
     ///
     /// \brief Render the \c generic::Generic in the wire format into a buffer.
     ///
@@ -316,7 +325,8 @@ public:
     /// be thrown.
     ///
     /// \param buffer An output buffer to store the wire data.
-    virtual void toWire(OutputBuffer& buffer) const;
+    virtual void toWire(isc::util::OutputBuffer& buffer) const;
+
     /// \brief Render the \c generic::Generic in the wire format into a
     /// \c MessageRenderer object.
     ///
@@ -327,8 +337,9 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer in which the \c Generic object is to be stored.
-    virtual void toWire(MessageRenderer& renderer) const;
+    virtual void toWire(AbstractMessageRenderer& renderer) const;
     //@}
+
     ///
     /// \name Comparison method
     ///
@@ -421,6 +432,7 @@ std::ostream& operator<<(std::ostream& os, const Generic& rdata);
 /// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      const std::string& rdata_string);
+
 /// \brief Create RDATA of a given pair of RR type and class from
 /// wire-format data.
 ///
@@ -443,7 +455,8 @@ RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
 /// \return An \c RdataPtr object pointing to the created \c Rdata
 /// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
-                     InputBuffer& buffer, size_t len);
+                     isc::util::InputBuffer& buffer, size_t len);
+
 /// \brief Create RDATA of a given pair of RR type and class, copying
 /// of another RDATA of same kind.
 ///
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
index e025ce4..2557965 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ b/src/lib/dns/rdata/any_255/tsig_250.cc
@@ -18,15 +18,18 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/encode/base64.h>
+
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
-
-#include <dns/util/base64.h>
+#include <dns/tsigerror.h>
 
 using namespace std;
 using namespace boost;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -68,7 +71,7 @@ getToken(istringstream& iss, const string& full_input) {
     string token;
     iss >> token;
     if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid TSIG text: parse error" <<
+        isc_throw(InvalidRdataText, "Invalid TSIG text: parse error " <<
                   full_input);
     }
     return (token);
@@ -310,15 +313,7 @@ TSIG::toText() const {
         result += encodeBase64(impl_->mac_) + " ";
     }
     result += lexical_cast<string>(impl_->original_id_) + " ";
-    if (impl_->error_ == 16) {  // XXX: we'll soon introduce generic converter.
-        result += "BADSIG ";
-    } else if (impl_->error_ == 17) {
-        result += "BADKEY ";
-    } else if (impl_->error_ == 18) {
-        result += "BADTIME ";
-    } else {
-        result += lexical_cast<string>(impl_->error_) + " ";
-    }
+    result += TSIGError(impl_->error_).toText() + " ";
     result += lexical_cast<string>(impl_->other_data_.size());
     if (impl_->other_data_.size() > 0) {
         result += " " + encodeBase64(impl_->other_data_);
@@ -377,9 +372,9 @@ TSIG::toWire(OutputBuffer& buffer) const {
 /// \param renderer DNS message rendering context that encapsulates the
 /// output buffer and name compression information.
 void
-TSIG::toWire(MessageRenderer& renderer) const {
+TSIG::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(impl_->algorithm_, false);
-    impl_->toWireCommon<MessageRenderer>(renderer);
+    impl_->toWireCommon<AbstractMessageRenderer>(renderer);
 }
 
 // A helper function commonly used for TSIG::compare().
diff --git a/src/lib/dns/rdata/ch_3/a_1.cc b/src/lib/dns/rdata/ch_3/a_1.cc
index 376cbdd..65378a1 100644
--- a/src/lib/dns/rdata/ch_3/a_1.cc
+++ b/src/lib/dns/rdata/ch_3/a_1.cc
@@ -16,12 +16,13 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -44,7 +45,7 @@ A::toWire(OutputBuffer&) const {
 }
 
 void
-A::toWire(MessageRenderer&) const {
+A::toWire(AbstractMessageRenderer&) const {
     // TBD
 }
 
diff --git a/src/lib/dns/rdata/generic/cname_5.cc b/src/lib/dns/rdata/generic/cname_5.cc
index c7f97d0..5bb0aea 100644
--- a/src/lib/dns/rdata/generic/cname_5.cc
+++ b/src/lib/dns/rdata/generic/cname_5.cc
@@ -16,13 +16,14 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -52,7 +53,7 @@ CNAME::toWire(OutputBuffer& buffer) const {
 }
 
 void
-CNAME::toWire(MessageRenderer& renderer) const {
+CNAME::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(cname_);
 }
 
diff --git a/src/lib/dns/rdata/generic/dname_39.cc b/src/lib/dns/rdata/generic/dname_39.cc
index b88720e..165c4a6 100644
--- a/src/lib/dns/rdata/generic/dname_39.cc
+++ b/src/lib/dns/rdata/generic/dname_39.cc
@@ -16,13 +16,14 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -52,7 +53,7 @@ DNAME::toWire(OutputBuffer& buffer) const {
 }
 
 void
-DNAME::toWire(MessageRenderer& renderer) const {
+DNAME::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(dname_);
 }
 
diff --git a/src/lib/dns/rdata/generic/dnskey_48.cc b/src/lib/dns/rdata/generic/dnskey_48.cc
index 16a748e..e0f5461 100644
--- a/src/lib/dns/rdata/generic/dnskey_48.cc
+++ b/src/lib/dns/rdata/generic/dnskey_48.cc
@@ -20,8 +20,8 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 
-#include <dns/util/base64.h>
-#include <dns/buffer.h>
+#include <util/encode/base64.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
@@ -31,6 +31,8 @@
 #include <time.h>
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -134,7 +136,7 @@ DNSKEY::toWire(OutputBuffer& buffer) const {
 }
 
 void
-DNSKEY::toWire(MessageRenderer& renderer) const {
+DNSKEY::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint16(impl_->flags_);
     renderer.writeUint8(impl_->protocol_);
     renderer.writeUint8(impl_->algorithm_);
diff --git a/src/lib/dns/rdata/generic/ds_43.cc b/src/lib/dns/rdata/generic/ds_43.cc
index cca19ae..1b48456 100644
--- a/src/lib/dns/rdata/generic/ds_43.cc
+++ b/src/lib/dns/rdata/generic/ds_43.cc
@@ -19,8 +19,9 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/buffer.h>
-#include <dns/util/hex.h>
+#include <util/buffer.h>
+#include <util/encode/hex.h>
+
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
@@ -30,6 +31,8 @@
 #include <time.h>
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -130,7 +133,7 @@ DS::toWire(OutputBuffer& buffer) const {
 }
 
 void
-DS::toWire(MessageRenderer& renderer) const {
+DS::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint16(impl_->tag_);
     renderer.writeUint8(impl_->algorithm_);
     renderer.writeUint8(impl_->digest_type_);
diff --git a/src/lib/dns/rdata/generic/mx_15.cc b/src/lib/dns/rdata/generic/mx_15.cc
index 0ae2251..4765222 100644
--- a/src/lib/dns/rdata/generic/mx_15.cc
+++ b/src/lib/dns/rdata/generic/mx_15.cc
@@ -20,7 +20,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 
 using namespace std;
 using namespace boost;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -71,7 +72,7 @@ MX::toWire(OutputBuffer& buffer) const {
 }
 
 void
-MX::toWire(MessageRenderer& renderer) const {
+MX::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint16(preference_);
     renderer.writeName(mxname_);
 }
diff --git a/src/lib/dns/rdata/generic/ns_2.cc b/src/lib/dns/rdata/generic/ns_2.cc
index 0e56911..631da9d 100644
--- a/src/lib/dns/rdata/generic/ns_2.cc
+++ b/src/lib/dns/rdata/generic/ns_2.cc
@@ -16,13 +16,14 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -48,7 +49,7 @@ NS::toWire(OutputBuffer& buffer) const {
 }
 
 void
-NS::toWire(MessageRenderer& renderer) const {
+NS::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(nsname_);
 }
 
diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc
index fbe6612..3bd0bb2 100644
--- a/src/lib/dns/rdata/generic/nsec3_50.cc
+++ b/src/lib/dns/rdata/generic/nsec3_50.cc
@@ -20,10 +20,11 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/util/base32hex.h>
-#include <dns/buffer.h>
+#include <util/encode/base32hex.h>
+#include <util/encode/hex.h>
+#include <util/buffer.h>
+
 #include <dns/exceptions.h>
-#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rrtype.h>
@@ -37,6 +38,8 @@
 
 using namespace std;
 using namespace isc::dns::rdata::generic::detail::nsec;
+using namespace isc::util::encode;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -259,7 +262,7 @@ NSEC3::toWire(OutputBuffer& buffer) const {
 }
 
 void
-NSEC3::toWire(MessageRenderer& renderer) const {
+NSEC3::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint8(impl_->hashalg_);
     renderer.writeUint8(impl_->flags_);
     renderer.writeUint16(impl_->iterations_);
diff --git a/src/lib/dns/rdata/generic/nsec3param_51.cc b/src/lib/dns/rdata/generic/nsec3param_51.cc
index 639feed..49f666b 100644
--- a/src/lib/dns/rdata/generic/nsec3param_51.cc
+++ b/src/lib/dns/rdata/generic/nsec3param_51.cc
@@ -19,8 +19,8 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/buffer.h>
-#include <dns/util/hex.h>
+#include <util/buffer.h>
+#include <util/encode/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
@@ -30,6 +30,8 @@
 #include <time.h>
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -134,7 +136,7 @@ NSEC3PARAM::toWire(OutputBuffer& buffer) const {
 }
 
 void
-NSEC3PARAM::toWire(MessageRenderer& renderer) const {
+NSEC3PARAM::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint8(impl_->hashalg_);
     renderer.writeUint8(impl_->flags_);
     renderer.writeUint16(impl_->iterations_);
diff --git a/src/lib/dns/rdata/generic/nsec_47.cc b/src/lib/dns/rdata/generic/nsec_47.cc
index 72eb946..93b8b5f 100644
--- a/src/lib/dns/rdata/generic/nsec_47.cc
+++ b/src/lib/dns/rdata/generic/nsec_47.cc
@@ -17,8 +17,8 @@
 #include <sstream>
 #include <vector>
 
-#include <dns/util/base64.h>
-#include <dns/buffer.h>
+#include <util/encode/base64.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
@@ -32,6 +32,8 @@
 #include <time.h>
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
 using namespace isc::dns::rdata::generic::detail::nsec;
 
 // BEGIN_ISC_NAMESPACE
@@ -171,7 +173,7 @@ NSEC::toWire(OutputBuffer& buffer) const {
 }
 
 void
-NSEC::toWire(MessageRenderer& renderer) const {
+NSEC::toWire(AbstractMessageRenderer& renderer) const {
     impl_->nextname_.toWire(renderer);
     renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
 }
diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc
index 1aae810..62cfc17 100644
--- a/src/lib/dns/rdata/generic/opt_41.cc
+++ b/src/lib/dns/rdata/generic/opt_41.cc
@@ -16,12 +16,13 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -56,7 +57,7 @@ OPT::toWire(OutputBuffer&) const {
 }
 
 void
-OPT::toWire(MessageRenderer&) const {
+OPT::toWire(AbstractMessageRenderer&) const {
     // nothing to do, as this simple version doesn't support any options.
 }
 
diff --git a/src/lib/dns/rdata/generic/ptr_12.cc b/src/lib/dns/rdata/generic/ptr_12.cc
index dc656b8..86ddeb4 100644
--- a/src/lib/dns/rdata/generic/ptr_12.cc
+++ b/src/lib/dns/rdata/generic/ptr_12.cc
@@ -16,13 +16,14 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -53,7 +54,7 @@ PTR::toWire(OutputBuffer& buffer) const {
 }
 
 void
-PTR::toWire(MessageRenderer& renderer) const {
+PTR::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(ptr_name_);
 }
 
diff --git a/src/lib/dns/rdata/generic/rp_17.cc b/src/lib/dns/rdata/generic/rp_17.cc
new file mode 100644
index 0000000..b8b2ba2
--- /dev/null
+++ b/src/lib/dns/rdata/generic/rp_17.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <sstream>
+
+#include <util/buffer.h>
+
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+
+using namespace std;
+using namespace isc::dns;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+/// \brief Constructor from string.
+///
+/// \c rp_str must be formatted as follows:
+/// \code <mailbox name> <text name>
+/// \endcode
+/// where both fields must represent a valid domain name.
+///
+/// \exception InvalidRdataText The number of RDATA fields (must be 2) is
+/// incorrect.
+/// \exception Other The constructor of the \c Name class will throw if the
+/// given name is invalid.
+/// \exception std::bad_alloc Memory allocation for names fails.
+RP::RP(const std::string& rp_str) :
+    // We cannot construct both names in the initialization list due to the
+    // necessary text processing, so we have to initialize them with a dummy
+    // name and replace them later.
+    mailbox_(Name::ROOT_NAME()), text_(Name::ROOT_NAME())
+{
+    istringstream iss(rp_str);
+    string mailbox_str, text_str;
+    iss >> mailbox_str >> text_str;
+
+    // Validation: A valid RP RR must have exactly two fields.
+    if (iss.bad() || iss.fail()) {
+        isc_throw(InvalidRdataText, "Invalid RP text: " << rp_str);
+    }
+    if (!iss.eof()) {
+        isc_throw(InvalidRdataText, "Invalid RP text (redundant field): "
+                  << rp_str);
+    }
+
+    mailbox_ = Name(mailbox_str);
+    text_ = Name(text_str);
+}
+
+/// \brief Constructor from wire-format data.
+///
+/// This constructor doesn't check the validity of the second parameter (rdata
+/// length) for parsing.
+/// If necessary, the caller will check consistency.
+///
+/// \exception std::bad_alloc Memory allocation for names fails.
+/// \exception Other The constructor of the \c Name class will throw if the
+/// names in the wire is invalid.
+RP::RP(InputBuffer& buffer, size_t) : mailbox_(buffer), text_(buffer) {
+}
+
+/// \brief Copy constructor.
+///
+/// \exception std::bad_alloc Memory allocation fails in copying internal
+/// member variables (this should be very rare).
+RP::RP(const RP& other) :
+    Rdata(), mailbox_(other.mailbox_), text_(other.text_)
+{}
+
+/// \brief Convert the \c RP to a string.
+///
+/// The output of this method is formatted as described in the "from string"
+/// constructor (\c RP(const std::string&))).
+///
+/// \exception std::bad_alloc Internal resource allocation fails.
+///
+/// \return A \c string object that represents the \c RP object.
+std::string
+RP::toText() const {
+    return (mailbox_.toText() + " " + text_.toText());
+}
+
+void
+RP::toWire(OutputBuffer& buffer) const {
+    mailbox_.toWire(buffer);
+    text_.toWire(buffer);
+}
+
+void
+RP::toWire(AbstractMessageRenderer& renderer) const {
+    // Type RP is not "well-known", and name compression must be disabled
+    // per RFC3597.
+    renderer.writeName(mailbox_, false);
+    renderer.writeName(text_, false);
+}
+
+int
+RP::compare(const Rdata& other) const {
+    const RP& other_rp = dynamic_cast<const RP&>(other);
+
+    const int cmp = compareNames(mailbox_, other_rp.mailbox_);
+    if (cmp != 0) {
+        return (cmp);
+    }
+    return (compareNames(text_, other_rp.text_));
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/rp_17.h b/src/lib/dns/rdata/generic/rp_17.h
new file mode 100644
index 0000000..a90a530
--- /dev/null
+++ b/src/lib/dns/rdata/generic/rp_17.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// BEGIN_HEADER_GUARD
+
+#include <string>
+
+#include <dns/name.h>
+#include <dns/rdata.h>
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+/// \brief \c rdata::generic::RP class represents the RP RDATA as defined in
+/// RFC1183.
+///
+/// This class implements the basic interfaces inherited from the abstract
+/// \c rdata::Rdata class, and provides trivial accessors specific to the
+/// RP RDATA.
+class RP : public Rdata {
+public:
+    // BEGIN_COMMON_MEMBERS
+    // END_COMMON_MEMBERS
+
+    /// We use the default copy constructor and assignment operator.
+
+    /// \brief Constructor from RDATA field parameters.
+    ///
+    /// The parameters are a straightforward mapping of %RP RDATA
+    /// fields as defined in RFC1183.
+    RP(const Name& mailbox, const Name& text) :
+        mailbox_(mailbox), text_(text)
+    {}
+
+    /// \brief Return the value of the mailbox field.
+    ///
+    /// This method normally does not throw an exception, but if resource
+    /// allocation for the returned \c Name object fails, a corresponding
+    /// standard exception will be thrown.
+    ///
+    /// \note
+    /// Unlike the case of some other RDATA classes (such as
+    /// \c NS::getNSName()), this method constructs a new \c Name object
+    /// and returns it, instead of returning a reference to a \c Name object
+    /// internally maintained in the class (which is a private member).
+    /// This is based on the observation that this method will be rarely used
+    /// and even when it's used it will not be in a performance context
+    /// (for example, a recursive resolver won't need this field in its
+    /// resolution process).  By returning a new object we have flexibility of
+    /// changing the internal representation without the risk of changing
+    /// the interface or method property.
+    /// The same note applies to the \c getText() method.
+    Name getMailbox() const { return (mailbox_); }
+
+    /// \brief Return the value of the text field.
+    ///
+    /// This method normally does not throw an exception, but if resource
+    /// allocation for the returned \c Name object fails, a corresponding
+    /// standard exception will be thrown.
+    Name getText() const { return (text_); }
+
+private:
+    Name mailbox_;
+    Name text_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rdata/generic/rrsig_46.cc b/src/lib/dns/rdata/generic/rrsig_46.cc
index c9d1e52..0c82406 100644
--- a/src/lib/dns/rdata/generic/rrsig_46.cc
+++ b/src/lib/dns/rdata/generic/rrsig_46.cc
@@ -20,9 +20,9 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/util/base64.h>
-#include <dns/buffer.h>
-#include <dns/dnssectime.h>
+#include <util/encode/base64.h>
+#include <util/buffer.h>
+#include <util/time_utilities.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rrtype.h>
@@ -34,6 +34,8 @@
 #include <time.h>
 
 using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -182,7 +184,7 @@ RRSIG::toWire(OutputBuffer& buffer) const {
 }
 
 void
-RRSIG::toWire(MessageRenderer& renderer) const {
+RRSIG::toWire(AbstractMessageRenderer& renderer) const {
     impl_->covered_.toWire(renderer);
     renderer.writeUint8(impl_->algorithm_);
     renderer.writeUint8(impl_->labels_);
diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc
index c4b87c6..7ecd84f 100644
--- a/src/lib/dns/rdata/generic/soa_6.cc
+++ b/src/lib/dns/rdata/generic/soa_6.cc
@@ -20,7 +20,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 
 using namespace std;
 using namespace boost;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -99,7 +100,7 @@ SOA::toWire(OutputBuffer& buffer) const {
 }
 
 void
-SOA::toWire(MessageRenderer& renderer) const {
+SOA::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeName(mname_);
     renderer.writeName(rname_);
     renderer.writeData(numdata_, sizeof(numdata_));
diff --git a/src/lib/dns/rdata/generic/txt_16.cc b/src/lib/dns/rdata/generic/txt_16.cc
index 0e20f4e..ac2ba8a 100644
--- a/src/lib/dns/rdata/generic/txt_16.cc
+++ b/src/lib/dns/rdata/generic/txt_16.cc
@@ -18,13 +18,14 @@
 #include <string>
 #include <vector>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -101,7 +102,7 @@ TXT::toWire(OutputBuffer& buffer) const {
 }
 
 void
-TXT::toWire(MessageRenderer& renderer) const {
+TXT::toWire(AbstractMessageRenderer& renderer) const {
     for (vector<vector<uint8_t> >::const_iterator it = string_list_.begin();
          it != string_list_.end();
          ++it)
diff --git a/src/lib/dns/rdata/hs_4/a_1.cc b/src/lib/dns/rdata/hs_4/a_1.cc
index 376cbdd..65378a1 100644
--- a/src/lib/dns/rdata/hs_4/a_1.cc
+++ b/src/lib/dns/rdata/hs_4/a_1.cc
@@ -16,12 +16,13 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -44,7 +45,7 @@ A::toWire(OutputBuffer&) const {
 }
 
 void
-A::toWire(MessageRenderer&) const {
+A::toWire(AbstractMessageRenderer&) const {
     // TBD
 }
 
diff --git a/src/lib/dns/rdata/in_1/a_1.cc b/src/lib/dns/rdata/in_1/a_1.cc
index ddd03f8..fa46f90 100644
--- a/src/lib/dns/rdata/in_1/a_1.cc
+++ b/src/lib/dns/rdata/in_1/a_1.cc
@@ -22,13 +22,14 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -69,7 +70,7 @@ A::toWire(OutputBuffer& buffer) const {
 }
 
 void
-A::toWire(MessageRenderer& renderer) const {
+A::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeData(&addr_, sizeof(addr_));
 }
 
diff --git a/src/lib/dns/rdata/in_1/aaaa_28.cc b/src/lib/dns/rdata/in_1/aaaa_28.cc
index 45c4682..e9fc122 100644
--- a/src/lib/dns/rdata/in_1/aaaa_28.cc
+++ b/src/lib/dns/rdata/in_1/aaaa_28.cc
@@ -22,13 +22,14 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -66,7 +67,7 @@ AAAA::toWire(OutputBuffer& buffer) const {
 }
 
 void
-AAAA::toWire(MessageRenderer& renderer) const {
+AAAA::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeData(&addr_, sizeof(addr_));
 }
 
diff --git a/src/lib/dns/rdata/template.cc b/src/lib/dns/rdata/template.cc
index 0e0bf46..d9f08ee 100644
--- a/src/lib/dns/rdata/template.cc
+++ b/src/lib/dns/rdata/template.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -14,12 +14,13 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
+using namespace isc::util;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -50,7 +51,7 @@ MyType::toWire(OutputBuffer& buffer) const {
 }
 
 void
-MyType::toWire(MessageRenderer& renderer) const {
+MyType::toWire(AbstractMessageRenderer& renderer) const {
 }
 
 int
diff --git a/src/lib/dns/rdata/template.h b/src/lib/dns/rdata/template.h
index e85a839..9e84cc3 100644
--- a/src/lib/dns/rdata/template.h
+++ b/src/lib/dns/rdata/template.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
diff --git a/src/lib/dns/rdatafields.cc b/src/lib/dns/rdatafields.cc
new file mode 100644
index 0000000..d3f282b
--- /dev/null
+++ b/src/lib/dns/rdatafields.cc
@@ -0,0 +1,223 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+
+#include <cassert>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatafields.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::util::OutputBuffer;
+using isc::util::InputBuffer;
+
+namespace isc {
+namespace dns {
+namespace rdata {
+
+/// This is a helper class for \c RdataFields.
+///
+/// It manages a local storage for the data when \c RdataFields is constructed
+/// from an \c Rdata.
+/// To minimize construction overhead in the other case, an instance of
+/// this class is instantiated only when necessary - we don't need the vectors
+/// when only rendering.
+struct RdataFields::RdataFieldsDetail {
+    RdataFieldsDetail(const vector<FieldSpec>& fields,
+                      const uint8_t* data, size_t data_length) :
+        allocated_fields_(fields),
+        allocated_data_(data, data + data_length)
+    {}
+    const vector<FieldSpec> allocated_fields_;
+    const vector<uint8_t> allocated_data_;
+};
+
+namespace {
+// This class is used to divide the content of RDATA into \c RdataField
+// fields via message rendering logic.
+// The idea is to identify domain name fields in the writeName() method,
+// and determine whether they are compressible using the "compress"
+// parameter.
+// Other types of data are simply copied into the internal buffer, and
+// consecutive such fields are combined into a single \c RdataField field.
+//
+// Technically, this use of inheritance may be considered a violation of
+// Liskov Substitution Principle in that it doesn't actually compress domain
+// names, and some of the methods are not expected to be used.
+// In fact, skip() or trim() may not be make much sense in this context.
+// Nevertheless we keep this idea at the moment.  Since the usage is limited
+// (it's only used within this file, and only used with \c Rdata variants),
+// it's hopefully an acceptable practice.
+class RdataFieldComposer : public AbstractMessageRenderer {
+public:
+    RdataFieldComposer(OutputBuffer& buffer) :
+        AbstractMessageRenderer(buffer),
+        truncated_(false), length_limit_(65535),
+        mode_(CASE_INSENSITIVE), last_data_pos_(0)
+    {}
+    virtual ~RdataFieldComposer() {}
+    virtual bool isTruncated() const { return (truncated_); }
+    virtual size_t getLengthLimit() const { return (length_limit_); }
+    virtual CompressMode getCompressMode() const { return (mode_); }
+    virtual void setTruncated() { truncated_ = true; }
+    virtual void setLengthLimit(size_t len) { length_limit_ = len; }
+    virtual void setCompressMode(CompressMode mode) { mode_ = mode; }
+    virtual void writeName(const Name& name, bool compress) {
+        extendData();
+        const RdataFields::Type field_type =
+            compress ? RdataFields::COMPRESSIBLE_NAME :
+            RdataFields::INCOMPRESSIBLE_NAME;
+        // TODO: When we get rid of need for getBuffer, we can output the name
+        // to a buffer and then write the buffer inside
+        name.toWire(getBuffer());
+        fields_.push_back(RdataFields::FieldSpec(field_type,
+                                                 name.getLength()));
+        last_data_pos_ = getLength();
+    }
+
+    virtual void clear() {
+        isc_throw(Unexpected, "unexpected clear() for RdataFieldComposer");
+    }
+    bool truncated_;
+    size_t length_limit_;
+    CompressMode mode_;
+    vector<RdataFields::FieldSpec> fields_;
+    vector<RdataFields::FieldSpec>& getFields() {
+        extendData();
+        return (fields_);
+    }
+    // We use generict write* methods, with the exception of writeName.
+    // So new data can arrive without us knowing it, this considers all new
+    // data to be just data and extends the fields to take it into account.
+    size_t last_data_pos_;
+    void extendData() {
+        // No news, return to work
+        if (getLength() == last_data_pos_) {
+            return;
+        }
+        // The new bytes are just ordinary uninteresting data
+        if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
+            fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
+        }
+        // We added this much data from last time
+        fields_.back().len += getLength() - last_data_pos_;
+        last_data_pos_ = getLength();
+    }
+};
+
+}
+
+RdataFields::RdataFields(const Rdata& rdata) {
+    OutputBuffer buffer(0);
+    RdataFieldComposer field_composer(buffer);
+    rdata.toWire(field_composer);
+    nfields_ = field_composer.getFields().size();
+    data_length_ = field_composer.getLength();
+    if (nfields_ > 0) {
+        assert(data_length_ > 0);
+        detail_ = new RdataFieldsDetail(field_composer.getFields(),
+                                        static_cast<const uint8_t*>
+                                        (field_composer.getData()),
+                                        field_composer.getLength());
+        data_ = &detail_->allocated_data_[0];
+        fields_ = &detail_->allocated_fields_[0];
+    } else {
+        assert(data_length_ == 0);
+        detail_ = NULL;
+        data_ = NULL;
+        fields_ = NULL;
+    }
+}
+
+RdataFields::RdataFields(const void* fields, const unsigned int fields_length,
+                         const void* data, const size_t data_length) :
+    fields_(static_cast<const FieldSpec*>(fields)),
+    nfields_(fields_length / sizeof(*fields_)),
+    data_(static_cast<const uint8_t*>(data)),
+    data_length_(data_length),
+    detail_(NULL)
+{
+    if ((fields_ == NULL && nfields_ > 0) ||
+        (fields_ != NULL && nfields_ == 0)) {
+        isc_throw(InvalidParameter,
+                  "Inconsistent parameters for RdataFields: fields_length ("
+                  << fields_length << ") and fields conflict each other");
+    }
+    if ((data_ == NULL && data_length_ > 0) ||
+        (data_ != NULL && data_length_ == 0)) {
+        isc_throw(InvalidParameter,
+                  "Inconsistent parameters for RdataFields: data length ("
+                  << data_length_ << ") and data conflict each other");
+    }
+
+    size_t total_length = 0;
+    for (int i = 0; i < nfields_; ++i) {
+        total_length += fields_[i].len;
+    }
+    if (total_length != data_length_) {
+        isc_throw(InvalidParameter,
+                  "Inconsistent parameters for RdataFields; "
+                  "fields len: " << total_length <<
+                  " data len: " << data_length_);
+    }
+}
+
+RdataFields::~RdataFields() {
+    delete detail_;
+}
+
+RdataFields::FieldSpec
+RdataFields::getFieldSpec(const unsigned int field_id) const {
+    if (field_id >= nfields_) {
+        isc_throw(OutOfRange, "Rdata field ID is out of range: " << field_id);
+    }
+    return (fields_[field_id]);
+}
+
+void
+RdataFields::toWire(AbstractMessageRenderer& renderer) const {
+    size_t offset = 0;
+
+    for (int i = 0; i < nfields_; ++i) {
+        if (fields_[i].type == DATA) {
+            renderer.writeData(data_ + offset, fields_[i].len);
+        } else {
+            // XXX: this is inefficient.  Even if it's quite likely the
+            // data is a valid wire representation of a name we parse
+            // it to construct the Name object in the generic mode.
+            // This should be improved in a future version.
+            InputBuffer buffer(data_ + offset, fields_[i].len);
+            renderer.writeName(Name(buffer),
+                               fields_[i].type == COMPRESSIBLE_NAME);
+        }
+        offset += fields_[i].len;
+    }
+}
+
+void
+RdataFields::toWire(OutputBuffer& buffer) const {
+    buffer.writeData(data_, data_length_);
+}
+} // end of namespace rdata
+} // end of namespace dns
+} // end of namespace isc
diff --git a/src/lib/dns/rdatafields.h b/src/lib/dns/rdatafields.h
new file mode 100644
index 0000000..e33bcd7
--- /dev/null
+++ b/src/lib/dns/rdatafields.h
@@ -0,0 +1,427 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __RDATAFIELDS_H
+#define __RDATAFIELDS_H 1
+
+#include <stdint.h>
+
+#include <cstddef>
+
+namespace isc {
+namespace util {
+class OutputBuffer;
+}
+namespace dns {
+class AbstractMessageRenderer;
+
+namespace rdata {
+class Rdata;
+
+/// A low-level, RR type-independent representation of DNS RDATA.
+///
+/// <b>Purpose of the Class</b>
+///
+/// This class intends to help "serialization" of the content of RDATA
+/// in a space-efficient manner.  Specific derived classes of \c Rdata
+/// focus on the convenience of accessing RDATA fields for RR type-specific
+/// protocol operations, and can be inefficient in terms of space.
+/// For example, a DNS character string may be internally represented as a
+/// \c std::string object with all of the overhead of the richer class.
+/// If an application needs to maintain a very large number of RRs and it
+/// does not have to perform RR specific operation so often, it may make more
+/// sense to store the data in memory in a lower-level but space efficient
+/// form.
+///
+/// Another purpose of this class is to improve rendering performance for
+/// RDATA.  If the only requirement were space efficiency, it would be just
+/// sufficient to convert the \c RDATA into a binary sequence in the wire
+/// format.  However, to render the data in a DNS message, we'd have to
+/// re-construct a corresponding \c Rdata object in the case where name
+/// compression is necessary.  This is not desirable, and this class is
+/// provided to avoid such unnecessary overhead.
+///
+/// <b>Data Format</b>
+///
+/// To meet these goals, this class helps convert an \c Rdata object into
+/// two pieces of information: Wire-format representation of the \c Rdata
+/// and associated meta information for efficient rendering.
+///
+/// Specifically, it maintains the wire-format data as a sequence of typed
+/// fields.  The types are:
+/// - Compressible name: a domain name as an RDATA field that can be compressed
+/// - Incompressible name: a domain name as an RDATA field that cannot be
+///   compressed
+/// - Other data: any other fields of RDATA, which should be treated as opaque
+///
+/// (See also the description of \c RdataFields::Type)
+/// Whether a name can or cannot be compressed is determined according to
+/// RFC3597.
+///
+/// A "other data" field may not always correspond to a single RDATA field.
+/// A \c RdataFields field (of other data) is just a contiguous region of the
+/// wire-format data that does not involve name compression.
+/// For example, the SOA RDATA begins with two "compressible" names followed
+/// by 5 32-bit fields.
+/// In \c RdataFields the last 5 fields would be considered a single 20-byte
+/// field.
+///
+/// Each \c RdataFields field is identified by the \c FieldSpec structure,
+/// which provides the type and length of the field.
+/// An \c RdataFields object internally maintains a sequence of \c FieldSpec
+/// objects in a form of plain C-style array, which can be referenced via
+/// a pointer returned by the \c getFieldSpecData() method.
+/// The \c \c FieldSpec for a specific field can also be retrieved by the
+/// \c getFieldSpec() method.
+///
+/// The following diagram shows the internal memory representation of
+/// an SOA RDATA in the form of \c RdataFields object and how an application
+/// can get access to the memory region.
+/** \verbatim
+accessible via      |0                               getDataLength() bytes
+getData()----------> <MNAME><RNAME><Rest of the data>
+                     <---------- 3 * sizeof(FieldSpec) bytes ------------->
+getFieldSpecData()-> { compressible name { compressible name { other data
+                       len: MNAME-len }    len: RNAME-len }    len: 20    }
+\endverbatim
+ */
+/// where MNAME and RNAME are wire format representations of the MNAME and
+/// RNAME fields of the SOA RDATA, respectively, and "Rest of the data"
+/// encodes the remaining 20 bytes of the RDATA in network byte order.
+///
+/// <b>Usage of the Class</b>
+///
+/// One major and common use case of the \c RdataFields class is to convert
+/// a \c Rdata object (possibly given from a DNS message or some configuration
+/// source such as a zone file) in the serialized format and store a copy of
+/// the data somewhere in memory.  The following code sample implements this
+/// scenario:
+/// \code // assume "rdata" is a reference type to Rdata
+/// const RdataFields fields(rdata);
+/// const unsigned int fields_size = fields.getFieldDataSize();
+/// memcpy(some_place, fields.getFieldSpecData(), fields_size);
+/// const size_t data_length = fields.getDataLength();
+/// memcpy(other_place, fields.getData(), data_length);
+/// // (fields_size and data_length should be stored somewhere, too)
+/// \endcode
+///
+/// Another typical usage is to render the stored data in the wire format
+/// as efficiently as possible.  The following code is an example of such
+/// usage:
+/// \code // assume "renderer" is of type MessageRenderer
+/// // retrieve data_length and fields_size from the storage
+/// RdataFields(some_place, fields_size, other_place,
+///             data_length).toWire(renderer);
+/// \endcode
+///
+/// <b>Notes to Users</b>
+///
+/// The main purposes of this class is to help efficient operation
+/// for some (limited classes of) performance sensitive application.
+/// For this reason the interface and implementation rely on relatively
+/// lower-level, riskier primitives such as passing around bare pointers.
+///
+/// It is therefore discouraged to use this class for general purpose
+/// applications that do not need to maximize performance in terms of either
+/// memory footprint or rendering speed.
+/// All functionality provided by this class can be achieved via higher level
+/// interfaces such as the \c Rdata class variants.
+/// Normal applications should use those interfaces.
+///
+/// The data format is public information so that an application can examine
+/// and use selected parts of data.  For example, an application may want to
+/// encode domain names in RDATA in a different way while storing the other
+/// data in a separate place.
+/// However, at this moment the format is still in flux, and it may not
+/// be compatible with future versions (see below).
+///
+/// <b>Development Notes</b>
+///
+/// We should conduct benchmark tests to measure rendering performance.
+///
+/// The current implementation needs to re-construct name objects from
+/// compressible and incompressible name fields as wire-format data.
+/// This is not efficient, and we'll probably want to improve this in a
+/// future version.  One possibility is to store offset information as well
+/// as the name data (at the cost of increasing memory footprint), and
+/// to use the pair of data for faster rendering.
+class RdataFields {
+public:
+    /// Types of \c RdataFields fields.
+    ///
+    /// \c COMPRESSIBLE_NAME and \c INCOMPRESSIBLE_NAME represent a domain
+    /// name used as a field of an RDATA that can and cannot be compressed
+    /// per RFC3597.
+    /// \c DATA means all other types of fields.
+    enum Type {
+        DATA,              ///< Plain data.
+        COMPRESSIBLE_NAME, ///< A domain name subject to name compression.
+        INCOMPRESSIBLE_NAME ///< A domain name that shouldn't be compressed.
+    };
+
+    /// Structure that specifies a single \c RdataFields field.
+    ///
+    /// This is a straightforward pair of the type and length of a single
+    /// \c RdataFields field.
+    ///
+    /// In some cases an application may want to do deeper inspection of
+    /// some \c RdataFields field(s).  For example, an application may want
+    /// to construct a \c Name object for each domain name field of an RDATA
+    /// and use it for some special purpose.
+    /// The \c FieldSpec structure provides necessary parameters to get access
+    /// to a specific \c RdataFields field.
+    ///
+    /// The following code snippet implements the above example scenario:
+    /// \code // assume "fields" is of type RdataFields
+    /// size_t offset = 0;
+    /// for (int i = 0; i < fields.getFieldCount(); ++i) {
+    ///     const FieldSpec spec = fields.getFieldSpec(i);
+    ///     if (spec.type == RdataFields::COMPRESSIBLE_NAME ||
+    ///         spec.type == RdataFields::INCOMPRESSIBLE_NAME) {
+    ///         InputBuffer ibuffer(fields.getData() + offset, spec.len);
+    ///         Name name(ibuffer);
+    ///         // do something with name
+    ///     }
+    ///     offset += spec.len;
+    /// } \endcode
+    ///
+    /// Note that the offset is not included in \c FieldSpec.
+    /// This is because such deeper inspection would be a relatively rare
+    /// operation while it is desirable to keep this structure as small as
+    /// possible for the purpose of space efficiency.
+    /// Also, if and when an application wants to look into a specific field,
+    /// it would be quite likely that the application iterates over all fields
+    /// and does something special for selected fields like the above example.
+    /// In that case the application can easily and efficiently identify the
+    /// necessary offset, again, as shown in the above code example.
+    ///
+    /// \todo We might find that 16bits per field is generally too much and
+    ///     squeeze the two bit type into it as well, having 14bit length
+    ///     (in the rare case of having too long field, it could be split into
+    ///     multiple ones). That would save 2 bytes per item (one for the type,
+    ///     one for padding).
+    struct FieldSpec {
+        FieldSpec(Type type_param, uint16_t len_param) :
+            type(type_param), len(len_param)
+        {}
+        Type type;              ///< The type of the field.
+        uint16_t len;           ///< The length of the field in bytes.
+    };
+
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    /// \b Note:
+    /// The copy constructor and the assignment operator are intentionally
+    /// defined as private, making this class non copyable.
+    //@{
+private:
+    RdataFields(const RdataFields& source);
+    RdataFields& operator=(const RdataFields& source);
+
+public:
+    /// Constructor from Rdata.
+    ///
+    /// This constructor converts the data of a given \c Rdata object into
+    /// an \c RdataFields object so that the resulting data can be stored
+    /// in memory in a space-efficient way.
+    ///
+    /// It makes a local copy of the original data and dynamically allocates
+    /// necessary memory, so is not very efficient.
+    /// The basic idea is to perform the expensive conversion once and keep
+    /// using the result as long as possible to improve overall performance
+    /// in a longer term.
+    ///
+    /// If the internal resource allocation fails, a corresponding standard
+    /// exception will be thrown.
+    /// The current implementation of this constructor internally calls
+    /// the <code>Rdata::toWire(AbstractMessageRenderer&) const</code> method
+    /// for the conversion.
+    /// If that method throws an exception it will be propagated to the caller
+    /// of this constructor.
+    ///
+    /// \param rdata The RDATA for which the \c RdataFields to be constructed.
+    RdataFields(const Rdata& rdata);
+
+    /// Constructor from field parameters.
+    ///
+    /// The intended usage of this version of constructor is to form a
+    /// structured representation of \c RDATA encoded by the other
+    /// constructor so that the resulting object can be used for subsequent
+    /// operations such as rendering in the wire format.
+    /// This version is intended to be efficient by not making any copy
+    /// of variable length data or expensive data inspection.
+    ///
+    /// This constructor is basically exception free, except against bogus
+    /// input parameters.
+    /// Specifically, the parameters must meet the following conditions;
+    /// otherwise an exception of class \c InvalidParameter will be thrown.
+    /// - \c fields can be \c NULL if and only if \c nfields is 0
+    /// - \c data can be \c NULL if and only if \c data_length is 0
+    /// - the sum of the lengths of \c fields entries must be equal to
+    ///   \c data_length
+    ///
+    /// This constructor assumes that the memory region pointed by \c data (if
+    /// non \c NULL) is encoded as a sequence of valid \c RdataFields fields,
+    /// and does not perform deep inspection on each field.
+    /// In particular, for fields of type \c COMPRESSIBLE_NAME or
+    /// \c INCOMPRESSIBLE_NAME, this constructor assumes the corresponding
+    /// memory region is a valid representation of domain name.
+    /// Otherwise, a subsequent method call such as
+    /// <code>toWire(AbstractMessageRenderer&) const</code>
+    /// may trigger an unexpected exception. It also expects the fields reside
+    /// on address that is valid for them (eg. it has valid alignment), see
+    /// getFieldSpecData() for details.
+    ///
+    /// It is the caller's responsibility to ensure this assumption.
+    /// In general, this constructor is expected to be used for serialized data
+    /// generated by the other constructor from a valid \c Rdata.
+    /// The result is not guaranteed if the data is generated in any other
+    /// ways.
+    ///
+    /// The resulting \c RdataFields object does not maintain a copy of
+    /// \c fields or \c data.  It is the caller's responsibility to ensure
+    /// the memory regions pointed to by these parameters are valid and intact
+    /// as long as the \c RdataFields object is used.
+    ///
+    /// \param fields An array of \c FieldSpec entries.  This can be \c NULL.
+    /// \param nfields The number of entries of \c fields.
+    /// \param data A pointer to memory region for the entire RDATA.  This can
+    /// be NULL.
+    /// \param data_length The length of \c data in bytes.
+    RdataFields(const void* fields, const unsigned int fields_length,
+                const void* data, const size_t data_length);
+
+    /// The destructor.
+    ~RdataFields();
+    //@}
+
+    ///
+    /// \name Getter Methods
+    ///
+    //@{
+    /// \brief Return the length of the entire RDATA encoded in the
+    /// \c RdataFields in bytes.
+    ///
+    /// This method never throws an exception.
+    unsigned int getDataLength() const { return (data_length_); }
+
+    /// \brief Return a pointer to the RDATA encoded in the \c RdataFields.
+    ///
+    /// The RdataFields holds ownership of the data.
+    ///
+    /// This method never throws an exception.
+    const void* getData() const { return (data_); }
+
+    /// \brief Return the number of bytes the buffer returned by
+    ///      getFieldSpecData() will occupy.
+    ///
+    /// This method never throws an exception.
+    unsigned int getFieldSpecDataSize() const { return (nfields_ *
+                                                    sizeof (*fields_)); }
+
+    /// \brief Return the number of specs fields.
+    ///
+    /// It specifies the range of parameter for getFieldSpec().
+    ///
+    /// This method never throws.
+    unsigned int getFieldCount() const { return (nfields_); }
+
+    /// \brief Return a pointer to a sequence of \c FieldSpec for the
+    /// \c RdataFields.
+    ///
+    /// This should be treated as an opaque internal representation you can
+    /// just store off somewhere and use it to construct a new RdataFields.
+    /// from it. If you are really interested, you can typecast it to
+    /// FieldSpec * (which is what it really is internally).
+    ///
+    /// The RdataFields holds ownership of the data.
+    ///
+    /// \note You should, however, be aware of alignment issues. The pointer
+    ///     you pass to the constructor must be an address where the FieldSpec
+    ///     can live. If you store it at a wrong address (eg. even one with
+    ///     current implementation on most architectures), it might lead bad
+    ///     things from slow access to SIGBUS. The easiest way is not to
+    ///     interleave the fields with data from getData(). It is OK to place
+    ///     all the fields first (even from multiple RdataFields) and then
+    ///     place all the data after them.
+    ///
+    /// This method never throws an exception.
+    const void* getFieldSpecData() const {
+        return (fields_);
+    }
+
+    /// \brief Return the specification of the field identified by the given
+    /// index.
+    ///
+    /// \c field_id is the field index, which must be in the range of
+    /// <code>[0, getFieldCount())</code>.  0 means the first field, and
+    /// <code>getFieldCount()-1</code> means the last.
+    ///
+    /// If the given index is not in the valid range, an exception of class
+    /// \c OutOfRange will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// \param field_id The index of an \c RdataFields field to be returned.
+    /// \return A \c FieldSpec structure that contains the information of
+    /// the \c field_id-th field.
+    FieldSpec getFieldSpec(const unsigned int field_id) const;
+    //@}
+
+    ///
+    /// \name Converter Methods
+    ///
+    //@{
+    /// \brief Render the RdataFields in the wire format with name compression.
+    ///
+    /// This method may require resource allocation in \c renderer.
+    /// If it fails, a corresponding standard exception will be thrown.
+    /// It should not throw any other exception as long as the \c RdataFields
+    /// object was constructed from valid parameters (see the description of
+    /// constructors).  The result is not guaranteed if it's constructed in
+    /// any other ways.
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer and name compression information.
+    void toWire(AbstractMessageRenderer& renderer) const;
+
+    /// \brief Render the RdataFields in the wire format without name
+    /// compression.
+    ///
+    /// This method may require resource allocation in \c buffer.
+    /// If it fails, a corresponding standard exception will be thrown.
+    ///
+    /// \param buffer An output buffer to store the wire data.
+    void toWire(isc::util::OutputBuffer& buffer) const;
+    //@}
+
+private:
+    const FieldSpec* fields_;
+    unsigned int nfields_;
+    const uint8_t* data_;
+    size_t data_length_;
+
+    // hide further details within the implementation and don't create vectors
+    // every time we don't need them.
+    struct RdataFieldsDetail;
+    RdataFieldsDetail* detail_;
+};
+}
+}
+}
+#endif  // __RDATAFIELDS_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index ce9a141..80035d8 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -23,12 +23,15 @@
 #include <exceptions/exceptions.h>
 
 namespace isc {
+namespace util {
+class InputBuffer;
+class OutputBuffer;
+}
+
 namespace dns {
 
 // forward declarations
-class InputBuffer;
-class OutputBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 
 ///
 /// \brief A standard DNS module exception that is thrown if an RRClass object
@@ -132,7 +135,7 @@ public:
     /// an exception of class \c IncompleteRRClass will be thrown.
     ///
     /// \param buffer A buffer storing the wire format data.
-    explicit RRClass(InputBuffer& buffer);
+    explicit RRClass(isc::util::InputBuffer& buffer);
     ///
     /// We use the default copy constructor intentionally.
     //@}
@@ -166,7 +169,7 @@ public:
     /// standard exception will be thrown.
     ///
     /// \param buffer An output buffer to store the wire data.
-    void toWire(MessageRenderer& renderer) const;
+    void toWire(AbstractMessageRenderer& renderer) const;
     /// \brief Render the \c RRClass in the wire format.
     ///
     /// This method renders the class code in network byte order into the
@@ -177,7 +180,7 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer in which the RRClass is to be stored.
-    void toWire(OutputBuffer& buffer) const;
+    void toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/rrclass.cc b/src/lib/dns/rrclass.cc
index 04ff59c..a28e5cf 100644
--- a/src/lib/dns/rrclass.cc
+++ b/src/lib/dns/rrclass.cc
@@ -18,13 +18,14 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrparamregistry.h>
 #include <dns/rrclass.h>
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -51,7 +52,7 @@ RRClass::toWire(OutputBuffer& buffer) const {
 }
 
 void
-RRClass::toWire(MessageRenderer& renderer) const {
+RRClass::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint16(classcode_);
 }
 
diff --git a/src/lib/dns/rrparamregistry-placeholder.cc b/src/lib/dns/rrparamregistry-placeholder.cc
index 19363a3..5058ca3 100644
--- a/src/lib/dns/rrparamregistry-placeholder.cc
+++ b/src/lib/dns/rrparamregistry-placeholder.cc
@@ -36,6 +36,7 @@
 using namespace std;
 using namespace boost;
 
+using namespace isc::util;
 using namespace isc::dns::rdata; 
 
 namespace isc {
diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h
index a856423..ae41b5f 100644
--- a/src/lib/dns/rrparamregistry.h
+++ b/src/lib/dns/rrparamregistry.h
@@ -102,7 +102,7 @@ public:
     /// \c Rdata to parse.
     /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
     /// \return An \c RdataPtr object pointing to the created \c Rdata object.
-    virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const = 0;
+    virtual RdataPtr create(isc::util::InputBuffer& buffer, size_t rdata_len) const = 0;
     ///
     /// \brief Create RDATA from another \c Rdata object of the same type.
     ///
@@ -473,7 +473,7 @@ public:
     /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
     /// object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
-                                InputBuffer& buffer, size_t len);
+                                isc::util::InputBuffer& buffer, size_t len);
     /// \brief Create RDATA of a given pair of RR type and class, copying
     /// of another RDATA of same kind.
     ///
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index b931bec..776d49f 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -18,7 +18,7 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
@@ -28,6 +28,7 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace isc {
@@ -103,8 +104,8 @@ AbstractRRset::toWire(OutputBuffer& buffer) const {
 }
 
 unsigned int
-AbstractRRset::toWire(MessageRenderer& renderer) const {
-    const unsigned int rrs_written = rrsetToWire<MessageRenderer>(
+AbstractRRset::toWire(AbstractMessageRenderer& renderer) const {
+    const unsigned int rrs_written = rrsetToWire<AbstractMessageRenderer>(
         *this, renderer, renderer.getLengthLimit());
     if (getRdataCount() > rrs_written) {
         renderer.setTruncated();
@@ -201,7 +202,7 @@ BasicRRset::toWire(OutputBuffer& buffer) const {
 }
 
 unsigned int
-BasicRRset::toWire(MessageRenderer& renderer) const {
+BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
     return (AbstractRRset::toWire(renderer));
 }
 
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index 926a58f..6c15b53 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -26,6 +26,10 @@
 #include <dns/rrtype.h>
 
 namespace isc {
+namespace util {
+class OututBuffer;
+}
+
 namespace dns {
 
 ///
@@ -43,8 +47,7 @@ class Name;
 class RRType;
 class RRClass;
 class RRTTL;
-class OututBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 class AbstractRRset;
 class BasicRRset;
 class RdataIterator;
@@ -308,7 +311,7 @@ public:
     /// \return The number of RRs rendered.  If the truncation is necessary
     /// this value may be different from the number of RDATA objects contained
     /// in the RRset.
-    virtual unsigned int toWire(MessageRenderer& renderer) const = 0;
+    virtual unsigned int toWire(AbstractMessageRenderer& renderer) const = 0;
 
     /// \brief Render the RRset in the wire format without any compression.
     ///
@@ -316,7 +319,7 @@ public:
     ///
     /// \param buffer An output buffer to store the wire data.
     /// \return The number of RRs rendered.
-    virtual unsigned int toWire(OutputBuffer& buffer) const = 0;
+    virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const = 0;
     //@}
 
     ///
@@ -614,13 +617,13 @@ public:
     ///
     /// This method simply uses the default implementation.
     /// See \c AbstractRRset::toWire(MessageRenderer&)const.
-    virtual unsigned int toWire(MessageRenderer& renderer) const;
+    virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
 
     /// \brief Render the RRset in the wire format without any compression.
     ///
     /// This method simply uses the default implementation.
     /// See \c AbstractRRset::toWire(OutputBuffer&)const.
-    virtual unsigned int toWire(OutputBuffer& buffer) const;
+    virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc
index 78bb355..ecd8cc6 100644
--- a/src/lib/dns/rrttl.cc
+++ b/src/lib/dns/rrttl.cc
@@ -17,12 +17,13 @@
 #include <sstream>
 #include <ostream>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrttl.h>
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace isc {
 namespace dns {
@@ -62,7 +63,7 @@ RRTTL::toWire(OutputBuffer& buffer) const {
 }
 
 void
-RRTTL::toWire(MessageRenderer& renderer) const {
+RRTTL::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint32(ttlval_);
 }
 
diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h
index 695306a..bf23295 100644
--- a/src/lib/dns/rrttl.h
+++ b/src/lib/dns/rrttl.h
@@ -20,12 +20,15 @@
 #include <exceptions/exceptions.h>
 
 namespace isc {
+namespace util {
+class InputBuffer;
+class OutputBuffer;
+}
+
 namespace dns {
 
 // forward declarations
-class InputBuffer;
-class OutputBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 
 ///
 /// \brief A standard DNS module exception that is thrown if an RRTTL object
@@ -91,7 +94,7 @@ public:
     /// an exception of class \c IncompleteRRTTL will be thrown.
     ///
     /// \param buffer A buffer storing the wire format data.
-    explicit RRTTL(InputBuffer& buffer);
+    explicit RRTTL(isc::util::InputBuffer& buffer);
     ///
     //@}
 
@@ -120,7 +123,7 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer in which the RRTTL is to be stored.
-    void toWire(MessageRenderer& renderer) const;
+    void toWire(AbstractMessageRenderer& renderer) const;
     /// \brief Render the \c RRTTL in the wire format.
     ///
     /// This method renders the TTL value in network byte order into the
@@ -130,7 +133,7 @@ public:
     /// standard exception will be thrown.
     ///
     /// \param buffer An output buffer to store the wire data.
-    void toWire(OutputBuffer& buffer) const;
+    void toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h
index 76cb29d..1cb028c 100644
--- a/src/lib/dns/rrtype-placeholder.h
+++ b/src/lib/dns/rrtype-placeholder.h
@@ -23,12 +23,15 @@
 #include <exceptions/exceptions.h>
 
 namespace isc {
+namespace util {
+class InputBuffer;
+class OutputBuffer;
+}
+
 namespace dns {
 
 // forward declarations
-class InputBuffer;
-class OutputBuffer;
-class MessageRenderer;
+class AbstractMessageRenderer;
 
 ///
 /// \brief A standard DNS module exception that is thrown if an RRType object
@@ -145,7 +148,7 @@ public:
     /// an exception of class \c IncompleteRRType will be thrown.
     ///
     /// \param buffer A buffer storing the wire format data.
-    explicit RRType(InputBuffer& buffer);
+    explicit RRType(isc::util::InputBuffer& buffer);
     ///
     /// We use the default copy constructor intentionally.
     //@}
@@ -178,7 +181,7 @@ public:
     /// standard exception will be thrown.
     ///
     /// \param buffer An output buffer to store the wire data.
-    void toWire(MessageRenderer& renderer) const;
+    void toWire(AbstractMessageRenderer& renderer) const;
     /// \brief Render the \c RRType in the wire format.
     ///
     /// This method renders the type code in network byte order into the
@@ -189,7 +192,7 @@ public:
     ///
     /// \param renderer DNS message rendering context that encapsulates the
     /// output buffer in which the RRType is to be stored.
-    void toWire(OutputBuffer& buffer) const;
+    void toWire(isc::util::OutputBuffer& buffer) const;
     //@}
 
     ///
diff --git a/src/lib/dns/rrtype.cc b/src/lib/dns/rrtype.cc
index 44377f5..af077d4 100644
--- a/src/lib/dns/rrtype.cc
+++ b/src/lib/dns/rrtype.cc
@@ -19,14 +19,14 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrparamregistry.h>
 #include <dns/rrtype.h>
 
 using namespace std;
+using namespace isc::util;
 using isc::dns::RRType;
-using isc::dns::OutputBuffer;
 
 namespace isc {
 namespace dns {
@@ -53,7 +53,7 @@ RRType::toWire(OutputBuffer& buffer) const {
 }
 
 void
-RRType::toWire(MessageRenderer& renderer) const {
+RRType::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint16(typecode_);
 }
 
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index 246adb7..9783beb 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = testdata .
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dns/tests/testdata\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -17,15 +18,15 @@ TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES = unittest_util.h unittest_util.cc
-run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
 run_unittests_SOURCES += edns_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
+run_unittests_SOURCES += name_unittest.cc
 run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
 run_unittests_SOURCES += rrttl_unittest.cc
-run_unittests_SOURCES += dnssectime_unittest.cc
 run_unittests_SOURCES += opcode_unittest.cc
 run_unittests_SOURCES += rcode_unittest.cc
 run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
+run_unittests_SOURCES += rdatafields_unittest.cc
 run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
 run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
 run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
@@ -39,22 +40,25 @@ run_unittests_SOURCES += rdata_nsec3_unittest.cc
 run_unittests_SOURCES += rdata_nsecbitmap_unittest.cc
 run_unittests_SOURCES += rdata_nsec3param_unittest.cc
 run_unittests_SOURCES += rdata_rrsig_unittest.cc
+run_unittests_SOURCES += rdata_rp_unittest.cc
 run_unittests_SOURCES += rdata_tsig_unittest.cc
 run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
 run_unittests_SOURCES += question_unittest.cc
 run_unittests_SOURCES += rrparamregistry_unittest.cc
 run_unittests_SOURCES += masterload_unittest.cc
 run_unittests_SOURCES += message_unittest.cc
-run_unittests_SOURCES += base32hex_unittest.cc
-run_unittests_SOURCES += base64_unittest.cc
-run_unittests_SOURCES += hex_unittest.cc
-run_unittests_SOURCES += sha1_unittest.cc
+run_unittests_SOURCES += tsig_unittest.cc
+run_unittests_SOURCES += tsigerror_unittest.cc
 run_unittests_SOURCES += tsigkey_unittest.cc
+run_unittests_SOURCES += tsigrecord_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 endif
 
diff --git a/src/lib/dns/tests/base32hex_unittest.cc b/src/lib/dns/tests/base32hex_unittest.cc
deleted file mode 100644
index 253d310..0000000
--- a/src/lib/dns/tests/base32hex_unittest.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <stdint.h>
-
-#include <cctype>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/util/base32hex.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-
-namespace {
-
-typedef pair<string, string> StringPair;
-
-class Base32HexTest : public ::testing::Test {
-protected:
-    Base32HexTest() : encoding_chars("0123456789ABCDEFGHIJKLMNOPQRSTUV=") {
-        // test vectors from RFC4648
-        test_sequence.push_back(StringPair("", ""));
-        test_sequence.push_back(StringPair("f", "CO======"));
-        test_sequence.push_back(StringPair("fo", "CPNG===="));
-        test_sequence.push_back(StringPair("foo", "CPNMU==="));
-        test_sequence.push_back(StringPair("foob", "CPNMUOG="));
-        test_sequence.push_back(StringPair("fooba", "CPNMUOJ1"));
-        test_sequence.push_back(StringPair("foobar", "CPNMUOJ1E8======"));
-
-        // the same data, encoded using lower case chars (testable only
-        // for the decode side)
-        test_sequence_lower.push_back(StringPair("f", "co======"));
-        test_sequence_lower.push_back(StringPair("fo", "cpng===="));
-        test_sequence_lower.push_back(StringPair("foo", "cpnmu==="));
-        test_sequence_lower.push_back(StringPair("foob", "cpnmuog="));
-        test_sequence_lower.push_back(StringPair("fooba", "cpnmuoj1"));
-        test_sequence_lower.push_back(StringPair("foobar",
-                                                 "cpnmuoj1e8======"));
-    }
-    vector<StringPair> test_sequence;
-    vector<StringPair> test_sequence_lower;
-    vector<uint8_t> decoded_data;
-    const string encoding_chars;
-};
-
-void
-decodeCheck(const string& input_string, vector<uint8_t>& output,
-            const string& expected)
-{
-    decodeBase32Hex(input_string, output);
-    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
-}
-
-TEST_F(Base32HexTest, decode) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decodeCheck((*it).second, decoded_data, (*it).first);
-    }
-
-    // whitespace should be allowed
-    decodeCheck("CP NM\tUOG=", decoded_data, "foob");
-    decodeCheck("CPNMU===\n", decoded_data, "foo");
-
-    // invalid number of padding characters
-    EXPECT_THROW(decodeBase32Hex("CPNMU0==", decoded_data), BadValue);
-    EXPECT_THROW(decodeBase32Hex("CO0=====", decoded_data), BadValue);
-    EXPECT_THROW(decodeBase32Hex("CO=======", decoded_data), // too many ='s
-                 BadValue);
-
-    // intermediate padding isn't allowed
-    EXPECT_THROW(decodeBase32Hex("CPNMUOG=CPNMUOG=", decoded_data), BadValue);
-
-    // Non canonical form isn't allowed.
-    // P => 25(11001), so the padding byte would be 01000000
-    EXPECT_THROW(decodeBase32Hex("0P======", decoded_data), BadValue);
-}
-
-TEST_F(Base32HexTest, decodeLower) {
-    for (vector<StringPair>::const_iterator it = test_sequence_lower.begin();
-         it != test_sequence_lower.end();
-         ++it) {
-        decodeCheck((*it).second, decoded_data, (*it).first);
-    }
-}
-
-TEST_F(Base32HexTest, encode) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decoded_data.assign((*it).first.begin(), (*it).first.end());
-        EXPECT_EQ((*it).second, encodeBase32Hex(decoded_data));
-    }
-}
-
-// For Base32Hex we use handmade mappings, so it's prudent to test the
-// entire mapping table explicitly.
-TEST_F(Base32HexTest, decodeMap) {
-    string input(8, '0');       // input placeholder
-
-    // We're going to populate an input string with only the last character
-    // not equal to the zero character ('0') for each valid base32hex encoding
-    // character.  Decoding that input should result in a data stream with
-    // the last byte equal to the numeric value represented by the that
-    // character.  For example, we'll generate and confirm the following:
-    // "00000000" => should be 0 (as a 40bit integer)
-    // "00000001" => should be 1 (as a 40bit integer)
-    // ...
-    // "0000000V" => should be 31 (as a 40bit integer)
-    // We also check the use of an invalid character for the last character
-    // surely fails. '=' should be accepted as a valid padding in this
-    // context; space characters shouldn't be allowed in this context.
-
-    for (int i = 0; i < 256; ++i) {
-        input[7] = i;
-
-        const char ch = toupper(i);
-        const size_t pos = encoding_chars.find(ch);
-        if (pos == string::npos) {
-            EXPECT_THROW(decodeBase32Hex(input, decoded_data), BadValue);
-        } else {
-            decodeBase32Hex(input, decoded_data);
-            if (ch == '=') {
-                EXPECT_EQ(4, decoded_data.size());
-            } else {
-                EXPECT_EQ(5, decoded_data.size());
-                EXPECT_EQ(pos, decoded_data[4]);
-            }
-        }
-    }
-}
-
-TEST_F(Base32HexTest, encodeMap) {
-    for (int i = 0; i < 32; ++i) {
-        decoded_data.assign(4, 0);
-        decoded_data.push_back(i);
-        EXPECT_EQ(encoding_chars[i], encodeBase32Hex(decoded_data)[7]);
-    }
-}
-
-}
diff --git a/src/lib/dns/tests/base64_unittest.cc b/src/lib/dns/tests/base64_unittest.cc
deleted file mode 100644
index 7333793..0000000
--- a/src/lib/dns/tests/base64_unittest.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/util/base64.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-
-namespace {
-
-typedef pair<string, string> StringPair;
-
-class Base64Test : public ::testing::Test {
-protected:
-    Base64Test()
-    {
-        // test vectors from RFC4648
-        test_sequence.push_back(StringPair("", ""));
-        test_sequence.push_back(StringPair("f", "Zg=="));
-        test_sequence.push_back(StringPair("fo", "Zm8="));
-        test_sequence.push_back(StringPair("foo", "Zm9v"));
-        test_sequence.push_back(StringPair("foob", "Zm9vYg=="));
-        test_sequence.push_back(StringPair("fooba", "Zm9vYmE="));
-        test_sequence.push_back(StringPair("foobar", "Zm9vYmFy"));
-    }
-    vector<StringPair> test_sequence;
-    vector<uint8_t> decoded_data;
-};
-
-void
-decodeCheck(const string& input_string, vector<uint8_t>& output,
-            const string& expected)
-{
-    decodeBase64(input_string, output);
-    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
-}
-
-TEST_F(Base64Test, decode) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decodeCheck((*it).second, decoded_data, (*it).first);
-    }
-
-    // whitespace should be allowed
-    decodeCheck("Zm 9v\tYmF\ny", decoded_data, "foobar");
-    decodeCheck("Zm9vYg==", decoded_data, "foob");
-    decodeCheck("Zm9vYmE=\n", decoded_data, "fooba");
-
-    // only up to 2 padding characters are allowed
-    EXPECT_THROW(decodeBase64("A===", decoded_data), BadValue);
-    EXPECT_THROW(decodeBase64("A= ==", decoded_data), BadValue);
-
-    // intermediate padding isn't allowed
-    EXPECT_THROW(decodeBase64("YmE=YmE=", decoded_data), BadValue);
-
-    // Non canonical form isn't allowed.
-    // Z => 25(011001), m => 38(100110), 9 => 60(111101), so the padding
-    // byte would be 0100 0000.
-    EXPECT_THROW(decodeBase64("Zm9=", decoded_data), BadValue);
-    // Same for the 1st padding byte.  This would make it 01100000.
-    EXPECT_THROW(decodeBase64("Zm==", decoded_data), BadValue);
-}
-
-TEST_F(Base64Test, encode) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decoded_data.assign((*it).first.begin(), (*it).first.end());
-        EXPECT_EQ((*it).second, encodeBase64(decoded_data));
-    }
-}
-}
diff --git a/src/lib/dns/tests/buffer_unittest.cc b/src/lib/dns/tests/buffer_unittest.cc
deleted file mode 100644
index 2fe5a10..0000000
--- a/src/lib/dns/tests/buffer_unittest.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <exceptions/exceptions.h>
-
-#include <dns/buffer.h>
-
-#include <gtest/gtest.h>
-
-using namespace isc;
-
-namespace {
-
-using isc::dns::InputBuffer;
-using isc::dns::OutputBuffer;
-
-class BufferTest : public ::testing::Test {
-protected:
-    BufferTest() : ibuffer(testdata, sizeof(testdata)), obuffer(0),
-                   expected_size(0)
-    {
-        data16 = (2 << 8) | 3;
-        data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
-        memset(vdata, 0, sizeof(testdata));
-    }
-
-    InputBuffer ibuffer;
-    OutputBuffer obuffer;
-    static const uint8_t testdata[5];
-    uint8_t vdata[sizeof(testdata)];
-    size_t expected_size;
-    uint16_t data16;
-    uint32_t data32;
-};
-
-const uint8_t BufferTest::testdata[5] = {1, 2, 3, 4, 5};
-
-TEST_F(BufferTest, inputBufferRead) {
-    EXPECT_EQ(5, ibuffer.getLength());
-    EXPECT_EQ(1, ibuffer.readUint8());
-    EXPECT_EQ(1, ibuffer.getPosition());
-    data16 = ibuffer.readUint16();
-    EXPECT_EQ((2 << 8) | 3, data16);
-    EXPECT_EQ(3, ibuffer.getPosition());
-    ibuffer.setPosition(1);
-    EXPECT_EQ(1, ibuffer.getPosition());
-    data32 = ibuffer.readUint32();
-    EXPECT_EQ((2 << 24) | (3 << 16) | (4 << 8) | 5, data32);
-    ibuffer.setPosition(0);
-    memset(vdata, 0, sizeof(vdata));
-    ibuffer.readData(vdata, sizeof(vdata));
-    EXPECT_EQ(0, memcmp(vdata, testdata, sizeof(testdata)));
-}
-
-TEST_F(BufferTest, inputBufferException) {
-    EXPECT_THROW(ibuffer.setPosition(6), isc::dns::InvalidBufferPosition);
-
-    ibuffer.setPosition(sizeof(testdata));
-    EXPECT_THROW(ibuffer.readUint8(), isc::dns::InvalidBufferPosition);
-
-    ibuffer.setPosition(sizeof(testdata) - 1);
-    EXPECT_THROW(ibuffer.readUint16(), isc::dns::InvalidBufferPosition);
-
-    ibuffer.setPosition(sizeof(testdata) - 3);
-    EXPECT_THROW(ibuffer.readUint32(), isc::dns::InvalidBufferPosition);
-
-    ibuffer.setPosition(sizeof(testdata) - 4);
-    EXPECT_THROW(ibuffer.readData(vdata, sizeof(vdata)),
-                 isc::dns::InvalidBufferPosition);
-}
-
-TEST_F(BufferTest, outputBufferExtend) {
-    EXPECT_EQ(0, obuffer.getCapacity());
-    EXPECT_EQ(0, obuffer.getLength());
-    obuffer.writeUint8(10);
-    EXPECT_LT(0, obuffer.getCapacity());
-    EXPECT_EQ(1, obuffer.getLength());
-}
-
-TEST_F(BufferTest, outputBufferWrite) {
-    const uint8_t* cp;
-
-    obuffer.writeUint8(1);
-    expected_size += sizeof(uint8_t);
-    EXPECT_EQ(expected_size, obuffer.getLength());
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(1, *cp);
-
-    obuffer.writeUint16(data16);
-    expected_size += sizeof(data16);
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(expected_size, obuffer.getLength());
-    EXPECT_EQ(2, *(cp + 1));
-    EXPECT_EQ(3, *(cp + 2));
-
-    obuffer.writeUint32(data32);
-    expected_size += sizeof(data32);
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(expected_size, obuffer.getLength());
-    EXPECT_EQ(4, *(cp + 3));
-    EXPECT_EQ(5, *(cp + 4));
-    EXPECT_EQ(6, *(cp + 5));
-    EXPECT_EQ(7, *(cp + 6));
-
-    obuffer.writeData(testdata, sizeof(testdata));
-    expected_size += sizeof(testdata);
-    EXPECT_EQ(expected_size, obuffer.getLength());
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(0, memcmp(cp + 7, testdata, sizeof(testdata)));
-}
-
-TEST_F(BufferTest, outputBufferWriteat) {
-    obuffer.writeUint32(data32);
-    expected_size += sizeof(data32);
-
-    // overwrite 2nd byte
-    obuffer.writeUint8At(4, 1);
-    EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
-    const uint8_t* cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(4, *(cp + 1));
-
-    // overwrite 2nd and 3rd bytes
-    obuffer.writeUint16At(data16, 1);
-    EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(2, *(cp + 1));
-    EXPECT_EQ(3, *(cp + 2));
-
-    // overwrite 3rd and 4th bytes
-    obuffer.writeUint16At(data16, 2);
-    EXPECT_EQ(expected_size, obuffer.getLength());
-    cp = static_cast<const uint8_t*>(obuffer.getData());
-    EXPECT_EQ(2, *(cp + 2));
-    EXPECT_EQ(3, *(cp + 3));
-
-    EXPECT_THROW(obuffer.writeUint8At(data16, 5),
-                 isc::dns::InvalidBufferPosition);
-    EXPECT_THROW(obuffer.writeUint8At(data16, 4),
-                 isc::dns::InvalidBufferPosition);
-    EXPECT_THROW(obuffer.writeUint16At(data16, 3),
-                 isc::dns::InvalidBufferPosition);
-    EXPECT_THROW(obuffer.writeUint16At(data16, 4),
-                 isc::dns::InvalidBufferPosition);
-    EXPECT_THROW(obuffer.writeUint16At(data16, 5),
-                 isc::dns::InvalidBufferPosition);
-}
-
-TEST_F(BufferTest, outputBufferSkip) {
-    obuffer.skip(4);
-    EXPECT_EQ(4, obuffer.getLength());
-
-    obuffer.skip(2);
-    EXPECT_EQ(6, obuffer.getLength());
-}
-
-TEST_F(BufferTest, outputBufferTrim) {
-    obuffer.writeData(testdata, sizeof(testdata));
-    EXPECT_EQ(5, obuffer.getLength());
-
-    obuffer.trim(1);
-    EXPECT_EQ(4, obuffer.getLength());
-
-    obuffer.trim(2);
-    EXPECT_EQ(2, obuffer.getLength());
-
-    EXPECT_THROW(obuffer.trim(3), OutOfRange);
-}
-
-TEST_F(BufferTest, outputBufferReadat) {
-    obuffer.writeData(testdata, sizeof(testdata));
-    for (int i = 0; i < sizeof(testdata); i ++) {
-        EXPECT_EQ(testdata[i], obuffer[i]);
-    }
-    EXPECT_THROW(obuffer[sizeof(testdata)], isc::dns::InvalidBufferPosition);
-}
-
-TEST_F(BufferTest, outputBufferClear) {
-    obuffer.writeData(testdata, sizeof(testdata));
-    obuffer.clear();
-    EXPECT_EQ(0, obuffer.getLength());
-}
-}
diff --git a/src/lib/dns/tests/dnssectime_unittest.cc b/src/lib/dns/tests/dnssectime_unittest.cc
deleted file mode 100644
index b2708cc..0000000
--- a/src/lib/dns/tests/dnssectime_unittest.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-
-#include <time.h>
-
-#include <dns/dnssectime.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-
-// See dnssectime.cc
-namespace isc {
-namespace dns {
-namespace dnssectime {
-namespace detail {
-extern int64_t (*gettimeFunction)();
-}
-}
-}
-}
-
-namespace {
-
-class DNSSECTimeTest : public ::testing::Test {
-protected:
-    ~DNSSECTimeTest() {
-        dnssectime::detail::gettimeFunction = NULL;
-    }
-};
-
-TEST_F(DNSSECTimeTest, fromText) {
-    // In most cases (in practice) the 32-bit and 64-bit versions should
-    // behave identically, so we'll mainly test the 32-bit version, which
-    // will be more commonly used in actual code (because many of the wire
-    // format time field are 32-bit).  The subtle cases where these two
-    // return different values will be tested at the end of this test case.
-
-    // These are bogus and should be rejected
-    EXPECT_THROW(timeFromText32("2011 101120000"), InvalidTime);
-    EXPECT_THROW(timeFromText32("201101011200-0"), InvalidTime);
-
-    // Short length (or "decimal integer" version of representation;
-    // it's valid per RFC4034, but is not supported in this implementation)
-    EXPECT_THROW(timeFromText32("20100223"), InvalidTime);
-
-    // Leap year checks
-    EXPECT_THROW(timeFromText32("20110229120000"), InvalidTime);
-    EXPECT_THROW(timeFromText32("21000229120000"), InvalidTime);
-    EXPECT_NO_THROW(timeFromText32("20000229120000"));
-    EXPECT_NO_THROW(timeFromText32("20120229120000"));
-
-    // unusual case: this implementation allows SS=60 for "leap seconds"
-    EXPECT_NO_THROW(timeFromText32("20110101120060"));
-
-    // Out of range parameters
-    EXPECT_THROW(timeFromText32("19100223214617"), InvalidTime); // YY<1970
-    EXPECT_THROW(timeFromText32("20110001120000"), InvalidTime); // MM=00
-    EXPECT_THROW(timeFromText32("20111301120000"), InvalidTime); // MM=13
-    EXPECT_THROW(timeFromText32("20110100120000"), InvalidTime); // DD=00
-    EXPECT_THROW(timeFromText32("20110132120000"), InvalidTime); // DD=32
-    EXPECT_THROW(timeFromText32("20110431120000"), InvalidTime); // 'Apr31'
-    EXPECT_THROW(timeFromText32("20110101250000"), InvalidTime); // HH=25
-    EXPECT_THROW(timeFromText32("20110101126000"), InvalidTime); // mm=60
-    EXPECT_THROW(timeFromText32("20110101120061"), InvalidTime); // SS=61
-
-    // Feb 7, 06:28:15 UTC 2106 is the possible maximum time that can be
-    // represented as an unsigned 32bit integer without overflow.
-    EXPECT_EQ(4294967295LU, timeFromText32("21060207062815"));
-
-    // After that, timeFromText32() should start returning the second count
-    // modulo 2^32.
-    EXPECT_EQ(0, timeFromText32("21060207062816"));
-    EXPECT_EQ(10, timeFromText32("21060207062826"));
-
-    // On the other hand, the 64-bit version should return monotonically
-    // increasing counters.
-    EXPECT_EQ(4294967296LL, timeFromText64("21060207062816"));
-    EXPECT_EQ(4294967306LL, timeFromText64("21060207062826"));
-}
-
-// This helper templated function tells timeToText32 a faked current time.
-// The template parameter is that faked time in the form of int64_t seconds
-// since epoch.
-template <int64_t NOW>
-int64_t
-testGetTime() {
-    return (NOW);
-}
-
-// Seconds since epoch for the year 10K eve.  Commonly used in some tests
-// below.
-const uint64_t YEAR10K_EVE = 253402300799LL;
-
-TEST_F(DNSSECTimeTest, toText) {
-    // Check a basic case with the default (normal) gettimeFunction
-    // based on the "real current time".
-    // Note: this will fail after year 2078, but at that point we won't use
-    // this program anyway:-)
-    EXPECT_EQ("20100311233000", timeToText32(1268350200));
-
-    // Set the current time to: Feb 18 09:04:14 UTC 2012 (an arbitrary choice
-    // in the range of the first half of uint32 since epoch).
-    dnssectime::detail::gettimeFunction = testGetTime<1329555854LL>;
-
-    // Test the "year 2038" problem.
-    // Check the result of toText() for "INT_MIN" in int32_t.  It's in the
-    // 68-year range from the faked current time, so the result should be
-    // in year 2038, instead of 1901.
-    EXPECT_EQ("20380119031408", timeToText64(0x80000000L));
-    EXPECT_EQ("20380119031408", timeToText32(0x80000000L));
-
-    // A controversial case: what should we do with "-1"?  It's out of range
-    // in future, but according to RFC time before epoch doesn't seem to be
-    // considered "in-range" either.  Our toText() implementation handles
-    // this range as a special case and always treats them as future time
-    // until year 2038.  This won't be a real issue in practice, though,
-    // since such too large values won't be used in actual deployment by then.
-    EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
-
-    // After the singular point of year 2038, the first half of uint32 can
-    // point to a future time.
-    // Set the current time to: Apr 1 00:00:00 UTC 2038:
-    dnssectime::detail::gettimeFunction = testGetTime<2153692800LL>;
-    // then time "10" is Feb 7 06:28:26 UTC 2106
-    EXPECT_EQ("21060207062826", timeToText32(10));
-    // in 64-bit, it's 2^32 + 10
-    EXPECT_EQ("21060207062826", timeToText64(0x10000000aLL));
-
-    // After year 2106, the upper half of uint32 can point to past time
-    // (as it should).
-    dnssectime::detail::gettimeFunction = testGetTime<0x10000000aLL>;
-    EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
-
-    // Try very large time value.  Actually it's the possible farthest time
-    // that can be represented in the form of YYYYMMDDHHmmSS.
-    EXPECT_EQ("99991231235959", timeToText64(YEAR10K_EVE));
-    dnssectime::detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
-    EXPECT_EQ("99991231235959", timeToText32(4294197631LU));
-}
-
-TEST_F(DNSSECTimeTest, overflow) {
-    // Jan 1, Year 10,000.
-    EXPECT_THROW(timeToText64(253402300800LL), InvalidTime);
-    dnssectime::detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
-    EXPECT_THROW(timeToText32(4294197632LU), InvalidTime);
-}
-
-}
diff --git a/src/lib/dns/tests/edns_unittest.cc b/src/lib/dns/tests/edns_unittest.cc
index fb9a7c2..26cc01c 100644
--- a/src/lib/dns/tests/edns_unittest.cc
+++ b/src/lib/dns/tests/edns_unittest.cc
@@ -16,7 +16,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/message.h>
@@ -35,6 +35,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 const uint8_t EDNS::SUPPORTED_VERSION;
diff --git a/src/lib/dns/tests/hex_unittest.cc b/src/lib/dns/tests/hex_unittest.cc
deleted file mode 100644
index 6f82b17..0000000
--- a/src/lib/dns/tests/hex_unittest.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <stdint.h>
-
-#include <vector>
-#include <string>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/util/hex.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-
-namespace {
-const string hex_txt("DEADBEEFDECADE");
-const string hex_txt_space("DEAD BEEF DECADE");
-const string hex_txt_lower("deadbeefdecade");
-
-class HexTest : public ::testing::Test {
-protected:
-    HexTest() : encoding_chars("0123456789ABCDEF") {}
-    vector<uint8_t> decoded_data;
-    const string encoding_chars;
-};
-
-TEST_F(HexTest, encodeHex) {
-    std::vector<uint8_t> data;
-
-    data.push_back(0xde);
-    data.push_back(0xad);
-    data.push_back(0xbe);
-    data.push_back(0xef);
-    data.push_back(0xde);
-    data.push_back(0xca);
-    data.push_back(0xde);
-    EXPECT_EQ(hex_txt, encodeHex(data));
-}
-
-void
-compareData(const std::vector<uint8_t>& data) {
-    EXPECT_EQ(0xde, data[0]);
-    EXPECT_EQ(0xad, data[1]);
-    EXPECT_EQ(0xbe, data[2]);
-    EXPECT_EQ(0xef, data[3]);
-    EXPECT_EQ(0xde, data[4]);
-    EXPECT_EQ(0xca, data[5]);
-    EXPECT_EQ(0xde, data[6]);
-}
-
-TEST_F(HexTest, decodeHex) {
-    std::vector<uint8_t> result;
-
-    decodeHex(hex_txt, result);
-    compareData(result);
-
-    // lower case hex digits should be accepted
-    result.clear();
-    decodeHex(hex_txt_lower, result);
-    compareData(result);
-
-    // white space should be ignored
-    result.clear();
-    decodeHex(hex_txt_space, result);
-    compareData(result);
-
-    // Bogus input: should fail
-    result.clear();
-    EXPECT_THROW(decodeHex("1x", result), BadValue);
-
-    // Bogus input: encoded string must have an even number of characters.
-    result.clear();
-    EXPECT_THROW(decodeHex("dea", result), BadValue);
-}
-
-// For Hex encode/decode we use handmade mappings, so it's prudent to test the
-// entire mapping table explicitly.
-TEST_F(HexTest, decodeMap) {
-    string input("00");       // input placeholder
-
-    // See Base32HexTest.decodeMap for details of the following tests.
-    for (int i = 0; i < 256; ++i) {
-        input[1] = i;
-
-        const char ch = toupper(i);
-        const size_t pos = encoding_chars.find(ch);
-        if (pos == string::npos) {
-            EXPECT_THROW(decodeHex(input, decoded_data), BadValue);
-        } else {
-            decodeHex(input, decoded_data);
-            EXPECT_EQ(1, decoded_data.size());
-            EXPECT_EQ(pos, decoded_data[0]);
-        }
-    }
-}
-
-TEST_F(HexTest, encodeMap) {
-    for (int i = 0; i < 16; ++i) {
-        decoded_data.clear();
-        decoded_data.push_back(i);
-        EXPECT_EQ(encoding_chars[i], encodeHex(decoded_data)[1]);
-    }
-}
-
-}
diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc
index 92adbc9..c79ea2c 100644
--- a/src/lib/dns/tests/message_unittest.cc
+++ b/src/lib/dns/tests/message_unittest.cc
@@ -12,9 +12,18 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <fstream>
+
+#include <boost/scoped_ptr.hpp>
+
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <util/unittests/testdata.h>
+#include <util/unittests/textdata.h>
+
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/message.h>
@@ -26,6 +35,8 @@
 #include <dns/rrclass.h>
 #include <dns/rrttl.h>
 #include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
 
 #include <gtest/gtest.h>
 
@@ -35,6 +46,7 @@ using isc::UnitTestUtil;
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 //
@@ -52,6 +64,18 @@ using namespace isc::dns::rdata;
 const uint16_t Message::DEFAULT_MAX_UDPSIZE;
 const Name test_name("test.example.com");
 
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+// XXX: this is defined as class static constants, but some compilers
+// seemingly cannot find the symbol when used in the EXPECT_xxx macros.
+const uint16_t TSIGContext::DEFAULT_FUDGE;
+
 namespace {
 class MessageTest : public ::testing::Test {
 protected:
@@ -59,7 +83,9 @@ protected:
                     message_parse(Message::PARSE),
                     message_render(Message::RENDER),
                     bogus_section(static_cast<Message::Section>(
-                                      Message::SECTION_ADDITIONAL + 1))
+                                      Message::SECTION_ADDITIONAL + 1)),
+                    tsig_ctx(TSIGKey("www.example.com:"
+                                     "SFuWd/q99SzF8Yzd1QbB9g=="))
     {
         rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
                                      RRType::A(), RRTTL(3600)));
@@ -87,6 +113,9 @@ protected:
     RRsetPtr rrset_a;           // A RRset with two RDATAs
     RRsetPtr rrset_aaaa;        // AAAA RRset with one RDATA with RRSIG
     RRsetPtr rrset_rrsig;       // RRSIG for the AAAA RRset
+    TSIGContext tsig_ctx;
+    vector<unsigned char> expected_data;
+
     static void factoryFromFile(Message& message, const char* datafile);
 };
 
@@ -165,6 +194,70 @@ TEST_F(MessageTest, setEDNS) {
     EXPECT_EQ(edns, message_render.getEDNS());
 }
 
+TEST_F(MessageTest, fromWireWithTSIG) {
+    // Initially there should be no TSIG
+    EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+
+    // getTSIGRecord() is only valid in the parse mode.
+    EXPECT_THROW(message_render.getTSIGRecord(), InvalidMessageOperation);
+
+    factoryFromFile(message_parse, "message_toWire2.wire");
+    const char expected_mac[] = {
+        0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+        0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+    };
+    const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+    ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+    EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+    EXPECT_EQ(85, tsig_rr->getLength()); // see TSIGRecordTest.getLength
+    EXPECT_EQ(TSIGKey::HMACMD5_NAME(), tsig_rr->getRdata().getAlgorithm());
+    EXPECT_EQ(0x4da8877a, tsig_rr->getRdata().getTimeSigned());
+    EXPECT_EQ(TSIGContext::DEFAULT_FUDGE, tsig_rr->getRdata().getFudge());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        tsig_rr->getRdata().getMAC(),
+                        tsig_rr->getRdata().getMACSize(),
+                        expected_mac, sizeof(expected_mac));
+    EXPECT_EQ(0, tsig_rr->getRdata().getError());
+    EXPECT_EQ(0, tsig_rr->getRdata().getOtherLen());
+    EXPECT_EQ(static_cast<void*>(NULL), tsig_rr->getRdata().getOtherData());
+
+    // If we clear the message for reuse, the recorded TSIG will be cleared.
+    message_parse.clear(Message::PARSE);
+    EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+}
+
+TEST_F(MessageTest, fromWireWithTSIGCompressed) {
+    // Mostly same as fromWireWithTSIG, but the TSIG owner name is compressed.
+    factoryFromFile(message_parse, "message_fromWire12.wire");
+    const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+    ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+    EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+    // len(www.example.com) = 17, but when fully compressed, the length is
+    // 2 bytes.  So the length of the record should be 15 bytes shorter.
+    EXPECT_EQ(70, tsig_rr->getLength());
+}
+
+TEST_F(MessageTest, fromWireWithBadTSIG) {
+    // Multiple TSIG RRs
+    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire13.wire"),
+                 DNSMessageFORMERR);
+    message_parse.clear(Message::PARSE);
+
+    // TSIG in the answer section (must be in additional)
+    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire14.wire"),
+                 DNSMessageFORMERR);
+    message_parse.clear(Message::PARSE);
+
+    // TSIG is not the last record.
+    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire15.wire"),
+                 DNSMessageFORMERR);
+    message_parse.clear(Message::PARSE);
+
+    // Unexpected RR Class (this will fail in constructing TSIGRecord)
+    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire16.wire"),
+                 DNSMessageFORMERR);
+}
+
 TEST_F(MessageTest, getRRCount) {
     // by default all counters should be 0
     EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
@@ -518,6 +611,65 @@ TEST_F(MessageTest, toWireInParseMode) {
     EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
 }
 
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+    return (NOW);
+}
+
+void
+commonTSIGToWireCheck(Message& message, MessageRenderer& renderer,
+                      TSIGContext& tsig_ctx, const char* const expected_file)
+{
+    message.setOpcode(Opcode::QUERY());
+    message.setRcode(Rcode::NOERROR());
+    message.setHeaderFlag(Message::HEADERFLAG_RD, true);
+    message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+                                 RRType::A()));
+
+    message.toWire(renderer, tsig_ctx);
+    vector<unsigned char> expected_data;
+    UnitTestUtil::readWireData(expected_file, expected_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(),
+                        &expected_data[0], expected_data.size());
+}
+
+TEST_F(MessageTest, toWireWithTSIG) {
+    // Rendering a message with TSIG.  Various special cases specific to
+    // TSIG are tested in the tsig tests.  We only check the message contains
+    // a TSIG at the end and the ARCOUNT of the header is updated.
+
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    message_render.setQid(0x2d65);
+
+    {
+        SCOPED_TRACE("Message sign with TSIG");
+        commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+                              "message_toWire2.wire");
+    }
+}
+
+TEST_F(MessageTest, toWireWithEDNSAndTSIG) {
+    // Similar to the previous test, but with an EDNS before TSIG.
+    // The wire data check will confirm the ordering.
+    isc::util::detail::gettimeFunction = testGetTime<0x4db60d1f>;
+
+    message_render.setQid(0x6cd);
+
+    EDNSPtr edns(new EDNS());
+    edns->setUDPSize(4096);
+    message_render.setEDNS(edns);
+
+    {
+        SCOPED_TRACE("Message sign with TSIG and EDNS");
+        commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+                              "message_toWire3.wire");
+    }
+}
+
 TEST_F(MessageTest, toWireWithoutOpcode) {
     message_render.setRcode(Rcode::NOERROR());
     EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
@@ -528,6 +680,45 @@ TEST_F(MessageTest, toWireWithoutRcode) {
     EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
 }
 
+TEST_F(MessageTest, toText) {
+    // Check toText() output for a typical DNS response with records in
+    // all sections
+    
+    factoryFromFile(message_parse, "message_toText1.wire");
+    {
+        SCOPED_TRACE("Message toText test (basic case)");
+        ifstream ifs;
+        unittests::openTestData("message_toText1.txt", ifs);
+        unittests::matchTextData(ifs, message_parse.toText());
+    }
+
+    // Another example with EDNS.  The expected data was slightly modified
+    // from the dig output (other than replacing tabs with a space): adding
+    // a newline after the "OPT PSEUDOSECTION".  This is an intentional change
+    // in our version for better readability.
+    message_parse.clear(Message::PARSE);
+    factoryFromFile(message_parse, "message_toText2.wire");
+    {
+        SCOPED_TRACE("Message toText test with EDNS");
+        ifstream ifs;
+        unittests::openTestData("message_toText2.txt", ifs);
+        unittests::matchTextData(ifs, message_parse.toText());
+    }
+
+    // Another example with TSIG.  The expected data was slightly modified
+    // from the dig output (other than replacing tabs with a space): removing
+    // a redundant white space at the end of TSIG RDATA.  We'd rather consider
+    // it a dig's defect than a feature.
+    message_parse.clear(Message::PARSE);
+    factoryFromFile(message_parse, "message_toText3.wire");
+    {
+        SCOPED_TRACE("Message toText test with TSIG");
+        ifstream ifs;
+        unittests::openTestData("message_toText3.txt", ifs);
+        unittests::matchTextData(ifs, message_parse.toText());
+    }
+}
+
 TEST_F(MessageTest, toTextWithoutOpcode) {
     message_render.setRcode(Rcode::NOERROR());
     EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
diff --git a/src/lib/dns/tests/messagerenderer_unittest.cc b/src/lib/dns/tests/messagerenderer_unittest.cc
index c3d3edb..fe790fe 100644
--- a/src/lib/dns/tests/messagerenderer_unittest.cc
+++ b/src/lib/dns/tests/messagerenderer_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <vector>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 
@@ -23,9 +23,9 @@
 #include <gtest/gtest.h>
 
 using isc::UnitTestUtil;
-using isc::dns::OutputBuffer;
 using isc::dns::Name;
 using isc::dns::MessageRenderer;
+using isc::util::OutputBuffer;
 
 namespace {
 class MessageRendererTest : public ::testing::Test {
diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc
index 5daba9c..6434229 100644
--- a/src/lib/dns/tests/name_unittest.cc
+++ b/src/lib/dns/tests/name_unittest.cc
@@ -19,7 +19,7 @@
 #include <limits>
 #include <stdexcept>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
@@ -31,6 +31,7 @@
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 
 //
 // XXX: these are defined as class static constants, but some compilers
diff --git a/src/lib/dns/tests/question_unittest.cc b/src/lib/dns/tests/question_unittest.cc
index 59a4815..25fd75b 100644
--- a/src/lib/dns/tests/question_unittest.cc
+++ b/src/lib/dns/tests/question_unittest.cc
@@ -17,7 +17,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
@@ -32,6 +32,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 class QuestionTest : public ::testing::Test {
diff --git a/src/lib/dns/tests/rdata_cname_unittest.cc b/src/lib/dns/tests/rdata_cname_unittest.cc
index e3137a7..d6b02aa 100644
--- a/src/lib/dns/tests/rdata_cname_unittest.cc
+++ b/src/lib/dns/tests/rdata_cname_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_dname_unittest.cc b/src/lib/dns/tests/rdata_dname_unittest.cc
index c2384b6..ebd9e0e 100644
--- a/src/lib/dns/tests/rdata_dname_unittest.cc
+++ b/src/lib/dns/tests/rdata_dname_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_dnskey_unittest.cc b/src/lib/dns/tests/rdata_dnskey_unittest.cc
index e26bf57..f0596ed 100644
--- a/src/lib/dns/tests/rdata_dnskey_unittest.cc
+++ b/src/lib/dns/tests/rdata_dnskey_unittest.cc
@@ -16,7 +16,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -32,6 +32,7 @@ using isc::UnitTestUtil;
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_ds_unittest.cc b/src/lib/dns/tests/rdata_ds_unittest.cc
index d7e3f88..5988620 100644
--- a/src/lib/dns/tests/rdata_ds_unittest.cc
+++ b/src/lib/dns/tests/rdata_ds_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -29,6 +29,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_in_a_unittest.cc b/src/lib/dns/tests/rdata_in_a_unittest.cc
index 7302881..47e2bfa 100644
--- a/src/lib/dns/tests/rdata_in_a_unittest.cc
+++ b/src/lib/dns/tests/rdata_in_a_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
index c1953d6..6fd4d0e 100644
--- a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
+++ b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_mx_unittest.cc b/src/lib/dns/tests/rdata_mx_unittest.cc
index dd7677d..c4c9757 100644
--- a/src/lib/dns/tests/rdata_mx_unittest.cc
+++ b/src/lib/dns/tests/rdata_mx_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -27,6 +27,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_ns_unittest.cc b/src/lib/dns/tests/rdata_ns_unittest.cc
index 6d4a69e..b805783 100644
--- a/src/lib/dns/tests/rdata_ns_unittest.cc
+++ b/src/lib/dns/tests/rdata_ns_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_nsec3_unittest.cc b/src/lib/dns/tests/rdata_nsec3_unittest.cc
index 749e262..441c6d8 100644
--- a/src/lib/dns/tests/rdata_nsec3_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec3_unittest.cc
@@ -16,9 +16,9 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/encode/hex.h>
 #include <dns/exceptions.h>
-#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -34,6 +34,8 @@ using isc::UnitTestUtil;
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_nsec3param_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_unittest.cc
index 53e9126..8d802d6 100644
--- a/src/lib/dns/tests/rdata_nsec3param_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec3param_unittest.cc
@@ -16,9 +16,9 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/util/base32hex.h>
-#include <dns/buffer.h>
-#include <dns/util/hex.h>
+#include <util/encode/base32hex.h>
+#include <util/encode/hex.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -34,6 +34,8 @@ using isc::UnitTestUtil;
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_nsec_unittest.cc b/src/lib/dns/tests/rdata_nsec_unittest.cc
index 8286dee..5aa1e9c 100644
--- a/src/lib/dns/tests/rdata_nsec_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <string>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -30,6 +30,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_opt_unittest.cc b/src/lib/dns/tests/rdata_opt_unittest.cc
index be92b91..698d586 100644
--- a/src/lib/dns/tests/rdata_opt_unittest.cc
+++ b/src/lib/dns/tests/rdata_opt_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -27,6 +27,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_ptr_unittest.cc b/src/lib/dns/tests/rdata_ptr_unittest.cc
index da13dcb..7f5de20 100644
--- a/src/lib/dns/tests/rdata_ptr_unittest.cc
+++ b/src/lib/dns/tests/rdata_ptr_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 //
diff --git a/src/lib/dns/tests/rdata_rp_unittest.cc b/src/lib/dns/tests/rdata_rp_unittest.cc
new file mode 100644
index 0000000..07f5a93
--- /dev/null
+++ b/src/lib/dns/tests/rdata_rp_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/rdataclass.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::util;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_RP_Test : public RdataTest {
+protected:
+    Rdata_RP_Test() :
+        mailbox_name("root.example.com."),
+        text_name("rp-text.example.com."),
+        // this also serves as a test for "from text" constructor in a normal
+        // case.
+        rdata_rp("root.example.com. rp-text.example.com."),
+        obuffer(0), renderer(obuffer)
+    {}
+
+    const Name mailbox_name, text_name;
+    const generic::RP rdata_rp; // commonly used test RDATA
+    OutputBuffer obuffer;
+    MessageRenderer renderer;
+    vector<uint8_t> expected_wire;
+};
+
+TEST_F(Rdata_RP_Test, createFromText) {
+    EXPECT_EQ(mailbox_name, rdata_rp.getMailbox());
+    EXPECT_EQ(text_name, rdata_rp.getText());
+
+    // Invalid textual input cases follow:
+    // names are invalid
+    EXPECT_THROW(generic::RP("bad..name. rp-text.example.com"), EmptyLabel);
+    EXPECT_THROW(generic::RP("mailbox.example.com. bad..name"), EmptyLabel);
+
+    // missing field
+    EXPECT_THROW(generic::RP("mailbox.example.com."), InvalidRdataText);
+
+    // redundant field
+    EXPECT_THROW(generic::RP("mailbox.example.com. rp-text.example.com. "
+                             "redundant.example."), InvalidRdataText);
+}
+
+TEST_F(Rdata_RP_Test, createFromWire) {
+    RdataPtr rdata(rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                        "rdata_rp_fromWire1.wire"));
+    EXPECT_EQ(mailbox_name, dynamic_cast<generic::RP&>(*rdata).getMailbox());
+    EXPECT_EQ(text_name, dynamic_cast<generic::RP&>(*rdata).getText());
+
+    // a similar test with names being compressed
+    rdata = rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                 "rdata_rp_fromWire2.wire", 30);
+    EXPECT_EQ(mailbox_name, dynamic_cast<generic::RP&>(*rdata).getMailbox());
+    EXPECT_EQ(Name("rp-text.example.net"),
+              dynamic_cast<generic::RP&>(*rdata).getText());
+}
+
+TEST_F(Rdata_RP_Test, badFromWire) {
+    // RDLEN is too short
+    EXPECT_THROW(rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                      "rdata_rp_fromWire3.wire"),
+                 InvalidRdataLength);
+
+    // RDLEN is too long
+    EXPECT_THROW(rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                      "rdata_rp_fromWire4.wire"),
+                 InvalidRdataLength);
+
+    // bogus mailbox name
+    EXPECT_THROW(rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                      "rdata_rp_fromWire5.wire"),
+                 DNSMessageFORMERR);
+
+    // bogus text name
+    EXPECT_THROW(rdataFactoryFromFile(RRType::RP(), RRClass::IN(),
+                                      "rdata_rp_fromWire6.wire"),
+                 DNSMessageFORMERR);
+}
+
+TEST_F(Rdata_RP_Test, createFromParams) {
+    EXPECT_EQ(mailbox_name, generic::RP(mailbox_name, text_name).getMailbox());
+    EXPECT_EQ(text_name, generic::RP(mailbox_name, text_name).getText());
+}
+
+TEST_F(Rdata_RP_Test, toWireBuffer) {
+    // construct expected data
+    UnitTestUtil::readWireData("rdata_rp_toWire1.wire", expected_wire);
+
+    // construct actual data
+    rdata_rp.toWire(obuffer);
+
+    // then compare them
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        &expected_wire[0], expected_wire.size());
+}
+
+TEST_F(Rdata_RP_Test, toWireRenderer) {
+    // similar to toWireBuffer, but names in RDATA could be compressed due to
+    // preceding names.  Actually they must not be compressed according to
+    // RFC3597, and this test checks that.
+
+    UnitTestUtil::readWireData("rdata_rp_toWire2.wire", expected_wire);
+
+    renderer.writeName(Name("a.example.com"));
+    renderer.writeName(Name("b.example.net"));
+    generic::RP(mailbox_name, Name("rp-text.example.net")).toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        renderer.getData(), renderer.getLength(),
+                        &expected_wire[0], expected_wire.size());
+}
+
+TEST_F(Rdata_RP_Test, toText) {
+    // there's not much to test for this method.  Only checking a simple case.
+    EXPECT_EQ("root.example.com. rp-text.example.com.", rdata_rp.toText());
+}
+
+TEST_F(Rdata_RP_Test, compare) {
+    // check reflexivity
+    EXPECT_EQ(0, rdata_rp.compare(rdata_rp));
+
+    // names must be compared in case-insensitive manner
+    EXPECT_EQ(0, rdata_rp.compare(generic::RP("ROOT.example.com. "
+                                              "rp-text.EXAMPLE.com.")));
+
+    // another RP whose mailbox name is larger than that of rdata_rp.
+    const generic::RP large1_rp("zzzz.example.com. rp-text.example.com.");
+    EXPECT_GT(0, rdata_rp.compare(large1_rp));
+    EXPECT_LT(0, large1_rp.compare(rdata_rp));
+
+    // yet another RP whose text name is larger than that of rdata_rp.
+    const generic::RP large2_rp("root.example.com. zzzzzzz.example.com.");
+    EXPECT_GT(0, rdata_rp.compare(large2_rp));
+    EXPECT_LT(0, large2_rp.compare(rdata_rp));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(rdata_rp.compare(*RdataTest::rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_rrsig_unittest.cc b/src/lib/dns/tests/rdata_rrsig_unittest.cc
index 04d9469..903021f 100644
--- a/src/lib/dns/tests/rdata_rrsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_rrsig_unittest.cc
@@ -14,8 +14,8 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
-#include <dns/dnssectime.h>
+#include <util/buffer.h>
+#include <util/time_utilities.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -31,6 +31,7 @@ using isc::UnitTestUtil;
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc
index 6858a0b..63fe1f7 100644
--- a/src/lib/dns/tests/rdata_soa_unittest.cc
+++ b/src/lib/dns/tests/rdata_soa_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -27,6 +27,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc
index 5c9a14f..76f91a6 100644
--- a/src/lib/dns/tests/rdata_tsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_tsig_unittest.cc
@@ -16,7 +16,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -32,6 +32,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_txt_unittest.cc b/src/lib/dns/tests/rdata_txt_unittest.cc
index 54993e1..e5f8ac9 100644
--- a/src/lib/dns/tests/rdata_txt_unittest.cc
+++ b/src/lib/dns/tests/rdata_txt_unittest.cc
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -28,6 +28,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc
index 5ce4c03..fa791dc 100644
--- a/src/lib/dns/tests/rdata_unittest.cc
+++ b/src/lib/dns/tests/rdata_unittest.cc
@@ -16,7 +16,7 @@
 #include <string>
 #include <sstream>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -31,6 +31,7 @@
 using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace isc {
diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h
index 748c8d3..1bc0fa4 100644
--- a/src/lib/dns/tests/rdata_unittest.h
+++ b/src/lib/dns/tests/rdata_unittest.h
@@ -15,7 +15,7 @@
 #ifndef __RDATA_UNITTEST_H
 #define __RDATA_UNITTEST_H 1
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrclass.h>
 #include <dns/rrtype.h>
@@ -23,6 +23,8 @@
 
 #include <gtest/gtest.h>
 
+using namespace isc::util;
+
 namespace isc {
 namespace dns {
 namespace rdata {
diff --git a/src/lib/dns/tests/rdatafields_unittest.cc b/src/lib/dns/tests/rdatafields_unittest.cc
new file mode 100644
index 0000000..d619220
--- /dev/null
+++ b/src/lib/dns/tests/rdatafields_unittest.cc
@@ -0,0 +1,380 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatafields.h>
+#include <dns/tests/unittest_util.h>
+
+#include <gtest/gtest.h>
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::util::OutputBuffer;
+using isc::util::InputBuffer;
+
+namespace {
+class RdataFieldsTest : public ::testing::Test {
+protected:
+    RdataFieldsTest() : obuffer(0), renderer_buffer(0),
+                        renderer(renderer_buffer),
+                        ns_name("example.com"),
+                        other_name("www.example.com")
+    {}
+    void constructCommonTests(const RdataFields& fields,
+                              const uint8_t* const expected_data,
+                              const size_t expected_data_len);
+    void constructCommonTestsNS(const RdataFields& fields);
+    void constructCommonTestsTXT(const RdataFields& fields);
+    void constructCommonTestsRRSIG(const RdataFields& fields);
+    void constructCommonTestsOPT(const RdataFields& fields);
+    OutputBuffer obuffer;
+    OutputBuffer renderer_buffer;
+    MessageRenderer renderer;
+    const Name ns_name;
+    const Name other_name;
+    vector<unsigned char> expected_wire;
+    vector<unsigned char> fields_wire;
+};
+
+const uint8_t in_a_data[] = { 192, 0, 2, 1 };
+// binary representation of example.com.
+const uint8_t ns_data[] = { 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+                            0x03, 0x63, 0x6f, 0x6d, 0x00 };
+
+//
+// IN/A RDATA: fixed length, single data field
+//
+void
+RdataFieldsTest::constructCommonTests(const RdataFields& fields,
+                                      const uint8_t* const expected_data,
+                                      const size_t expected_data_len)
+{
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data,
+                        expected_data_len, fields.getData(),
+                        fields.getDataLength());
+    EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize());
+    EXPECT_EQ(1, fields.getFieldCount());
+    EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type);
+    EXPECT_EQ(4, fields.getFieldSpec(0).len);
+
+    fields.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data,
+                        expected_data_len, obuffer.getData(),
+                        obuffer.getLength());
+
+    fields.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data,
+                        expected_data_len, renderer.getData(),
+                        renderer.getLength());
+}
+
+TEST_F(RdataFieldsTest, constructFromRdata) {
+    const RdataFields fields(in::A("192.0.2.1"));
+    constructCommonTests(fields, in_a_data, sizeof(in_a_data));
+}
+
+TEST_F(RdataFieldsTest, constructFromParams) {
+    const RdataFields::FieldSpec spec(RdataFields::DATA, 4);
+    const RdataFields fields(&spec, sizeof(spec), in_a_data,
+                             sizeof(in_a_data));
+    constructCommonTests(fields, in_a_data, sizeof(in_a_data));
+}
+
+//
+// NS RDATA: containing a compressible name.
+//
+void
+RdataFieldsTest::constructCommonTestsNS(const RdataFields& fields) {
+    EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize());
+    EXPECT_EQ(1, fields.getFieldCount());
+    EXPECT_EQ(RdataFields::COMPRESSIBLE_NAME, fields.getFieldSpec(0).type);
+    EXPECT_EQ(ns_name.getLength(), fields.getFieldSpec(0).len);
+
+    expected_wire.clear();
+    UnitTestUtil::readWireData("rdatafields1.wire", expected_wire);
+    other_name.toWire(obuffer);
+    fields.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), obuffer.getData(),
+                        obuffer.getLength());
+
+    expected_wire.clear();
+    UnitTestUtil::readWireData("rdatafields2.wire", expected_wire);
+    other_name.toWire(renderer);
+    fields.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), renderer.getData(),
+                        renderer.getLength());
+}
+
+TEST_F(RdataFieldsTest, constructFromRdataNS) {
+    const RdataFields fields_ns((generic::NS(ns_name)));
+    constructCommonTestsNS(fields_ns);
+}
+
+TEST_F(RdataFieldsTest, constructFromParamsNS) {
+    const RdataFields::FieldSpec spec(RdataFields::COMPRESSIBLE_NAME,
+                                      sizeof(ns_data));
+    const RdataFields fields_ns(&spec, sizeof(spec), ns_data, sizeof(ns_data));
+    constructCommonTestsNS(fields_ns);
+}
+
+//
+// TXT RDATA: multiple fields, lengths vary
+//
+void
+RdataFieldsTest::constructCommonTestsTXT(const RdataFields& fields) {
+    // Since all fields are plain data, they are handled as a single data
+    // field.
+    EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize());
+    EXPECT_EQ(1, fields.getFieldCount());
+    EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type);
+    EXPECT_EQ(expected_wire.size(), fields.getFieldSpec(0).len);
+
+    fields.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), obuffer.getData(),
+                        obuffer.getLength());
+
+    fields.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), renderer.getData(),
+                        renderer.getLength());
+}
+
+TEST_F(RdataFieldsTest, constructFromRdataTXT) {
+    UnitTestUtil::readWireData("rdatafields3.wire", expected_wire);
+    InputBuffer ibuffer(&expected_wire[0], expected_wire.size());
+    const uint16_t rdlen = ibuffer.readUint16();
+    const RdataFields fields(generic::TXT(ibuffer, rdlen));
+
+    // drop the RDLEN part
+    expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2);
+
+    constructCommonTestsTXT(fields);
+}
+
+TEST_F(RdataFieldsTest, constructFromParamsTXT) {
+    UnitTestUtil::readWireData("rdatafields3.wire", expected_wire);
+    expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2);
+    const RdataFields::FieldSpec spec(RdataFields::DATA, expected_wire.size());
+    const RdataFields fields(&spec, sizeof(spec), &expected_wire[0],
+                             expected_wire.size());
+    constructCommonTestsTXT(fields);
+}
+
+//
+// RRSIG: multiple fields, with an incompressible name
+//
+void
+RdataFieldsTest::constructCommonTestsRRSIG(const RdataFields& fields) {
+    // In terms of RdataFields RRSIG RDATA consists of 3 fields:
+    // - 18-byte data field (from the "type covered" field to "key tag" field)
+    // - an incompressible name field (for the signer's name field).
+    //   this is a variable length field.  In this test it's a 13-byte field.
+    // - a variable-length data field for the signature.  In this tests
+    //   it's a 15-byte field.
+    EXPECT_EQ(3 * sizeof(RdataFields::FieldSpec),
+              fields.getFieldSpecDataSize());
+    EXPECT_EQ(3, fields.getFieldCount());
+    EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type);
+    EXPECT_EQ(18, fields.getFieldSpec(0).len);
+    EXPECT_EQ(RdataFields::INCOMPRESSIBLE_NAME, fields.getFieldSpec(1).type);
+    EXPECT_EQ(13, fields.getFieldSpec(1).len);
+    EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(2).type);
+    EXPECT_EQ(15, fields.getFieldSpec(2).len);
+
+    expected_wire.clear();
+    UnitTestUtil::readWireData("rdatafields5.wire", expected_wire);
+    Name("com").toWire(obuffer);
+    obuffer.writeUint16(fields.getDataLength());
+    fields.toWire(obuffer);
+    other_name.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), obuffer.getData(),
+                        obuffer.getLength());
+
+    expected_wire.clear();
+    UnitTestUtil::readWireData("rdatafields6.wire", expected_wire);
+    Name("com").toWire(renderer);
+    renderer.writeUint16(fields.getDataLength());
+    fields.toWire(renderer);    // the signer field won't be compressed
+    other_name.toWire(renderer); // but will be used as a compression target
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0],
+                        expected_wire.size(), renderer.getData(),
+                        renderer.getLength());
+}
+
+TEST_F(RdataFieldsTest, constructFromRdataRRSIG) {
+    UnitTestUtil::readWireData("rdatafields4.wire", expected_wire);
+    InputBuffer ibuffer(&expected_wire[0], expected_wire.size());
+    const uint16_t rdlen = ibuffer.readUint16();
+    const RdataFields fields(generic::RRSIG(ibuffer, rdlen));
+
+    // drop the RDLEN part
+    expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2);
+
+    constructCommonTestsRRSIG(fields);
+}
+
+TEST_F(RdataFieldsTest, constructFromParamsRRSIG) {
+    UnitTestUtil::readWireData("rdatafields4.wire", fields_wire);
+    fields_wire.erase(fields_wire.begin(), fields_wire.begin() + 2);
+
+    const RdataFields::FieldSpec specs[] = {
+        RdataFields::FieldSpec(RdataFields::DATA, 18),
+        RdataFields::FieldSpec(RdataFields::INCOMPRESSIBLE_NAME, 13),
+        RdataFields::FieldSpec(RdataFields::DATA, 15)
+    };
+    const RdataFields fields(specs, sizeof(specs), &fields_wire[0],
+                             fields_wire.size());
+    constructCommonTestsRRSIG(fields);
+}
+
+TEST_F(RdataFieldsTest, convertRdatatoParams) {
+    // Confirm we can restore the original data from the serialized data.
+    // We use RRSIG as a relatively complicated field structure.
+    UnitTestUtil::readWireData("rdatafields4.wire", expected_wire);
+    InputBuffer ibuffer(&expected_wire[0], expected_wire.size());
+    const uint16_t rdlen = ibuffer.readUint16();
+    const RdataFields fields(generic::RRSIG(ibuffer, rdlen));
+
+    expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2);
+
+    // Copy the data in separate storage
+    vector<uint8_t> spec_store(fields.getFieldSpecDataSize());
+    void* cp_spec = &spec_store[0];
+    memcpy(cp_spec, fields.getFieldSpecData(), spec_store.size());
+    vector<uint8_t> data_store(fields.getDataLength());
+    memcpy(&data_store[0], fields.getData(), fields.getDataLength());
+
+    // Restore the data in the form of RdataFields
+    const RdataFields fields_byparams(cp_spec, fields.getFieldSpecDataSize(),
+                                      &data_store[0], fields.getDataLength());
+
+    // Check it's valid
+    constructCommonTestsRRSIG(fields_byparams);
+}
+
+//
+// OPT: an empty RDATA
+//
+void
+RdataFieldsTest::constructCommonTestsOPT(const RdataFields& fields) {
+    EXPECT_EQ(0, fields.getFieldSpecDataSize());
+    EXPECT_EQ(0, fields.getFieldCount());
+    EXPECT_EQ(0, fields.getDataLength());
+    EXPECT_EQ((const uint8_t*) NULL, fields.getData());
+    fields.toWire(obuffer);
+    EXPECT_EQ(0, obuffer.getLength());
+    fields.toWire(renderer);
+    EXPECT_EQ(0, renderer.getLength());
+}
+
+TEST_F(RdataFieldsTest, constructFromRdataOPT) {
+    InputBuffer ibuffer(NULL, 0);
+    const RdataFields fields(generic::OPT(ibuffer, 0));
+    constructCommonTestsOPT(fields);
+}
+
+TEST_F(RdataFieldsTest, constructFromParamsOPT) {
+    const RdataFields fields(NULL, 0, NULL, 0);
+    constructCommonTestsOPT(fields);
+}
+
+// Invalid input to the "from parameter" constructor: sum of the field lengths
+// is not equal to the data length.
+TEST_F(RdataFieldsTest, invalidFieldLength) {
+    UnitTestUtil::readWireData("rdatafields4.wire", fields_wire);
+    fields_wire.erase(fields_wire.begin(), fields_wire.begin() + 2);
+
+    const RdataFields::FieldSpec specs[] = {
+        RdataFields::FieldSpec(RdataFields::DATA, 18),
+        RdataFields::FieldSpec(RdataFields::INCOMPRESSIBLE_NAME, 13),
+        RdataFields::FieldSpec(RdataFields::DATA, 14)
+    };
+    // sum of field len < data len
+    EXPECT_THROW(RdataFields(specs, 3, &fields_wire[0], fields_wire.size()),
+                 isc::InvalidParameter);
+    // sum of field len > data len
+    EXPECT_THROW(RdataFields(specs, 3, &fields_wire[0],
+                             fields_wire.size() - 2),
+                 isc::InvalidParameter);
+}
+
+// Invalid input to the "from parameter" constructor: NULL vs length mismatch
+TEST_F(RdataFieldsTest, mismatchFieldLengthAndData) {
+    const unsigned char dummy_data = 0;
+    const RdataFields::FieldSpec dummy_spec(RdataFields::DATA, 1);
+
+    EXPECT_THROW(RdataFields(NULL, 1, &dummy_data, 1), isc::InvalidParameter);
+    EXPECT_THROW(RdataFields(&dummy_spec, 0, NULL, 0), isc::InvalidParameter);
+    EXPECT_THROW(RdataFields(&dummy_spec, 1, NULL, 1), isc::InvalidParameter);
+    EXPECT_THROW(RdataFields(NULL, 0, &dummy_data, 0), isc::InvalidParameter);
+}
+
+// Bogus input to getFieldSpec()
+TEST_F(RdataFieldsTest, getFieldSpecWithBadFieldId) {
+    const RdataFields fields_in_a(in::A("192.0.2.1"));
+    EXPECT_THROW(fields_in_a.getFieldSpec(1), isc::OutOfRange);
+}
+
+// Tests for unexpected methods in RdataFieldComposerTest.  Confirm
+// a call to these methods triggers an exception.  Expected methods are
+// tested via other tests above.
+class DummyRdata : public Rdata {
+public:
+    enum Mode { CLEAR, SKIP, TRIM };
+    explicit DummyRdata(Mode mode) : mode_(mode) {}
+    DummyRdata(const DummyRdata& source) : Rdata(), mode_(source.mode_) {}
+    virtual ~DummyRdata() {}
+    virtual void toWire(AbstractMessageRenderer& renderer) const {
+        // call the unexpected method corresponding to the test mode.
+        // method parameters don't matter.
+        switch (mode_) {
+        case CLEAR:
+            renderer.clear();
+            break;
+        case SKIP:
+            renderer.skip(2);
+            break;
+        case TRIM:
+            renderer.trim(2);
+            break;
+        }
+    }
+    
+    // These are defined only to make the compiler happy.  We don't use them
+    // for the test.
+    virtual string toText() const { return (""); }
+    virtual void toWire(OutputBuffer&) const {}
+    virtual int compare(const Rdata&) const { return (0); }
+private:
+    const int mode_;
+};
+
+TEST(RdataFieldComposerTest, unusedMethods) {
+    EXPECT_THROW(RdataFields(DummyRdata(DummyRdata::CLEAR)), isc::Unexpected);
+}
+}
diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc
index 4eeb1e0..15f9a8c 100644
--- a/src/lib/dns/tests/rrclass_unittest.cc
+++ b/src/lib/dns/tests/rrclass_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <gtest/gtest.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrclass.h>
 
@@ -23,6 +23,7 @@
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 class RRClassTest : public ::testing::Test {
diff --git a/src/lib/dns/tests/rrparamregistry_unittest.cc b/src/lib/dns/tests/rrparamregistry_unittest.cc
index a75eed5..d2bec5c 100644
--- a/src/lib/dns/tests/rrparamregistry_unittest.cc
+++ b/src/lib/dns/tests/rrparamregistry_unittest.cc
@@ -27,6 +27,7 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index c704cc8..f951341 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <stdexcept>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
@@ -32,6 +32,7 @@ using isc::UnitTestUtil;
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
diff --git a/src/lib/dns/tests/rrttl_unittest.cc b/src/lib/dns/tests/rrttl_unittest.cc
index b8f5ac2..fe75eb6 100644
--- a/src/lib/dns/tests/rrttl_unittest.cc
+++ b/src/lib/dns/tests/rrttl_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <gtest/gtest.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrttl.h>
 
@@ -23,6 +23,7 @@
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 class RRTTLTest : public ::testing::Test {
diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc
index 6da7381..12f6001 100644
--- a/src/lib/dns/tests/rrtype_unittest.cc
+++ b/src/lib/dns/tests/rrtype_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <gtest/gtest.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrtype.h>
 
@@ -23,6 +23,7 @@
 using namespace std;
 using namespace isc;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 class RRTypeTest : public ::testing::Test {
diff --git a/src/lib/dns/tests/run_unittests.cc b/src/lib/dns/tests/run_unittests.cc
index 3cdc61d..18eb0a5 100644
--- a/src/lib/dns/tests/run_unittests.cc
+++ b/src/lib/dns/tests/run_unittests.cc
@@ -14,13 +14,16 @@
 
 #include <gtest/gtest.h>
 
+#include <util/unittests/testdata.h>
 #include <dns/tests/unittest_util.h>
 
 int
 main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
     isc::UnitTestUtil::addDataPath(TEST_DATA_SRCDIR);
+    isc::util::unittests::addTestDataPath(TEST_DATA_SRCDIR);
     isc::UnitTestUtil::addDataPath(TEST_DATA_BUILDDIR);
+    isc::util::unittests::addTestDataPath(TEST_DATA_BUILDDIR);
 
     return (RUN_ALL_TESTS());
 }
diff --git a/src/lib/dns/tests/sha1_unittest.cc b/src/lib/dns/tests/sha1_unittest.cc
deleted file mode 100644
index 79bc37d..0000000
--- a/src/lib/dns/tests/sha1_unittest.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <stdint.h>
-#include <string>
-
-#include <dns/util/sha1.h>
-
-#include <gtest/gtest.h>
-
-#include <dns/tests/unittest_util.h>
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-
-namespace {
-class Sha1Test : public ::testing::Test {
-protected:
-    Sha1Test() {}
-};
-
-// Tests copied from RFC 3174
-TEST_F(Sha1Test, Test1) {
-    SHA1Context sha;
-    uint8_t digest[SHA1_HASHSIZE];
-    uint8_t expected[SHA1_HASHSIZE] = {
-        0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
-        0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
-    };
-
-    EXPECT_EQ(0, SHA1Reset(&sha));
-    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "abc", 3));
-    EXPECT_EQ(0, SHA1Result(&sha, digest));
-    for (int i = 0; i < SHA1_HASHSIZE; i++) {
-        EXPECT_EQ(digest[i], expected[i]);
-    }
-}
-
-TEST_F(Sha1Test, Test2) {
-    SHA1Context sha;
-    string test("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
-    uint8_t digest[SHA1_HASHSIZE];
-    uint8_t expected[SHA1_HASHSIZE] = {
-        0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
-        0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1
-    };
-
-    EXPECT_EQ(0, SHA1Reset(&sha));
-    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
-                           test.length()));
-    EXPECT_EQ(0, SHA1Result(&sha, digest));
-    for (int i = 0; i < SHA1_HASHSIZE; i++) {
-        EXPECT_EQ(digest[i], expected[i]);
-    }
-}
-
-TEST_F(Sha1Test, Test3) {
-    SHA1Context sha;
-    uint8_t digest[SHA1_HASHSIZE];
-    uint8_t expected[SHA1_HASHSIZE] = {
-        0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e,
-        0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f
-    };
-
-    EXPECT_EQ(0, SHA1Reset(&sha));
-    for (int i = 0; i < 1000000; i++) {
-        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "a", 1));
-    }
-    EXPECT_EQ(0, SHA1Result(&sha, digest));
-    for (int i = 0; i < SHA1_HASHSIZE; i++) {
-        EXPECT_EQ(digest[i], expected[i]);
-    }
-}
-
-TEST_F(Sha1Test, Test4) {
-    SHA1Context sha;
-    string test("01234567012345670123456701234567"
-                "01234567012345670123456701234567");
-    uint8_t digest[SHA1_HASHSIZE];
-    uint8_t expected[SHA1_HASHSIZE] = {
-        0xde, 0xa3, 0x56, 0xa2, 0xcd, 0xdd, 0x90, 0xc7, 0xa7, 0xec,
-        0xed, 0xc5, 0xeb, 0xb5, 0x63, 0x93, 0x4f, 0x46, 0x04, 0x52
-    };
-
-    EXPECT_EQ(0, SHA1Reset(&sha));
-    for (int i = 0; i < 10; i++) {
-        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
-                               test.length()));
-    }
-    EXPECT_EQ(0, SHA1Result(&sha, digest));
-    for (int i = 0; i < SHA1_HASHSIZE; i++) {
-        EXPECT_EQ(digest[i], expected[i]);
-    }
-}
-}
-
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 1aaddb6..cb1bb1c 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -3,7 +3,15 @@ CLEANFILES = *.wire
 BUILT_SOURCES = edns_toWire1.wire edns_toWire2.wire edns_toWire3.wire
 BUILT_SOURCES += edns_toWire4.wire
 BUILT_SOURCES += message_fromWire10.wire message_fromWire11.wire
+BUILT_SOURCES += message_fromWire12.wire message_fromWire13.wire
+BUILT_SOURCES += message_fromWire14.wire message_fromWire15.wire
+BUILT_SOURCES += message_fromWire16.wire
+BUILT_SOURCES += message_toWire2.wire message_toWire3.wire
+BUILT_SOURCES += message_toText1.wire message_toText2.wire
+BUILT_SOURCES += message_toText3.wire
 BUILT_SOURCES += name_toWire5.wire name_toWire6.wire
+BUILT_SOURCES += rdatafields1.wire rdatafields2.wire rdatafields3.wire
+BUILT_SOURCES += rdatafields4.wire rdatafields5.wire rdatafields6.wire
 BUILT_SOURCES += rdata_nsec_fromWire4.wire rdata_nsec_fromWire5.wire
 BUILT_SOURCES += rdata_nsec_fromWire6.wire rdata_nsec_fromWire7.wire
 BUILT_SOURCES += rdata_nsec_fromWire8.wire rdata_nsec_fromWire9.wire
@@ -16,6 +24,10 @@ BUILT_SOURCES += rdata_nsec3_fromWire10.wire rdata_nsec3_fromWire11.wire
 BUILT_SOURCES += rdata_nsec3_fromWire12.wire rdata_nsec3_fromWire13.wire
 BUILT_SOURCES += rdata_nsec3_fromWire14.wire rdata_nsec3_fromWire15.wire
 BUILT_SOURCES += rdata_rrsig_fromWire2.wire
+BUILT_SOURCES += rdata_rp_fromWire1.wire rdata_rp_fromWire2.wire
+BUILT_SOURCES += rdata_rp_fromWire3.wire rdata_rp_fromWire4.wire
+BUILT_SOURCES += rdata_rp_fromWire5.wire rdata_rp_fromWire6.wire
+BUILT_SOURCES += rdata_rp_toWire1.wire rdata_rp_toWire2.wire
 BUILT_SOURCES += rdata_soa_toWireUncompressed.wire
 BUILT_SOURCES += rdata_txt_fromWire2.wire rdata_txt_fromWire3.wire
 BUILT_SOURCES += rdata_txt_fromWire4.wire rdata_txt_fromWire5.wire
@@ -27,6 +39,11 @@ BUILT_SOURCES += rdata_tsig_fromWire9.wire
 BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
 BUILT_SOURCES += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
 BUILT_SOURCES += rdata_tsig_toWire5.wire
+BUILT_SOURCES += tsigrecord_toWire1.wire tsigrecord_toWire2.wire
+BUILT_SOURCES += tsig_verify1.wire tsig_verify2.wire tsig_verify3.wire
+BUILT_SOURCES += tsig_verify4.wire tsig_verify5.wire tsig_verify6.wire
+BUILT_SOURCES += tsig_verify7.wire tsig_verify8.wire tsig_verify9.wire
+BUILT_SOURCES += tsig_verify10.wire
 
 # NOTE: keep this in sync with real file listing
 # so is included in tarball
@@ -39,8 +56,13 @@ EXTRA_DIST += message_fromWire3 message_fromWire4
 EXTRA_DIST += message_fromWire5 message_fromWire6
 EXTRA_DIST += message_fromWire7 message_fromWire8
 EXTRA_DIST += message_fromWire9 message_fromWire10.spec
-EXTRA_DIST += message_fromWire11.spec
-EXTRA_DIST += message_toWire1
+EXTRA_DIST += message_fromWire11.spec message_fromWire12.spec
+EXTRA_DIST += message_fromWire13.spec message_fromWire14.spec
+EXTRA_DIST += message_fromWire15.spec message_fromWire16.spec
+EXTRA_DIST += message_toWire1 message_toWire2.spec message_toWire3.spec
+EXTRA_DIST += message_toText1.txt message_toText1.spec
+EXTRA_DIST += message_toText2.txt message_toText2.spec
+EXTRA_DIST += message_toText3.txt message_toText3.spec
 EXTRA_DIST += name_fromWire1 name_fromWire2 name_fromWire3_1 name_fromWire3_2
 EXTRA_DIST += name_fromWire4 name_fromWire6 name_fromWire7 name_fromWire8
 EXTRA_DIST += name_fromWire9 name_fromWire10 name_fromWire11 name_fromWire12
@@ -48,6 +70,8 @@ EXTRA_DIST += name_fromWire13 name_fromWire14
 EXTRA_DIST += name_toWire1 name_toWire2 name_toWire3 name_toWire4
 EXTRA_DIST += name_toWire5.spec name_toWire6.spec
 EXTRA_DIST += question_fromWire question_toWire1 question_toWire2
+EXTRA_DIST += rdatafields1.spec rdatafields2.spec rdatafields3.spec
+EXTRA_DIST += rdatafields4.spec rdatafields5.spec rdatafields6.spec
 EXTRA_DIST += rdata_cname_fromWire rdata_dname_fromWire rdata_dnskey_fromWire
 EXTRA_DIST += rdata_ds_fromWire rdata_in_a_fromWire rdata_in_aaaa_fromWire
 EXTRA_DIST += rdata_mx_fromWire rdata_mx_toWire1 rdata_mx_toWire2
@@ -58,7 +82,8 @@ EXTRA_DIST += rdata_nsec_fromWire6.spec rdata_nsec_fromWire7.spec
 EXTRA_DIST += rdata_nsec_fromWire8.spec rdata_nsec_fromWire9.spec
 EXTRA_DIST += rdata_nsec_fromWire10.spec
 EXTRA_DIST += rdata_nsec3param_fromWire1
-EXTRA_DIST += rdata_nsec3_fromWire1 rdata_nsec3_fromWire3
+EXTRA_DIST += rdata_nsec3_fromWire1
+EXTRA_DIST += rdata_nsec3_fromWire2.spec rdata_nsec3_fromWire3
 EXTRA_DIST += rdata_nsec3_fromWire4.spec rdata_nsec3_fromWire5.spec
 EXTRA_DIST += rdata_nsec3_fromWire6.spec rdata_nsec3_fromWire7.spec
 EXTRA_DIST += rdata_nsec3_fromWire8.spec rdata_nsec3_fromWire9.spec
@@ -67,6 +92,10 @@ EXTRA_DIST += rdata_nsec3_fromWire12.spec rdata_nsec3_fromWire13.spec
 EXTRA_DIST += rdata_nsec3_fromWire14.spec rdata_nsec3_fromWire15.spec
 EXTRA_DIST += rdata_opt_fromWire rdata_rrsig_fromWire1
 EXTRA_DIST += rdata_rrsig_fromWire2.spec
+EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec
+EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec
+EXTRA_DIST += rdata_rp_fromWire5.spec rdata_rp_fromWire6.spec
+EXTRA_DIST += rdata_rp_toWire1.spec rdata_rp_toWire2.spec
 EXTRA_DIST += rdata_soa_fromWire rdata_soa_toWireUncompressed.spec
 EXTRA_DIST += rdata_txt_fromWire1 rdata_txt_fromWire2.spec
 EXTRA_DIST += rdata_txt_fromWire3.spec rdata_txt_fromWire4.spec
@@ -82,7 +111,11 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec
 EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
 EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
 EXTRA_DIST += rdata_tsig_toWire5.spec
-EXTRA_DIST += rdata_nsec3_fromWire2.spec
+EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec
+EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
+EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
+EXTRA_DIST += tsig_verify7.spec tsig_verify8.spec tsig_verify9.spec
+EXTRA_DIST += tsig_verify10.spec
 
 .spec.wire:
 	./gen-wiredata.py -o $@ $<
diff --git a/src/lib/dns/tests/testdata/gen-wiredata.py.in b/src/lib/dns/tests/testdata/gen-wiredata.py.in
index 645430c..fd98c6e 100755
--- a/src/lib/dns/tests/testdata/gen-wiredata.py.in
+++ b/src/lib/dns/tests/testdata/gen-wiredata.py.in
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-import configparser, re, time, sys
+import configparser, re, time, socket, sys
 from datetime import datetime
 from optparse import OptionParser
 
@@ -90,7 +90,7 @@ def encode_name(name, absolute=True):
     for l in labels:
         if len(l) > 4 and l[0:4] == 'ptr=':
             # special meta-syntax for compression pointer
-            wire += ' %04x' % (0xc000 | int(l[4:]))
+            wire += '%04x' % (0xc000 | int(l[4:]))
             break
         if absolute or len(l) > 0:
             wire += '%02x' % len(l)
@@ -215,9 +215,76 @@ class EDNS:
         f.write('# RDLEN=%d\n' % self.rdlen)
         f.write('%04x\n' % self.rdlen)
 
-class SOA:
-    # this currently doesn't support name compression within the RDATA.
-    rdlen = -1                  # auto-calculate
+class RR:
+    '''This is a base class for various types of RR test data.
+    For each RR type (A, AAAA, NS, etc), we define a derived class of RR
+    to dump type specific RDATA parameters.  This class defines parameters
+    common to all types of RDATA, namely the owner name, RR class and TTL.
+    The dump() method of derived classes are expected to call dump_header(),
+    whose default implementation is provided in this class.  This method
+    decides whether to dump the test data as an RR (with name, type, class)
+    or only as RDATA (with its length), and dumps the corresponding data
+    via the specified file object.
+
+    By convention we assume derived classes are named after the common
+    standard mnemonic of the corresponding RR types.  For example, the
+    derived class for the RR type SOA should be named "SOA".
+
+    Configurable parameters are as follows:
+    - as_rr (bool): Whether or not the data is to be dumped as an RR.  False
+      by default.
+    - rr_class (string): The RR class of the data.  Only meaningful when the
+      data is dumped as an RR.  Default is 'IN'.
+    - rr_ttl (integer): The TTL value of the RR.  Only meaningful when the
+      data is dumped as an RR.  Default is 86400 (1 day).
+    '''
+
+    def __init__(self):
+        self.as_rr = False
+        # only when as_rr is True, same for class/TTL:
+        self.rr_name = 'example.com'
+        self.rr_class = 'IN'
+        self.rr_ttl = 86400
+    def dump_header(self, f, rdlen):
+        type_txt = self.__class__.__name__
+        type_code = parse_value(type_txt, dict_rrtype)
+        if self.as_rr:
+            rrclass = parse_value(self.rr_class, dict_rrclass)
+            f.write('\n# %s RR (QNAME=%s Class=%s TTL=%d RDLEN=%d)\n' %
+                    (type_txt, self.rr_name,
+                     code_totext(rrclass, rdict_rrclass), self.rr_ttl, rdlen))
+            f.write('%s %04x %04x %08x %04x\n' %
+                    (encode_name(self.rr_name), type_code, rrclass,
+                     self.rr_ttl, rdlen))
+        else:
+            f.write('\n# %s RDATA (RDLEN=%d)\n' % (type_txt, rdlen))
+            f.write('%04x\n' % rdlen)
+
+class A(RR):
+    rdlen = 4                   # fixed by default
+    address = '192.0.2.1'
+
+    def dump(self, f):
+        self.dump_header(f, self.rdlen)
+        f.write('# Address=%s\n' % (self.address))
+        bin_address = socket.inet_aton(self.address)
+        f.write('%02x%02x%02x%02x\n' % (bin_address[0], bin_address[1],
+                                        bin_address[2], bin_address[3]))
+
+class NS(RR):
+    rdlen = None                   # auto calculate
+    nsname = 'ns.example.com'
+
+    def dump(self, f):
+        nsname_wire = encode_name(self.nsname)
+        if self.rdlen is None:
+            self.rdlen = len(nsname_wire) / 2
+        self.dump_header(f, self.rdlen)
+        f.write('# NS name=%s\n' % (self.nsname))
+        f.write('%s\n' % nsname_wire)
+
+class SOA(RR):
+    rdlen = None                  # auto-calculate
     mname = 'ns.example.com'
     rname = 'root.example.com'
     serial = 2010012601
@@ -228,11 +295,9 @@ class SOA:
     def dump(self, f):
         mname_wire = encode_name(self.mname)
         rname_wire = encode_name(self.rname)
-        rdlen = self.rdlen
-        if rdlen < 0:
-            rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
-        f.write('\n# SOA RDATA (RDLEN=%d)\n' % rdlen)
-        f.write('%04x\n' % rdlen);
+        if self.rdlen is None:
+            self.rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
+        self.dump_header(f, self.rdlen)
         f.write('# NNAME=%s RNAME=%s\n' % (self.mname, self.rname))
         f.write('%s %s\n' % (mname_wire, rname_wire))
         f.write('# SERIAL(%d) REFRESH(%d) RETRY(%d) EXPIRE(%d) MINIMUM(%d)\n' %
@@ -277,6 +342,34 @@ class TXT:
                                     ' ' if len(wirestring_list[i]) > 0 else '',
                                     wirestring_list[i]))
 
+class RP:
+    '''Implements rendering RP RDATA in the wire format.
+    Configurable parameters are as follows:
+    - rdlen: 16-bit RDATA length.  If omitted, the accurate value is auto
+      calculated and used; if negative, the RDLEN field will be omitted from
+      the output data.
+    - mailbox: The mailbox field.
+    - text: The text field.
+    All of these parameters have the default values and can be omitted.
+    '''
+    rdlen = None                # auto-calculate
+    mailbox = 'root.example.com'
+    text = 'rp-text.example.com'
+    def dump(self, f):
+        mailbox_wire = encode_name(self.mailbox)
+        text_wire = encode_name(self.text)
+        if self.rdlen is None:
+            self.rdlen = (len(mailbox_wire) + len(text_wire)) / 2
+        else:
+            self.rdlen = int(self.rdlen)
+        if self.rdlen >= 0:
+            f.write('\n# RP RDATA (RDLEN=%d)\n' % self.rdlen)
+            f.write('%04x\n' % self.rdlen)
+        else:
+            f.write('\n# RP RDATA (RDLEN omitted)\n')
+        f.write('# MAILBOX=%s TEXT=%s\n' % (self.mailbox, self.text))
+        f.write('%s %s\n' % (mailbox_wire, text_wire))
+
 class NSECBASE:
     '''Implements rendering NSEC/NSEC3 type bitmaps commonly used for
     these RRs.  The NSEC and NSEC3 classes will be inherited from this
@@ -404,7 +497,7 @@ class RRSIG:
         f.write('# Tag=%d Signer=%s and Signature\n' % (self.tag, self.signer))
         f.write('%04x %s %s\n' % (self.tag, name_wire, sig_wire))
 
-class TSIG:
+class TSIG(RR):
     rdlen = None                # auto-calculate
     algorithm = 'hmac-sha256'
     time_signed = 1286978795    # arbitrarily chosen default
@@ -416,12 +509,18 @@ class TSIG:
     other_len = None         # 6 if error is BADTIME; otherwise 0
     other_data = None        # use time_signed + fudge + 1 for BADTIME
     dict_macsize = { 'hmac-md5' : 16, 'hmac-sha1' : 20, 'hmac-sha256' : 32 }
+
+    # TSIG has some special defaults
+    def __init__(self):
+        super().__init__()
+        self.rr_class = 'ANY'
+        self.rr_ttl = 0
+
     def dump(self, f):
         if str(self.algorithm) == 'hmac-md5':
             name_wire = encode_name('hmac-md5.sig-alg.reg.int')
         else:
             name_wire = encode_name(self.algorithm)
-        rdlen = self.rdlen
         mac_size = self.mac_size
         if mac_size is None:
             if self.algorithm in self.dict_macsize.keys():
@@ -440,11 +539,10 @@ class TSIG:
                 if self.error == 18 else ''
         else:
             other_data = encode_string(self.other_data, other_len)
-        if rdlen is None:
-            rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
-                            len(other_data) / 2)
-        f.write('\n# TSIG RDATA (RDLEN=%d)\n' % rdlen)
-        f.write('%04x\n' % rdlen);
+        if self.rdlen is None:
+            self.rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
+                                 len(other_data) / 2)
+        self.dump_header(f, self.rdlen)
         f.write('# Algorithm=%s Time-Signed=%d Fudge=%d\n' %
                 (self.algorithm, self.time_signed, self.fudge))
         f.write('%s %012x %04x\n' % (name_wire, self.time_signed, self.fudge))
@@ -460,9 +558,11 @@ def get_config_param(section):
     config_param = {'name' : (Name, {}),
                     'header' : (DNSHeader, header_xtables),
                     'question' : (DNSQuestion, question_xtables),
-                    'edns' : (EDNS, {}), 'soa' : (SOA, {}), 'txt' : (TXT, {}),
-                    'rrsig' : (RRSIG, {}), 'nsec' : (NSEC, {}),
-                    'nsec3' : (NSEC3, {}), 'tsig' : (TSIG, {}) }
+                    'edns' : (EDNS, {}), 'a' : (A, {}), 'ns' : (NS, {}),
+                    'soa' : (SOA, {}), 'txt' : (TXT, {}),
+                    'rp' : (RP, {}), 'rrsig' : (RRSIG, {}),
+                    'nsec' : (NSEC, {}), 'nsec3' : (NSEC3, {}),
+                    'tsig' : (TSIG, {}) }
     s = section
     m = re.match('^([^:]+)/\d+$', section)
     if m:
diff --git a/src/lib/dns/tests/testdata/message_fromWire12.spec b/src/lib/dns/tests/testdata/message_fromWire12.spec
new file mode 100644
index 0000000..4eadeed
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire12.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS response message with TSIG signed, but the owner name of TSIG
+# is compressed
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: ptr=12
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire13.spec b/src/lib/dns/tests/testdata/message_fromWire13.spec
new file mode 100644
index 0000000..e81ec4c
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire13.spec
@@ -0,0 +1,20 @@
+#
+# Invalid TSIG: containing 2 TSIG RRs.
+#
+
+[custom]
+sections: header:question:tsig:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire14.spec b/src/lib/dns/tests/testdata/message_fromWire14.spec
new file mode 100644
index 0000000..bf68a93
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire14.spec
@@ -0,0 +1,21 @@
+#
+# Invalid TSIG: not in the additional section.
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+# TSIG goes to the answer section
+ancount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire15.spec b/src/lib/dns/tests/testdata/message_fromWire15.spec
new file mode 100644
index 0000000..25d810f
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire15.spec
@@ -0,0 +1,22 @@
+#
+# Invalid TSIG: not at the end of the message
+#
+
+[custom]
+sections: header:question:tsig:edns
+[header]
+id: 0x2d65
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
+[edns]
+# (all default)
diff --git a/src/lib/dns/tests/testdata/message_fromWire16.spec b/src/lib/dns/tests/testdata/message_fromWire16.spec
new file mode 100644
index 0000000..be0abc3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire16.spec
@@ -0,0 +1,21 @@
+#
+# Invalid TSIG: not in the additional section.
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_class: IN
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_toText1.spec b/src/lib/dns/tests/testdata/message_toText1.spec
new file mode 100644
index 0000000..b31310e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText1.spec
@@ -0,0 +1,24 @@
+#
+# A standard DNS message (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:a/1:ns:a/2
+[header]
+id: 29174
+qr: 1
+aa: 1
+ancount: 1
+nscount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a/1]
+as_rr: True
+rr_name: www.example.com
+address: 192.0.2.80
+[ns]
+as_rr: True
+[a/2]
+as_rr: True
+rr_name: ns.example.com
diff --git a/src/lib/dns/tests/testdata/message_toText1.txt b/src/lib/dns/tests/testdata/message_toText1.txt
new file mode 100644
index 0000000..58c7239
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText1.txt
@@ -0,0 +1,14 @@
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29174
+;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
+
+;; QUESTION SECTION:
+;www.example.com. IN A
+
+;; ANSWER SECTION:
+www.example.com. 86400 IN A 192.0.2.80
+
+;; AUTHORITY SECTION:
+example.com. 86400 IN NS ns.example.com.
+
+;; ADDITIONAL SECTION:
+ns.example.com. 86400 IN A 192.0.2.1
diff --git a/src/lib/dns/tests/testdata/message_toText2.spec b/src/lib/dns/tests/testdata/message_toText2.spec
new file mode 100644
index 0000000..978aab3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText2.spec
@@ -0,0 +1,14 @@
+#
+# A standard DNS message with EDNS (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:edns
+[header]
+id: 45981
+qr: 1
+rcode: refused
+arcount: 1
+[question]
+[edns]
+do: 1
diff --git a/src/lib/dns/tests/testdata/message_toText2.txt b/src/lib/dns/tests/testdata/message_toText2.txt
new file mode 100644
index 0000000..42cc2c1
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText2.txt
@@ -0,0 +1,8 @@
+;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 45981
+;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags: do; udp: 4096
+
+;; QUESTION SECTION:
+;example.com. IN A
diff --git a/src/lib/dns/tests/testdata/message_toText3.spec b/src/lib/dns/tests/testdata/message_toText3.spec
new file mode 100644
index 0000000..a74ea1b
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText3.spec
@@ -0,0 +1,31 @@
+#
+# A standard DNS message with TSIG (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:a/1:ns:a/2:tsig
+[header]
+id: 10140
+qr: 1
+aa: 1
+ancount: 1
+nscount: 1
+arcount: 2
+[question]
+name: www.example.com
+[a/1]
+as_rr: True
+rr_name: www.example.com
+address: 192.0.2.80
+[ns]
+as_rr: True
+[a/2]
+as_rr: True
+rr_name: ns.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 1304384318
+original_id: 10140
+mac: 0x5257c80396f2fa95b20c77ae9a652fb2
diff --git a/src/lib/dns/tests/testdata/message_toText3.txt b/src/lib/dns/tests/testdata/message_toText3.txt
new file mode 100644
index 0000000..359b9c5
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText3.txt
@@ -0,0 +1,17 @@
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10140
+;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
+
+;; QUESTION SECTION:
+;www.example.com. IN A
+
+;; ANSWER SECTION:
+www.example.com. 86400 IN A 192.0.2.80
+
+;; AUTHORITY SECTION:
+example.com. 86400 IN NS ns.example.com.
+
+;; ADDITIONAL SECTION:
+ns.example.com. 86400 IN A 192.0.2.1
+
+;; TSIG PSEUDOSECTION:
+www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1304384318 300 16 UlfIA5by+pWyDHeummUvsg== 10140 NOERROR 0
diff --git a/src/lib/dns/tests/testdata/message_toWire2.spec b/src/lib/dns/tests/testdata/message_toWire2.spec
new file mode 100644
index 0000000..d256052
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire2.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS query message with TSIG signed
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_toWire3.spec b/src/lib/dns/tests/testdata/message_toWire3.spec
new file mode 100644
index 0000000..c8e9453
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire3.spec
@@ -0,0 +1,22 @@
+#
+# A simple DNS query message with EDNS and TSIG
+#
+
+[custom]
+sections: header:question:edns:tsig
+[header]
+id: 0x06cd
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[edns]
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4db60d1f
+mac_size: 16
+mac: 0x93444053881c83d7eb120e86f25b369e
+original_id: 0x06cd
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec
new file mode 100644
index 0000000..edb9f34
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec
@@ -0,0 +1,6 @@
+#
+# A simplest form of RP: all default parameters
+#
+[custom]
+sections: rp
+[rp]
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec
new file mode 100644
index 0000000..57adb5a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec
@@ -0,0 +1,12 @@
+#
+# A simplest form of RP: names are compressed.
+#
+[custom]
+sections: name/1:name/2:rp
+[name/1]
+name: a.example.com
+[name/2]
+name: b.example.net
+[rp]
+mailbox: root.ptr=2
+text: rp-text.ptr=17
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec
new file mode 100644
index 0000000..a238b7e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec
@@ -0,0 +1,7 @@
+#
+# RP-like RDATA but RDLEN is too short.
+#
+[custom]
+sections: rp
+[rp]
+rdlen: 38
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec
new file mode 100644
index 0000000..6f3abd1
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec
@@ -0,0 +1,7 @@
+#
+# RP-like RDATA but RDLEN is too long.
+#
+[custom]
+sections: rp
+[rp]
+rdlen: 40
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec
new file mode 100644
index 0000000..b8d5e29
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec
@@ -0,0 +1,7 @@
+#
+# RP-like RDATA but mailbox name is broken.
+#
+[custom]
+sections: rp
+[rp]
+mailbox: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec
new file mode 100644
index 0000000..e9e79f3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec
@@ -0,0 +1,7 @@
+#
+# RP-like RDATA but text name is broken.
+#
+[custom]
+sections: rp
+[rp]
+text: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec b/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec
new file mode 100644
index 0000000..948bd1a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec
@@ -0,0 +1,8 @@
+#
+# A simplest form of RP for toWire test: all default parameters except rdlen,
+# which is to be omitted.
+#
+[custom]
+sections: rp
+[rp]
+rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec b/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec
new file mode 100644
index 0000000..09a7ddc
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec
@@ -0,0 +1,14 @@
+#
+# A simple form of RP: names could be compressed (but MUST NOT).
+# rdlen is omitted for the "to wire" test.
+#
+[custom]
+sections: name/1:name/2:rp
+[name/1]
+name: a.example.com
+[name/2]
+name: b.example.net
+[rp]
+rdlen: -1
+mailbox: root.example.com
+text: rp-text.example.net
diff --git a/src/lib/dns/tests/testdata/rdatafields1.spec b/src/lib/dns/tests/testdata/rdatafields1.spec
new file mode 100644
index 0000000..6e105fb
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields1.spec
@@ -0,0 +1,10 @@
+#
+# A sequence of names that could be compressed (but not compressed)
+#
+
+[custom]
+sections: name/1:name/2
+[name/1]
+name: www.example.com
+[name/2]
+name: example.com
diff --git a/src/lib/dns/tests/testdata/rdatafields2.spec b/src/lib/dns/tests/testdata/rdatafields2.spec
new file mode 100644
index 0000000..920dc95
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields2.spec
@@ -0,0 +1,11 @@
+#
+# A sequence of names that can be compressed.
+#
+
+[custom]
+sections: name/1:name/2
+[name/1]
+name: www.example.com
+[name/2]
+name: ''
+pointer: 4
diff --git a/src/lib/dns/tests/testdata/rdatafields3.spec b/src/lib/dns/tests/testdata/rdatafields3.spec
new file mode 100644
index 0000000..b37fca3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields3.spec
@@ -0,0 +1,11 @@
+#
+# TXT RDATA with multiple character-strings.
+#
+
+[custom]
+sections: txt
+[txt]
+nstring: 3
+string0: 'first string'
+string1: 'second string'
+string2: 'last string'
diff --git a/src/lib/dns/tests/testdata/rdatafields4.spec b/src/lib/dns/tests/testdata/rdatafields4.spec
new file mode 100644
index 0000000..24b59aa
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields4.spec
@@ -0,0 +1,7 @@
+#
+# Simple form of RRSIG (all fields use the default of generator script)
+#
+
+[custom]
+sections: rrsig
+[rrsig]
diff --git a/src/lib/dns/tests/testdata/rdatafields5.spec b/src/lib/dns/tests/testdata/rdatafields5.spec
new file mode 100644
index 0000000..2c78282
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields5.spec
@@ -0,0 +1,12 @@
+#
+# Names and RDATA (RRSIG) with an incompressible name.  All names are
+# rendered without compression.
+#
+
+[custom]
+sections: name/1:rrsig:name/2
+[name/1]
+name: com
+[rrsig]
+[name/2]
+name: www.example.com
diff --git a/src/lib/dns/tests/testdata/rdatafields6.spec b/src/lib/dns/tests/testdata/rdatafields6.spec
new file mode 100644
index 0000000..f9f0da1
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdatafields6.spec
@@ -0,0 +1,13 @@
+#
+# Names and RDATA (RRSIG) with an incompressible name.  The name in RRSIG
+# isn't compressed, but it's used as the compression target.
+#
+
+[custom]
+sections: name/1:rrsig:name/2
+[name/1]
+name: com
+[rrsig]
+[name/2]
+name: www
+pointer: 25
diff --git a/src/lib/dns/tests/testdata/tsig_verify1.spec b/src/lib/dns/tests/testdata/tsig_verify1.spec
new file mode 100644
index 0000000..687013a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify1.spec
@@ -0,0 +1,19 @@
+#
+# An example of signed AXFR request
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x3410
+arcount: 1
+[question]
+rrtype: AXFR
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0x35b2fd08268781634400c7c8a5533b13
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify10.spec b/src/lib/dns/tests/testdata/tsig_verify10.spec
new file mode 100644
index 0000000..33ce83e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify10.spec
@@ -0,0 +1,22 @@
+#
+# A simple DNS query message with TSIG signed whose MAC is too short
+# (only 1 byte)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 1
+mac: 0x22
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify2.spec b/src/lib/dns/tests/testdata/tsig_verify2.spec
new file mode 100644
index 0000000..ff98ca3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify2.spec
@@ -0,0 +1,32 @@
+#
+# An example of signed AXFR response
+#
+
+[custom]
+sections: header:question:soa:tsig
+[header]
+id: 0x3410
+aa: 1
+qr: 1
+ancount: 1
+arcount: 1
+[question]
+rrtype: AXFR
+[soa]
+# note that names are compressed in this RR
+as_rr: True
+rr_name: ptr=12
+mname: ns.ptr=12
+rname: root.ptr=12
+serial: 2011041503
+refresh: 7200
+retry: 3600
+expire: 2592000
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0xbdd612cd2c7f9e0648bd6dc23713e83c
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify3.spec b/src/lib/dns/tests/testdata/tsig_verify3.spec
new file mode 100644
index 0000000..7e2f797
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify3.spec
@@ -0,0 +1,26 @@
+#
+# An example of signed AXFR response (continued)
+#
+
+[custom]
+sections: header:ns:tsig
+[header]
+id: 0x3410
+aa: 1
+qr: 1
+qdcount: 0
+ancount: 1
+arcount: 1
+[ns]
+# note that names are compressed in this RR
+as_rr: True
+rr_name: example.com.
+nsname: ns.ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0x102458f7f62ddd7d638d746034130968
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify4.spec b/src/lib/dns/tests/testdata/tsig_verify4.spec
new file mode 100644
index 0000000..4ffbbcf
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify4.spec
@@ -0,0 +1,27 @@
+#
+# An example of signed DNS response with bogus MAC
+#
+
+[custom]
+sections: header:question:a:tsig
+[header]
+id: 0x2d65
+aa: 1
+qr: 1
+rd: 1
+ancount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a]
+as_rr: True
+rr_name: ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+# bogus MAC
+mac: 0xdeadbeefdeadbeefdeadbeefdeadbeef
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify5.spec b/src/lib/dns/tests/testdata/tsig_verify5.spec
new file mode 100644
index 0000000..a6cc643
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify5.spec
@@ -0,0 +1,26 @@
+#
+# An example of signed DNS response
+#
+
+[custom]
+sections: header:question:a:tsig
+[header]
+id: 0x2d65
+aa: 1
+qr: 1
+rd: 1
+ancount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a]
+as_rr: True
+rr_name: ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x8fcda66a7cd1a3b9948eb1869d384a9f
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify6.spec b/src/lib/dns/tests/testdata/tsig_verify6.spec
new file mode 100644
index 0000000..32e0818
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify6.spec
@@ -0,0 +1,21 @@
+#
+# Forwarded DNS query message with TSIG signed (header ID != orig ID)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x1035
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify7.spec b/src/lib/dns/tests/testdata/tsig_verify7.spec
new file mode 100644
index 0000000..377578e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify7.spec
@@ -0,0 +1,21 @@
+#
+# DNS query message with TSIG that has empty MAC (invalidly)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 0
+mac: ''
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify8.spec b/src/lib/dns/tests/testdata/tsig_verify8.spec
new file mode 100644
index 0000000..5432d4a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify8.spec
@@ -0,0 +1,23 @@
+#
+# DNS query message with TSIG that has empty MAC + BADKEY error
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 0
+mac: ''
+# 17: BADKEY
+error: 17
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify9.spec b/src/lib/dns/tests/testdata/tsig_verify9.spec
new file mode 100644
index 0000000..5888455
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify9.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS query message with TSIG signed, but TSIG key and algorithm
+# names have upper case characters (unusual)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: WWW.EXAMPLE.COM
+algorithm: HMAC-MD5.SIG-ALG.REG.INT
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
new file mode 100644
index 0000000..a25dc46
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
@@ -0,0 +1,16 @@
+#
+# A simple TSIG RR (some of the parameters are taken from a live example
+# and don't have a specific meaning)
+#
+
+[custom]
+sections: tsig
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
new file mode 100644
index 0000000..f667e4c
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
@@ -0,0 +1,19 @@
+#
+# TSIG RR after some names that could (unexpectedly) cause name compression
+#
+
+[custom]
+sections: name/1:name/2:tsig
+[name/1]
+name: hmac-md5.sig-alg.reg.int
+[name/2]
+name: foo.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
new file mode 100644
index 0000000..55c3ac2
--- /dev/null
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -0,0 +1,907 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <time.h>
+#include <string>
+#include <stdexcept>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/base64.h>
+#include <util/unittests/newhook.h>
+#include <util/time_utilities.h>
+
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+// See dnssectime.cc
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+    return (NOW);
+}
+
+class TSIGTest : public ::testing::Test {
+protected:
+    TSIGTest() :
+        tsig_ctx(NULL), qid(0x2d65), test_name("www.example.com"),
+        badkey_name("badkey.example.com"), test_class(RRClass::IN()),
+        test_ttl(86400), message(Message::RENDER), buffer(0), renderer(buffer),
+        dummy_data(1024, 0xdd),  // should be sufficiently large for all tests
+        dummy_record(badkey_name, any::TSIG(TSIGKey::HMACMD5_NAME(),
+                                            0x4da8877a,
+                                            TSIGContext::DEFAULT_FUDGE,
+                                            0, NULL, qid, 0, 0, NULL))
+    {
+        // Make sure we use the system time by default so that we won't be
+        // confused due to other tests that tweak the time.
+        isc::util::detail::gettimeFunction = NULL;
+
+        decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
+        tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
+                                               TSIGKey::HMACMD5_NAME(),
+                                               &secret[0], secret.size())));
+        tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
+                                                      TSIGKey::HMACMD5_NAME(),
+                                                      &secret[0],
+                                                      secret.size())));
+    }
+    ~TSIGTest() {
+        isc::util::detail::gettimeFunction = NULL;
+    }
+
+    // Many of the tests below create some DNS message and sign it under
+    // some specific TSIG context.  This helper method unifies the common
+    // logic with slightly different parameters.
+    ConstTSIGRecordPtr createMessageAndSign(uint16_t qid, const Name& qname,
+                                            TSIGContext* ctx,
+                                            unsigned int message_flags =
+                                            RD_FLAG,
+                                            RRType qtype = RRType::A(),
+                                            const char* answer_data = NULL,
+                                            const RRType* answer_type = NULL,
+                                            bool add_question = true,
+                                            Rcode rcode = Rcode::NOERROR());
+
+    void createMessageFromFile(const char* datafile);
+
+    // bit-wise constant flags to configure DNS header flags for test
+    // messages.
+    static const unsigned int QR_FLAG = 0x1;
+    static const unsigned int AA_FLAG = 0x2;
+    static const unsigned int RD_FLAG = 0x4;
+
+    boost::scoped_ptr<TSIGContext> tsig_ctx;
+    boost::scoped_ptr<TSIGContext> tsig_verify_ctx;
+    TSIGKeyRing keyring;
+    const uint16_t qid;
+    const Name test_name;
+    const Name badkey_name;
+    const RRClass test_class;
+    const RRTTL test_ttl;
+    Message message;
+    OutputBuffer buffer;
+    MessageRenderer renderer;
+    vector<uint8_t> secret;
+    vector<uint8_t> dummy_data;
+    const TSIGRecord dummy_record;
+    vector<uint8_t> received_data;
+};
+
+ConstTSIGRecordPtr
+TSIGTest::createMessageAndSign(uint16_t id, const Name& qname,
+                               TSIGContext* ctx, unsigned int message_flags,
+                               RRType qtype, const char* answer_data,
+                               const RRType* answer_type, bool add_question,
+                               Rcode rcode)
+{
+    message.clear(Message::RENDER);
+    message.setQid(id);
+    message.setOpcode(Opcode::QUERY());
+    message.setRcode(rcode);
+    if ((message_flags & QR_FLAG) != 0) {
+        message.setHeaderFlag(Message::HEADERFLAG_QR);
+    }
+    if ((message_flags & AA_FLAG) != 0) {
+        message.setHeaderFlag(Message::HEADERFLAG_AA);
+    }
+    if ((message_flags & RD_FLAG) != 0) {
+        message.setHeaderFlag(Message::HEADERFLAG_RD);
+    }
+    if (add_question) {
+        message.addQuestion(Question(qname, test_class, qtype));
+    }
+    if (answer_data != NULL) {
+        if (answer_type == NULL) {
+            answer_type = &qtype;
+        }
+        RRsetPtr answer_rrset(new RRset(qname, test_class, *answer_type,
+                                        test_ttl));
+        answer_rrset->addRdata(createRdata(*answer_type, test_class,
+                                           answer_data));
+        message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+    }
+    renderer.clear();
+    message.toWire(renderer);
+
+    TSIGContext::State expected_new_state =
+        (ctx->getState() == TSIGContext::INIT) ?
+        TSIGContext::SENT_REQUEST : TSIGContext::SENT_RESPONSE;
+    ConstTSIGRecordPtr tsig = ctx->sign(id, renderer.getData(),
+                                        renderer.getLength());
+    EXPECT_EQ(expected_new_state, ctx->getState());
+
+    return (tsig);
+}
+
+void
+TSIGTest::createMessageFromFile(const char* datafile) {
+    message.clear(Message::PARSE);
+    received_data.clear();
+    UnitTestUtil::readWireData(datafile, received_data);
+    InputBuffer buffer(&received_data[0], received_data.size());
+    message.fromWire(buffer);
+}
+
+void
+commonSignChecks(ConstTSIGRecordPtr tsig, uint16_t expected_qid,
+                 uint64_t expected_timesigned,
+                 const uint8_t* expected_mac, size_t expected_maclen,
+                 uint16_t expected_error = 0,
+                 uint16_t expected_otherlen = 0,
+                 const uint8_t* expected_otherdata = NULL,
+                 const Name& expected_algorithm = TSIGKey::HMACMD5_NAME())
+{
+    ASSERT_TRUE(tsig != NULL);
+    const any::TSIG& tsig_rdata = tsig->getRdata();
+
+    EXPECT_EQ(expected_algorithm, tsig_rdata.getAlgorithm());
+    EXPECT_EQ(expected_timesigned, tsig_rdata.getTimeSigned());
+    EXPECT_EQ(300, tsig_rdata.getFudge());
+    EXPECT_EQ(expected_maclen, tsig_rdata.getMACSize());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        tsig_rdata.getMAC(), tsig_rdata.getMACSize(),
+                        expected_mac, expected_maclen);
+    EXPECT_EQ(expected_qid, tsig_rdata.getOriginalID());
+    EXPECT_EQ(expected_error, tsig_rdata.getError());
+    EXPECT_EQ(expected_otherlen, tsig_rdata.getOtherLen());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        tsig_rdata.getOtherData(), tsig_rdata.getOtherLen(),
+                        expected_otherdata, expected_otherlen);
+}
+
+void
+commonVerifyChecks(TSIGContext& ctx, const TSIGRecord* record,
+                   const void* data, size_t data_len, TSIGError expected_error,
+                   TSIGContext::State expected_new_state =
+                   TSIGContext::VERIFIED_RESPONSE)
+{
+    EXPECT_EQ(expected_error, ctx.verify(record, data, data_len));
+    EXPECT_EQ(expected_error, ctx.getError());
+    EXPECT_EQ(expected_new_state, ctx.getState());
+}
+
+TEST_F(TSIGTest, initialState) {
+    // Until signing or verifying, the state should be INIT
+    EXPECT_EQ(TSIGContext::INIT, tsig_ctx->getState());
+
+    // And there should be no error code.
+    EXPECT_EQ(TSIGError(Rcode::NOERROR()), tsig_ctx->getError());
+}
+
+TEST_F(TSIGTest, constructFromKeyRing) {
+    // Construct a TSIG context with an empty key ring.  Key shouldn't be
+    // found, and the BAD_KEY error should be recorded.
+    TSIGContext ctx1(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+    EXPECT_EQ(TSIGContext::INIT, ctx1.getState());
+    EXPECT_EQ(TSIGError::BAD_KEY(), ctx1.getError());
+
+    // Add a matching key (we don't use the secret so leave it empty), and
+    // construct it again.  This time it should be constructed with a valid
+    // key.
+    keyring.add(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(), NULL, 0));
+    TSIGContext ctx2(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+    EXPECT_EQ(TSIGContext::INIT, ctx2.getState());
+    EXPECT_EQ(TSIGError::NOERROR(), ctx2.getError());
+
+    // Similar to the first case except that the key ring isn't empty but
+    // it doesn't contain a matching key.
+    TSIGContext ctx3(test_name, TSIGKey::HMACSHA1_NAME(), keyring);
+    EXPECT_EQ(TSIGContext::INIT, ctx3.getState());
+    EXPECT_EQ(TSIGError::BAD_KEY(), ctx3.getError());
+
+    TSIGContext ctx4(Name("different-key.example"), TSIGKey::HMACMD5_NAME(),
+                     keyring);
+    EXPECT_EQ(TSIGContext::INIT, ctx4.getState());
+    EXPECT_EQ(TSIGError::BAD_KEY(), ctx4.getError());
+
+    // "Unknown" algorithm name will result in BADKEY, too.
+    TSIGContext ctx5(test_name, Name("unknown.algorithm"), keyring);
+    EXPECT_EQ(TSIGContext::INIT, ctx5.getState());
+    EXPECT_EQ(TSIGError::BAD_KEY(), ctx5.getError());
+}
+
+// Example output generated by
+// "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com
+// QID: 0x2d65
+// Time Signed: 0x00004da8877a
+// MAC: 227026ad297beee721ce6c6fff1e9ef3
+const uint8_t common_expected_mac[] = {
+    0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+    0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+};
+TEST_F(TSIGTest, sign) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    {
+        SCOPED_TRACE("Sign test for query");
+        commonSignChecks(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+                         qid, 0x4da8877a, common_expected_mac,
+                         sizeof(common_expected_mac));
+    }
+}
+
+// Same test as sign, but specifying the key name with upper-case (i.e.
+// non canonical) characters.  The digest must be the same.  It should actually
+// be ensured at the level of TSIGKey, but we confirm that at this level, too.
+TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
+                                TSIGKey::HMACMD5_NAME(),
+                                &secret[0], secret.size()));
+
+    {
+        SCOPED_TRACE("Sign test for query using non canonical key name");
+        commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+                         0x4da8877a, common_expected_mac,
+                         sizeof(common_expected_mac));
+    }
+}
+
+// Same as the previous test, but for the algorithm name.
+TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    TSIGContext cap_ctx(TSIGKey(test_name,
+                                Name("HMAC-md5.SIG-alg.REG.int"),
+                                &secret[0], secret.size()));
+
+    {
+        SCOPED_TRACE("Sign test for query using non canonical algorithm name");
+        commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+                         0x4da8877a, common_expected_mac,
+                         sizeof(common_expected_mac));
+    }
+}
+
+TEST_F(TSIGTest, signAtActualTime) {
+    // Sign the message using the actual time, and check the accuracy of it.
+    // We cannot reasonably predict the expected MAC, so don't bother to
+    // check it.
+    const uint64_t now = static_cast<uint64_t>(time(NULL));
+
+    {
+        SCOPED_TRACE("Sign test for query at actual time");
+        ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                       tsig_ctx.get());
+        const any::TSIG& tsig_rdata = tsig->getRdata();
+
+        // Check the resulted time signed is in the range of [now, now + 5]
+        // (5 is an arbitrary choice).  Note that due to the order of the call
+        // to time() and sign(), time signed must not be smaller than the
+        // current time.
+        EXPECT_LE(now, tsig_rdata.getTimeSigned());
+        EXPECT_GE(now + 5, tsig_rdata.getTimeSigned());
+    }
+}
+
+TEST_F(TSIGTest, signBadData) {
+    // some specific bad data should be rejected proactively.
+    const unsigned char dummy_data = 0;
+    EXPECT_THROW(tsig_ctx->sign(0, NULL, 10), InvalidParameter);
+    EXPECT_THROW(tsig_ctx->sign(0, &dummy_data, 0), InvalidParameter);
+}
+
+TEST_F(TSIGTest, verifyBadData) {
+    // the data must at least hold the DNS message header and the specified
+    // TSIG.
+    EXPECT_THROW(tsig_ctx->verify(&dummy_record, &dummy_data[0],
+                                  12 + dummy_record.getLength() - 1),
+                 InvalidParameter);
+
+    // And the data must not be NULL.
+    EXPECT_THROW(tsig_ctx->verify(&dummy_record, NULL,
+                                  12 + dummy_record.getLength()),
+                 InvalidParameter);
+}
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+// We enable this test only when we enable custom new/delete at build time
+// We could enable/disable the test runtime using the gtest filter, but
+// we'd basically like to minimize the number of disabled tests (they
+// should generally be considered tests that temporarily fail and should
+// be fixed).
+TEST_F(TSIGTest, signExceptionSafety) {
+    // Check sign() provides the strong exception guarantee for the simpler
+    // case (with a key error and empty MAC).  The general case is more
+    // complicated and involves more memory allocation, so the test result
+    // won't be reliable.
+
+    commonVerifyChecks(*tsig_verify_ctx, &dummy_record, &dummy_data[0],
+                       dummy_data.size(), TSIGError::BAD_KEY(),
+                       TSIGContext::RECEIVED_REQUEST);
+
+    try {
+        int dummydata;
+        isc::util::unittests::force_throw_on_new = true;
+        isc::util::unittests::throw_size_on_new = sizeof(TSIGRecord);
+        tsig_verify_ctx->sign(0, &dummydata, sizeof(dummydata));
+        isc::util::unittests::force_throw_on_new = false;
+        ASSERT_FALSE(true) << "Expected throw on new, but it didn't happen";
+    } catch (const std::bad_alloc&) {
+        isc::util::unittests::force_throw_on_new = false;
+
+        // sign() threw, so the state should still be RECEIVED_REQUEST
+        EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+    }
+    isc::util::unittests::force_throw_on_new = false;
+}
+#endif  // ENABLE_CUSTOM_OPERATOR_NEW
+
+// Same test as "sign" but use a different algorithm just to confirm we don't
+// naively hardcode constants specific to a particular algorithm.
+// Test data generated by
+// "dig -y hmac-sha1:www.example.com:MA+QDhXbyqUak+qnMFyTyEirzng= www.example.com"
+//   QID: 0x0967, RDflag
+//   Current Time: 00004da8be86
+//   Time Signed:  00004dae7d5f
+//   HMAC Size: 20
+//   HMAC: 415340c7daf824ed684ee586f7b5a67a2febc0d3
+TEST_F(TSIGTest, signUsingHMACSHA1) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+
+    secret.clear();
+    decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
+    TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
+                                 &secret[0], secret.size()));
+
+    const uint16_t sha1_qid = 0x0967;
+    const uint8_t expected_mac[] = {
+        0x41, 0x53, 0x40, 0xc7, 0xda, 0xf8, 0x24, 0xed, 0x68, 0x4e,
+        0xe5, 0x86, 0xf7, 0xb5, 0xa6, 0x7a, 0x2f, 0xeb, 0xc0, 0xd3
+    };
+    {
+        SCOPED_TRACE("Sign test using HMAC-SHA1");
+        commonSignChecks(createMessageAndSign(sha1_qid, test_name, &sha1_ctx),
+                         sha1_qid, 0x4dae7d5f, expected_mac,
+                         sizeof(expected_mac), 0, 0, NULL,
+                         TSIGKey::HMACSHA1_NAME());
+    }
+}
+
+// The first part of this test checks verifying the signed query used for
+// the "sign" test.
+// The second part of this test generates a signed response to the signed
+// query as follows:
+// Answer: www.example.com. 86400 IN A 192.0.2.1
+// MAC: 8fcda66a7cd1a3b9948eb1869d384a9f
+TEST_F(TSIGTest, verifyThenSignResponse) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    // This test data for the message test has the same wire format data
+    // as the message used in the "sign" test.
+    createMessageFromFile("message_toWire2.wire");
+    {
+        SCOPED_TRACE("Verify test for request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+    }
+
+    // Transform the original message to a response, then sign the response
+    // with the context of "verified state".
+    ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                   tsig_verify_ctx.get(),
+                                                   QR_FLAG|AA_FLAG|RD_FLAG,
+                                                   RRType::A(), "192.0.2.1");
+    const uint8_t expected_mac[] = {
+        0x8f, 0xcd, 0xa6, 0x6a, 0x7c, 0xd1, 0xa3, 0xb9,
+        0x94, 0x8e, 0xb1, 0x86, 0x9d, 0x38, 0x4a, 0x9f
+    };
+    {
+        SCOPED_TRACE("Sign test for response");
+        commonSignChecks(tsig, qid, 0x4da8877a, expected_mac,
+                         sizeof(expected_mac));
+    }
+}
+
+TEST_F(TSIGTest, verifyUpperCaseNames) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    // This test data for the message test has the same wire format data
+    // as the message used in the "sign" test.
+    createMessageFromFile("tsig_verify9.wire");
+    {
+        SCOPED_TRACE("Verify test for request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+    }
+}
+
+TEST_F(TSIGTest, verifyForwardedMessage) {
+    // Similar to the first part of the previous test, but this test emulates
+    // the "forward" case, where the ID of the Header and the original ID in
+    // TSIG is different.
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    createMessageFromFile("tsig_verify6.wire");
+    {
+        SCOPED_TRACE("Verify test for forwarded request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+    }
+}
+
+// Example of signing multiple messages in a single TCP stream,
+// taken from data using BIND 9's "one-answer" transfer-format.
+// Request:
+//   QID: 0x3410, flags (none)
+//   Question: example.com/IN/AXFR
+//   Time Signed: 0x4da8e951
+//   MAC: 35b2fd08268781634400c7c8a5533b13
+// First message:
+//   QID: 0x3410, flags QR, AA
+//   Question: example.com/IN/AXFR
+//   Answer: example.com. 86400 IN SOA ns.example.com. root.example.com. (
+//                          2011041503 7200 3600 2592000 1200)
+//   MAC: bdd612cd2c7f9e0648bd6dc23713e83c
+// Second message:
+//   Answer: example.com. 86400 IN NS ns.example.com.
+//   MAC: 102458f7f62ddd7d638d746034130968
+TEST_F(TSIGTest, signContinuation) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8e951>;
+
+    const uint16_t axfr_qid = 0x3410;
+    const Name zone_name("example.com");
+
+    // Create and sign the AXFR request
+    ConstTSIGRecordPtr tsig = createMessageAndSign(axfr_qid, zone_name,
+                                                   tsig_ctx.get(), 0,
+                                                   RRType::AXFR());
+    // Then verify it (the wire format test data should contain the same
+    // message data, and verification should succeed).
+    received_data.clear();
+    UnitTestUtil::readWireData("tsig_verify1.wire", received_data);
+    {
+        SCOPED_TRACE("Verify AXFR query");
+        commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &received_data[0],
+                           received_data.size(), TSIGError::NOERROR(),
+                           TSIGContext::RECEIVED_REQUEST);
+    }
+
+    // Create and sign the first response message
+    tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+                                AA_FLAG|QR_FLAG, RRType::AXFR(),
+                                "ns.example.com. root.example.com. "
+                                "2011041503 7200 3600 2592000 1200",
+                                &RRType::SOA());
+
+    // Then verify it at the requester side.
+    received_data.clear();
+    UnitTestUtil::readWireData("tsig_verify2.wire", received_data);
+    {
+        SCOPED_TRACE("Verify first AXFR response");
+        commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+                           received_data.size(), TSIGError::NOERROR());
+    }
+
+    // Create and sign the second response message
+    const uint8_t expected_mac[] = {
+        0x10, 0x24, 0x58, 0xf7, 0xf6, 0x2d, 0xdd, 0x7d,
+        0x63, 0x8d, 0x74, 0x60, 0x34, 0x13, 0x09, 0x68
+    };
+    {
+        SCOPED_TRACE("Sign test for continued response in TCP stream");
+        tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+                                    AA_FLAG|QR_FLAG, RRType::AXFR(),
+                                    "ns.example.com.", &RRType::NS(), false);
+        commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac,
+                         sizeof(expected_mac));
+    }
+
+    // Then verify it at the requester side.
+    received_data.clear();
+    UnitTestUtil::readWireData("tsig_verify3.wire", received_data);
+    {
+        SCOPED_TRACE("Verify second AXFR response");
+        commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+                           received_data.size(), TSIGError::NOERROR());
+    }
+}
+
+// BADTIME example, taken from data using specially hacked BIND 9's nsupdate
+// Query:
+//   QID: 0x1830, RD flag
+//   Current Time: 00004da8be86
+//   Time Signed:  00004da8b9d6
+//   Question: www.example.com/IN/SOA
+//(mac) 8406 7d50 b8e7 d054 3d50 5bd9 de2a bb68
+// Response:
+//   QRbit, RCODE=9(NOTAUTH)
+//   Time Signed: 00004da8b9d6 (the one in the query)
+//   MAC: d4b043f6f44495ec8a01260e39159d76
+//   Error: 0x12 (BADTIME), Other Len: 6
+//   Other data: 00004da8be86
+TEST_F(TSIGTest, badtimeResponse) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+    const uint16_t test_qid = 0x7fc4;
+    ConstTSIGRecordPtr tsig = createMessageAndSign(test_qid, test_name,
+                                                   tsig_ctx.get(), 0,
+                                                   RRType::SOA());
+
+    // "advance the clock" and try validating, which should fail due to BADTIME
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8be86>;
+    {
+        SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+        commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_TIME(),
+                           TSIGContext::RECEIVED_REQUEST);
+    }
+
+    // make and sign a response in the context of TSIG error.
+    tsig = createMessageAndSign(test_qid, test_name, tsig_verify_ctx.get(),
+                                QR_FLAG, RRType::SOA(), NULL, NULL,
+                                true, Rcode::NOTAUTH());
+    const uint8_t expected_otherdata[] = { 0, 0, 0x4d, 0xa8, 0xbe, 0x86 };
+    const uint8_t expected_mac[] = {
+        0xd4, 0xb0, 0x43, 0xf6, 0xf4, 0x44, 0x95, 0xec,
+        0x8a, 0x01, 0x26, 0x0e, 0x39, 0x15, 0x9d, 0x76
+    };
+    {
+        SCOPED_TRACE("Sign test for response with BADTIME");
+        commonSignChecks(tsig, message.getQid(), 0x4da8b9d6,
+                         expected_mac, sizeof(expected_mac),
+                         18,     // error: BADTIME
+                         sizeof(expected_otherdata),
+                         expected_otherdata);
+    }
+}
+
+TEST_F(TSIGTest, badtimeResponse2) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+    ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                   tsig_ctx.get(), 0,
+                                                   RRType::SOA());
+
+    // "rewind the clock" and try validating, which should fail due to BADTIME
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 600>;
+    {
+        SCOPED_TRACE("Verify resulting in BADTIME due to too future SIG");
+        commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_TIME(),
+                           TSIGContext::RECEIVED_REQUEST);
+    }
+}
+
+TEST_F(TSIGTest, badtimeBoundaries) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+    // Test various boundary conditions.  We intentionally use the magic
+    // number of 300 instead of the constant variable for testing.
+    // In the okay cases, signature is not correct, but it's sufficient to
+    // check the error code isn't BADTIME for the purpose of this test.
+    ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                   tsig_ctx.get(), 0,
+                                                   RRType::SOA());
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 301>;
+    EXPECT_EQ(TSIGError::BAD_TIME(),
+              tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+                                      dummy_data.size()));
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 300>;
+    EXPECT_NE(TSIGError::BAD_TIME(),
+              tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+                                      dummy_data.size()));
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 301>;
+    EXPECT_EQ(TSIGError::BAD_TIME(),
+              tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+                                      dummy_data.size()));
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 300>;
+    EXPECT_NE(TSIGError::BAD_TIME(),
+              tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+                                      dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badtimeOverflow) {
+    isc::util::detail::gettimeFunction = testGetTime<200>;
+    ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                   tsig_ctx.get(), 0,
+                                                   RRType::SOA());
+
+    // This should be in the okay range, but since "200 - fudge" overflows
+    // and we compare them as 64-bit unsigned integers, it results in a false
+    // positive (we intentionally accept that).
+    isc::util::detail::gettimeFunction = testGetTime<100>;
+    EXPECT_EQ(TSIGError::BAD_TIME(),
+              tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+                                      dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badsigResponse) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    // Try to sign a simple message with bogus secret.  It should fail
+    // with BADSIG.
+    createMessageFromFile("message_toWire2.wire");
+    TSIGContext bad_ctx(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
+                                &dummy_data[0], dummy_data.size()));
+    {
+        SCOPED_TRACE("Verify resulting in BADSIG");
+        commonVerifyChecks(bad_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+    }
+
+    // Sign the same message (which doesn't matter for this test) with the
+    // context of "checked state".
+    {
+        SCOPED_TRACE("Sign test for response with BADSIG error");
+        commonSignChecks(createMessageAndSign(qid, test_name, &bad_ctx),
+                         message.getQid(), 0x4da8877a, NULL, 0,
+                         16);   // 16: BADSIG
+    }
+}
+
+TEST_F(TSIGTest, badkeyResponse) {
+    // A similar test as badsigResponse but for BADKEY
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+    tsig_ctx.reset(new TSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+                                   keyring));
+    {
+        SCOPED_TRACE("Verify resulting in BADKEY");
+        commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_KEY(),
+                           TSIGContext::RECEIVED_REQUEST);
+    }
+
+    {
+        SCOPED_TRACE("Sign test for response with BADKEY error");
+        ConstTSIGRecordPtr sig = createMessageAndSign(qid, test_name,
+                                                      tsig_ctx.get());
+        EXPECT_EQ(badkey_name, sig->getName());
+        commonSignChecks(sig, qid, 0x4da8877a, NULL, 0, 17);   // 17: BADKEY
+    }
+}
+
+TEST_F(TSIGTest, badkeyForResponse) {
+    // "BADKEY" case for a response to a signed message
+    createMessageAndSign(qid, test_name, tsig_ctx.get());
+    {
+        SCOPED_TRACE("Verify a response resulting in BADKEY");
+        commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_KEY(),
+                           TSIGContext::SENT_REQUEST);
+    }
+
+    // A similar case with a different algorithm
+    const TSIGRecord dummy_record2(test_name,
+                                  any::TSIG(TSIGKey::HMACSHA1_NAME(),
+                                            0x4da8877a,
+                                            TSIGContext::DEFAULT_FUDGE,
+                                            0, NULL, qid, 0, 0, NULL));
+    {
+        SCOPED_TRACE("Verify a response resulting in BADKEY due to bad alg");
+        commonVerifyChecks(*tsig_ctx, &dummy_record2, &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_KEY(),
+                           TSIGContext::SENT_REQUEST);
+    }
+}
+
+TEST_F(TSIGTest, badsigThenValidate) {
+    // According to RFC2845 4.6, if TSIG verification fails the client
+    // should discard that message and wait for another signed response.
+    // This test emulates that situation.
+
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+    createMessageFromFile("tsig_verify4.wire");
+    {
+        SCOPED_TRACE("Verify a response that should fail due to BADSIG");
+        commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::BAD_SIG(), TSIGContext::SENT_REQUEST);
+    }
+
+    createMessageFromFile("tsig_verify5.wire");
+    {
+        SCOPED_TRACE("Verify a response after a BADSIG failure");
+        commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(),
+                           TSIGContext::VERIFIED_RESPONSE);
+    }
+}
+
+TEST_F(TSIGTest, nosigThenValidate) {
+    // Similar to the previous test, but the first response doesn't contain
+    // TSIG.
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+    {
+        SCOPED_TRACE("Verify a response without TSIG that should exist");
+        commonVerifyChecks(*tsig_ctx, NULL, &dummy_data[0],
+                           dummy_data.size(), TSIGError::FORMERR(),
+                           TSIGContext::SENT_REQUEST);
+    }
+
+    createMessageFromFile("tsig_verify5.wire");
+    {
+        SCOPED_TRACE("Verify a response after a FORMERR failure");
+        commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(),
+                           TSIGContext::VERIFIED_RESPONSE);
+    }
+}
+
+TEST_F(TSIGTest, badtimeThenValidate) {
+    // Similar to the previous test, but the first response results in BADTIME.
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+                                                   tsig_ctx.get());
+
+    // "advance the clock" and try validating, which should fail due to BADTIME
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a + 600>;
+    {
+        SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+        commonVerifyChecks(*tsig_ctx, tsig.get(), &dummy_data[0],
+                           dummy_data.size(), TSIGError::BAD_TIME(),
+                           TSIGContext::SENT_REQUEST);
+    }
+
+    // revert the clock again.
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+    createMessageFromFile("tsig_verify5.wire");
+    {
+        SCOPED_TRACE("Verify a response after a BADTIME failure");
+        commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::NOERROR(),
+                           TSIGContext::VERIFIED_RESPONSE);
+    }
+}
+
+TEST_F(TSIGTest, emptyMAC) {
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+    // We don't allow empty MAC unless the TSIG error is BADSIG or BADKEY.
+    createMessageFromFile("tsig_verify7.wire");
+    {
+        SCOPED_TRACE("Verify test for request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+    }
+
+    // If the empty MAC comes with a BADKEY error, the error is passed
+    // transparently.
+    createMessageFromFile("tsig_verify8.wire");
+    {
+        SCOPED_TRACE("Verify test for request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::BAD_KEY(), TSIGContext::RECEIVED_REQUEST);
+    }
+}
+
+TEST_F(TSIGTest, verifyAfterSendResponse) {
+    // Once the context is used for sending a signed response, it shouldn't
+    // be used for further verification.
+
+    // The following are essentially the same as what verifyThenSignResponse
+    // does with simplification.
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+    createMessageFromFile("message_toWire2.wire");
+    tsig_verify_ctx->verify(message.getTSIGRecord(), &received_data[0],
+                            received_data.size());
+    EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+    createMessageAndSign(qid, test_name, tsig_verify_ctx.get(),
+                         QR_FLAG|AA_FLAG|RD_FLAG, RRType::A(), "192.0.2.1");
+    EXPECT_EQ(TSIGContext::SENT_RESPONSE, tsig_verify_ctx->getState());
+
+    // Now trying further verification.
+    createMessageFromFile("message_toWire2.wire");
+    EXPECT_THROW(tsig_verify_ctx->verify(message.getTSIGRecord(),
+                                         &received_data[0],
+                                         received_data.size()),
+                 TSIGContextError);
+}
+
+TEST_F(TSIGTest, signAfterVerified) {
+    // Likewise, once the context verifies a response, it shouldn't for
+    // signing any more.
+
+    // The following are borrowed from badsigThenValidate (without the
+    // intermediate failure)
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+    createMessageAndSign(qid, test_name, tsig_ctx.get());
+    createMessageFromFile("tsig_verify5.wire");
+    tsig_ctx->verify(message.getTSIGRecord(), &received_data[0],
+                     received_data.size());
+    EXPECT_EQ(TSIGContext::VERIFIED_RESPONSE, tsig_ctx->getState());
+
+    // Now trying further signing.
+    EXPECT_THROW(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+                 TSIGContextError);
+}
+
+TEST_F(TSIGTest, tooShortMAC) {
+    // Too short MAC should be rejected.
+    // Note: when we implement RFC4635-based checks, the error code will
+    // (probably) be FORMERR.
+
+    isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+    createMessageFromFile("tsig_verify10.wire");
+    {
+        SCOPED_TRACE("Verify test for request");
+        commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+                           &received_data[0], received_data.size(),
+                           TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+    }
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/tsigerror_unittest.cc b/src/lib/dns/tests/tsigerror_unittest.cc
new file mode 100644
index 0000000..bb08aef
--- /dev/null
+++ b/src/lib/dns/tests/tsigerror_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+TEST(TSIGErrorTest, constructFromErrorCode) {
+    // These are pretty trivial, and also test getCode();
+    EXPECT_EQ(0, TSIGError(0).getCode());
+    EXPECT_EQ(18, TSIGError(18).getCode());
+    EXPECT_EQ(65535, TSIGError(65535).getCode());
+}
+
+TEST(TSIGErrorTest, constructFromRcode) {
+    // We use RCODE for code values from 0-15.
+    EXPECT_EQ(0, TSIGError(Rcode::NOERROR()).getCode());
+    EXPECT_EQ(15, TSIGError(Rcode(15)).getCode());
+
+    // From error code 16 TSIG errors define a separate space, so passing
+    // corresponding RCODE for such code values should be prohibited.
+    EXPECT_THROW(TSIGError(Rcode(16)).getCode(), OutOfRange);
+}
+
+TEST(TSIGErrorTest, constants) {
+    // We'll only test arbitrarily chosen subsets of the codes.
+    // This class is quite simple, so it should be suffice.
+
+    EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError(16).getCode());
+    EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError(17).getCode());
+    EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError(18).getCode());
+
+    EXPECT_EQ(0, TSIGError::NOERROR().getCode());
+    EXPECT_EQ(9, TSIGError::NOTAUTH().getCode());
+    EXPECT_EQ(14, TSIGError::RESERVED14().getCode());
+    EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError::BAD_SIG().getCode());
+    EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError::BAD_KEY().getCode());
+    EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError::BAD_TIME().getCode());
+}
+
+TEST(TSIGErrorTest, equal) {
+    EXPECT_TRUE(TSIGError::NOERROR() == TSIGError(Rcode::NOERROR()));
+    EXPECT_TRUE(TSIGError(Rcode::NOERROR()) == TSIGError::NOERROR());
+    EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+    EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+
+    EXPECT_TRUE(TSIGError::BAD_SIG() == TSIGError(16));
+    EXPECT_TRUE(TSIGError(16) == TSIGError::BAD_SIG());
+    EXPECT_TRUE(TSIGError::BAD_SIG().equals(TSIGError(16)));
+    EXPECT_TRUE(TSIGError(16).equals(TSIGError::BAD_SIG()));
+}
+
+TEST(TSIGErrorTest, nequal) {
+    EXPECT_TRUE(TSIGError::BAD_KEY() != TSIGError(Rcode::NOERROR()));
+    EXPECT_TRUE(TSIGError(Rcode::NOERROR()) != TSIGError::BAD_KEY());
+    EXPECT_TRUE(TSIGError::BAD_KEY().nequals(TSIGError(Rcode::NOERROR())));
+    EXPECT_TRUE(TSIGError(Rcode::NOERROR()).nequals(TSIGError::BAD_KEY()));
+}
+
+TEST(TSIGErrorTest, toText) {
+    // TSIGError derived from the standard Rcode
+    EXPECT_EQ("NOERROR", TSIGError(Rcode::NOERROR()).toText());
+
+    // Well known TSIG errors
+    EXPECT_EQ("BADSIG", TSIGError::BAD_SIG().toText());
+    EXPECT_EQ("BADKEY", TSIGError::BAD_KEY().toText());
+    EXPECT_EQ("BADTIME", TSIGError::BAD_TIME().toText());
+
+    // Unknown (or not yet supported) codes.  Simply converted as numeric.
+    EXPECT_EQ("19", TSIGError(19).toText());
+    EXPECT_EQ("65535", TSIGError(65535).toText());
+}
+
+TEST(TSIGErrorTest, toRcode) {
+    // TSIGError derived from the standard Rcode
+    EXPECT_EQ(Rcode::NOERROR(), TSIGError(Rcode::NOERROR()).toRcode());
+
+    // Well known TSIG errors
+    EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_SIG().toRcode());
+    EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_KEY().toRcode());
+    EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_TIME().toRcode());
+
+    // Unknown (or not yet supported) codes are treated as SERVFAIL.
+    EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(19).toRcode());
+    EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(65535).toRcode());
+}
+
+// test operator<<.  We simply confirm it appends the result of toText().
+TEST(TSIGErrorTest, LeftShiftOperator) {
+    ostringstream oss;
+    oss << TSIGError::BAD_KEY();
+    EXPECT_EQ(TSIGError::BAD_KEY().toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 6b2b8c5..20ee802 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -18,6 +18,8 @@
 
 #include <exceptions/exceptions.h>
 
+#include <cryptolink/cryptolink.h>
+
 #include <dns/tsigkey.h>
 
 #include <dns/tests/unittest_util.h>
@@ -31,13 +33,34 @@ class TSIGKeyTest : public ::testing::Test {
 protected:
     TSIGKeyTest() : secret("someRandomData"), key_name("example.com") {}
     string secret;
-    Name key_name;
+    const Name key_name;
 };
 
 TEST_F(TSIGKeyTest, algorithmNames) {
     EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), TSIGKey::HMACMD5_NAME());
     EXPECT_EQ(Name("hmac-sha1"), TSIGKey::HMACSHA1_NAME());
     EXPECT_EQ(Name("hmac-sha256"), TSIGKey::HMACSHA256_NAME());
+    EXPECT_EQ(Name("hmac-sha224"), TSIGKey::HMACSHA224_NAME());
+    EXPECT_EQ(Name("hmac-sha384"), TSIGKey::HMACSHA384_NAME());
+    EXPECT_EQ(Name("hmac-sha512"), TSIGKey::HMACSHA512_NAME());
+
+    // Also check conversion to cryptolink definitions
+    EXPECT_EQ(isc::cryptolink::MD5, TSIGKey(key_name, TSIGKey::HMACMD5_NAME(),
+                                            NULL, 0).getAlgorithm());
+    EXPECT_EQ(isc::cryptolink::SHA1, TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(),
+                                             NULL, 0).getAlgorithm());
+    EXPECT_EQ(isc::cryptolink::SHA256, TSIGKey(key_name,
+                                               TSIGKey::HMACSHA256_NAME(),
+                                               NULL, 0).getAlgorithm());
+    EXPECT_EQ(isc::cryptolink::SHA224, TSIGKey(key_name,
+                                               TSIGKey::HMACSHA224_NAME(),
+                                               NULL, 0).getAlgorithm());
+    EXPECT_EQ(isc::cryptolink::SHA384, TSIGKey(key_name,
+                                               TSIGKey::HMACSHA384_NAME(),
+                                               NULL, 0).getAlgorithm());
+    EXPECT_EQ(isc::cryptolink::SHA512, TSIGKey(key_name,
+                                               TSIGKey::HMACSHA512_NAME(),
+                                               NULL, 0).getAlgorithm());
 }
 
 TEST_F(TSIGKeyTest, construct) {
@@ -48,9 +71,13 @@ TEST_F(TSIGKeyTest, construct) {
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret.c_str(),
                         secret.size(), key.getSecret(), key.getSecretLength());
 
+    // "unknown" algorithm is only accepted with empty secret.
     EXPECT_THROW(TSIGKey(key_name, Name("unknown-alg"),
                          secret.c_str(), secret.size()),
                  isc::InvalidParameter);
+    TSIGKey key2(key_name, Name("unknown-alg"), NULL, 0);
+    EXPECT_EQ(key_name, key2.getKeyName());
+    EXPECT_EQ(Name("unknown-alg"), key2.getAlgorithmName());
 
     // The algorithm name should be converted to the canonical form.
     EXPECT_EQ("hmac-sha1.",
@@ -58,6 +85,12 @@ TEST_F(TSIGKeyTest, construct) {
                       secret.c_str(),
                       secret.size()).getAlgorithmName().toText());
 
+    // Same for key name
+    EXPECT_EQ("example.com.",
+              TSIGKey(Name("EXAMPLE.CoM."), TSIGKey::HMACSHA256_NAME(),
+                      secret.c_str(),
+                      secret.size()).getKeyName().toText());
+
     // Invalid combinations of secret and secret_len:
     EXPECT_THROW(TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(), secret.c_str(), 0),
                  isc::InvalidParameter);
@@ -109,12 +142,18 @@ class TSIGKeyRingTest : public ::testing::Test {
 protected:
     TSIGKeyRingTest() :
         key_name("example.com"),
+        md5_name("hmac-md5.sig-alg.reg.int"),
+        sha1_name("hmac-sha1"),
+        sha256_name("hmac-sha256"),
         secretstring("anotherRandomData"),
         secret(secretstring.c_str()),
         secret_len(secretstring.size())
     {}
     TSIGKeyRing keyring;
-    Name key_name;
+    const Name key_name;
+    const Name md5_name;
+    const Name sha1_name;
+    const Name sha256_name;
 private:
     const string secretstring;
 protected:
@@ -134,8 +173,8 @@ TEST_F(TSIGKeyRingTest, add) {
     EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
                   TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
                           secret, secret_len)));
-    // keys are identified their names, the same name of key with a different
-    // algorithm would be considered a duplicate.
+    // keys are identified by their names, the same name of key with a
+    // different algorithm would be considered a duplicate.
     EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
                   TSIGKey(Name("example.com"), TSIGKey::HMACSHA1_NAME(),
                           secret, secret_len)));
@@ -187,44 +226,90 @@ TEST_F(TSIGKeyRingTest, removeFromSome) {
 }
 
 TEST_F(TSIGKeyRingTest, find) {
-    EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.find(key_name).code);
-    EXPECT_EQ(static_cast<const TSIGKey*>(NULL), keyring.find(key_name).key);
-
-    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
-                  TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
-                          secret, secret_len)));
-    const TSIGKeyRing::FindResult result(keyring.find(key_name));
-    EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
-    EXPECT_EQ(key_name, result.key->getKeyName());
-    EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result.key->getAlgorithmName());
+    // If the keyring is empty the search should fail.
+    EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.find(key_name, md5_name).code);
+    EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+              keyring.find(key_name, md5_name).key);
+
+    // Add a key and try to find it.  Should succeed.
+    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+                                                        secret, secret_len)));
+    const TSIGKeyRing::FindResult result1(keyring.find(key_name, sha256_name));
+    EXPECT_EQ(TSIGKeyRing::SUCCESS, result1.code);
+    EXPECT_EQ(key_name, result1.key->getKeyName());
+    EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result1.key->getAlgorithmName());
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret, secret_len,
-                        result.key->getSecret(),
-                        result.key->getSecretLength());
+                        result1.key->getSecret(),
+                        result1.key->getSecretLength());
+
+    // If either key name or algorithm doesn't match, search should fail.
+    const TSIGKeyRing::FindResult result2 =
+        keyring.find(Name("different-key.example"), sha256_name);
+    EXPECT_EQ(TSIGKeyRing::NOTFOUND, result2.code);
+    EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result2.key);
+
+    const TSIGKeyRing::FindResult result3 = keyring.find(key_name, md5_name);
+    EXPECT_EQ(TSIGKeyRing::NOTFOUND, result3.code);
+    EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result3.key);
 }
 
 TEST_F(TSIGKeyRingTest, findFromSome) {
     // essentially the same test, but search a larger set
 
-    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
-                  TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
-                          secret, secret_len)));
-    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
-                  TSIGKey(Name("another.example"), TSIGKey::HMACMD5_NAME(),
-                          secret, secret_len)));
-    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
-                  TSIGKey(Name("more.example"), TSIGKey::HMACSHA1_NAME(),
-                          secret, secret_len)));
+    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+                                                        secret, secret_len)));
+    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("another.example"),
+                                                        md5_name,
+                                                        secret, secret_len)));
+    EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("more.example"),
+                                                        sha1_name,
+                                                        secret, secret_len)));
 
     const TSIGKeyRing::FindResult result(
-        keyring.find(Name("another.example")));
+        keyring.find(Name("another.example"), md5_name));
     EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
     EXPECT_EQ(Name("another.example"), result.key->getKeyName());
     EXPECT_EQ(TSIGKey::HMACMD5_NAME(), result.key->getAlgorithmName());
 
     EXPECT_EQ(TSIGKeyRing::NOTFOUND,
-              keyring.find(Name("noexist.example")).code);
+              keyring.find(Name("noexist.example"), sha1_name).code);
     EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
-              keyring.find(Name("noexist.example")).key);
+              keyring.find(Name("noexist.example"), sha256_name).key);
+
+    EXPECT_EQ(TSIGKeyRing::NOTFOUND,
+              keyring.find(Name("another.example"), sha1_name).code);
+    EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+              keyring.find(Name("another.example"), sha256_name).key);
 }
 
+TEST(TSIGStringTest, TSIGKeyFromToString) {
+    TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
+    TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
+    TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
+    TSIGKey k4 = TSIGKey(Name("test.example."), Name("hmac-sha1."), NULL, 0);
+    // "Unknown" key with empty secret is okay
+    TSIGKey k5 = TSIGKey("test.example.::unknown");
+
+    EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+              k1.toText());
+    EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+              k2.toText());
+    EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+              k3.toText());
+    EXPECT_EQ("test.example.::hmac-sha1.", k4.toText());
+    EXPECT_EQ(Name("test.example."), k5.getKeyName());
+    EXPECT_EQ(Name("unknown"), k5.getAlgorithmName());
+
+    EXPECT_THROW(TSIGKey(""), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey(":"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("::"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("..:aa:"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("test.example:xxxx:"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("test.example.::"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("test.example.:"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:"), isc::InvalidParameter);
+    EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:unknown"), isc::InvalidParameter);
+}
+
+
 } // end namespace
diff --git a/src/lib/dns/tests/tsigrecord_unittest.cc b/src/lib/dns/tests/tsigrecord_unittest.cc
new file mode 100644
index 0000000..e1b3e93
--- /dev/null
+++ b/src/lib/dns/tests/tsigrecord_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <vector>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+namespace {
+class TSIGRecordTest : public ::testing::Test {
+protected:
+    TSIGRecordTest() :
+        test_name("www.example.com"), test_mac(16, 0xda),
+        test_rdata(any::TSIG(TSIGKey::HMACMD5_NAME(), 0x4da8877a,
+                             TSIGContext::DEFAULT_FUDGE,
+                             test_mac.size(), &test_mac[0],
+                             0x2d65, 0, 0, NULL)),
+        test_record(test_name, test_rdata),
+        buffer(0), renderer(buffer)
+    {}
+    const Name test_name;
+    vector<unsigned char> test_mac;
+    const any::TSIG test_rdata;
+    const TSIGRecord test_record;
+    OutputBuffer buffer;
+    MessageRenderer renderer;
+    vector<unsigned char> data;
+};
+
+TEST_F(TSIGRecordTest, getName) {
+    EXPECT_EQ(test_name, test_record.getName());
+}
+
+TEST_F(TSIGRecordTest, getLength) {
+    // 85 = 17 + 26 + 16 + 26
+    // len(www.example.com) = 17
+    // len(hmac-md5.sig-alg.reg.int) = 26
+    // len(MAC) = 16
+    // the rest are fixed length fields (26 in total)
+    EXPECT_EQ(85, test_record.getLength());
+}
+
+TEST_F(TSIGRecordTest, fromParams) {
+    // Construct the same TSIG RR as test_record from parameters.
+    // See the getLength test for the magic number of 85 (although it
+    // actually doesn't matter)
+    const TSIGRecord record(test_name, TSIGRecord::getClass(),
+                            TSIGRecord::getTTL(), test_rdata, 85);
+    // Perform straight sanity checks
+    EXPECT_EQ(test_name, record.getName());
+    EXPECT_EQ(85, record.getLength());
+    EXPECT_EQ(0, test_rdata.compare(record.getRdata()));
+
+    // The constructor doesn't check the length...
+    EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+                               TSIGRecord::getTTL(), test_rdata, 82));
+    // ...even for impossibly small values...
+    EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+                               TSIGRecord::getTTL(), test_rdata, 1));
+    // ...or too large values.
+    EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+                               TSIGRecord::getTTL(), test_rdata, 65536));
+
+    // RDATA must indeed be TSIG
+    EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+                            TSIGRecord::getTTL(), in::A("192.0.2.1"), 85),
+                 DNSMessageFORMERR);
+
+    // Unexpected class
+    EXPECT_THROW(TSIGRecord(test_name, RRClass::IN(), TSIGRecord::getTTL(),
+                            test_rdata, 85), DNSMessageFORMERR);
+
+    // Unexpected TTL
+    EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+                            RRTTL(3600), test_rdata, 85), DNSMessageFORMERR);
+}
+
+TEST_F(TSIGRecordTest, recordToWire) {
+    UnitTestUtil::readWireData("tsigrecord_toWire1.wire", data);
+    EXPECT_EQ(1, test_record.toWire(renderer));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        renderer.getData(), renderer.getLength(),
+                        &data[0], data.size());
+
+    // Same test for a dumb buffer
+    buffer.clear();
+    EXPECT_EQ(1, test_record.toWire(buffer));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        buffer.getData(), buffer.getLength(),
+                        &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, recordToOLongToWire) {
+    // By setting the limit to "record length - 1", it will fail, and the
+    // renderer will be marked as "truncated".
+    renderer.setLengthLimit(test_record.getLength() - 1);
+    EXPECT_FALSE(renderer.isTruncated()); // not marked before render attempt
+    EXPECT_EQ(0, test_record.toWire(renderer));
+    EXPECT_TRUE(renderer.isTruncated());
+}
+
+TEST_F(TSIGRecordTest, recordToWireAfterNames) {
+    // A similar test but the TSIG RR follows some domain names that could
+    // cause name compression inside TSIG.  Our implementation shouldn't
+    // compress either owner (key) name or the algorithm name.  This test
+    // confirms that.
+
+    UnitTestUtil::readWireData("tsigrecord_toWire2.wire", data);
+    renderer.writeName(TSIGKey::HMACMD5_NAME());
+    renderer.writeName(Name("foo.example.com"));
+    EXPECT_EQ(1, test_record.toWire(renderer));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        renderer.getData(), renderer.getLength(),
+                        &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, toText) {
+    EXPECT_EQ("www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. "
+              "1302890362 300 16 2tra2tra2tra2tra2tra2g== 11621 NOERROR 0\n",
+              test_record.toText());
+}
+
+// test operator<<.  We simply confirm it appends the result of toText().
+TEST_F(TSIGRecordTest, LeftShiftOperator) {
+    ostringstream oss;
+    oss << test_record;
+    EXPECT_EQ(test_record.toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
new file mode 100644
index 0000000..714b2a5
--- /dev/null
+++ b/src/lib/dns/tsig.cc
@@ -0,0 +1,453 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <sys/time.h>
+
+#include <stdint.h>
+
+#include <cassert>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::cryptolink;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace dns {
+namespace {
+typedef boost::shared_ptr<HMAC> HMACPtr;
+
+// TSIG uses 48-bit unsigned integer to represent time signed.
+// Since gettimeWrapper() returns a 64-bit *signed* integer, we
+// make sure it's stored in an unsigned 64-bit integer variable and
+// represents a value in the expected range.  (In reality, however,
+// gettimeWrapper() will return a positive integer that will fit
+// in 48 bits)
+uint64_t
+getTSIGTime() {
+    return (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
+}
+}
+
+struct TSIGContext::TSIGContextImpl {
+    TSIGContextImpl(const TSIGKey& key) :
+        state_(INIT), key_(key), error_(Rcode::NOERROR()),
+        previous_timesigned_(0)
+    {}
+
+    // This helper method is used from verify().  It's expected to be called
+    // just before verify() returns.  It updates internal state based on
+    // the verification result and return the TSIGError to be returned to
+    // the caller of verify(), so that verify() can call this method within
+    // its 'return' statement.
+    TSIGError postVerifyUpdate(TSIGError error, const void* digest,
+                               uint16_t digest_len)
+    {
+        if (state_ == INIT) {
+            state_ = RECEIVED_REQUEST;
+        } else if (state_ == SENT_REQUEST && error == TSIGError::NOERROR()) {
+            state_ = VERIFIED_RESPONSE;
+        }
+        if (digest != NULL) {
+            previous_digest_.assign(static_cast<const uint8_t*>(digest),
+                                    static_cast<const uint8_t*>(digest) +
+                                    digest_len);
+        }
+        error_ = error;
+        return (error);
+    }
+
+    // The following three are helper methods to compute the digest for
+    // TSIG sign/verify in order to unify the common code logic for sign()
+    // and verify() and to keep these callers concise.
+    // These methods take an HMAC object, which will be updated with the
+    // calculated digest.
+    // Note: All methods construct a local OutputBuffer as a work space with a
+    // fixed initial buffer size to avoid intermediate buffer extension.
+    // This should be efficient enough, especially for fundamentally expensive
+    // operation like cryptographic sign/verify, but if the creation of the
+    // buffer in each helper method is still identified to be a severe
+    // performance bottleneck, we could have this class a buffer as a member
+    // variable and reuse it throughout the object's lifetime.  Right now,
+    // we prefer keeping the scope for local things as small as possible.
+    void digestPreviousMAC(HMACPtr hmac) const;
+    void digestTSIGVariables(HMACPtr hmac, uint16_t rrclass, uint32_t rrttl,
+                             uint64_t time_signed, uint16_t fudge,
+                             uint16_t error, uint16_t otherlen,
+                             const void* otherdata,
+                             bool time_variables_only) const;
+    void digestDNSMessage(HMACPtr hmac, uint16_t qid, const void* data,
+                          size_t data_len) const;
+    State state_;
+    const TSIGKey key_;
+    vector<uint8_t> previous_digest_;
+    TSIGError error_;
+    uint64_t previous_timesigned_; // only meaningful for response with BADTIME
+};
+
+void
+TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) const {
+    // We should have ensured the digest size fits 16 bits within this class
+    // implementation.
+    assert(previous_digest_.size() <= 0xffff);
+
+    OutputBuffer buffer(sizeof(uint16_t) + previous_digest_.size());
+    const uint16_t previous_digest_len(previous_digest_.size());
+    buffer.writeUint16(previous_digest_len);
+    if (previous_digest_len != 0) {
+        buffer.writeData(&previous_digest_[0], previous_digest_len);
+    }
+    hmac->update(buffer.getData(), buffer.getLength());
+}
+
+void
+TSIGContext::TSIGContextImpl::digestTSIGVariables(
+    HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed,
+    uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata,
+    bool time_variables_only) const
+{
+    // It's bit complicated, but we can still predict the necessary size of
+    // the data to be digested.  So we precompute it to avoid possible
+    // reallocation inside OutputBuffer (not absolutely necessary, but this
+    // is a bit more efficient)
+    size_t data_size = 8;
+    if (!time_variables_only) {
+        data_size += 10 + key_.getKeyName().getLength() +
+            key_.getAlgorithmName().getLength();
+    }
+    OutputBuffer buffer(data_size);
+
+    if (!time_variables_only) {
+        key_.getKeyName().toWire(buffer);
+        buffer.writeUint16(rrclass);
+        buffer.writeUint32(rrttl);
+        key_.getAlgorithmName().toWire(buffer);
+    }
+    buffer.writeUint16(time_signed >> 32);
+    buffer.writeUint32(time_signed & 0xffffffff);
+    buffer.writeUint16(fudge);
+
+    if (!time_variables_only) {
+        buffer.writeUint16(error);
+        buffer.writeUint16(otherlen);
+    }
+
+    hmac->update(buffer.getData(), buffer.getLength());
+    if (!time_variables_only && otherlen > 0) {
+        hmac->update(otherdata, otherlen);
+    }
+}
+
+// In digestDNSMessage, we exploit some minimum knowledge of DNS message
+// format:
+// - the header section has a fixed length of 12 octets (MESSAGE_HEADER_LEN)
+// - the offset in the header section to the ID field is 0
+// - the offset in the header section to the ARCOUNT field is 10 (and the field
+//   length is 2 octets)
+// We could construct a separate Message object from the given data, adjust
+// fields via the Message interfaces and then render it back to a separate
+// buffer, but that would be overkilling.  The DNS message header has a
+// fixed length and necessary modifications are quite straightforward, so
+// we do the job using lower level interfaces.
+namespace {
+const size_t MESSAGE_HEADER_LEN = 12;
+}
+void
+TSIGContext::TSIGContextImpl::digestDNSMessage(HMACPtr hmac,
+                                               uint16_t qid, const void* data,
+                                               size_t data_len) const
+{
+    OutputBuffer buffer(MESSAGE_HEADER_LEN);
+    const uint8_t* msgptr = static_cast<const uint8_t*>(data);
+
+    // Install the original ID
+    buffer.writeUint16(qid);
+    msgptr += sizeof(uint16_t);
+
+    // Copy the rest of the header except the ARCOUNT field.
+    buffer.writeData(msgptr, 8);
+    msgptr += 8;
+
+    // Install the adjusted ARCOUNT (we don't care even if the value is bogus
+    // and it underflows; it would simply result in verification failure)
+    buffer.writeUint16(InputBuffer(msgptr, sizeof(uint16_t)).readUint16() - 1);
+    msgptr += 2;
+
+    // Digest the header and the rest of the DNS message
+    hmac->update(buffer.getData(), buffer.getLength());
+    hmac->update(msgptr, data_len - MESSAGE_HEADER_LEN);
+}
+
+TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
+{
+}
+
+TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
+                         const TSIGKeyRing& keyring) : impl_(NULL)
+{
+    const TSIGKeyRing::FindResult result(keyring.find(key_name,
+                                                      algorithm_name));
+    if (result.code == TSIGKeyRing::NOTFOUND) {
+        // If not key is found, create a dummy key with the specified key
+        // parameters and empty secret.  In the common scenario this will
+        // be used in subsequent response with a TSIG indicating a BADKEY
+        // error.
+        impl_ = new TSIGContextImpl(TSIGKey(key_name, algorithm_name,
+                                            NULL, 0));
+        impl_->error_ = TSIGError::BAD_KEY();
+    } else {
+        impl_ = new TSIGContextImpl(*result.key);
+    }
+}
+
+TSIGContext::~TSIGContext() {
+    delete impl_;
+}
+
+TSIGContext::State
+TSIGContext::getState() const {
+    return (impl_->state_);
+}
+
+TSIGError
+TSIGContext::getError() const {
+    return (impl_->error_);
+}
+
+ConstTSIGRecordPtr
+TSIGContext::sign(const uint16_t qid, const void* const data,
+                  const size_t data_len)
+{
+    if (impl_->state_ == VERIFIED_RESPONSE) {
+        isc_throw(TSIGContextError,
+                  "TSIG sign attempt after verifying a response");
+    }
+
+    if (data == NULL || data_len == 0) {
+        isc_throw(InvalidParameter, "TSIG sign error: empty data is given");
+    }
+
+    TSIGError error(TSIGError::NOERROR());
+    const uint64_t now = getTSIGTime();
+
+    // For responses adjust the error code.
+    if (impl_->state_ == RECEIVED_REQUEST) {
+        error = impl_->error_;
+    }
+
+    // For errors related to key or MAC, return an unsigned response as
+    // specified in Section 4.3 of RFC2845.
+    if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
+        ConstTSIGRecordPtr tsig(new TSIGRecord(
+                                    impl_->key_.getKeyName(),
+                                    any::TSIG(impl_->key_.getAlgorithmName(),
+                                              now, DEFAULT_FUDGE, 0, NULL,
+                                              qid, error.getCode(), 0, NULL)));
+        impl_->previous_digest_.clear();
+        impl_->state_ = SENT_RESPONSE;
+        return (tsig);
+    }
+
+    HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
+                     impl_->key_.getSecret(),
+                     impl_->key_.getSecretLength(),
+                     impl_->key_.getAlgorithm()),
+                 deleteHMAC);
+
+    // If the context has previous MAC (either the Request MAC or its own
+    // previous MAC), digest it.
+    if (impl_->state_ != INIT) {
+        impl_->digestPreviousMAC(hmac);
+    }
+
+    // Digest the message (without TSIG)
+    hmac->update(data, data_len);
+
+    // Digest TSIG variables.
+    // First, prepare some non constant variables.
+    const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ?
+        impl_->previous_timesigned_ : now;
+    // For BADTIME error, we include 6 bytes of other data.
+    // (6 bytes = size of time signed value)
+    const uint16_t otherlen = (error == TSIGError::BAD_TIME()) ? 6 : 0;
+    OutputBuffer otherdatabuf(otherlen);
+    if (error == TSIGError::BAD_TIME()) {
+            otherdatabuf.writeUint16(now >> 32);
+            otherdatabuf.writeUint32(now & 0xffffffff);
+    }
+    const void* const otherdata =
+        (otherlen == 0) ? NULL : otherdatabuf.getData();
+    // Then calculate the digest.  If state_ is SENT_RESPONSE we are sending
+    // a continued message in the same TCP stream so skip digesting
+    // variables except for time related variables (RFC2845 4.4).
+    impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
+                               TSIGRecord::TSIG_TTL, time_signed,
+                               DEFAULT_FUDGE, error.getCode(),
+                               otherlen, otherdata,
+                               impl_->state_ == SENT_RESPONSE);
+
+    // Get the final digest, update internal state, then finish.
+    vector<uint8_t> digest = hmac->sign();
+    assert(digest.size() <= 0xffff); // cryptolink API should have ensured it.
+    ConstTSIGRecordPtr tsig(new TSIGRecord(
+                                impl_->key_.getKeyName(),
+                                any::TSIG(impl_->key_.getAlgorithmName(),
+                                          time_signed, DEFAULT_FUDGE,
+                                          digest.size(), &digest[0],
+                                          qid, error.getCode(), otherlen,
+                                          otherdata)));
+    // Exception free from now on.
+    impl_->previous_digest_.swap(digest);
+    impl_->state_ = (impl_->state_ == INIT) ? SENT_REQUEST : SENT_RESPONSE;
+    return (tsig);
+}
+
+TSIGError
+TSIGContext::verify(const TSIGRecord* const record, const void* const data,
+                    const size_t data_len)
+{
+    if (impl_->state_ == SENT_RESPONSE) {
+        isc_throw(TSIGContextError,
+                  "TSIG verify attempt after sending a response");
+    }
+
+    // This case happens when we sent a signed request and have received an
+    // unsigned response.  According to RFC2845 Section 4.6 this case should be
+    // considered a "format error" (although the specific error code
+    // wouldn't matter much for the caller).
+    if (record == NULL) {
+        return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0));
+    }
+
+    const any::TSIG& tsig_rdata = record->getRdata();
+
+    // Reject some obviously invalid data
+    if (data_len < MESSAGE_HEADER_LEN + record->getLength()) {
+        isc_throw(InvalidParameter,
+                  "TSIG verify: data length is invalid: " << data_len);
+    }
+    if (data == NULL) {
+        isc_throw(InvalidParameter, "TSIG verify: empty data is invalid");
+    }
+
+    // Check key: whether we first verify it with a known key or we verify
+    // it using the consistent key in the context.  If the check fails we are
+    // done with BADKEY.
+    if (impl_->state_ == INIT && impl_->error_ == TSIGError::BAD_KEY()) {
+        return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
+    }
+    if (impl_->key_.getKeyName() != record->getName() ||
+        impl_->key_.getAlgorithmName() != tsig_rdata.getAlgorithm()) {
+        return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
+    }
+
+    // Check time: the current time must be in the range of
+    // [time signed - fudge, time signed + fudge].  Otherwise verification
+    // fails with BADTIME. (RFC2845 Section 4.6.2)
+    // Note: for simplicity we don't explicitly catch the case of too small
+    // current time causing underflow.  With the fact that fudge is quite
+    // small and (for now) non configurable, it shouldn't be a real concern
+    // in practice.
+    const uint64_t now = getTSIGTime();
+    if (tsig_rdata.getTimeSigned() + DEFAULT_FUDGE < now ||
+        tsig_rdata.getTimeSigned() - DEFAULT_FUDGE > now) {
+        const void* digest = NULL;
+        size_t digest_len = 0;
+        if (impl_->state_ == INIT) {
+            digest = tsig_rdata.getMAC();
+            digest_len = tsig_rdata.getMACSize();
+            impl_->previous_timesigned_ = tsig_rdata.getTimeSigned();
+        }
+        return (impl_->postVerifyUpdate(TSIGError::BAD_TIME(), digest,
+                                        digest_len));
+    }
+
+    // TODO: signature length check based on RFC4635
+    // (Right now we enforce the standard signature length in libcryptolink)
+
+    // Handling empty MAC.  While RFC2845 doesn't explicitly prohibit other
+    // cases, it can only reasonably happen in a response with BADSIG or
+    // BADKEY.  We reject other cases as if it were BADSIG to avoid unexpected
+    // acceptance of a bogus signature.  This behavior follows the BIND 9
+    // implementation.
+    if (tsig_rdata.getMACSize() == 0) {
+        TSIGError error = TSIGError(tsig_rdata.getError());
+        if (error != TSIGError::BAD_SIG() && error != TSIGError::BAD_KEY()) {
+            error = TSIGError::BAD_SIG();
+        }
+        return (impl_->postVerifyUpdate(error, NULL, 0));
+    }
+
+    HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
+                     impl_->key_.getSecret(),
+                     impl_->key_.getSecretLength(),
+                     impl_->key_.getAlgorithm()),
+                 deleteHMAC);
+
+    // If the context has previous MAC (either the Request MAC or its own
+    // previous MAC), digest it.
+    if (impl_->state_ != INIT) {
+        impl_->digestPreviousMAC(hmac);
+    }
+
+    //
+    // Digest DNS message (excluding the trailing TSIG RR and adjusting the
+    // QID and ARCOUNT header fields)
+    //
+    impl_->digestDNSMessage(hmac, tsig_rdata.getOriginalID(),
+                            data, data_len - record->getLength());
+
+    // Digest TSIG variables.  If state_ is VERIFIED_RESPONSE, it's a
+    // continuation of the same TCP stream and skip digesting them except
+    // for time related variables (RFC2845 4.4).
+    // Note: we use the constant values for RR class and TTL specified
+    // in RFC2845, not received values (we reject other values in constructing
+    // the TSIGRecord).
+    impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
+                               TSIGRecord::TSIG_TTL,
+                               tsig_rdata.getTimeSigned(),
+                               tsig_rdata.getFudge(), tsig_rdata.getError(),
+                               tsig_rdata.getOtherLen(),
+                               tsig_rdata.getOtherData(),
+                               impl_->state_ == VERIFIED_RESPONSE);
+
+    // Verify the digest with the received signature.
+    if (hmac->verify(tsig_rdata.getMAC(), tsig_rdata.getMACSize())) {
+        return (impl_->postVerifyUpdate(TSIGError::NOERROR(),
+                                        tsig_rdata.getMAC(),
+                                        tsig_rdata.getMACSize()));
+    }
+
+    return (impl_->postVerifyUpdate(TSIGError::BAD_SIG(), NULL, 0));
+}
+
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
new file mode 100644
index 0000000..bceec25
--- /dev/null
+++ b/src/lib/dns/tsig.h
@@ -0,0 +1,394 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIG_H
+#define __TSIG_H 1
+
+#include <boost/noncopyable.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+namespace isc {
+namespace dns {
+
+/// An exception that is thrown for logic errors identified in TSIG
+/// sign/verify operations.
+///
+/// Note that this exception is not thrown for TSIG protocol errors such as
+/// verification failures.  In general, this exception indicates an internal
+/// program bug.
+class TSIGContextError : public isc::Exception {
+public:
+    TSIGContextError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// TSIG session context.
+///
+/// The \c TSIGContext class maintains a context of a signed session of
+/// DNS transactions by TSIG.  In many cases a TSIG signed session consists
+/// of a single set of request (e.g. normal query) and reply (e.g. normal
+/// response), where the request is initially signed by the client, and the
+/// reply is signed by the server using the initial signature.  As mentioned
+/// in RFC2845, a session can consist of multiple exchanges in a TCP
+/// connection.  As also mentioned in the RFC, an AXFR response often contains
+/// multiple DNS messages, which can belong to the same TSIG session.
+/// This class supports all these cases.
+///
+/// A \c TSIGContext object is generally constructed with a TSIG key to be
+/// used for the session, and keeps track of various kinds of session specific
+/// information, such as the original digest while waiting for a response or
+/// verification error information that is to be used for a subsequent
+/// response.
+///
+/// This class has two main methods, \c sign() and \c verify().
+/// The \c sign() method signs given data (which is supposed to be a complete
+/// DNS message without the TSIG itself) using the TSIG key and other
+/// related information associated with the \c TSIGContext object.
+/// The \c verify() method verifies a given DNS message that contains a TSIG
+/// RR using the key and other internal information.
+///
+/// In general, a DNS client that wants to send a signed query will construct
+/// a \c TSIGContext object with the TSIG key that the client is intending to
+/// use, and sign the query with the context.  The client will keeps the
+/// context, and verify the response with it.
+///
+/// On the other hand, a DNS server will construct a \c TSIGContext object
+/// with the information of the TSIG RR included in a query with a set of
+/// possible keys (in the form of a \c TSIGKeyRing object).  The constructor
+/// in this mode will identify the appropriate TSIG key (or internally record
+/// an error if it doesn't find a key).  The server will then verify the
+/// query with the context, and generate a signed response using the same
+/// same context.
+///
+/// When multiple messages belong to the same TSIG session, either side
+/// (signer or verifier) will keep using the same context.  It records
+/// the latest session state (such as the previous digest) so that repeated
+/// calls to \c sign() or \c verify() work correctly in terms of the TSIG
+/// protocol.
+///
+/// \b Examples
+///
+/// This is a typical client application that sends a TSIG signed query
+/// and verifies the response.
+///
+/// \code
+///    // "renderer" is of MessageRenderer to render the message.
+///    // (TSIGKey would be configured from config or command line in real app)
+///    TSIGContext ctx(TSIGKey("key.example:MSG6Ng=="));
+///    Message message(Message::RENDER);
+///    message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+///                                 RRType::A()));
+///    message.toWire(renderer, ctx);
+///
+///    // sendto, then recvfrom.  received result in (data, data_len)
+///
+///    message.clear(Message::PARSE);
+///    InputBuffer buffer(data, data_len);
+///    message.fromWire(buffer);
+///    TSIGError tsig_error = ctx.verify(message.getTSIGRecord(),
+///                                      data, data_len);
+///    if (tsig_error == TSIGError::NOERROR()) {
+///        // okay.  ctx can be continuously used if it's receiving subsequent
+///        // signed responses from a TCP stream.
+///    } else if (message.getRcode() == Rcode::NOTAUTH()) {
+///        // hard error.  give up this transaction per RFC2845 4.6.
+///    } else {
+///        // Other error: discard response keep waiting with the same ctx
+///        // for another (again, RFC2845 4.6).
+///    } \endcode
+///
+/// And this is a typical server application that authenticates a signed
+/// query and returns a response according to the result.
+///
+/// \code
+///    // Assume "message" is of type Message for query handling and
+///    // "renderer" is of MessageRenderer to render responses.
+///    Message message(Message::RENDER);
+///
+///    TSIGKeyRing keyring; // this must be configured with keys somewhere
+///
+///    // Receive a query and store it in (data, data_len)
+///    InputBuffer buffer(data, data_len);
+///    message.clear(Message::PARSE);
+///    message.fromWire(buffer);
+///
+///    const TSIGRecord* tsig = message.getTSIGRecord();
+///    if (tsig != NULL) {
+///        TSIGContext ctx(tsig->getName(), tsig->getRdata().getAlgorithm(),
+///                        keyring);
+///        ctx.verify(tsig, data, data_len);
+///
+///        // prepare response
+///        message.makeResponse();
+///        //...
+///        message.toWire(renderer, ctx);
+///
+///        // send the response data back to the client.
+///        // If this is a beginning of a signed session over a TCP and
+///        // server has more data to send to the client, this ctx
+///        // will be used to sign subsequent messages.
+///    } \endcode
+///
+/// <b>TCP Consideration</b>
+///
+/// RFC2845 describes the case where a single TSIG session is used for
+/// multiple DNS messages (Section 4.4).  This class supports signing and
+/// verifying the messages in this scenario, but does not care if the messages
+/// were delivered over a TCP connection or not.  If, for example, the
+/// same \c TSIGContext object is used to sign two independent DNS queries
+/// sent over UDP, they will be considered to belong to the same TSIG
+/// session, and, as a result, verification will be likely to fail.
+///
+/// \b Copyability
+///
+/// This class is currently non copyable based on the observation of the
+/// typical usage as described above.  But there is no strong technical
+/// reason why this class cannot be copyable.  If we see the need for it
+/// in future we may change the implementation on this point.
+///
+/// <b>Note to developers:</b>
+/// One basic design choice is to make the \c TSIGContext class is as
+/// independent from the \c Message class.  This is because the latter is
+/// much more complicated, depending on many other classes, while TSIG is
+/// a very specific part of the entire DNS protocol set.  If the \c TSIGContext
+/// class depends on \c \c Message, it will be more vulnerable to changes
+/// to other classes, and will be more difficult to test due to the
+/// direct or indirect dependencies.  The interface of \c sign() that takes
+/// opaque data (instead of, e.g., a \c Message or \c MessageRenderer object)
+/// is therefore a deliberate design decision.
+class TSIGContext : boost::noncopyable {
+public:
+    /// Internal state of context
+    ///
+    /// The constants of this enum type define a specific state of
+    /// \c TSIGContext to adjust the behavior.  The definition is public
+    /// and the state can be seen via the \c getState() method, but this is
+    /// mostly private information.  It's publicly visible mainly for testing
+    /// purposes; there is no API for the application to change the state
+    /// directly.
+    enum State {
+        INIT,                   ///< Initial state
+        SENT_REQUEST, ///< Client sent a signed request, waiting response
+        RECEIVED_REQUEST,       ///< Server received a signed request
+        SENT_RESPONSE,          ///< Server sent a signed response
+        VERIFIED_RESPONSE       ///< Client successfully verified a response
+    };
+
+    /// \name Constructors and destructor
+    ///
+    //@{
+    /// Constructor from a TSIG key.
+    ///
+    /// \exception std::bad_alloc Resource allocation for internal data fails
+    ///
+    /// \param key The TSIG key to be used for TSIG sessions with this context.
+    explicit TSIGContext(const TSIGKey& key);
+
+    /// Constructor from key parameters and key ring.
+    TSIGContext(const Name& key_name, const Name& algorithm_name,
+                const TSIGKeyRing& keyring);
+
+    /// The destructor.
+    ~TSIGContext();
+    //@}
+
+    /// Sign a DNS message.
+    ///
+    /// This method computes the TSIG MAC for the given data, which is
+    /// generally expected to be a complete, wire-format DNS message
+    /// that doesn't contain a TSIG RR, based on the TSIG key and
+    /// other context information of \c TSIGContext, and returns a
+    /// result in the form of a (pointer object pointing to)
+    /// \c TSIGRecord object.
+    ///
+    /// The caller of this method will use the returned value to render a
+    /// complete TSIG RR into the message that has been signed so that it
+    /// will become a complete TSIG-signed message.
+    ///
+    /// In general, this method is called once by a client to send a
+    /// signed request or one more times by a server to sign
+    /// response(s) to a signed request.  To avoid allowing accidental
+    /// misuse, if this method is called after a "client" validates a
+    /// response, an exception of class \c TSIGContextError will be
+    /// thrown.
+    ///
+    /// \note Normal applications are not expected to call this method
+    /// directly; they will usually use the \c Message::toWire() method
+    /// with a \c TSIGContext object being a parameter and have the
+    /// \c Message class create a complete signed message.
+    ///
+    /// This method treats the given data as opaque, even though it's generally
+    /// expected to represent a wire-format DNS message (see also the class
+    /// description), and doesn't inspect it in any way.  For example, it
+    /// doesn't check whether the data length is sane for a valid DNS message.
+    /// This is also the reason why this method takes the \c qid parameter,
+    /// which will be used as the original ID of the resulting
+    /// \c TSIGRecordx object, even though this value should be stored in the
+    /// first two octets (in wire format) of the given data.
+    ///
+    /// \note This method still checks and rejects empty data (\c NULL pointer
+    /// data or the specified data length is 0) in order to avoid catastrophic
+    /// effect such as program crash.  Empty data is not necessarily invalid
+    /// for HMAC computation, but obviously it doesn't make sense for a DNS
+    /// message.
+    ///
+    /// This method provides the strong exception guarantee; unless the method
+    /// returns (without an exception being thrown), the internal state of
+    /// the \c TSIGContext won't be modified.
+    ///
+    /// \exception TSIGContextError Context already verified a response.
+    /// \exception InvalidParameter \c data is NULL or \c data_len is 0
+    /// \exception cryptolink::LibraryError Some unexpected error in the
+    /// underlying crypto operation
+    /// \exception std::bad_alloc Temporary resource allocation failure
+    ///
+    /// \param qid The QID to be as the value of the original ID field of
+    /// the resulting TSIG record
+    /// \param data Points to the wire-format data to be signed
+    /// \param data_len The length of \c data in bytes
+    ///
+    /// \return A TSIG record for the given data along with the context.
+    ConstTSIGRecordPtr sign(const uint16_t qid, const void* const data,
+                            const size_t data_len);
+
+    /// Verify a DNS message.
+    ///
+    /// This method verifies given data along with the context and a given
+    /// TSIG in the form of a \c TSIGRecord object.  The data to be verified
+    /// is generally expected to be a complete, wire-format DNS message,
+    /// exactly as received by the host, and ending with a TSIG RR.
+    /// After verification process this method updates its internal state,
+    /// and returns the result in the form of a \c TSIGError object.
+    /// Possible return values are (see the \c TSIGError class description
+    /// for the mnemonics):
+    ///
+    /// - \c NOERROR: The data has been verified correctly.
+    /// - \c FORMERR: \c TSIGRecord is not given (see below).
+    /// - \c BAD_KEY: Appropriate key is not found or specified key doesn't
+    ///               match for the data.
+    /// - \c BAD_TIME: The current time doesn't fall in the range specified
+    ///                in the TSIG.
+    /// - \c BAD_SIG: The signature given in the TSIG doesn't match against
+    ///               the locally computed digest or is the signature is
+    ///               invalid in other way.
+    ///
+    /// If this method is called by a DNS client waiting for a signed
+    /// response and the result is not \c NOERROR, the context can be used
+    /// to try validating another signed message as described in RFC2845
+    /// Section 4.6.
+    ///
+    /// If this method is called by a DNS server that tries to authenticate
+    /// a signed request, and if the result is not \c NOERROR, the
+    /// corresponding error condition is recorded in the context so that
+    /// the server can return a response indicating what was wrong by calling
+    /// \c sign() with the updated context.
+    ///
+    /// In general, this method is called once by a server for
+    /// authenticating a signed request or one more times by a client to
+    /// validate signed response(s) to a signed request.  To avoid allowing
+    /// accidental misuse, if this method is called after a "server" signs
+    /// a response, an exception of class \c TSIGContextError will be thrown.
+    ///
+    /// The \c record parameter can be NULL; in that case this method simply
+    /// returns \c FORMERR as the case described in Section 4.6 of RFC2845,
+    /// i.e., receiving an unsigned response to a signed request.  This way
+    /// a client can transparently pass the result of
+    /// \c Message::getTSIGRecord() without checking whether it's non NULL
+    /// and take an appropriate action based on the result of this method.
+    ///
+    /// This method handles the given data mostly as opaque.  It digests
+    /// the data assuming it begins with a DNS header and ends with a TSIG
+    /// RR whose length is given by calling \c TSIGRecord::getLength() on
+    /// \c record, but otherwise it doesn't parse the data to confirm the
+    /// assumption.  It's caller's responsibility to ensure the data is
+    /// valid and consistent with \c record.  To avoid disruption, this
+    /// method performs minimal validation on the given \c data and \c record:
+    /// \c data must not be NULL; \c data_len must not be smaller than the
+    /// sum of the DNS header length (fixed, 12 octets) and the length of
+    /// the TSIG RR.  If this check fails it throws an \c InvalidParameter
+    /// exception.
+    ///
+    /// One unexpected case that is not covered by this method is that a
+    /// client receives a signed response to an unsigned request.  RFC2845 is
+    /// silent about such cases; BIND 9 explicitly identifies the case and
+    /// rejects it.  With this implementation, the client can know that the
+    /// response contains a TSIG via the result of
+    /// \c Message::getTSIGRecord() and that it is an unexpected TSIG due to
+    /// the fact that it doesn't have a corresponding \c TSIGContext.
+    /// It's up to the client implementation whether to react to such a case
+    /// explicitly (for example, it could either ignore the TSIG and accept
+    /// the response or drop it).
+    ///
+    /// This method provides the strong exception guarantee; unless the method
+    /// returns (without an exception being thrown), the internal state of
+    /// the \c TSIGContext won't be modified.
+    ///
+    /// \todo Support intermediate TCP DNS messages without TSIG (RFC2845 4.4)
+    /// \todo Signature truncation support based on RFC4635
+    ///
+    /// \exception TSIGContextError Context already signed a response.
+    /// \exception InvalidParameter \c data is NULL or \c data_len is too small.
+    ///
+    /// \param record The \c TSIGRecord to be verified with \c data
+    /// \param data Points to the wire-format data (exactly as received) to
+    /// be verified
+    /// \param data_len The length of \c data in bytes
+    /// \return The \c TSIGError that indicates verification result
+    TSIGError verify(const TSIGRecord* const record, const void* const data,
+                     const size_t data_len);
+
+    /// Return the current state of the context
+    ///
+    /// \note
+    /// The states are visible in public mainly for testing purposes.
+    /// Normal applications won't have to deal with them.
+    ///
+    /// \exception None
+    State getState() const;
+
+    /// Return the TSIG error as a result of the latest verification
+    ///
+    /// This method can be called even before verifying anything, but the
+    /// returned value is meaningless in that case.
+    ///
+    /// \exception None
+    TSIGError getError() const;
+
+    /// \name Protocol constants and defaults
+    ///
+    //@{
+    /// The recommended fudge value (in seconds) by RFC2845.
+    ///
+    /// Right now fudge is not tunable, and all TSIGs generated by this API
+    /// will have this value of fudge.
+    static const uint16_t DEFAULT_FUDGE = 300;
+    //@}
+
+private:
+    struct TSIGContextImpl;
+    TSIGContextImpl* impl_;
+};
+}
+}
+
+#endif  // __TSIG_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigerror.cc b/src/lib/dns/tsigerror.cc
new file mode 100644
index 0000000..36ef47d
--- /dev/null
+++ b/src/lib/dns/tsigerror.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <ostream>
+#include <string>
+
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+namespace isc {
+namespace dns {
+namespace {
+const char* const tsigerror_text[] = {
+    "BADSIG",
+    "BADKEY",
+    "BADTIME"
+};
+}
+
+TSIGError::TSIGError(Rcode rcode) : code_(rcode.getCode()) {
+    if (code_ > MAX_RCODE_FOR_TSIGERROR) {
+        isc_throw(OutOfRange, "Invalid RCODE for TSIG Error: " << rcode);
+    }
+}
+
+std::string
+TSIGError::toText() const {
+    if (code_ <= MAX_RCODE_FOR_TSIGERROR) {
+        return (Rcode(code_).toText());
+    } else if (code_ <= BAD_TIME_CODE) {
+        return (tsigerror_text[code_ - (MAX_RCODE_FOR_TSIGERROR + 1)]);
+    } else {
+        return (boost::lexical_cast<std::string>(code_));
+    }
+}
+
+Rcode
+TSIGError::toRcode() const {
+    if (code_ <= MAX_RCODE_FOR_TSIGERROR) {
+        return (Rcode(code_));
+    }
+    if (code_ > BAD_TIME_CODE) {
+        return (Rcode::SERVFAIL());
+    }
+    return (Rcode::NOTAUTH());
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGError& error) {
+    return (os << error.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigerror.h b/src/lib/dns/tsigerror.h
new file mode 100644
index 0000000..8efd3ae
--- /dev/null
+++ b/src/lib/dns/tsigerror.h
@@ -0,0 +1,338 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIGERROR_H
+#define __TSIGERROR_H 1
+
+#include <ostream>
+#include <string>
+
+#include <dns/rcode.h>
+
+namespace isc {
+namespace dns {
+/// TSIG errors
+///
+/// The \c TSIGError class objects represent standard errors related to
+/// TSIG protocol operations as defined in related specifications, mainly
+/// in RFC2845.
+class TSIGError {
+public:
+    /// Constants for pre-defined TSIG error values.
+    ///
+    /// Code values from 0 through 15 (inclusive) are derived from those of
+    /// RCODE and are not defined here.  See the \c Rcode class.
+    ///
+    /// \note Unfortunately some systems define "BADSIG" as a macro in a public
+    /// header file.  To avoid conflict with it we add an underscore to our
+    /// definitions.
+    enum CodeValue {
+        BAD_SIG_CODE = 16, ///< 16: TSIG verification failure
+        BAD_KEY_CODE = 17, ///< 17: TSIG key is not recognized
+        BAD_TIME_CODE = 18 ///< 18: Current time and time signed are too different
+    };
+
+    /// \name Constructors
+    ///
+    /// We use the default versions of destructor, copy constructor,
+    /// and assignment operator.
+    //@{
+    /// Constructor from the code value.
+    ///
+    /// \exception None
+    ///
+    /// \param error_code The underlying 16-bit error code value of the \c TSIGError.
+    explicit TSIGError(uint16_t error_code) : code_(error_code) {}
+
+    /// Constructor from \c Rcode.
+    ///
+    /// As defined in RFC2845, error code values from 0 to 15 (inclusive) are
+    /// derived from the DNS RCODEs, which are represented via the \c Rcode
+    /// class in this library.  This constructor works as a converter from
+    /// these RCODEs to corresponding TSIGError objects.
+    ///
+    /// \exception isc::OutOfRange Given rcode is not convertible to
+    /// TSIGErrors.
+    ///
+    /// \param rcode the \c Rcode from which the TSIGError should be derived.
+    explicit TSIGError(Rcode rcode);
+    //@}
+
+    /// \brief Returns the \c TSIGCode error code value.
+    ///
+    /// \exception None
+    ///
+    /// \return The underlying code value corresponding to the \c TSIGError.
+    uint16_t getCode() const { return (code_); }
+
+    /// \brief Return true iff two \c TSIGError objects are equal.
+    ///
+    /// Two TSIGError objects are equal iff their error codes are equal.
+    ///
+    /// \exception None
+    ///
+    /// \param other the \c TSIGError object to compare against.
+    /// \return true if the two TSIGError are equal; otherwise false.
+    bool equals(const TSIGError& other) const
+    { return (code_ == other.code_); }
+
+    /// \brief Same as \c equals().
+    bool operator==(const TSIGError& other) const { return (equals(other)); }
+
+    /// \brief Return true iff two \c TSIGError objects are not equal.
+    ///
+    /// \exception None
+    ///
+    /// \param other the \c TSIGError object to compare against.
+    /// \return true if the two TSIGError objects are not equal;
+    /// otherwise false.
+    bool nequals(const TSIGError& other) const
+    { return (code_ != other.code_); }
+
+    /// \brief Same as \c nequals().
+    bool operator!=(const TSIGError& other) const { return (nequals(other)); }
+
+    /// \brief Convert the \c TSIGError to a string.
+    ///
+    /// For codes derived from RCODEs up to 15, this method returns the
+    /// same string as \c Rcode::toText() for the corresponding code.
+    /// For other pre-defined code values (see TSIGError::CodeValue),
+    /// this method returns a string representation of the "mnemonic' used
+    /// for the enum and constant objects as defined in RFC2845.
+    /// For example, the string for code value 16 is "BADSIG", etc.
+    /// For other code values it returns a string representation of the decimal
+    /// number of the value, e.g. "32", "100", etc.
+    ///
+    /// \exception std::bad_alloc Resource allocation for the string fails
+    ///
+    /// \return A string representation of the \c TSIGError.
+    std::string toText() const;
+
+    /// \brief Convert the \c TSIGError to a \c Rcode
+    ///
+    /// This method returns an \c Rcode object that is corresponding to
+    /// the TSIG error.  The returned \c Rcode is expected to be used
+    /// by a verifying server to specify the RCODE of a response when
+    /// TSIG verification fails.
+    ///
+    /// Specifically, this method returns \c Rcode::NOTAUTH() for the
+    /// TSIG specific errors, BADSIG, BADKEY, BADTIME, as described in
+    /// RFC2845.  For errors derived from the standard Rcode (code 0-15),
+    /// it returns the corresponding \c Rcode.  For others, this method
+    /// returns \c Rcode::SERVFAIL() as a last resort.
+    ///
+    /// \exception None
+    Rcode toRcode() const;
+
+    /// A constant TSIG error object derived from \c Rcode::NOERROR()
+    static const TSIGError& NOERROR();
+
+    /// A constant TSIG error object derived from \c Rcode::FORMERR()
+    static const TSIGError& FORMERR();
+
+    /// A constant TSIG error object derived from \c Rcode::SERVFAIL()
+    static const TSIGError& SERVFAIL();
+
+    /// A constant TSIG error object derived from \c Rcode::NXDOMAIN()
+    static const TSIGError& NXDOMAIN();
+
+    /// A constant TSIG error object derived from \c Rcode::NOTIMP()
+    static const TSIGError& NOTIMP();
+
+    /// A constant TSIG error object derived from \c Rcode::REFUSED()
+    static const TSIGError& REFUSED();
+
+    /// A constant TSIG error object derived from \c Rcode::YXDOMAIN()
+    static const TSIGError& YXDOMAIN();
+
+    /// A constant TSIG error object derived from \c Rcode::YXRRSET()
+    static const TSIGError& YXRRSET();
+
+    /// A constant TSIG error object derived from \c Rcode::NXRRSET()
+    static const TSIGError& NXRRSET();
+
+    /// A constant TSIG error object derived from \c Rcode::NOTAUTH()
+    static const TSIGError& NOTAUTH();
+
+    /// A constant TSIG error object derived from \c Rcode::NOTZONE()
+    static const TSIGError& NOTZONE();
+
+    /// A constant TSIG error object derived from \c Rcode::RESERVED11()
+    static const TSIGError& RESERVED11();
+
+    /// A constant TSIG error object derived from \c Rcode::RESERVED12()
+    static const TSIGError& RESERVED12();
+
+    /// A constant TSIG error object derived from \c Rcode::RESERVED13()
+    static const TSIGError& RESERVED13();
+
+    /// A constant TSIG error object derived from \c Rcode::RESERVED14()
+    static const TSIGError& RESERVED14();
+
+    /// A constant TSIG error object derived from \c Rcode::RESERVED15()
+    static const TSIGError& RESERVED15();
+
+    /// A constant TSIG error object for the BADSIG code
+    /// (see \c TSIGError::BAD_SIG_CODE).
+    static const TSIGError& BAD_SIG();
+
+    /// A constant TSIG error object for the BADKEY code
+    /// (see \c TSIGError::BAD_KEY_CODE).
+    static const TSIGError& BAD_KEY();
+
+    /// A constant TSIG error object for the BADTIME code
+    /// (see \c TSIGError::BAD_TIME_CODE).
+    static const TSIGError& BAD_TIME();
+
+private:
+    // This is internally used to specify the maximum possible RCODE value
+    // that can be convertible to TSIGErrors.
+    static const int MAX_RCODE_FOR_TSIGERROR = 15;
+
+    uint16_t code_;
+};
+
+inline const TSIGError&
+TSIGError::NOERROR() {
+    static TSIGError e(Rcode::NOERROR());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::FORMERR() {
+    static TSIGError e(Rcode::FORMERR());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::SERVFAIL() {
+    static TSIGError e(Rcode::SERVFAIL());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXDOMAIN() {
+    static TSIGError e(Rcode::NXDOMAIN());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTIMP() {
+    static TSIGError e(Rcode::NOTIMP());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::REFUSED() {
+    static TSIGError e(Rcode::REFUSED());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXDOMAIN() {
+    static TSIGError e(Rcode::YXDOMAIN());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXRRSET() {
+    static TSIGError e(Rcode::YXRRSET());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXRRSET() {
+    static TSIGError e(Rcode::NXRRSET());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTAUTH() {
+    static TSIGError e(Rcode::NOTAUTH());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTZONE() {
+    static TSIGError e(Rcode::NOTZONE());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED11() {
+    static TSIGError e(Rcode::RESERVED11());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED12() {
+    static TSIGError e(Rcode::RESERVED12());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED13() {
+    static TSIGError e(Rcode::RESERVED13());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED14() {
+    static TSIGError e(Rcode::RESERVED14());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED15() {
+    static TSIGError e(Rcode::RESERVED15());
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_SIG() {
+    static TSIGError e(BAD_SIG_CODE);
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_KEY() {
+    static TSIGError e(BAD_KEY_CODE);
+    return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_TIME() {
+    static TSIGError e(BAD_TIME_CODE);
+    return (e);
+}
+
+/// Insert the \c TSIGError as a string into stream.
+///
+/// This method convert \c tsig_error into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param tsig_error An \c TSIGError object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGError& tsig_error);
+}
+}
+
+#endif  // __TSIGERROR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc
index 057191d..d7d60eb 100644
--- a/src/lib/dns/tsigkey.cc
+++ b/src/lib/dns/tsigkey.cc
@@ -15,50 +15,134 @@
 #include <map>
 #include <utility>
 #include <vector>
+#include <sstream>
 
 #include <exceptions/exceptions.h>
 
+#include <cryptolink/cryptolink.h>
+
 #include <dns/name.h>
+#include <util/encode/base64.h>
 #include <dns/tsigkey.h>
 
 using namespace std;
+using namespace isc::cryptolink;
 
 namespace isc {
 namespace dns {
+namespace {
+    HashAlgorithm
+    convertAlgorithmName(const isc::dns::Name& name) {
+        if (name == TSIGKey::HMACMD5_NAME()) {
+            return (isc::cryptolink::MD5);
+        }
+        if (name == TSIGKey::HMACSHA1_NAME()) {
+            return (isc::cryptolink::SHA1);
+        }
+        if (name == TSIGKey::HMACSHA256_NAME()) {
+            return (isc::cryptolink::SHA256);
+        }
+        if (name == TSIGKey::HMACSHA224_NAME()) {
+            return (isc::cryptolink::SHA224);
+        }
+        if (name == TSIGKey::HMACSHA384_NAME()) {
+            return (isc::cryptolink::SHA384);
+        }
+        if (name == TSIGKey::HMACSHA512_NAME()) {
+            return (isc::cryptolink::SHA512);
+        }
+ 
+        return (isc::cryptolink::UNKNOWN_HASH);
+    }
+}
+
 struct
 TSIGKey::TSIGKeyImpl {
     TSIGKeyImpl(const Name& key_name, const Name& algorithm_name,
+                isc::cryptolink::HashAlgorithm algorithm,
                 const void* secret, size_t secret_len) :
         key_name_(key_name), algorithm_name_(algorithm_name),
+        algorithm_(algorithm),
         secret_(static_cast<const uint8_t*>(secret),
                 static_cast<const uint8_t*>(secret) + secret_len)
     {
-        // Convert the name to the canonical form.
+        // Convert the key and algorithm names to the canonical form.
+        key_name_.downcase();
         algorithm_name_.downcase();
     }
-    const Name key_name_;
+    Name key_name_;
     Name algorithm_name_;
+    const isc::cryptolink::HashAlgorithm algorithm_;
     const vector<uint8_t> secret_;
 };
 
 TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
                  const void* secret, size_t secret_len) : impl_(NULL)
 {
-    if (algorithm_name != HMACMD5_NAME() &&
-        algorithm_name != HMACSHA1_NAME() &&
-        algorithm_name != HMACSHA256_NAME()) {
-        isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
-                  algorithm_name);
-    }
+    const HashAlgorithm algorithm = convertAlgorithmName(algorithm_name);
     if ((secret != NULL && secret_len == 0) ||
         (secret == NULL && secret_len != 0)) {
         isc_throw(InvalidParameter,
-                  "TSIGKey secret and its length are inconsistent");
+                  "TSIGKey secret and its length are inconsistent: " <<
+                  key_name << ":" << algorithm_name);
     }
+    if (algorithm == isc::cryptolink::UNKNOWN_HASH && secret_len != 0) {
+        isc_throw(InvalidParameter,
+                  "TSIGKey with unknown algorithm has non empty secret: " <<
+                  key_name << ":" << algorithm_name);
+    }
+    impl_ = new TSIGKeyImpl(key_name, algorithm_name, algorithm, secret,
+                            secret_len);
+}
+
+TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
+    try {
+        istringstream iss(str);
 
-    impl_ = new TSIGKeyImpl(key_name, algorithm_name, secret, secret_len);
+        string keyname_str;
+        getline(iss, keyname_str, ':');
+        if (iss.fail() || iss.bad() || iss.eof()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+        }
+
+        string secret_str;
+        getline(iss, secret_str, ':');
+        if (iss.fail() || iss.bad()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+        }
+
+        string algo_str;
+        if (!iss.eof()) {
+            getline(iss, algo_str);
+        }
+        if (iss.fail() || iss.bad()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+        }
+
+        const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
+                             algo_str);
+        const HashAlgorithm algorithm = convertAlgorithmName(algo_name);
+
+        vector<uint8_t> secret;
+        isc::util::encode::decodeBase64(secret_str, secret);
+
+        if (algorithm == isc::cryptolink::UNKNOWN_HASH && !secret.empty()) {
+            isc_throw(InvalidParameter,
+                      "TSIG key with unknown algorithm has non empty secret: "
+                      << str);
+        }
+
+        impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm,
+                                secret.empty() ? NULL : &secret[0],
+                                secret.size());
+    } catch (const Exception& e) {
+        // 'reduce' the several types of exceptions name parsing and
+        // Base64 decoding can throw to just the InvalidParameter
+        isc_throw(InvalidParameter, e.what());
+    }
 }
 
+
 TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
 {}
 
@@ -89,6 +173,11 @@ TSIGKey::getAlgorithmName() const {
     return (impl_->algorithm_name_);
 }
 
+isc::cryptolink::HashAlgorithm
+TSIGKey::getAlgorithm() const {
+    return (impl_->algorithm_);
+}
+
 const void*
 TSIGKey::getSecret() const {
     return ((impl_->secret_.size() > 0) ? &impl_->secret_[0] : NULL);
@@ -99,6 +188,17 @@ TSIGKey::getSecretLength() const {
     return (impl_->secret_.size());
 }
 
+std::string
+TSIGKey::toText() const {
+    const vector<uint8_t> secret_v(static_cast<const uint8_t*>(getSecret()),
+                                   static_cast<const uint8_t*>(getSecret()) +
+                                   getSecretLength());
+    std::string secret_str = isc::util::encode::encodeBase64(secret_v);
+
+    return (getKeyName().toText() + ":" + secret_str + ":" +
+            getAlgorithmName().toText());
+}
+
 const
 Name& TSIGKey::HMACMD5_NAME() {
     static Name alg_name("hmac-md5.sig-alg.reg.int");
@@ -117,6 +217,24 @@ Name& TSIGKey::HMACSHA256_NAME() {
     return (alg_name);
 }
 
+const
+Name& TSIGKey::HMACSHA224_NAME() {
+    static Name alg_name("hmac-sha224");
+    return (alg_name);
+}
+
+const
+Name& TSIGKey::HMACSHA384_NAME() {
+    static Name alg_name("hmac-sha384");
+    return (alg_name);
+}
+
+const
+Name& TSIGKey::HMACSHA512_NAME() {
+    static Name alg_name("hmac-sha512");
+    return (alg_name);
+}
+
 struct TSIGKeyRing::TSIGKeyRingImpl {
     typedef map<Name, TSIGKey> TSIGKeyMap;
     typedef pair<Name, TSIGKey> NameAndKey;
@@ -152,10 +270,11 @@ TSIGKeyRing::remove(const Name& key_name) {
 }
 
 TSIGKeyRing::FindResult
-TSIGKeyRing::find(const Name& key_name) {
+TSIGKeyRing::find(const Name& key_name, const Name& algorithm_name) const {
     TSIGKeyRingImpl::TSIGKeyMap::const_iterator found =
         impl_->keys.find(key_name);
-    if (found == impl_->keys.end()) {
+    if (found == impl_->keys.end() ||
+        (*found).second.getAlgorithmName() != algorithm_name) {
         return (FindResult(NOTFOUND, NULL));
     }
     return (FindResult(SUCCESS, &((*found).second)));
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index e56fa88..31211d1 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -15,6 +15,8 @@
 #ifndef __TSIGKEY_H
 #define __TSIGKEY_H 1
 
+#include <cryptolink/cryptolink.h>
+
 namespace isc {
 namespace dns {
 
@@ -66,12 +68,30 @@ public:
     //@{
     /// \brief Constructor from key parameters
     ///
-    /// In the current implementation, \c algorithm_name must be a known
-    /// algorithm to this implementation, which are defined via the
-    /// <code>static const</code> member functions.  For other names
-    /// an exception of class \c InvalidParameter will be thrown.
-    /// Note: This restriction may be too strict, and we may revisit it
-    /// later.
+    /// \c algorithm_name should generally be a known algorithm to this
+    /// implementation, which are defined via the
+    /// <code>static const</code> member functions.
+    ///
+    /// Other names are still accepted as long as the secret is empty
+    /// (\c secret is \c NULL and \c secret_len is 0), however; in some cases
+    /// we might want to treat just the pair of key name and algorithm name
+    /// opaquely, e.g., when generating a response TSIG with a BADKEY error
+    /// because the algorithm is unknown as specified in Section 3.2 of
+    /// RFC2845 (in which case the algorithm name would be copied from the
+    /// request to the response, and for that purpose it would be convenient
+    /// if a \c TSIGKey object can hold a name for an "unknown" algorithm).
+    ///
+    /// \note RFC2845 does not specify which algorithm name should be used
+    /// in such a BADKEY response.  The behavior of using the same algorithm
+    /// is derived from the BIND 9 implementation.
+    ///
+    /// It is unlikely that a TSIG key with an unknown algorithm is of any
+    /// use with actual crypto operation, so care must be taken when dealing
+    /// with such keys. (The restriction for the secret will prevent
+    /// accidental creation of such a dangerous key, e.g., due to misspelling
+    /// in a configuration file).
+    /// If the given algorithm name is unknown and non empty secret is
+    /// specified, an exception of type \c InvalidParameter will be thrown.
     ///
     /// \c secret and \c secret_len must be consistent in that the latter
     /// is 0 if and only if the former is \c NULL;
@@ -90,6 +110,28 @@ public:
     TSIGKey(const Name& key_name, const Name& algorithm_name,
             const void* secret, size_t secret_len);
 
+    /// \brief Constructor from an input string
+    ///
+    /// The string must be of the form:
+    /// <name>:<secret>[:<algorithm>]
+    /// Where <name> is a domain name for the key, <secret> is a
+    /// base64 representation of the key secret, and the optional
+    /// algorithm is an algorithm identifier as specified in RFC4635.
+    /// The default algorithm is hmac-md5.sig-alg.reg.int.
+    ///
+    /// The same restriction about the algorithm name (and secret) as that
+    /// for the other constructor applies.
+    ///
+    /// Since ':' is used as a separator here, it is not possible to
+    /// use this constructor to create keys with a ':' character in
+    /// their name.
+    ///
+    /// \exception InvalidParameter exception if the input string is
+    /// invalid.
+    ///
+    /// \param str The string to make a TSIGKey from
+    explicit TSIGKey(const std::string& str);
+
     /// \brief The copy constructor.
     ///
     /// It internally allocates a resource, and if it fails a corresponding
@@ -123,6 +165,9 @@ public:
     /// Return the algorithm name.
     const Name& getAlgorithmName() const;
 
+    /// Return the hash algorithm name in the form of cryptolink::HashAlgorithm
+    isc::cryptolink::HashAlgorithm getAlgorithm() const;
+
     /// Return the length of the TSIG secret in bytes.
     size_t getSecretLength() const;
 
@@ -139,6 +184,18 @@ public:
     const void* getSecret() const;
     //@}
 
+    /// \brief Converts the TSIGKey to a string value
+    ///
+    /// The resulting string will be of the form
+    /// name:secret:algorithm
+    /// Where <name> is a domain name for the key, <secret> is a
+    /// base64 representation of the key secret, and algorithm is
+    /// an algorithm identifier as specified in RFC4635
+    ///
+    /// \param key the TSIG key to convert
+    /// \return The string representation of the given TSIGKey.
+    std::string toText() const;
+
     ///
     /// \name Well known algorithm names as defined in RFC2845 and RFC4635.
     ///
@@ -149,6 +206,9 @@ public:
     static const Name& HMACMD5_NAME();    ///< HMAC-MD5 (RFC2845)
     static const Name& HMACSHA1_NAME();   ///< HMAC-SHA1 (RFC4635)
     static const Name& HMACSHA256_NAME(); ///< HMAC-SHA256 (RFC4635)
+    static const Name& HMACSHA224_NAME(); ///< HMAC-SHA256 (RFC4635)
+    static const Name& HMACSHA384_NAME(); ///< HMAC-SHA256 (RFC4635)
+    static const Name& HMACSHA512_NAME(); ///< HMAC-SHA256 (RFC4635)
     //@}
 
 private:
@@ -268,7 +328,9 @@ public:
     /// Find a \c TSIGKey for the given name in the \c TSIGKeyRing.
     ///
     /// It searches the internal storage for a \c TSIGKey whose name is
-    /// \c key_name, and returns the result in the form of a \c FindResult
+    /// \c key_name and that uses the hash algorithm identified by
+    /// \c algorithm_name.
+    /// It returns the result in the form of a \c FindResult
     /// object as follows:
     /// - \c code: \c SUCCESS if a key is found; otherwise \c NOTFOUND.
     /// - \c key: A pointer to the found \c TSIGKey object if one is found;
@@ -282,8 +344,9 @@ public:
     /// This method never throws an exception.
     ///
     /// \param key_name The name of the key to be found.
+    /// \param algorithm_name The name of the algorithm of the found key.
     /// \return A \c FindResult object enclosing the search result (see above).
-    FindResult find(const Name& key_name);
+    FindResult find(const Name& key_name, const Name& algorithm_name) const;
 private:
     struct TSIGKeyRingImpl;
     TSIGKeyRingImpl* impl_;
diff --git a/src/lib/dns/tsigrecord.cc b/src/lib/dns/tsigrecord.cc
new file mode 100644
index 0000000..9dd3f78
--- /dev/null
+++ b/src/lib/dns/tsigrecord.cc
@@ -0,0 +1,147 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <ostream>
+#include <string>
+
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/tsigrecord.h>
+
+using namespace isc::util;
+using namespace isc::dns::rdata;
+
+namespace {
+// Internally used constants:
+
+// Size in octets for the RR type, class TTL, RDLEN fields.
+const size_t RR_COMMON_LEN = 10;
+
+// Size in octets for the fixed part of TSIG RDATAs.
+// - Time Signed (6)
+// - Fudge (2)
+// - MAC Size (2)
+// - Original ID (2)
+// - Error (2)
+// - Other Len (2)
+const size_t RDATA_COMMON_LEN = 16;
+}
+
+namespace isc {
+namespace dns {
+TSIGRecord::TSIGRecord(const Name& key_name,
+                       const rdata::any::TSIG& tsig_rdata) :
+    key_name_(key_name), rdata_(tsig_rdata),
+    length_(RR_COMMON_LEN + RDATA_COMMON_LEN + key_name_.getLength() +
+            rdata_.getAlgorithm().getLength() +
+            rdata_.getMACSize() + rdata_.getOtherLen())
+{}
+
+namespace {
+// This is a straightforward wrapper of dynamic_cast<const any::TSIG&>.
+// We use this so that we can throw the DNSMessageFORMERR exception when
+// unexpected type of RDATA is detected in the member initialization list
+// of the constructor below.
+const any::TSIG&
+castToTSIGRdata(const rdata::Rdata& rdata) {
+    try {
+        return (dynamic_cast<const any::TSIG&>(rdata));
+    } catch (std::bad_cast&) {
+        isc_throw(DNSMessageFORMERR,
+                  "TSIG record is being constructed from "
+                  "incompatible RDATA:" << rdata.toText());
+    }
+}
+}
+
+TSIGRecord::TSIGRecord(const Name& name, const RRClass& rrclass,
+                       const RRTTL& ttl, const rdata::Rdata& rdata,
+                       size_t length) :
+    key_name_(name), rdata_(castToTSIGRdata(rdata)), length_(length)
+{
+    if (rrclass != getClass()) {
+        isc_throw(DNSMessageFORMERR, "Unexpected TSIG RR class: " << rrclass);
+    }
+    if (ttl != RRTTL(TSIG_TTL)) {
+        isc_throw(DNSMessageFORMERR, "Unexpected TSIG TTL: " << ttl);
+    }
+}
+
+const RRClass&
+TSIGRecord::getClass() {
+    return (RRClass::ANY());
+}
+
+const RRTTL&
+TSIGRecord::getTTL() {
+    static RRTTL ttl(TSIG_TTL);
+    return (ttl);
+}
+
+namespace {
+template <typename OUTPUT>
+void
+toWireCommon(OUTPUT& output, const rdata::any::TSIG& rdata) {
+    // RR type, class, TTL are fixed constants.
+    RRType::TSIG().toWire(output);
+    TSIGRecord::getClass().toWire(output);
+    output.writeUint32(TSIGRecord::TSIG_TTL);
+
+    // RDLEN
+    output.writeUint16(RDATA_COMMON_LEN + rdata.getAlgorithm().getLength() +
+                       rdata.getMACSize() + rdata.getOtherLen());
+
+    // TSIG RDATA
+    rdata.toWire(output);
+}
+}
+
+int
+TSIGRecord::toWire(AbstractMessageRenderer& renderer) const {
+    // If adding the TSIG would exceed the size limit, don't do it.
+    if (renderer.getLength() + length_ > renderer.getLengthLimit()) {
+        renderer.setTruncated();
+        return (0);
+    }
+
+    // key name = owner.  note that we disable compression.
+    renderer.writeName(key_name_, false);
+    toWireCommon(renderer, rdata_);
+    return (1);
+}
+
+int
+TSIGRecord::toWire(OutputBuffer& buffer) const {
+    key_name_.toWire(buffer);
+    toWireCommon(buffer, rdata_);
+    return (1);
+}
+
+std::string
+TSIGRecord::toText() const {
+    return (key_name_.toText() + " " + RRTTL(TSIG_TTL).toText() + " " +
+            getClass().toText() + " " + RRType::TSIG().toText() + " " +
+            rdata_.toText() + "\n");
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGRecord& record) {
+    return (os << record.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigrecord.h b/src/lib/dns/tsigrecord.h
new file mode 100644
index 0000000..03de746
--- /dev/null
+++ b/src/lib/dns/tsigrecord.h
@@ -0,0 +1,308 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIGRECORD_H
+#define __TSIGRECORD_H 1
+
+#include <ostream>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/rdataclass.h>
+
+namespace isc {
+namespace util {
+class OutputBuffer;
+}
+namespace dns {
+class AbstractMessageRenderer;
+
+/// TSIG resource record.
+///
+/// A \c TSIGRecord class object represents a TSIG resource record and is
+/// responsible for conversion to and from wire format TSIG record based on
+/// the protocol specification (RFC2845).
+/// This class is provided so that other classes and applications can handle
+/// TSIG without knowing protocol details of TSIG, such as that it uses a
+/// fixed constant of TTL.
+///
+/// \todo So the plan is to eventually provide  the "from wire" constructor.
+/// It's not yet provided in the current phase of development.
+///
+/// \note
+/// This class could be a derived class of \c AbstractRRset.  That way
+/// it would be able to be used in a polymorphic way; for example,
+/// an application can construct a TSIG RR by itself and insert it to a
+/// \c Message object as a generic RRset.  On the other hand, it would mean
+/// this class would have to implement an \c RdataIterator (even though it
+/// can be done via straightforward forwarding) while the iterator is mostly
+/// redundant since there should be one and only one RDATA for a valid TSIG
+/// RR.  Likewise, some methods such as \c setTTL() method wouldn't be well
+/// defined due to such special rules for TSIG as using a fixed TTL.
+/// Overall, TSIG is a very special RR type that simply uses the compatible
+/// resource record format, and it will be unlikely that a user wants to
+/// handle it through a generic interface in a polymorphic way.
+/// We therefore chose to define it as a separate class.  This is also
+/// similar to why \c EDNS is a separate class.
+class TSIGRecord {
+public:
+    ///
+    /// \name Constructors
+    ///
+    /// We use the default copy constructor, default copy assignment operator,
+    /// (and default destructor) intentionally.
+    //@{
+    /// Constructor from TSIG key name and RDATA
+    ///
+    /// \exception std::bad_alloc Resource allocation for copying the name or
+    /// RDATA fails
+    TSIGRecord(const Name& key_name, const rdata::any::TSIG& tsig_rdata);
+
+    /// Constructor from resource record (RR) parameters.
+    ///
+    /// This constructor is intended to be used in the context of parsing
+    /// an incoming DNS message that contains a TSIG.  The parser would
+    /// first extract the owner name, RR type (which is TSIG) class, TTL and
+    /// the TSIG RDATA from the message.  This constructor is expected to
+    /// be given these RR parameters (except the RR type, because it must be
+    /// TSIG).
+    ///
+    /// According to RFC2845, a TSIG RR uses fixed RR class (ANY) and TTL (0).
+    /// If the RR class or TTL is different from the expected one, this
+    /// implementation considers it an invalid record and throws an exception
+    /// of class \c DNSMessageFORMERR.
+    ///
+    /// \note This behavior is not specified in the protocol specification,
+    /// but this implementation rejects unexpected values for the following
+    /// reasons (but in any case, this won't matter much in practice as
+    /// RFC2848 clearly states these fields always have the fixed values and
+    /// any sane implementation of TSIG signer will follow that):
+    /// According to the RFC editor (in a private communication), the intended
+    /// use of the TSIG TTL field is to signal protocol extensions (currently
+    /// no such extension is defined), so this field may actually be
+    /// validly non 0 in future.  However, until the implementation supports
+    /// that extension it may not always be able to handle the extended
+    /// TSIG as intended; the extension may even affect digest computation.
+    /// There's a related issue on this point.  Different implementations
+    /// interpret the RFC in different ways on the received TTL when
+    /// digesting the message: BIND 9 uses the received value (even if
+    /// it's not 0) as part of the TSIG variables; NLnet Labs' LDNS and NSD
+    /// always use a fixed constant of 0 regardless of the received TTL value.
+    /// This means if and when an extension with non 0 TTL is introduced
+    /// there will be interoperability problems in the form of verification
+    /// failure.  By explicitly rejecting it (and subsequently returning
+    /// a response with a format error) we can indicate the source of the
+    /// problem more clearly than a "bad signature" TSIG error, which can
+    /// happen for various reasons.  On the other hand, rejecting unexpected
+    /// RR classes is mostly for consistency; the RFC lists these two fields
+    /// in the same way, so it makes more sense to handle them equally.
+    /// (BIND 9 rejects unexpected RR classes for TSIG, but that is part of
+    /// general check on RR classes on received RRs; it generally requests
+    /// all classes are the same, and if the protocol specifies the use of
+    /// a particular class for a particular type of RR, it requests that
+    /// class be used).
+    ///
+    /// Likewise, if \c rdata is not of type \c any::TSIG, an exception of
+    /// class DNSMessageFORMERR will be thrown.  When the caller is a
+    /// DNS message parser and builds \c rdata from incoming wire format
+    /// data as described above, this case happens when the RR class is
+    /// different from ANY (in the implementation, the type check takes place
+    /// before the explicit check against the RR class explained in the
+    /// previous paragraph).
+    ///
+    /// The \c length parameter is intended to be the length of the TSIG RR
+    /// (from the beginning of the owner name to the end of the RDATA) when
+    /// the caller is a DNS message parser.  Note that it is the actual length
+    /// for the RR in the format; if the owner name or the algorithm name
+    /// (in the RDATA) is compressed (although the latter should not be
+    /// compressed according to RFC3597), the length must be the size of the
+    /// compressed data.  The length is recorded inside the class and will
+    /// be returned via subsequent calls to \c getLength().  It's intended to
+    /// be used in the context TSIG verification; in the verify process
+    /// the MAC computation must be performed for the original data without
+    /// TSIG, so, to avoid parsing the entire data in the verify process
+    /// again, it's necessary to record information that can identify the
+    /// length to be digested for the MAC.  This parameter serves for that
+    /// purpose.
+    ///
+    /// \note Since the constructor doesn't take the wire format data per se,
+    /// it doesn't (and cannot) check the validity of \c length, and simply
+    /// accepts any given value.  It even accepts obviously invalid values
+    /// such as 0.  It's caller's responsibility to provide a valid value of
+    /// length, and, the verifier's responsibility to use the length safely.
+    ///
+    /// <b>DISCUSSION:</b> this design is fragile in that it introduces
+    /// a tight coupling between message parsing and TSIG verification via
+    /// the \c TSIGRecord class.  In terms of responsibility decoupling,
+    /// the ideal way to have \c TSIGRecord remember the entire wire data
+    /// along with the length of the TSIG.  Then in the TSIG verification
+    /// we could refer to the necessary potion of data solely from a
+    /// \c TSIGRecord object.  However, this approach would require expensive
+    /// heavy copy of the original data or introduce another kind of coupling
+    /// between the data holder and this class (if the original data is freed
+    /// while a \c TSIGRecord object referencing the data still exists, the
+    /// result will be catastrophic).  As a "best current compromise", we
+    /// use the current design.  We may reconsider it if it turns out to
+    /// cause a big problem or we come up with a better idea.
+    ///
+    /// \exception DNSMessageFORMERR Given RR parameters are invalid for TSIG.
+    /// \exception std::bad_alloc Internal resource allocation fails.
+    ///
+    /// \param name The owner name of the TSIG RR
+    /// \param rrclass The RR class of the RR.  Must be \c RRClass::ANY()
+    /// (see above)
+    /// \param ttl The TTL of the RR.  Must be 0 (see above)
+    /// \param rdata The RDATA of the RR.  Must be of type \c any::TSIG.
+    /// \param length The size of the RR (see above)
+    TSIGRecord(const Name& name, const RRClass& rrclass, const RRTTL& ttl,
+               const rdata::Rdata& rdata, size_t length);
+    //@}
+
+    /// Return the owner name of the TSIG RR, which is the TSIG key name
+    ///
+    /// \exception None
+    const Name& getName() const { return (key_name_); }
+
+    /// Return the RDATA of the TSIG RR
+    ///
+    /// \exception None
+    const rdata::any::TSIG& getRdata() const { return (rdata_); }
+
+    /// \name Protocol constants and defaults
+    ///
+    //@{
+    /// Return the RR class of TSIG
+    ///
+    /// TSIG always uses the ANY RR class.  This static method returns it,
+    /// when, though unlikely, an application wants to know which class TSIG
+    /// is supposed to use.
+    ///
+    /// \exception None
+    static const RRClass& getClass();
+
+    /// Return the TTL value of TSIG
+    ///
+    /// TSIG always uses 0 TTL.  This static method returns it,
+    /// when, though unlikely, an application wants to know the TTL TSIG
+    /// is supposed to use.
+    ///
+    /// \exception None
+    static const RRTTL& getTTL();
+    //@}
+
+    /// Return the length of the TSIG record
+    ///
+    /// When constructed from the key name and RDATA, it is the length of
+    /// the record when it is rendered by the \c toWire() method.
+    ///
+    /// \note When constructed "from wire", that will mean the length of
+    /// the wire format data for the TSIG RR.  The length will be necessary
+    /// to verify the message once parse is completed.
+    ///
+    /// \exception None
+    size_t getLength() const { return (length_); }
+
+    /// \brief Render the \c TSIG RR in the wire format.
+    ///
+    /// This method renders the TSIG record as a form of a DNS TSIG RR
+    /// via \c renderer, which encapsulates output buffer and other rendering
+    /// contexts.
+    ///
+    /// Normally this version of \c toWire() method tries to compress the
+    /// owner name of the RR whenever possible, but this method intentionally
+    /// skips owner name compression.  This is due to a report that some
+    /// Windows clients refuse a TSIG if its owner name is compressed
+    /// (See http://marc.info/?l=bind-workers&m=126637138430819&w=2).
+    /// Reportedly this seemed to be specific to GSS-TSIG, but this
+    /// implementation skip compression regardless of the algorithm.
+    ///
+    /// If by adding the TSIG RR the message size would exceed the limit
+    /// maintained in \c renderer, this method skips rendering the RR
+    /// and returns 0 and mark \c renderer as "truncated" (so that a
+    /// subsequent call to \c isTruncated() on \c renderer will result in
+    /// \c true); otherwise it returns 1, which is the number of RR
+    /// rendered.
+    ///
+    /// \note If the caller follows the specification of adding TSIG
+    /// as described in RFC2845, this should not happen; the caller is
+    /// generally expected to leave a sufficient room in the message for
+    /// the TSIG.  But this method checks the unexpected case nevertheless.
+    ///
+    /// \exception std::bad_alloc Internal resource allocation fails (this
+    /// should be rare).
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer and name compression information.
+    /// \return 1 if the TSIG RR fits in the message size limit; otherwise 0.
+    int toWire(AbstractMessageRenderer& renderer) const;
+
+    /// \brief Render the \c TSIG RR in the wire format.
+    ///
+    /// This method is same as \c toWire(AbstractMessageRenderer&)const
+    /// except it renders the RR in an \c OutputBuffer and therefore
+    /// does not care about message size limit.
+    /// As a consequence it always returns 1.
+    int toWire(isc::util::OutputBuffer& buffer) const;
+
+    /// Convert the TSIG record to a string.
+    ///
+    /// The output format is the same as the result of \c toText() for
+    /// other normal types of RRsets (with always using the same RR class
+    /// and TTL).  It also ends with a newline.
+    ///
+    /// \exception std::bad_alloc Internal resource allocation fails (this
+    /// should be rare).
+    ///
+    /// \return A string representation of \c TSIG record
+    std::string toText() const;
+
+    /// The TTL value to be used in TSIG RRs.
+    static const uint32_t TSIG_TTL = 0;
+    //@}
+
+private:
+    const Name key_name_;
+    const rdata::any::TSIG rdata_;
+    const size_t length_;
+};
+
+/// A pointer-like type pointing to a \c TSIGRecord object.
+typedef boost::shared_ptr<TSIGRecord> TSIGRecordPtr;
+
+/// A pointer-like type pointing to an immutable \c TSIGRecord object.
+typedef boost::shared_ptr<const TSIGRecord> ConstTSIGRecordPtr;
+
+/// Insert the \c TSIGRecord as a string into stream.
+///
+/// This method convert \c record into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param record A \c TSIGRecord object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGRecord& record);
+}
+}
+
+#endif  // __TSIGRECORD_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/util/README b/src/lib/dns/util/README
deleted file mode 100644
index 1b9d1e8..0000000
--- a/src/lib/dns/util/README
+++ /dev/null
@@ -1,31 +0,0 @@
-This "util" directory is provided for utility header files and
-implementations that are internally used in the DNS library
-(libdns++).
-
-The functionality provided in these tools is generally available in
-other external or perhaps system supplied libraries.  The basic
-development policy of BIND 10 is to avoid "reinventing wheels" unless
-they belong to the exact technology area that BIND 10 targets (e.g.,
-DNS).  However, libdns++ is a very core part of BIND 10, and is also
-intended to be used as a public library, so dependency from libdns++
-to external libraries should be minimized.  The utilities in this
-directory are provided balancing two policies and as a kind of
-compromise.
-
-The header files in this directory are therefore not intended to be
-installed.  Likewise, classes and public functions defined in this
-directory are not intended to be used outside libdns++, although we
-cannot prohibit it at the language level.
-
-They are not even expected to be used in other modules of BIND 10 than
-libdns++ based on the basic policy explained above.  Other modules
-should only rely on the DNS specific interface that may internally
-rely on these utility interfaces, or should use external libraries if
-the other module really needs to use the utility feature directly.
-There seem to be some violations as of this writing, but we should
-eventually fix it.  A notable example is the SHA1 interfaces.  They
-are defined here in the context of NSEC3 processing, but, in fact,
-they are not even used from any of the other libdns++ classes or
-functions.  The SHA1 related interfaces should be moved to the
-application that needs it or the application should only access it
-through DNS specific interfaces defined in libdns++.
diff --git a/src/lib/dns/util/base16_from_binary.h b/src/lib/dns/util/base16_from_binary.h
deleted file mode 100644
index 8606c61..0000000
--- a/src/lib/dns/util/base16_from_binary.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
-#define BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
-
-// MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// base16_from_binary.h (derived from boost base64_from_binary.hpp)
-
-// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
-// Use, modification and distribution is subject to the Boost Software
-// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org for updates, documentation, and revision history.
-
-#include <cassert>
-
-#include <cstddef> // size_t
-#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
-#if defined(BOOST_NO_STDC_NAMESPACE)
-namespace std{ 
-    using ::size_t; 
-} // namespace std
-#endif
-
-// See base32hex_from_binary.h for why we need base64_from...hpp here.
-#include <boost/archive/iterators/base64_from_binary.hpp>
-
-namespace boost { 
-namespace archive {
-namespace iterators {
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// convert binary integers to base16 characters
-
-namespace detail {
-
-template<class CharType>
-struct from_4_bit {
-    typedef CharType result_type;
-    CharType operator()(CharType t) const{
-        const char * lookup_table = 
-            "0123456789"
-            "ABCDEF";
-        assert(t < 16);
-        return (lookup_table[static_cast<size_t>(t)]);
-    }
-};
-
-} // namespace detail
-
-// note: what we would like to do is
-// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-//  typedef transform_iterator<
-//      from_4_bit<CharType>,
-//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
-//  > base16_from_binary;
-// but C++ won't accept this.  Rather than using a "type generator" and
-// using a different syntax, make a derivation which should be equivalent.
-//
-// Another issue addressed here is that the transform_iterator doesn't have
-// a templated constructor.  This makes it incompatible with the dataflow
-// ideal.  This is also addressed here.
-
-//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-template<
-    class Base, 
-    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
->
-class base16_from_binary : 
-    public transform_iterator<
-        detail::from_4_bit<CharType>,
-        Base
-    >
-{
-    friend class boost::iterator_core_access;
-    typedef transform_iterator<
-        BOOST_DEDUCED_TYPENAME detail::from_4_bit<CharType>,
-        Base
-    > super_t;
-
-public:
-    // make composible buy using templated constructor
-    template<class T>
-    base16_from_binary(BOOST_PFTO_WRAPPER(T) start) :
-        super_t(
-            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
-            detail::from_4_bit<CharType>()
-        )
-    {}
-    // intel 7.1 doesn't like default copy constructor
-    base16_from_binary(const base16_from_binary & rhs) : 
-        super_t(
-            Base(rhs.base_reference()),
-            detail::from_4_bit<CharType>()
-        )
-    {}
-//    base16_from_binary(){};
-};
-
-} // namespace iterators
-} // namespace archive
-} // namespace boost
-
-#endif // BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
diff --git a/src/lib/dns/util/base32hex.h b/src/lib/dns/util/base32hex.h
deleted file mode 100644
index cba172e..0000000
--- a/src/lib/dns/util/base32hex.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __BASE32HEX_H
-#define __BASE32HEX_H 1
-
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-//
-// Note: this helper module isn't specific to the DNS protocol per se.
-// We should probably move this to somewhere else, possibly in some common
-// utility area.
-//
-
-namespace isc {
-namespace dns {
-
-/// \brief Encode binary data in the base32hex format.
-///
-/// The underlying implementation is shared with \c encodeBase64, and all
-/// description except the format (base32hex) equally applies.
-///
-/// Note: the encoding format is base32hex, not base32.
-///
-/// \param binary A vector object storing the data to be encoded. 
-/// \return A newly created string that stores base32hex encoded value for
-/// binary.
-std::string encodeBase32Hex(const std::vector<uint8_t>& binary);
-
-/// \brief Decode a text encoded in the base32hex format into the
-/// original %data.
-///
-/// The underlying implementation is shared with \c decodeBase64, and all
-/// description except the format (base32hex) equally applies.
-///
-/// Note: the encoding format is base32hex, not base32.
-///
-/// \param input A text encoded in the base32hex format.
-/// \param result A vector in which the decoded %data is to be stored.
-void decodeBase32Hex(const std::string& input, std::vector<uint8_t>& result);
-}
-}
-
-#endif  // __BASE32HEX_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/dns/util/base32hex_from_binary.h b/src/lib/dns/util/base32hex_from_binary.h
deleted file mode 100644
index 5d16d04..0000000
--- a/src/lib/dns/util/base32hex_from_binary.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
-#define BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
-
-// MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// base32hex_from_binary.h (derived from boost base64_from_binary.hpp)
-
-// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
-// Use, modification and distribution is subject to the Boost Software
-// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org for updates, documentation, and revision history.
-
-#include <cassert>
-
-#include <cstddef> // size_t
-#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
-#if defined(BOOST_NO_STDC_NAMESPACE)
-namespace std{ 
-    using ::size_t; 
-} // namespace std
-#endif
-
-// We use the same boost header files used in "base64_from_".  Since the
-// precise path to these headers may vary depending on the boost version we
-// simply include the base64 header here.
-#include <boost/archive/iterators/base64_from_binary.hpp>
-
-namespace boost { 
-namespace archive {
-namespace iterators {
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// convert binary integers to base32hex characters
-
-namespace detail {
-
-template<class CharType>
-struct from_5_bit {
-    typedef CharType result_type;
-    CharType operator()(CharType t) const{
-        const char * lookup_table = 
-            "0123456789"
-            "ABCDEFGHIJKLMNOPQRSTUV";
-        assert(t < 32);
-        return (lookup_table[static_cast<size_t>(t)]);
-    }
-};
-
-} // namespace detail
-
-// note: what we would like to do is
-// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-//  typedef transform_iterator<
-//      from_5_bit<CharType>,
-//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
-//  > base32hex_from_binary;
-// but C++ won't accept this.  Rather than using a "type generator" and
-// using a different syntax, make a derivation which should be equivalent.
-//
-// Another issue addressed here is that the transform_iterator doesn't have
-// a templated constructor.  This makes it incompatible with the dataflow
-// ideal.  This is also addressed here.
-
-//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-template<
-    class Base, 
-    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
->
-class base32hex_from_binary : 
-    public transform_iterator<
-        detail::from_5_bit<CharType>,
-        Base
-    >
-{
-    friend class boost::iterator_core_access;
-    typedef transform_iterator<
-        BOOST_DEDUCED_TYPENAME detail::from_5_bit<CharType>,
-        Base
-    > super_t;
-
-public:
-    // make composible buy using templated constructor
-    template<class T>
-    base32hex_from_binary(BOOST_PFTO_WRAPPER(T) start) :
-        super_t(
-            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
-            detail::from_5_bit<CharType>()
-        )
-    {}
-    // intel 7.1 doesn't like default copy constructor
-    base32hex_from_binary(const base32hex_from_binary & rhs) : 
-        super_t(
-            Base(rhs.base_reference()),
-            detail::from_5_bit<CharType>()
-        )
-    {}
-//    base32hex_from_binary(){};
-};
-
-} // namespace iterators
-} // namespace archive
-} // namespace boost
-
-#endif // BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
diff --git a/src/lib/dns/util/base64.h b/src/lib/dns/util/base64.h
deleted file mode 100644
index 46e10a6..0000000
--- a/src/lib/dns/util/base64.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __BASE64_H
-#define __BASE64_H 1
-
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-//
-// Note: this helper module isn't specific to the DNS protocol per se.
-// We should probably move this to somewhere else, possibly in some common
-// utility area.
-//
-
-namespace isc {
-namespace dns {
-
-/// \brief Encode binary data in the base64 format.
-///
-/// This function returns a new \c std::string object that stores a text
-/// encoded in the base64 format for the given \c binary %data.
-/// The resulting string will be a valid, canonical form of base64
-/// representation as specified in RFC4648.
-///
-/// If memory allocation for the returned string fails, a corresponding
-/// standard exception will be thrown.  This function never throws exceptions
-/// otherwise.
-///
-/// \param binary A vector object storing the data to be encoded. 
-/// \return A newly created string that stores base64 encoded value for binary.
-std::string encodeBase64(const std::vector<uint8_t>& binary);
-
-/// \brief Decode a text encoded in the base64 format into the original %data.
-///
-/// The \c input argument must be a valid string represented in the base64
-/// format as specified in RFC4648.  Space characters (spaces, tabs, newlines)
-/// can be included in \c input and will be ignored.  Without spaces, the
-/// length of string must be a multiple of 4 bytes with necessary paddings.
-/// Also it must be encoded using the canonical encoding (see RFC4648).
-/// If any of these conditions is not met, an exception of class
-/// \c isc::BadValue will be thrown.
-///
-/// If \c result doesn't have sufficient capacity to store all decoded %data
-/// and memory allocation fails, a corresponding standard exception will be
-/// thrown.  If the caller knows the necessary length (which can in theory
-/// be calculated from the input string), this situation can be avoided by
-/// reserving sufficient space for \c result beforehand.
-///
-/// Any existing %data in \c result will be removed.  This is the case in some
-/// of the cases where an exception is thrown; that is, this function only
-/// provides the basic exception guarantee.
-///
-/// \param input A text encoded in the base64 format.
-/// \param result A vector in which the decoded %data is to be stored.
-void decodeBase64(const std::string& input, std::vector<uint8_t>& result);
-}
-}
-
-#endif  // __BASE64_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/util/base_n.cc b/src/lib/dns/util/base_n.cc
deleted file mode 100644
index 9d0c777..0000000
--- a/src/lib/dns/util/base_n.cc
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <stdint.h>
-#include <cassert>
-#include <iterator>
-#include <string>
-#include <vector>
-
-#include <boost/archive/iterators/base64_from_binary.hpp>
-#include <boost/archive/iterators/binary_from_base64.hpp>
-#include <boost/archive/iterators/transform_width.hpp>
-#include <boost/math/common_factor.hpp>
-
-#include <dns/util/base32hex_from_binary.h>
-#include <dns/util/binary_from_base32hex.h>
-
-#include <dns/util/base16_from_binary.h>
-#include <dns/util/binary_from_base16.h>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/util/base32hex.h>
-#include <dns/util/base64.h>
-
-using namespace std;
-using namespace boost::archive::iterators;
-
-namespace isc {
-namespace dns {
-
-// In the following anonymous namespace, we provide a generic framework
-// to encode/decode baseN format.  We use the following tools:
-// - boost base64_from_binary/binary_from_base64: provide mapping table for
-//   base64.
-//   These classes take another iterator (Base) as a template argument, and
-//   their dereference operator (operator*()) first retrieves an input value
-//   from Base via Base::operator* and converts the value using their mapping
-//   table.  The converted value is returned as their own operator*.
-// - base{32hex,16}_from_binary/binary_from_base{32hex,16}: provide mapping
-//   table for base32hex and base16.  A straightforward variation of their
-//   base64 counterparts.
-// - EncodeNormalizer/DecodeNormalizer: supplemental filter handling baseN
-//   padding characters (=)
-// - boost transform_width: an iterator framework for handling data stream
-//   per bit-group.  It takes another iterator (Base) and output/input bit
-//   numbers (BitsOut/BitsIn) template arguments.  A transform_width object
-//   internally maintains a bit stream, which can be retrieved per BitsOut
-//   bits via its dereference operator (operator*()).  It builds the stream
-//   by internally iterating over the Base object via Base::operator++ and
-//   Base::operator*, using the least BitsIn bits of the result of
-//   Base::operator*.  In our usage BitsIn for encoding and BitsOut for
-//   decoding are always 8 (# of bits for one byte).
-//
-// Its dereference operator
-//   retrieves BitsIn bits from the result of "*Base" (if necessary it
-//   internally calls ++Base) 
-//
-// A conceptual description of how the encoding and decoding work is as
-// follows:
-// Encoding:
-//   input binary data => Normalizer (append sufficient number of 0 bits)
-//                     => transform_width (extract bit groups from the original
-//                                         stream)
-//                     => baseXX_from_binary (convert each bit group to an
-//                                            encoded byte using the mapping)
-// Decoding:
-//   input baseXX text => Normalizer (convert '='s to the encoded characters
-//                                    corresponding to 0, e.g. 'A's in base64)
-//                     => binary_from_baseXX (convert each encoded byte into
-//                                            the original group bit)
-//                     => transform_width (build original byte stream by
-//                                         concatenating the decoded bit
-//                                         stream)
-//
-// Below, we define a set of templated classes to handle different parameters
-// for different encoding algorithms.
-namespace {
-// Common constants used for all baseN encoding.
-const char BASE_PADDING_CHAR = '=';
-const uint8_t BINARY_ZERO_CODE = 0;
-  
-// EncodeNormalizer is an input iterator intended to be used as a filter
-// between the binary stream and baseXX_from_binary translator (via
-// transform_width).  An EncodeNormalizer object is configured with two
-// iterators (base and base_end), specifying the head and end of the input
-// stream.  It internally iterators over the original stream, and return
-// each byte of the stream intact via its dereference operator until it
-// reaches the end of the stream.  After that the EncodeNormalizer object
-// will return 0 no matter how many times it is subsequently incremented.
-// This is necessary because the input binary stream may not contain
-// sufficient bits for a full encoded text while baseXX_from_binary expects
-// a sufficient length of input.
-// Note: this class is intended to be used within this implementation file,
-// and assumes "base < base_end" on construction without validating the
-// arguments.  The behavior is undefined if this assumption doesn't hold.
-class EncodeNormalizer : public iterator<input_iterator_tag, uint8_t> {
-public:
-    EncodeNormalizer(const vector<uint8_t>::const_iterator& base,
-                     const vector<uint8_t>::const_iterator& base_end) :
-        base_(base), base_end_(base_end), in_pad_(false)
-    {}
-    EncodeNormalizer& operator++() {
-        if (!in_pad_) {
-            ++base_;
-        }
-        if (base_ == base_end_) {
-            in_pad_ = true;
-        }
-        return (*this);
-    }
-    const uint8_t& operator*() const {
-        if (in_pad_) {
-            return (BINARY_ZERO_CODE);
-        } else {
-            return (*base_);
-        }
-    }
-    bool operator==(const EncodeNormalizer& other) const {
-        return (base_ == other.base_);
-    }
-private:
-    vector<uint8_t>::const_iterator base_;
-    const vector<uint8_t>::const_iterator base_end_;
-    bool in_pad_;
-};
-
-// DecodeNormalizer is an input iterator intended to be used as a filter
-// between the encoded baseX stream and binary_from_baseXX.
-// A DecodeNormalizer object is configured with three string iterators
-// (base, base_beinpad, and base_beginpad), specifying the head of the string,
-// the beginning position of baseX padding (when there's padding), and
-// end of the string, respectively.  It internally iterators over the original
-// stream, and return each character of the encoded string via its dereference
-// operator until it reaches base_beginpad.  After that the DecodeNormalizer
-// will return the encoding character corresponding to the all-0 value
-// (which is specified on construction via base_zero_code.  see also
-// BaseZeroCode below).  This translation is necessary because
-// binary_from_baseXX doesn't accept the padding character (i.e. '=').
-// Note: this class is intended to be used within this implementation file,
-// and for simplicity assumes "base < base_beginpad <= base_end" on
-// construction without validating the arguments.  The behavior is undefined
-// if this assumption doesn't hold.
-class DecodeNormalizer : public iterator<input_iterator_tag, char> {
-public:
-    DecodeNormalizer(const char base_zero_code,
-                     const string::const_iterator& base,
-                     const string::const_iterator& base_beginpad,
-                     const string::const_iterator& base_end) :
-        base_zero_code_(base_zero_code),
-        base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
-        in_pad_(false)
-    {}
-    DecodeNormalizer& operator++() {
-        ++base_;
-        while (base_ != base_end_ && isspace(*base_)) {
-            ++base_;
-        }
-        if (base_ == base_beginpad_) {
-            in_pad_ = true;
-        }
-        return (*this);
-    }
-    const char& operator*() const {
-        if (in_pad_ && *base_ == BASE_PADDING_CHAR) {
-            return (base_zero_code_);
-        } else {
-            return (*base_);
-        }
-    }
-    bool operator==(const DecodeNormalizer& other) const {
-        return (base_ == other.base_);
-    }
-private:
-    const char base_zero_code_;
-    string::const_iterator base_;
-    const string::const_iterator base_beginpad_;
-    const string::const_iterator base_end_;
-    bool in_pad_;
-};
-
-// BitsPerChunk: number of bits to be converted using the baseN mapping table.
-//               e.g. 6 for base64.
-// BaseZeroCode: the byte character that represents a value of 0 in
-//               the corresponding encoding.  e.g. 'A' for base64.
-// Encoder: baseX_from_binary<transform_width<EncodeNormalizer,
-//                                            BitsPerChunk, 8> >
-// Decoder: transform_width<binary_from_baseX<DecodeNormalizer>,
-//                          8, BitsPerChunk>
-template <int BitsPerChunk, char BaseZeroCode,
-          typename Encoder, typename Decoder>
-struct BaseNTransformer {
-    static string encode(const vector<uint8_t>& binary);
-    static void decode(const char* algorithm,
-                       const string& base64, vector<uint8_t>& result);
-
-    // BITS_PER_GROUP is the number of bits for the smallest possible (non
-    // empty) bit string that can be converted to a valid baseN encoded text
-    // without padding.  It's the least common multiple of 8 and BitsPerChunk,
-    // e.g. 24 for base64.
-    static const int BITS_PER_GROUP =
-        boost::math::static_lcm<BitsPerChunk, 8>::value;
-
-    // MAX_PADDING_CHARS is the maximum number of padding characters
-    // that can appear in a valid baseN encoded text.
-    // It's group_len - chars_for_byte, where group_len is the number of
-    // encoded characters to represent BITS_PER_GROUP bits, and
-    // chars_for_byte is the number of encoded character that is needed to
-    // represent a single byte, which is ceil(8 / BitsPerChunk).
-    // For example, for base64 we need two encoded characters to represent a
-    // byte, and each group consists of 4 encoded characters, so
-    // MAX_PADDING_CHARS is 4 - 2 = 2.
-    static const int MAX_PADDING_CHARS =
-        BITS_PER_GROUP / BitsPerChunk -
-        (8 / BitsPerChunk + ((8 % BitsPerChunk) == 0 ? 0 : 1));
-}; 
-
-template <int BitsPerChunk, char BaseZeroCode,
-          typename Encoder, typename Decoder>
-string
-BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::encode(
-    const vector<uint8_t>& binary)
-{
-    // calculate the resulting length.
-    size_t bits = binary.size() * 8;
-    if (bits % BITS_PER_GROUP > 0) {
-        bits += (BITS_PER_GROUP - (bits % BITS_PER_GROUP));
-    }
-    const size_t len = bits / BitsPerChunk;
-
-    string result;
-    result.reserve(len);
-    result.assign(Encoder(EncodeNormalizer(binary.begin(), binary.end())),
-                  Encoder(EncodeNormalizer(binary.end(), binary.end())));
-    assert(len >= result.length());
-    result.append(len - result.length(), BASE_PADDING_CHAR);
-    return (result);
-}
-
-template <int BitsPerChunk, char BaseZeroCode,
-          typename Encoder, typename Decoder>
-void
-BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::decode(
-    const char* const algorithm,
-    const string& input,
-    vector<uint8_t>& result)
-{
-    // enumerate the number of trailing padding characters (=), ignoring
-    // white spaces.  since baseN_from_binary doesn't accept padding,
-    // we handle it explicitly.
-    size_t padchars = 0;
-    string::const_reverse_iterator srit = input.rbegin();
-    string::const_reverse_iterator srit_end = input.rend();
-    while (srit != srit_end) {
-        char ch = *srit;
-        if (ch == BASE_PADDING_CHAR) {
-            if (++padchars > MAX_PADDING_CHARS) {
-                isc_throw(BadValue, "Too many " << algorithm
-                          << " padding characters: " << input);
-            }
-        } else if (!isspace(ch)) {
-            break;
-        }
-        ++srit;
-    }
-    // then calculate the number of padding bits corresponding to the padding
-    // characters.  In general, the padding bits consist of all-zero
-    // trailing bits of the last encoded character followed by zero bits
-    // represented by the padding characters:
-    // 1st pad  2nd pad  3rd pad...
-    // +++===== =======  ===...    (+: from encoded chars, =: from pad chars)
-    // 0000...0 0......0 000...
-    // 0      7 8     15 16.... (bits)
-    // The number of bits for the '==...' part is padchars * BitsPerChunk.
-    // So the total number of padding bits is the smallest multiple of 8 
-    // that is >= padchars * BitsPerChunk.
-    // (Below, note the common idiom of the bitwise AND with ~7.  It clears the
-    // lowest three bits, so has the effect of rounding the result down to the
-    // nearest multiple of 8)
-    const size_t padbits = (padchars * BitsPerChunk + 7) & ~7;
-
-    // In some encoding algorithm, it could happen that a padding byte would
-    // contain a full set of encoded bits, which is not allowed by definition
-    // of padding.  For example, if BitsPerChunk is 5, the following
-    // representation could happen:
-    // ++00000= (+: from encoded chars, 0: encoded char for '0', =: pad chars)
-    // 0      7 (bits)
-    // This must actually be encoded as follows:
-    // ++======
-    // 0      7 (bits)
-    // The following check rejects this type of invalid encoding.
-    if (padbits > BitsPerChunk * (padchars + 1)) {
-        isc_throw(BadValue, "Invalid " << algorithm << "padding: " << input);
-    }
-
-    // convert the number of bits in bytes for convenience.
-    const size_t padbytes = padbits / 8;
-
-    try {
-        result.assign(Decoder(DecodeNormalizer(BaseZeroCode, input.begin(),
-                                               srit.base(), input.end())),
-                      Decoder(DecodeNormalizer(BaseZeroCode, input.end(),
-                                               input.end(), input.end())));
-    } catch (const dataflow_exception& ex) {
-        // convert any boost exceptions into our local one.
-        isc_throw(BadValue, ex.what());
-    }
-
-    // Confirm the original BaseX text is the canonical encoding of the
-    // data, that is, that the first byte of padding is indeed 0.
-    // (DecodeNormalizer and binary_from_baseXX ensure that the rest of the
-    // padding is all zero).
-    assert(result.size() >= padbytes);
-    if (padbytes > 0 && *(result.end() - padbytes) != 0) {
-            isc_throw(BadValue, "Non 0 bits included in " << algorithm
-                      << " padding: " << input);
-    }
-
-    // strip the padded zero-bit fields
-    result.resize(result.size() - padbytes);
-}
-
-//
-// Instantiation for BASE-64
-//
-typedef
-base64_from_binary<transform_width<EncodeNormalizer, 6, 8> > base64_encoder;
-typedef
-transform_width<binary_from_base64<DecodeNormalizer>, 8, 6> base64_decoder;
-typedef BaseNTransformer<6, 'A', base64_encoder, base64_decoder>
-Base64Transformer;
-
-//
-// Instantiation for BASE-32HEX
-//
-typedef
-base32hex_from_binary<transform_width<EncodeNormalizer, 5, 8> >
-base32hex_encoder;
-typedef
-transform_width<binary_from_base32hex<DecodeNormalizer>, 8, 5>
-base32hex_decoder;
-typedef BaseNTransformer<5, '0', base32hex_encoder, base32hex_decoder>
-Base32HexTransformer;
-
-//
-// Instantiation for BASE-16 (HEX)
-//
-typedef
-base16_from_binary<transform_width<EncodeNormalizer, 4, 8> > base16_encoder;
-typedef
-transform_width<binary_from_base16<DecodeNormalizer>, 8, 4> base16_decoder;
-typedef BaseNTransformer<4, '0', base16_encoder, base16_decoder>
-Base16Transformer;
-}
-
-string
-encodeBase64(const vector<uint8_t>& binary) {
-    return (Base64Transformer::encode(binary));
-}
-
-void
-decodeBase64(const string& input, vector<uint8_t>& result) {
-    Base64Transformer::decode("base64", input, result);
-}
-
-string
-encodeBase32Hex(const vector<uint8_t>& binary) {
-    return (Base32HexTransformer::encode(binary));
-}
-
-void
-decodeBase32Hex(const string& input, vector<uint8_t>& result) {
-    Base32HexTransformer::decode("base32hex", input, result);
-}
-
-string
-encodeHex(const vector<uint8_t>& binary) {
-    return (Base16Transformer::encode(binary));
-}
-
-void
-decodeHex(const string& input, vector<uint8_t>& result) {
-    Base16Transformer::decode("base16", input, result);
-}
-
-}
-}
diff --git a/src/lib/dns/util/binary_from_base16.h b/src/lib/dns/util/binary_from_base16.h
deleted file mode 100644
index 50342f1..0000000
--- a/src/lib/dns/util/binary_from_base16.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
-#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
-
-// MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// binary_from_base16.h (derived from boost binary_from_base64.hpp)
-
-// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
-// Use, modification and distribution is subject to the Boost Software
-// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org for updates, documentation, and revision history.
-
-#include <cassert>
-
-// See binary_from_base32hex.h for why we need _from_base64.hpp here.
-#include <boost/archive/iterators/binary_from_base64.hpp>
-
-#include <exceptions/exceptions.h>
-
-namespace boost { 
-namespace archive {
-namespace iterators {
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// convert base16 characters to binary data
-
-namespace detail {
-
-template<class CharType>
-struct to_4_bit {
-    typedef CharType result_type;
-    CharType operator()(CharType t) const{
-        const char lookup_table[] = {
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
-             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
-            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 40-4f
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
-            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 60-6f
-        };
-        // metrowerks trips this assertion - how come?
-        #if ! defined(__MWERKS__)
-        BOOST_STATIC_ASSERT(0x70 == sizeof(lookup_table));
-        #endif
-        signed char value = -1;
-        if((unsigned)t < sizeof(lookup_table))
-            value = lookup_table[(unsigned)t];
-        if(-1 == value) { 
-            isc_throw(isc::BadValue,
-                      "attempt to decode a value not in base16 char set");
-        }
-        return (value);
-    }
-};
-
-} // namespace detail
-
-// note: what we would like to do is
-// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-//  typedef transform_iterator<
-//      from_4_bit<CharType>,
-//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
-//  > base16_from_binary;
-// but C++ won't accept this.  Rather than using a "type generator" and
-// using a different syntax, make a derivation which should be equivalent.
-//
-// Another issue addressed here is that the transform_iterator doesn't have
-// a templated constructor.  This makes it incompatible with the dataflow
-// ideal.  This is also addressed here.
-
-template<
-    class Base, 
-    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
->
-class binary_from_base16 : public
-    transform_iterator<
-        detail::to_4_bit<CharType>,
-        Base
-    >
-{
-    friend class boost::iterator_core_access;
-    typedef transform_iterator<
-        detail::to_4_bit<CharType>,
-        Base
-    > super_t;
-public:
-    // make composible buy using templated constructor
-    template<class T>
-    binary_from_base16(BOOST_PFTO_WRAPPER(T)  start) :
-        super_t(
-            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
-            detail::to_4_bit<CharType>()
-        )
-    {}
-    // intel 7.1 doesn't like default copy constructor
-    binary_from_base16(const binary_from_base16 & rhs) : 
-        super_t(
-            Base(rhs.base_reference()),
-            detail::to_4_bit<CharType>()
-        )
-    {}
-//    binary_from_base16(){};
-};
-
-} // namespace iterators
-} // namespace archive
-} // namespace boost
-
-#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/util/binary_from_base32hex.h b/src/lib/dns/util/binary_from_base32hex.h
deleted file mode 100644
index 1d83f54..0000000
--- a/src/lib/dns/util/binary_from_base32hex.h
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
-#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
-
-// MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// binary_from_base32hex.h (derived from boost binary_from_base64.hpp)
-
-// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
-// Use, modification and distribution is subject to the Boost Software
-// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org for updates, documentation, and revision history.
-
-#include <cassert>
-
-// We use the same boost header files used in "_from_base64".  Since the
-// precise path to these headers may vary depending on the boost version we
-// simply include the base64 header here.
-#include <boost/archive/iterators/binary_from_base64.hpp>
-
-#include <exceptions/exceptions.h>
-
-namespace boost { 
-namespace archive {
-namespace iterators {
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// convert base32hex characters to binary data
-
-namespace detail {
-
-template<class CharType>
-struct to_5_bit {
-    typedef CharType result_type;
-    CharType operator()(CharType t) const{
-        const char lookup_table[] = {
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
-            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
-             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
-            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 40-4f
-            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
-            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 60-6f
-            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 70-7f
-        };
-        // metrowerks trips this assertion - how come?
-        #if ! defined(__MWERKS__)
-        BOOST_STATIC_ASSERT(0x80 == sizeof(lookup_table));
-        #endif
-        signed char value = -1;
-        if((unsigned)t < sizeof(lookup_table))
-            value = lookup_table[(unsigned)t];
-        if(-1 == value) { 
-            isc_throw(isc::BadValue,
-                      "attempt to decode a value not in base32hex char set");
-        }
-        return (value);
-    }
-};
-
-} // namespace detail
-
-// note: what we would like to do is
-// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
-//  typedef transform_iterator<
-//      from_5_bit<CharType>,
-//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
-//  > base32hex_from_binary;
-// but C++ won't accept this.  Rather than using a "type generator" and
-// using a different syntax, make a derivation which should be equivalent.
-//
-// Another issue addressed here is that the transform_iterator doesn't have
-// a templated constructor.  This makes it incompatible with the dataflow
-// ideal.  This is also addressed here.
-
-template<
-    class Base, 
-    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
->
-class binary_from_base32hex : public
-    transform_iterator<
-        detail::to_5_bit<CharType>,
-        Base
-    >
-{
-    friend class boost::iterator_core_access;
-    typedef transform_iterator<
-        detail::to_5_bit<CharType>,
-        Base
-    > super_t;
-public:
-    // make composible buy using templated constructor
-    template<class T>
-    binary_from_base32hex(BOOST_PFTO_WRAPPER(T)  start) :
-        super_t(
-            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
-            detail::to_5_bit<CharType>()
-        )
-    {}
-    // intel 7.1 doesn't like default copy constructor
-    binary_from_base32hex(const binary_from_base32hex & rhs) : 
-        super_t(
-            Base(rhs.base_reference()),
-            detail::to_5_bit<CharType>()
-        )
-    {}
-//    binary_from_base32hex(){};
-};
-
-} // namespace iterators
-} // namespace archive
-} // namespace boost
-
-#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/util/hex.h b/src/lib/dns/util/hex.h
deleted file mode 100644
index e2626bf..0000000
--- a/src/lib/dns/util/hex.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __HEX_H
-#define __HEX_H 1
-
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-//
-// Note: this helper module isn't specific to the DNS protocol per se.
-// We should probably move this to somewhere else, possibly in some common
-// utility area.
-//
-
-namespace isc {
-namespace dns {
-/// \brief Encode binary data in the base16 ('hex') format.
-///
-/// The underlying implementation is shared with \c encodeBase64, and most of
-/// the description except the format (base16) equally applies.
-/// Another notable exception is that the base16 encoding doesn't require
-/// padding, so padding related considerations and the notion of canonical
-/// encoding don't apply.
-///
-/// \param binary A vector object storing the data to be encoded. 
-/// \return A newly created string that stores base16 encoded value for
-/// binary.
-std::string encodeHex(const std::vector<uint8_t>& binary);
-
-/// \brief Decode a text encoded in the base16 ('hex') format into the
-/// original %data.
-///
-/// The underlying implementation is shared with \c decodeBase64, and most
-/// of the description except the format (base16) equally applies.
-/// Another notable exception is that the base16 encoding doesn't require
-/// padding, so padding related considerations and the notion of canonical
-/// encoding don't apply.
-///
-/// \param input A text encoded in the base16 format.
-/// \param result A vector in which the decoded %data is to be stored.
-void decodeHex(const std::string& input, std::vector<uint8_t>& result);
-}
-}
-
-#endif  // __HEX_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/util/sha1.cc b/src/lib/dns/util/sha1.cc
deleted file mode 100644
index 62e885b..0000000
--- a/src/lib/dns/util/sha1.cc
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- *  Description:
- *      This file implements the Secure Hash Signature Standard
- *      algorithms as defined in the National Institute of Standards
- *      and Technology Federal Information Processing Standards
- *      Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2
- *      published on August 1, 2002, and the FIPS PUB 180-2 Change
- *      Notice published on February 28, 2004.
- *
- *      A combined document showing all algorithms is available at
- *              http://csrc.nist.gov/publications/fips/
- *              fips180-2/fips180-2withchangenotice.pdf
- *
- *      The SHA-1 algorithm produces a 160-bit message digest for a
- *      given data stream.  It should take about 2**n steps to find a
- *      message with the same digest as a given message and
- *      2**(n/2) to find any two messages with the same digest,
- *      when n is the digest size in bits.  Therefore, this
- *      algorithm can serve as a means of providing a
- *      "fingerprint" for a message.
- *
- *  Portability Issues:
- *      SHA-1 is defined in terms of 32-bit "words".  This code
- *      uses <stdint.h> (included via "sha.h") to define 32 and 8
- *      bit unsigned integer types.  If your C compiler does not
- *      support 32 bit unsigned integers, this code is not
- *      appropriate.
- *
- *  Caveats:
- *      SHA-1 is designed to work with messages less than 2^64 bits
- *      long. This implementation uses SHA1Input() to hash the bits
- *      that are a multiple of the size of an 8-bit character, and then
- *      uses SHA1FinalBits() to hash the final few bits of the input.
- *
- *  Authorship:
- *      This file is adapted from RFC 4634, by D. Eastlake et al.
- *      Copyright (C) The Internet Society (2006).
- *
- *      Permission is granted for all uses, commercial and non-commercial,
- *      of the sample code found in Section 8.  Royalty free license to
- *      use, copy, modify and distribute the software found in Section 8 is
- *      granted, provided that this document is identified in all material
- *      mentioning or referencing this software, and provided that
- *      redistributed derivative works do not contain misleading author or
- *      version information.
- *
- *      The authors make no representations concerning either the
- *      merchantability of this software or the suitability of this
- *      software for any particular purpose.  It is provided "as is"
- *      without express or implied warranty of any kind.
- *      
- */
-#include <dns/util/sha1.h>
-
-/* Local Function Prototyptes */
-static void SHA1Finalize(SHA1Context *, uint8_t Pad_Byte);
-static void SHA1PadMessage(SHA1Context *, uint8_t Pad_Byte);
-static void SHA1ProcessMessageBlock(SHA1Context *);
-
-/*
- * Define functions used by SHA1 hash
- */
-static inline uint32_t
-SHA_Ch(const uint32_t x, const uint32_t y, const uint32_t z) {
-    return (((x) & ((y) ^ (z))) ^ (z));
-}
-
-static inline uint32_t
-SHA_Maj(const uint32_t x, const uint32_t y, const uint32_t z) {
-    return (((x) & ((y) | (z))) | ((y) & (z)));
-}
-
-static inline uint32_t
-SHA_Parity(const uint32_t x, const uint32_t y, const uint32_t z) {
-    return ((x) ^ (y) ^ (z));
-}
-
-static inline int 
-SHA1CircularShift(uint8_t bits, uint32_t word) {
-    return ((word << bits) | (word >> (32 - bits)));
-}
-
-static inline bool
-SHA1AddLength(SHA1Context *context, uint32_t length) {
-    uint32_t addTemp = context->Length_Low;
-    context->Length_Low += length;
-    if (context->Length_Low < addTemp && ++context->Length_High == 0) {
-        return (true);
-    } else {
-        return (false);
-    }
-}
-
-/*
- *  SHA1Reset
- *
- *  Description:
- *      This function will initialize the SHA1Context in preparation
- *      for computing a new SHA1 message digest.
- *
- *  Parameters:
- *      context: [in/out]
- *          The context to reset.
- *
- *  Returns:
- *      sha Error Code.
- *
- */
-int
-SHA1Reset(SHA1Context *context) {
-    if (!context) {
-        return (SHA_NULL);
-    }
-
-    context->Length_Low             = 0;
-    context->Length_High            = 0;
-    context->Message_Block_Index    = 0;
-
-    context->Intermediate_Hash[0]   = 0x67452301;
-    context->Intermediate_Hash[1]   = 0xEFCDAB89;
-    context->Intermediate_Hash[2]   = 0x98BADCFE;
-    context->Intermediate_Hash[3]   = 0x10325476;
-    context->Intermediate_Hash[4]   = 0xC3D2E1F0;
-
-    context->Computed   = 0;
-    context->Corrupted  = 0;
-    return (SHA_SUCCESS);
-}
-
-
-/*
- *  SHA1Input
- *
- *  Description:
- *      This function accepts an array of octets as the next portion
- *      of the message.
- *
- *  Parameters:
- *      context: [in/out]
- *          The SHA context to update
- *      message_array: [in]
- *          An array of characters representing the next portion of
- *          the message.
- *      length: [in]
- *          The length of the message in message_array
- *
- *  Returns:
- *      sha Error Code.
- *
- */
-int
-SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned length) {
-    if (!length) {
-        return (SHA_SUCCESS);
-    }
-
-    if (!context || !message_array) {
-        return (SHA_NULL);
-    }
-
-    if (context->Computed) {
-        context->Corrupted = SHA_STATEERROR;
-        return (SHA_STATEERROR);
-    }
-
-    if (context->Corrupted) {
-         return (context->Corrupted);
-    }
-
-    while(length-- && !context->Corrupted) {
-        context->Message_Block[context->Message_Block_Index++] =
-                                                    (*message_array & 0xFF);
-
-        if (!SHA1AddLength(context, 8) &&
-            (context->Message_Block_Index == SHA1_BLOCKSIZE))
-        {
-            SHA1ProcessMessageBlock(context);
-        }
-
-        message_array++;
-    }
-
-    return (SHA_SUCCESS);
-}
-
-/*
- * SHA1FinalBits
- *
- * Description:
- *   This function will add in any final bits of the message.
- *
- * Parameters:
- *   context: [in/out]
- *     The SHA context to update
- *   message_bits: [in]
- *     The final bits of the message, in the upper portion of the
- *     byte. (Use 0b###00000 instead of 0b00000### to input the
- *     three bits ###.)
- *   length: [in]
- *     The number of bits in message_bits, between 1 and 7.
- *
- * Returns:
- *   sha Error Code.
- */
-int SHA1FinalBits(SHA1Context *context, const uint8_t message_bits,
-                  unsigned int length)
-{
-    uint8_t masks[8] = {
-        /* 0 0b00000000 */ 0x00,
-        /* 1 0b10000000 */ 0x80,
-        /* 2 0b11000000 */ 0xC0,
-        /* 3 0b11100000 */ 0xE0,
-        /* 4 0b11110000 */ 0xF0,
-        /* 5 0b11111000 */ 0xF8,
-        /* 6 0b11111100 */ 0xFC,
-        /* 7 0b11111110 */ 0xFE
-    };
-    uint8_t markbit[8] = {
-        /* 0 0b10000000 */ 0x80,
-        /* 1 0b01000000 */ 0x40,
-        /* 2 0b00100000 */ 0x20,
-        /* 3 0b00010000 */ 0x10,
-        /* 4 0b00001000 */ 0x08,
-        /* 5 0b00000100 */ 0x04,
-        /* 6 0b00000010 */ 0x02,
-        /* 7 0b00000001 */ 0x01
-    };
-
-    if (!length) {
-        return (SHA_SUCCESS);
-    }
-
-    if (!context) {
-        return (SHA_NULL);
-    }
-
-    if (context->Computed || (length >= 8) || (length == 0)) {
-        context->Corrupted = SHA_STATEERROR;
-        return (SHA_STATEERROR);
-    }
-
-    if (context->Corrupted) {
-        return (context->Corrupted);
-    }
-
-    SHA1AddLength(context, length);
-    SHA1Finalize(context,
-                 (uint8_t) ((message_bits & masks[length]) | markbit[length]));
-
-    return (SHA_SUCCESS);
-}
-
-/*
- *  SHA1Result
- *
- *  Description:
- *      This function will return the 160-bit message digest into the
- *      Message_Digest array  provided by the caller.
- *      NOTE: The first octet of hash is stored in the 0th element,
- *            the last octet of hash in the 19th element.
- *
- *  Parameters:
- *      context: [in/out]
- *          The context to use to calculate the SHA-1 hash.
- *      Message_Digest: [out]
- *          Where the digest is returned.
- *
- *  Returns:
- *      sha Error Code.
- *
- */
-int
-SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1_HASHSIZE]) {
-    int i;
-
-    if (!context || !Message_Digest) {
-        return (SHA_NULL);
-    }
-
-    if (context->Corrupted) {
-        return (context->Corrupted);
-    }
-
-    if (!context->Computed) {
-        SHA1Finalize(context, 0x80);
-    }
-
-    for(i = 0; i < SHA1_HASHSIZE; ++i) {
-        Message_Digest[i] = context->Intermediate_Hash[i>>2]
-                            >> 8 * (3 - (i & 0x03));
-    }
-
-    return (SHA_SUCCESS);
-}
-
-/*
- * SHA1Finalize
- *
- * Description:
- *   This helper function finishes off the digest calculations.
- *
- * Parameters:
- *   context: [in/out]
- *     The SHA context to update
- *   Pad_Byte: [in]
- *     The last byte to add to the digest before the 0-padding
- *     and length. This will contain the last bits of the message
- *     followed by another single bit. If the message was an
- *     exact multiple of 8-bits long, Pad_Byte will be 0x80.
- *
- * Returns:
- *   sha Error Code.
- *
- */
-static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) {
-    int i;
-    SHA1PadMessage(context, Pad_Byte);
-    /* message may be sensitive, clear it out */
-    for (i = 0; i < SHA1_BLOCKSIZE; ++i)
-        context->Message_Block[i] = 0;
-    context->Length_Low = 0;  /* and clear length */
-    context->Length_High = 0;
-    context->Computed = 1;
-}
-
-/*
- *  SHA1PadMessage
- *
- *  Description:
- *      According to the standard, the message must be padded to an even
- *      512 bits.  The first padding bit must be a '1'.  The last 64
- *      bits represent the length of the original message.  All bits in
- *      between should be 0.  This function will pad the message
- *      according to those rules by filling the Message_Block array
- *      accordingly.  It will also call the ProcessMessageBlock function
- *      provided appropriately.  When it returns, it can be assumed that
- *      the message digest has been computed.
- *
- *  Parameters:
- *      context: [in/out]
- *          The context to pad
- *      Pad_Byte: [in]
- *          The last byte to add to the digest before the 0-padding
- *          and length. This will contain the last bits of the message
- *          followed by another single bit. If the message was an
- *          exact multiple of 8-bits long, Pad_Byte will be 0x80.
- *
- *  Returns:
- *      Nothing.
- *
- */
-static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) {
-    /*
-     * Check to see if the current message block is too small to hold
-     * the initial padding bits and length. If so, we will pad the
-     * block, process it, and then continue padding into a second
-     * block.
-     */
-    if (context->Message_Block_Index >= (SHA1_BLOCKSIZE - 8)) {
-        context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
-        while (context->Message_Block_Index < SHA1_BLOCKSIZE) {
-            context->Message_Block[context->Message_Block_Index++] = 0;
-        }
-
-        SHA1ProcessMessageBlock(context);
-    } else
-        context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
-
-    while (context->Message_Block_Index < (SHA1_BLOCKSIZE - 8))
-        context->Message_Block[context->Message_Block_Index++] = 0;
-
-    /*
-     * Store the message length as the last 8 octets
-     */
-    context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
-    context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
-    context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
-    context->Message_Block[59] = (uint8_t) (context->Length_High);
-    context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
-    context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
-    context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
-    context->Message_Block[63] = (uint8_t) (context->Length_Low);
-
-    SHA1ProcessMessageBlock(context);
-}
-
-/*
- *  SHA1ProcessMessageBlock
- *
- *  Description:
- *      This helper function will process the next 512 bits of the
- *      message stored in the Message_Block array.
- *
- *  Parameters:
- *      None.
- *
- *  Returns:
- *      Nothing.
- *
- *  Comments:
- *      Many of the variable names in this code, especially the
- *      single character names, were used because those were the
- *      names used in the publication.
- *
- *
- */
-static void
-SHA1ProcessMessageBlock(SHA1Context *context) {
-    /* Constants defined in FIPS-180-2, section 4.2.1 */
-    const uint32_t K[] = {
-        0x5A827999,
-        0x6ED9EBA1,
-        0x8F1BBCDC,
-        0xCA62C1D6
-    };
-    int           t;                 /* Loop counter                */
-    uint32_t      temp;              /* Temporary word value        */
-    uint32_t      W[80];             /* Word sequence               */
-    uint32_t      A, B, C, D, E;     /* Word buffers                */
-
-    /*
-     * Initialize the first 16 words in the array W
-     */
-    for (t = 0; t < 16; t++) {
-        W[t]  = ((uint32_t)context->Message_Block[t * 4]) << 24;
-        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16;
-        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8;
-        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]);
-    }
-
-    for (t = 16; t < 80; t++) {
-        W[t] = SHA1CircularShift(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
-    }
-
-    A = context->Intermediate_Hash[0];
-    B = context->Intermediate_Hash[1];
-    C = context->Intermediate_Hash[2];
-    D = context->Intermediate_Hash[3];
-    E = context->Intermediate_Hash[4];
-
-    for (t = 0; t < 20; t++) {
-        temp = SHA1CircularShift(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    for (t = 20; t < 40; t++) {
-        temp = SHA1CircularShift(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    for (t = 40; t < 60; t++) {
-        temp = SHA1CircularShift(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    for (t = 60; t < 80; t++) {
-        temp = SHA1CircularShift(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    context->Intermediate_Hash[0] += A;
-    context->Intermediate_Hash[1] += B;
-    context->Intermediate_Hash[2] += C;
-    context->Intermediate_Hash[3] += D;
-    context->Intermediate_Hash[4] += E;
-
-    context->Message_Block_Index = 0;
-}
diff --git a/src/lib/dns/util/sha1.h b/src/lib/dns/util/sha1.h
deleted file mode 100644
index f0f45f3..0000000
--- a/src/lib/dns/util/sha1.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  sha1.h
- *
- *  Description:
- *      This is the header file for code which implements the Secure
- *      Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
- *      April 17, 1995.
- *
- *      Many of the variable names in this code, especially the
- *      single character names, were used because those were the names
- *      used in the publication.
- *
- *      Please read the file sha1.cc for more information.
- *
- *  Authorship:
- *      This file is adapted from RFC 4634, by D. Eastlake et al.
- *      Copyright (C) The Internet Society (2006).
- *
- *      Permission is granted for all uses, commercial and non-commercial,
- *      of the sample code found in Section 8.  Royalty free license to
- *      use, copy, modify and distribute the software found in Section 8 is
- *      granted, provided that this document is identified in all material
- *      mentioning or referencing this software, and provided that
- *      redistributed derivative works do not contain misleading author or
- *      version information.
- *
- *      The authors make no representations concerning either the
- *      merchantability of this software or the suitability of this
- *      software for any particular purpose.  It is provided "as is"
- *      without express or implied warranty of any kind.
- */
-
-#ifndef _SHA1_H_
-#define _SHA1_H_
-
-#include <stdint.h>
-/*
- * If you do not have the ISO standard stdint.h header file, then you
- * must typdef the following:
- *    name              meaning
- *  uint32_t         unsigned 32 bit integer
- *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)
- *  int_least16_t    integer of >= 16 bits
- *
- */
-
-enum {
-    SHA_SUCCESS = 0,
-    SHA_NULL,            /* Null pointer parameter */
-    SHA_STATEERROR       /* called Input after Result */
-};
-
-enum {
-    SHA1_HASHSIZE = 20,
-    SHA1_HASHBITS = 20,
-    SHA1_BLOCKSIZE = 64
-};
-
-/*
- *  This structure will hold context information for the SHA-1
- *  hashing operation
- */
-typedef struct SHA1Context
-{
-    uint32_t Intermediate_Hash[SHA1_HASHSIZE/4]; /* Message Digest */
-    uint32_t Length_Low;                /* Message length in bits */
-    uint32_t Length_High;               /* Message length in bits */
-    int_least16_t Message_Block_Index;  /* Index into message block array */
-    uint8_t Message_Block[64];          /* 512-bit message blocks */
-    int Computed;                       /* Is the digest computed? */
-    int Corrupted;                      /* Is the message digest corrupted? */
-} SHA1Context;
-
-/*
- *  Function Prototypes
- */
-extern int SHA1Reset(SHA1Context *);
-extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
-                     unsigned int bytecount);
-extern int SHA1FinalBits(SHA1Context *, const uint8_t bits,
-                         unsigned int bitcount);
-extern int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1_HASHSIZE]);
-
-#endif
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index d941b01..c27b3e4 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = . compiler tests
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 
 CLEANFILES = *.gcno *.gcda
 
@@ -10,18 +11,18 @@ lib_LTLIBRARIES = liblog.la
 liblog_la_SOURCES  =
 liblog_la_SOURCES += debug_levels.h logger_levels.h
 liblog_la_SOURCES += dummylog.h dummylog.cc
-liblog_la_SOURCES += filename.h filename.cc
 liblog_la_SOURCES += logger.cc logger.h
 liblog_la_SOURCES += logger_impl.cc logger_impl.h
 liblog_la_SOURCES += logger_support.cc logger_support.h
 liblog_la_SOURCES += messagedef.cc messagedef.h
 liblog_la_SOURCES += message_dictionary.cc message_dictionary.h
-liblog_la_SOURCES += message_exception.h message_exception.cc
+liblog_la_SOURCES += message_exception.h
 liblog_la_SOURCES += message_initializer.cc message_initializer.h
 liblog_la_SOURCES += message_reader.cc message_reader.h
 liblog_la_SOURCES += message_types.h
 liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
-liblog_la_SOURCES += strutil.h strutil.cc
+liblog_la_SOURCES += log_formatter.h log_formatter.cc
+liblog_la_SOURCES += macros.h
 
 EXTRA_DIST  = README
 EXTRA_DIST += messagedef.mes
@@ -39,3 +40,4 @@ if USE_CLANGPP
 liblog_la_CXXFLAGS += -Wno-error
 endif
 liblog_la_CPPFLAGS = $(AM_CPPFLAGS)
+liblog_la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
diff --git a/src/lib/log/README b/src/lib/log/README
index ed11b5b..529eefc 100644
--- a/src/lib/log/README
+++ b/src/lib/log/README
@@ -44,7 +44,7 @@ stored definitions; this updated text is logged.  However, to aid support,
 the message identifier so in the example above, the message finally logged
 would be something like:
 
-    OPENIN, unable to open a.txt for input
+    FAC_OPENIN, unable to open a.txt for input
 
 
 Using The System
@@ -55,17 +55,15 @@ The steps in using the system are:
    mnemonic for the message, typically 6-12 characters long - and a message.
    The file is described in more detail below.
 
-   Ideally the file should have a file type of ".msg".
+   Ideally the file should have a file type of ".mes".
 
-2. Run it through the message compiler to produce the .h and .cc files.  It
-   is intended that this step be included in the build process.  However,
-   for now run the compiler (found in the "compiler" subdirectory) manually.
-   The only argument is the name of the message file: it will produce as
-   output two files, having the same name as the input file but with file
-   types of ".h" and ".cc".
-
-   The compiler is built in the "compiler" subdirectory of the "src/lib/log"
-   directory.
+2. Run it through the message compiler to produce the .h and .cc files.  This
+   step should be included in the build process. (For an example of how to
+   do this, see src/lib/nsas/Makefile.am.) During development though, the
+   message compiler (found in the "src/lib/log/compiler" directory) will need
+   to be run manually.  The only argument is the name of the message file: it
+   will produce as output two files in the default directory, having the same
+   name as the input file but with file types of ".h" and ".cc".
 
 3. Include the .h file in your source code to define message symbols, and
    make sure that the .cc file is compiled and linked into your program -
@@ -96,11 +94,12 @@ An example file could be:
 
 $PREFIX TEST_
 $NAMESPACE isc::log
-TEST1       message %s is much too large
-+ This message is a test for the general message code
 
-UNKNOWN     unknown message
-+ Issued when the message is unknown.
+% TEST1       message %1 is much too large
+This message is a test for the general message code
+
+% UNKNOWN     unknown message
+Issued when the message is unknown.
 
 -- END --
 
@@ -117,23 +116,31 @@ Points to note:
 
 * Lines starting $ are directives.  At present, two directives are recognised:
 
-  * $PREFIX, which has one argument: the string used to prefix symbols.  If
-    absent, there is no prefix to the symbols. (Prefixes are explained below.)
+  * $PREFIX, which has one optional argument: the string used to prefix symbols.
+    If absent, there is no prefix to the symbols. (Prefixes are explained below.)
+
   * $NAMESPACE, which has one argument: the namespace in which the symbols are
-    created.  In the absence of a $NAMESPACE directive, symbols will be put
-    in the global namespace.
+    created.  In the absence of a $NAMESPACE directive, symbols will be put in
+    the anonymous namespace.
 
-* Lines starting + indicate an explanation for the preceding message.  These
-  are intended to be processed by a separate program and used to generate
-  an error messages manual.  However they are treated like comments by the
-  message compiler.  As with comments, these must be on a line by themselves;
-  if inline, the text (including the leading "+") will be interpreted as
-  part of the line.
+* Message lines.  These start with a "%" and are followed by the message
+  identification and the message text, the latter including zero or more
+  replacement tokens, e.g.
 
-* Message lines.  These comprise a symbol name and a message, which may
-  include zero or more printf-style tokens.  Symbol names will be upper-cased
-  by the compiler.
+     % TEST  message %1 is larger than the permitted length of %2
 
+  * There may be zero or more spaces between the leading "%" and the message
+    identification (which, in the example above, is the word "TEST").
+
+  * The replacement tokens are the strings "%1", "%2" etc.  When a message
+    is logged, these are replaced with the arguments passed to the logging
+    call: %1 refers to the first argument, %2 to the second etc.  Within the
+    message text, the placeholders can appear in any order, and placeholders
+    can be repeated.
+     
+* Remaining lines indicate an explanation for the preceding message.  These
+  are intended to be processed by a separate program and used to generate
+  an error messages manual.  They are ignored by the message compiler.
 
 Message Compiler
 ----------------
@@ -153,9 +160,8 @@ the form:
       :
    }
 
-The symbols define the keys in the global message dictionary.
-
-The namespace enclosing the symbols is set by the $NAMESPACE directive.
+The symbols define the keys in the global message dictionary, with the
+namespace enclosing the symbols set by the $NAMESPACE directive.
 
 The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
 the argument to the directive.  So "$PREFIX MSG_" would prefix the identifier
@@ -163,12 +169,20 @@ ABC with "MSG_" to give the symbol MSG_ABC.  Similarly "$PREFIX E" would
 prefix it with "E" to give the symbol EABC.  If no $PREFIX is given, no
 prefix appears (so the symbol in this example would be ABC).
 
+The prefix is "syntactic sugar".  Generally all symbols in a given message file
+will be prefixed with the same set of letters.  By extracting these into
+a separate prefix, it becomes easier to disambiguate the different symbols.
+
+There may be multiple $PREFIX directives in a file.  A $PREFIX directive applies
+to all message definitions between it an the next $PREFIX directive.  A $PREFIX
+directive with no arguments clears the current prefix.
+
 2) A C++ source file (called <message-file-name>.cc) that holds the definitions
 of the global symbols and code to insert the symbols and messages into the map.
 
 Symbols are defined to be equal to strings holding the identifier, e.g.
 
-   extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
+   extern const isc::log::MessageID MSG_DUPLNS = "MSG_DUPLNS";
 
 (The implementation allows symbols to be compared.  However, use of strings
 should not be assumed - a future implementation may change this.)
@@ -243,27 +257,49 @@ To use the current version of the logging:
       highest-level debug messages and 99 for the lowest-level (and typically
       more verbose) messages.
 
-   c) Name of an external message file.  This is the same as a standard message
-      file, although it should not include any directives. (A single directive
-      of a particular type will be ignored; multiple directives will cause the
-      read of the file to fail with an error.)  If a message is replaced, the
-      message should include the same printf-format directives in the same order
-      as the original message.
+   c) The external message file.  If present, this is the same as a standard
+      message file, although it should not include any directives. (A single
+      directive of a particular type will be ignored; multiple directives will
+      cause the read of the file to fail with an error.)
 
 4. Issue logging calls using methods on logger, e.g.
 
-       logger.error(DPS_NSTIMEOUT, "isc.org");
+       logger.error(DPS_NSTIMEOUT).arg("isc.org");
 
    (where, in the example above we might have defined the symbol in the message
    file with something along the lines of:
 
        $PREFIX DPS_
            :
-       NSTIMEOUT  queries to all nameservers for %s have timed out
+       NSTIMEOUT  queries to all nameservers for %1 have timed out
 
    At present, the only logging is to the console.
 
 
+Efficiency Considerations
+-------------------------
+A common pattern in logging is a debug call of the form:
+
+   logger.debug(dbglevel, MSGID).arg(expensive_call()).arg(...
+
+... where "expensive_call()" is a function call to obtain logging information
+that may be computationally intensive.  Although the cost may be justified
+when debugging is enabled, the cost is still incurred even if debugging is
+disabled and the debug() method returns without outputting anything.  (The
+same may be true of other logging levels, although there are likely to be
+fewer calls to logger.info(), logger.error() etc. throughout the code and
+they are less likely to be disabled.)
+
+For this reason, a set of macros is provided and are called using the
+construct:
+
+   LOG_DEBUG(logger, dbglevel, MSGID).arg(expensive_call()).arg(...
+   LOG_INFO(logger, MSGID).arg(expensive_call()...)
+
+If these are used, the arguments passed to the arg() method are not evaluated
+if the relevant logging level is disabled.
+
+
 Severity Guidelines
 ===================
 When using logging, the question arises, what severity should a message be
@@ -361,9 +397,6 @@ is only one piece of code that does this functionality.
 Outstanding Issues
 ==================
 * Ability to configure system according to configuration database.
-* Update the build procedure to create .cc and .h files from the .msg file
-  during the build process. (Requires that the message compiler is built
-  first.)
 
 
 log4cxx Issues
diff --git a/src/lib/log/compiler/Makefile.am b/src/lib/log/compiler/Makefile.am
index 9343793..d51ba05 100644
--- a/src/lib/log/compiler/Makefile.am
+++ b/src/lib/log/compiler/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = .
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -15,4 +16,5 @@ CLEANFILES = *.gcno *.gcda
 noinst_PROGRAMS = message
 message_SOURCES = message.cc
 message_LDADD  = $(top_builddir)/src/lib/log/liblog.la
+message_LDADD += $(top_builddir)/src/lib/util/libutil.la
 
diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index 6f9c4e0..457a62e 100644
--- a/src/lib/log/compiler/message.cc
+++ b/src/lib/log/compiler/message.cc
@@ -25,17 +25,19 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <log/filename.h>
+#include <util/filename.h>
+#include <util/strutil.h>
+
 #include <log/message_dictionary.h>
 #include <log/message_exception.h>
 #include <log/message_reader.h>
 #include <log/messagedef.h>
-#include <log/strutil.h>
 
 #include <log/logger.h>
 
 using namespace std;
 using namespace isc::log;
+using namespace isc::util;
 
 static const char* VERSION = "1.0-0";
 
@@ -48,17 +50,13 @@ static const char* VERSION = "1.0-0";
 /// \li A .cc file containing code that adds the messages to the program's
 /// message dictionary at start-up time.
 ///
-/// Alternatively, the program can produce a .py file that contains the
-/// message definitions.
-///
-
 /// \b Invocation<BR>
 /// The program is invoked with the command:
 ///
 /// <tt>message [-v | -h | \<message-file\>]</tt>
 ///
-/// It reads the message file and writes out two files of the same name but with
-/// extensions of .h and .cc.
+/// It reads the message file and writes out two files of the same name in the
+/// default directory but with extensions of .h and .cc.
 ///
 /// \-v causes it to print the version number and exit. \-h prints a help
 /// message (and exits).
@@ -105,7 +103,7 @@ currentTime() {
 
     // Convert to string and strip out the trailing newline
     string current_time = buffer;
-    return isc::strutil::trim(current_time);
+    return isc::util::str::trim(current_time);
 }
 
 
@@ -125,7 +123,7 @@ sentinel(Filename& file) {
     string name = file.name();
     string ext = file.extension();
     string sentinel_text = "__" + name + "_" + ext.substr(1);
-    isc::strutil::uppercase(sentinel_text);
+    isc::util::str::uppercase(sentinel_text);
     return sentinel_text;
 }
 
@@ -206,7 +204,7 @@ splitNamespace(string ns) {
 
     // ... and return the vector of namespace components split on the single
     // colon.
-    return isc::strutil::tokens(ns, ":");
+    return isc::util::str::tokens(ns, ":");
 }
 
 
@@ -249,17 +247,16 @@ writeClosingNamespace(ostream& output, const vector<string>& ns) {
 ///
 /// \param file Name of the message file.  The header file is written to a
 /// file of the same name but with a .h suffix.
-/// \param prefix Prefix string to use in symbols
 /// \param ns Namespace in which the definitions are to be placed.  An empty
 /// string indicates no namespace.
 /// \param dictionary Dictionary holding the message definitions.
 
 void
-writeHeaderFile(const string& file, const string& prefix,
-        const vector<string>& ns_components, MessageDictionary& dictionary)
+writeHeaderFile(const string& file, const vector<string>& ns_components,
+                MessageDictionary& dictionary)
 {
     Filename message_file(file);
-    Filename header_file(message_file.useAsDefault(".h"));
+    Filename header_file(Filename(message_file.name()).useAsDefault(".h"));
 
     // Text to use as the sentinels.
     string sentinel_text = sentinel(header_file);
@@ -269,7 +266,7 @@ writeHeaderFile(const string& file, const string& prefix,
 
     try {
         if (hfile.fail()) {
-            throw MessageException(MSG_OPNMSGOUT, header_file.fullName(),
+            throw MessageException(MSG_OPENOUT, header_file.fullName(),
                 strerror(errno));
         }
 
@@ -292,7 +289,7 @@ writeHeaderFile(const string& file, const string& prefix,
         vector<string> idents = sortedIdentifiers(dictionary);
         for (vector<string>::const_iterator j = idents.begin();
             j != idents.end(); ++j) {
-            hfile << "extern const isc::log::MessageID " << prefix << *j << ";\n";
+            hfile << "extern const isc::log::MessageID " << *j << ";\n";
         }
         hfile << "\n";
 
@@ -303,7 +300,7 @@ writeHeaderFile(const string& file, const string& prefix,
 
         // Report errors (if any) and exit
         if (hfile.fail()) {
-            throw MessageException(MSG_MSGWRTERR, header_file.fullName(),
+            throw MessageException(MSG_WRITERR, header_file.fullName(),
                 strerror(errno));
         }
 
@@ -352,17 +349,17 @@ replaceNonAlphaNum(char c) {
 /// to it.  But until BIND-10 is ported to Windows, we won't know.
 
 void
-writeProgramFile(const string& file, const string& prefix,
-    const vector<string>& ns_components, MessageDictionary& dictionary)
+writeProgramFile(const string& file, const vector<string>& ns_components,
+                 MessageDictionary& dictionary)
 {
     Filename message_file(file);
-    Filename program_file(message_file.useAsDefault(".cc"));
+    Filename program_file(Filename(message_file.name()).useAsDefault(".cc"));
 
     // Open the output file for writing
     ofstream ccfile(program_file.fullName().c_str());
     try {
         if (ccfile.fail()) {
-            throw MessageException(MSG_OPNMSGOUT, program_file.fullName(),
+            throw MessageException(MSG_OPENOUT, program_file.fullName(),
                 strerror(errno));
         }
 
@@ -385,7 +382,7 @@ writeProgramFile(const string& file, const string& prefix,
         vector<string> idents = sortedIdentifiers(dictionary);
         for (vector<string>::const_iterator j = idents.begin();
             j != idents.end(); ++j) {
-            ccfile << "extern const isc::log::MessageID " << prefix << *j <<
+            ccfile << "extern const isc::log::MessageID " << *j <<
                 " = \"" << *j << "\";\n";
         }
         ccfile << "\n";
@@ -420,7 +417,7 @@ writeProgramFile(const string& file, const string& prefix,
 
         // Report errors (if any) and exit
         if (ccfile.fail()) {
-            throw MessageException(MSG_MSGWRTERR, program_file.fullName(),
+            throw MessageException(MSG_WRITERR, program_file.fullName(),
                 strerror(errno));
         }
 
@@ -516,13 +513,10 @@ main(int argc, char* argv[]) {
         vector<string> ns_components = splitNamespace(reader.getNamespace());
 
         // Write the header file.
-        writeHeaderFile(message_file, reader.getPrefix(), ns_components,
-            dictionary);
+        writeHeaderFile(message_file, ns_components, dictionary);
 
         // Write the file that defines the message symbols and text
-        writeProgramFile(message_file, reader.getPrefix(), ns_components,
-            dictionary);
-
+        writeProgramFile(message_file, ns_components, dictionary);
 
         // Finally, warn of any duplicates encountered.
         warnDuplicates(reader);
@@ -533,9 +527,12 @@ main(int argc, char* argv[]) {
         string text = e.id();
         text += ", ";
         text += global.getText(e.id());
-
         // Format with arguments
-        text = isc::strutil::format(text, e.arguments());
+        vector<string> args(e.arguments());
+        for (size_t i(0); i < args.size(); ++ i) {
+            replacePlaceholder(&text, args[i], i + 1);
+        }
+
         cerr << text << "\n";
 
         return 1;
diff --git a/src/lib/log/filename.cc b/src/lib/log/filename.cc
deleted file mode 100644
index 91835af..0000000
--- a/src/lib/log/filename.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <iostream>
-#include <algorithm>
-#include <string>
-
-#include <ctype.h>
-
-#include <log/filename.h>
-#include <log/strutil.h>
-
-using namespace std;
-
-
-namespace isc {
-namespace log {
-
-// Split string into components.  Any backslashes are assumed to have
-// been replaced by forward slashes.
-
-void
-Filename::split(const string& full_name, string& directory,
-    string& name, string& extension) const
-{
-    directory = name = extension = "";
-    bool dir_present = false;
-    if (!full_name.empty()) {
-
-        // Find the directory.
-        size_t last_slash = full_name.find_last_of('/');
-        if (last_slash != string::npos) {
-
-            // Found the last slash, so extract directory component and
-            // set where the scan for the last_dot should terminate.
-            directory = full_name.substr(0, last_slash + 1);
-            if (last_slash == full_name.size()) {
-
-                // The entire string was a directory, so exit not and don't
-                // do any more searching.
-                return;
-            }
-
-            // Found a directory so note the fact.
-            dir_present = true;
-        }
-
-        // Now search backwards for the last ".".
-        size_t last_dot = full_name.find_last_of('.');
-        if ((last_dot == string::npos) ||
-            (dir_present && (last_dot < last_slash))) {
-
-            // Last "." either not found or it occurs to the left of the last
-            // slash if a directory was present (so it is part of a directory
-            // name).  In this case, the remainder of the string after the slash
-            // is the name part.
-            name = full_name.substr(last_slash + 1);
-            return;
-        }
-
-        // Did find a valid dot, so it and everything to the right is the
-        // extension...
-        extension = full_name.substr(last_dot);
-
-        // ... and the name of the file is everything in between.
-        if ((last_dot - last_slash) > 1) {
-            name = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
-        }
-    }
-
-}
-
-// Expand the stored filename with the default.
-
-string
-Filename::expandWithDefault(const string& defname) const {
-
-    string def_directory("");
-    string def_name("");
-    string def_extension("");
-
-    // Normalize the input string.
-    string copy_defname = isc::strutil::trim(defname);
-#ifdef WIN32
-    isc::strutil::normalizeSlash(copy_defname);
-#endif
-
-    // Split into the components
-    split(copy_defname, def_directory, def_name, def_extension);
-
-    // Now construct the result.
-    string retstring =
-        (directory_.empty() ? def_directory : directory_) +
-        (name_.empty() ? def_name : name_) +
-        (extension_.empty() ? def_extension : extension_);
-    return (retstring);
-}
-
-// Use the stored name as default for a given name
-
-string
-Filename::useAsDefault(const string& name) const {
-
-    string name_directory("");
-    string name_name("");
-    string name_extension("");
-
-    // Normalize the input string.
-    string copy_name = isc::strutil::trim(name);
-#ifdef WIN32
-    isc::strutil::normalizeSlash(copy_name);
-#endif
-
-    // Split into the components
-    split(copy_name, name_directory, name_name, name_extension);
-
-    // Now construct the result.
-    string retstring =
-        (name_directory.empty() ? directory_ : name_directory) +
-        (name_name.empty() ? name_ : name_name) +
-        (name_extension.empty() ? extension_ : name_extension);
-    return (retstring);
-}
-
-
-} // namespace log
-} // namespace isc
diff --git a/src/lib/log/filename.h b/src/lib/log/filename.h
deleted file mode 100644
index e3cda16..0000000
--- a/src/lib/log/filename.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __FILENAME_H
-#define __FILENAME_H
-
-#include <string>
-
-#include <strutil.h>
-
-namespace isc {
-namespace log {
-
-/// \brief Class to Manipulate Filenames
-///
-/// This is a utility class to manipulate filenames.  It repeats some of the
-/// features found in the Boost filename class, but is self-contained so avoids
-/// the need to link in the Boost library.
-///
-/// A Unix-style filename comprises three parts:
-///
-/// Directory - everything up to and including the last "/".  If there is no
-/// "/" in the string, there is no directory component.  Note that the
-/// requirement of a trailing slash eliminates the ambiguity of whether a
-/// component is a directory or not, e.g. in /alpha/beta", "beta" could be the
-/// name of a directory or is could be a file.  The interpretation here is that
-/// "beta" is the name of a file (although that file could be a directory).
-///
-/// Note: Under Windows, the drive letter is considered to be part of the
-/// directory specification.  Unless this class becomes more widely-used on
-/// Windows, there is no point in adding redundant code.
-///
-/// Name - everthing from the character after the last "/" up to but not
-/// including the last ".".
-///
-/// Extension - everthing from the right-most "." (after the right-most "/") to
-/// the end of the string.  If there is no "." after the last "/", there is
-/// no file extension.
-///
-/// (Note that on Windows, this function will replace all "\" characters
-/// with "/" characters on input strings.)
-///
-/// This class provides functions for extracting the components and for
-/// substituting components.
-
-
-class Filename {
-public:
-
-    /// \brief Constructor
-    Filename(const std::string& name) :
-        full_name_(""), directory_(""), name_(""), extension_("")
-    {
-        setName(name);
-    }
-
-    /// \brief Sets Stored Filename
-    ///
-    /// \param name New name to replaced currently stored name
-    void setName(const std::string& name) {
-        full_name_ = isc::strutil::trim(name);
-#ifdef WIN32
-        isc::strutil::normalizeSlash(full_name_);
-#endif
-        split(full_name_, directory_, name_, extension_);
-    }
-
-    /// \return Stored Filename
-    std::string fullName() const {
-        return (full_name_);
-    }
-
-    /// \return Directory of Given File Name
-    std::string directory() const {
-        return (directory_);
-    }
-
-    /// \return Name of Given File Name
-    std::string name() const {
-        return (name_);
-    }
-
-    /// \return Extension of Given File Name
-    std::string extension() const {
-        return (extension_);
-    }
-
-    /// \brief Expand Name with Default
-    ///
-    /// A default file specified is supplied and used to fill in any missing
-    /// fields.  For example, if the name stored is "/a/b" and the supplied
-    /// name is "c.d", the result is "/a/b.d": the only field missing from the
-    /// stored name is the extension, which is supplied by the default.
-    /// Another example would be to store "a.b" and to supply a default of
-    /// "/c/d/" - the result is "/c/d/a.b".  (Note that if the supplied default
-    /// was "/c/d", the result would be "/c/a.b", even if "/c/d" were actually
-    /// a directory.)
-    ///
-    /// \param defname Default name
-    ///
-    /// \return Name expanded with defname.
-    std::string expandWithDefault(const std::string& defname) const;
-
-    /// \brief Use as Default and Substitute into String
-    ///
-    /// Does essentially the inverse of expand(); that filled in the stored
-    /// name with a default and returned the result.  This treats the stored
-    /// name as the default and uses it to fill in a given name.  In essence,
-    /// the code:
-    /// \code
-    ///       Filename f("/a/b");
-    ///       result = f.expandWithdefault("c.d");
-    /// \endcode
-    /// gives as a result "/a/b.d".  This is the same as:
-    /// \code
-    ///       Filename f("c.d");
-    ///       result = f.useAsDefault("/a/b");
-    /// \endcode
-    ///
-    /// \param name Name to expand
-    ///
-    /// \return Name expanded with stored name
-    std::string useAsDefault(const std::string& name) const;
-
-private:
-    /// \brief Split Name into Components
-    ///
-    /// Splits the file name into the directory, name and extension parts.
-    /// The name is assumed to have had back slashes replaced by forward
-    /// slashes (if appropriate).
-    ///
-    /// \param full_name Name to split
-    /// \param directory Returned directory part
-    /// \param name Returned name part
-    /// \param extension Returned extension part
-    void split(const std::string& full_name, std::string& directory,
-       std::string& name, std::string& extension) const;
-
-    // Members
-
-    std::string full_name_;     ///< Given name
-    std::string directory_;     ///< Directory part
-    std::string name_;          ///< Name part
-    std::string extension_;     ///< Extension part
-};
-
-} // namespace log
-} // namespace isc
-
-#endif // __FILENAME_H
diff --git a/src/lib/log/log_formatter.cc b/src/lib/log/log_formatter.cc
new file mode 100644
index 0000000..18c4741
--- /dev/null
+++ b/src/lib/log/log_formatter.cc
@@ -0,0 +1,42 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <log/log_formatter.h>
+
+using namespace std;
+using namespace boost;
+
+namespace isc {
+namespace log {
+
+void
+replacePlaceholder(string* message, const string& arg,
+                   const unsigned placeholder)
+{
+    string mark("%" + lexical_cast<string>(placeholder));
+    size_t pos(message->find(mark));
+    if (pos != string::npos) {
+        do {
+            message->replace(pos, mark.size(), arg);
+            pos = message->find(mark, pos + arg.size());
+        } while (pos != string::npos);
+    } else {
+        // We're missing the placeholder, so add some complain
+        message->append(" @@Missing placeholder " + mark + " for '" + arg +
+                        "'@@");
+    }
+}
+
+}
+}
diff --git a/src/lib/log/log_formatter.h b/src/lib/log/log_formatter.h
new file mode 100644
index 0000000..cda1d96
--- /dev/null
+++ b/src/lib/log/log_formatter.h
@@ -0,0 +1,150 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LOG_FORMATTER_H
+#define __LOG_FORMMATER_H
+
+#include <string>
+#include <boost/lexical_cast.hpp>
+
+namespace isc {
+namespace log {
+
+/// \brief The internal replacement routine
+///
+/// This is used internally by the Formatter. Replaces a placeholder
+/// in the message by replacement. If the placeholder is not found,
+/// it adds a complain at the end.
+void
+replacePlaceholder(std::string* message, const std::string& replacement,
+                   const unsigned placeholder);
+
+///
+/// \brief The log message formatter
+///
+/// This class allows us to format logging messages conveniently. We
+/// call something like logger.warn(WARN_MSG).arg(15).arg(dnsMsg). This
+/// outputs some text with placeholders replaced by the arguments, if
+/// the logging verbosity is at WARN level or more.
+///
+/// To make this work, we use the Formatter. The warn (or whatever logging
+/// function) returns a Formatter object. That one holds the string to be
+/// output with the placeholders. It also remembers if there should be any
+/// output at all (eg. if the logging is enabled for this level). When there's
+/// no .arg call on the object, it is destroyed right away and we use the
+/// destructor to output the text (but only in case we should output anything).
+///
+/// If there's an .arg call, we return reference to the same object, so another
+/// .arg can be called on it. After the last .arg call is done, the object is
+/// destroyed and, again, we can produce the output.
+///
+/// Of course, if the logging is turned off, we don't bother with any replacing
+/// and just return.
+///
+/// User of logging code should not really care much about this class, only
+/// call the .arg method to generate the correct output.
+///
+/// The class is a template to allow easy testing. Also, we want everything
+/// here in the header anyway and it doesn't depend on the details of what
+/// Logger really is, so it doesn't hurt anything.
+///
+/// Also, if you are interested in the internals, you might find the copy
+/// constructor a bit strange. It deactivates the original formatter. We don't
+/// really want to support copying of the Formatter by user, but C++ needs a
+/// copy constructor when returning from the logging functions, so we need one.
+/// And if we did not deactivate the original Formatter, that one would get
+/// destroyed before any call to .arg, producing an output, and then the one
+/// the .arg calls are called on would get destroyed as well, producing output
+/// again. So, think of this behaviour as soul moving from one to another.
+template<class Logger> class Formatter {
+private:
+    /// \brief The logger we will use to output the final message.
+    ///
+    /// If NULL, we are not active and should not produce anything.
+    mutable Logger* logger_;
+    /// \brief Prefix (eg. "ERROR", "DEBUG" or like that)
+    const char* prefix_;
+    /// \brief The messages with %1, %2... placeholders
+    std::string* message_;
+    /// \brief Which will be the next placeholder to replace
+    unsigned nextPlaceholder_;
+    Formatter& operator =(const Formatter& other);
+public:
+    /// \brief Constructor of "active" formatter
+    ///
+    /// This will create a formatter. If the arguments are set, it
+    /// will be active (will produce output). If you leave them all as NULL,
+    /// it will create an inactive Formatter -- one that'll produce no output.
+    ///
+    /// It is not expected to be called by user of logging system directly.
+    ///
+    /// \param prefix The severity prefix, like "ERROR" or "DEBUG"
+    /// \param message The message with placeholders. We take ownership of
+    ///     it and we will modify the string. Must not be NULL unless
+    ///     logger is also NULL, but it's not checked.
+    /// \param logger The logger where the final output will go, or NULL
+    ///     if no output is wanted.
+    Formatter(const char* prefix = NULL, std::string* message = NULL,
+              Logger* logger = NULL) :
+        logger_(logger), prefix_(prefix), message_(message),
+        nextPlaceholder_(1)
+    {
+    }
+
+    Formatter(const Formatter& other) :
+        logger_(other.logger_), prefix_(other.prefix_),
+        message_(other.message_), nextPlaceholder_(other.nextPlaceholder_)
+    {
+        other.logger_ = false;
+    }
+    /// \brief Destructor.
+    //
+    /// This is the place where output happens if the formatter is active.
+    ~ Formatter() {
+        if (logger_) {
+            logger_->output(prefix_, *message_);
+            delete message_;
+        }
+    }
+    /// \brief Replaces another placeholder
+    ///
+    /// Replaces another placeholder and returns a new formatter with it.
+    /// Deactivates the current formatter. In case the formatter is not active,
+    /// only produces another inactive formatter.
+    ///
+    /// \param arg The argument to place into the placeholder.
+    template<class Arg> Formatter& arg(const Arg& value) {
+        if (logger_) {
+            return (arg(boost::lexical_cast<std::string>(value)));
+        } else {
+            return (*this);
+        }
+    }
+    /// \brief String version of arg.
+    Formatter& arg(const std::string& arg) {
+        if (logger_) {
+            // FIXME: This logic has a problem. If we had a message like
+            // "%1 %2" and called .arg("%2").arg(42), we would get "42 %2".
+            // But we consider this to be rare enough not to complicate
+            // matters.
+            replacePlaceholder(message_, arg, nextPlaceholder_ ++);
+        }
+        return (*this);
+    }
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index a2465de..c340315 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -20,7 +20,8 @@
 #include <log/message_dictionary.h>
 #include <log/message_types.h>
 #include <log/root_logger_name.h>
-#include <log/strutil.h>
+
+#include <util/strutil.h>
 
 using namespace std;
 
@@ -111,52 +112,57 @@ Logger::isFatalEnabled() {
 // Output methods
 
 void
-Logger::debug(int dbglevel, const isc::log::MessageID& ident, ...) {
+Logger::output(const char* sevText, const string& message) {
+    getLoggerPtr()->outputRaw(sevText, message);
+}
+
+Logger::Formatter
+Logger::debug(int dbglevel, const isc::log::MessageID& ident) {
     if (isDebugEnabled(dbglevel)) {
-        va_list ap;
-        va_start(ap, ident);
-        getLoggerPtr()->debug(ident, ap);
-        va_end(ap);
+        return (Formatter("DEBUG", getLoggerPtr()->lookupMessage(ident),
+                          this));
+    } else {
+        return (Formatter());
     }
 }
 
-void
-Logger::info(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::info(const isc::log::MessageID& ident) {
     if (isInfoEnabled()) {
-        va_list ap;
-        va_start(ap, ident);
-        getLoggerPtr()->info(ident, ap);
-        va_end(ap);
+        return (Formatter("INFO ", getLoggerPtr()->lookupMessage(ident),
+                          this));
+    } else {
+        return (Formatter());
     }
 }
 
-void
-Logger::warn(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::warn(const isc::log::MessageID& ident) {
     if (isWarnEnabled()) {
-        va_list ap;
-        va_start(ap, ident);
-        getLoggerPtr()->warn(ident, ap);
-        va_end(ap);
+        return (Formatter("WARN ", getLoggerPtr()->lookupMessage(ident),
+                          this));
+    } else {
+        return (Formatter());
     }
 }
 
-void
-Logger::error(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::error(const isc::log::MessageID& ident) {
     if (isErrorEnabled()) {
-        va_list ap;
-        va_start(ap, ident);
-        getLoggerPtr()->error(ident, ap);
-        va_end(ap);
+        return (Formatter("ERROR", getLoggerPtr()->lookupMessage(ident),
+                          this));
+    } else {
+        return (Formatter());
     }
 }
 
-void
-Logger::fatal(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::fatal(const isc::log::MessageID& ident) {
     if (isFatalEnabled()) {
-        va_list ap;
-        va_start(ap, ident);
-        getLoggerPtr()->fatal(ident, ap);
-        va_end(ap);
+        return (Formatter("FATAL", getLoggerPtr()->lookupMessage(ident),
+                          this));
+    } else {
+        return (Formatter());
     }
 }
 
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 88e88e2..6bd8924 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -21,6 +21,7 @@
 #include <log/debug_levels.h>
 #include <log/logger_levels.h>
 #include <log/message_types.h>
+#include <log/log_formatter.h>
 
 namespace isc {
 namespace log {
@@ -83,10 +84,11 @@ public:
         loggerptr_(NULL), name_(name), infunc_(infunc)
     {}
 
-
     /// \brief Destructor
     virtual ~Logger();
 
+    /// \brief The formatter used to replace placeholders
+    typedef isc::log::Formatter<Logger> Formatter;
 
     /// \brief Get Name of Logger
     ///
@@ -157,36 +159,31 @@ public:
     /// \param dbglevel Debug level, ranging between 0 and 99.  Higher numbers
     /// are used for more verbose output.
     /// \param ident Message identification.
-    /// \param ... Optional arguments for the message.
-    void debug(int dbglevel, const MessageID& ident, ...);
+    Formatter debug(int dbglevel, const MessageID& ident);
 
 
     /// \brief Output Informational Message
     ///
     /// \param ident Message identification.
-    /// \param ... Optional arguments for the message.
-    void info(const MessageID& ident, ...);
+    Formatter info(const MessageID& ident);
 
 
     /// \brief Output Warning Message
     ///
     /// \param ident Message identification.
-    /// \param ... Optional arguments for the message.
-    void warn(const MessageID& ident, ...);
+    Formatter warn(const MessageID& ident);
 
 
     /// \brief Output Error Message
     ///
     /// \param ident Message identification.
-    /// \param ... Optional arguments for the message.
-    void error(const MessageID& ident, ...);
+    Formatter error(const MessageID& ident);
 
 
     /// \brief Output Fatal Message
     ///
     /// \param ident Message identification.
-    /// \param ... Optional arguments for the message.
-    void fatal(const MessageID& ident, ...);
+    Formatter fatal(const MessageID& ident);
 
     /// \brief Equality
     ///
@@ -205,6 +202,12 @@ protected:
     static void reset();
 
 private:
+    friend class isc::log::Formatter<Logger>;
+    /// \brief Raw output function
+    ///
+    /// This is used by the formatter to output formatted output.
+    void output(const char* sevText, const std::string& message);
+
     /// \brief Copy Constructor
     ///
     /// Disabled (marked private) as it makes no sense to copy the logger -
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 4b19360..b30f835 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE
 
 #include <iostream>
+#include <iomanip>
 #include <algorithm>
 
 #include <stdarg.h>
@@ -26,7 +27,8 @@
 #include <log/message_dictionary.h>
 #include <log/message_types.h>
 #include <log/root_logger_name.h>
-#include <log/strutil.h>
+
+#include <util/strutil.h>
 
 using namespace std;
 
@@ -193,17 +195,14 @@ LoggerImpl::isDebugEnabled(int dbglevel) {
 }
 
 // Output a general message
+string*
+LoggerImpl::lookupMessage(const MessageID& ident) {
+    return (new string(string(ident) + ", " +
+                       MessageDictionary::globalDictionary().getText(ident)));
+}
 
 void
-LoggerImpl::output(const char* sev_text, const MessageID& ident,
-    va_list ap)
-{
-    char message[512];      // Should be large enough for any message
-
-    // Obtain text of the message and substitute arguments.
-    const string format = MessageDictionary::globalDictionary().getText(ident);
-    vsnprintf(message, sizeof(message), format.c_str(), ap);
-
+LoggerImpl::outputRaw(const char* sevText, const string& message) {
     // Get the time in a struct tm format, and convert to text
     time_t t_time;
     time(&t_time);
@@ -213,8 +212,8 @@ LoggerImpl::output(const char* sev_text, const MessageID& ident,
     (void) strftime(chr_time, sizeof(chr_time), "%Y-%m-%d %H:%M:%S", tm_time);
 
     // Now output.
-    std::cout << chr_time << " " << sev_text << " [" << getName() << "] " <<
-        ident << ", " << message << "\n";
+    cout << chr_time << " " << sevText << " [" << getName() << "] " <<
+        message << endl;
 }
 
 } // namespace log
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 9fc9cf9..187e478 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -167,64 +167,16 @@ public:
         }
     }
 
-
-    /// \brief Output General Message
-    ///
-    /// The message is formatted to include the date and time, the severity
-    /// and the logger generating the message.
+    /// \brief Raw output
     ///
-    /// \param sev_text Severity level as a text string
-    /// \param ident Message identification
-    /// \param ap Variable argument list holding message arguments
-    void output(const char* sev_text, const MessageID& ident,
-        va_list ap);
-
+    /// Writes the message with time into the log. Used by the Formatter
+    /// to produce output.
+    void outputRaw(const char* sev_text, const std::string& message);
 
-    /// \brief Output Debug Message
+    /// \brief Look up message text in dictionary
     ///
-    /// \param ident Message identification.
-    /// \param text Text to log
-    /// \param ap Variable argument list holding message arguments
-    void debug(const MessageID& ident, va_list ap) {
-        output("DEBUG", ident, ap);
-    }
-
-
-    /// \brief Output Informational Message
-    ///
-    /// \param ident Message identification.
-    /// \param text Text to log
-    /// \param ap Variable argument list holding message arguments
-    void info(const MessageID& ident, va_list ap) {
-        output("INFO ", ident, ap);
-    }
-
-    /// \brief Output Warning Message
-    ///
-    /// \param ident Message identification.
-    /// \param text Text to log
-    /// \param ap Variable argument list holding message arguments
-    void warn(const MessageID& ident, va_list ap) {
-        output("WARN ", ident, ap);
-    }
-
-    /// \brief Output Error Message
-    ///
-    /// \param ident Message identification.
-    /// \param text Text to log
-    /// \param ap Variable argument list holding message arguments
-    void error(const MessageID& ident, va_list ap) {
-        output("ERROR", ident, ap);
-    }
-
-    /// \brief Output Fatal Message
-    ///
-    /// \param ident Message identification.
-    /// \param text Text to log
-    /// \param ap Variable argument list holding message arguments
-    void fatal(const MessageID& ident, va_list ap) {
-        output("FATAL", ident, ap);
-    }
+    /// This gets you the unformatted text of message for given ID.
+    std::string* lookupMessage(const MessageID& id);
 
     /// \brief Equality
     ///
diff --git a/src/lib/log/logger_impl_log4cxx.cc b/src/lib/log/logger_impl_log4cxx.cc
index 404fd03..afe2d56 100644
--- a/src/lib/log/logger_impl_log4cxx.cc
+++ b/src/lib/log/logger_impl_log4cxx.cc
@@ -27,9 +27,10 @@
 #include <log/logger_impl.h>
 #include <log/message_dictionary.h>
 #include <log/message_types.h>
-#include <log/strutil.h>
 #include <log/xdebuglevel.h>
 
+#include <util/strutil.h>
+
 using namespace std;
 
 namespace isc {
diff --git a/src/lib/log/logger_support.cc b/src/lib/log/logger_support.cc
index f8bf075..e17c47d 100644
--- a/src/lib/log/logger_support.cc
+++ b/src/lib/log/logger_support.cc
@@ -24,7 +24,9 @@
 /// These functions will be replaced once the code has been written to obtain
 /// the logging parameters from the configuration database.
 
+#include <iostream>
 #include <algorithm>
+#include <iostream>
 #include <string>
 #include <vector>
 #include <boost/lexical_cast.hpp>
@@ -62,7 +64,7 @@ readLocalMessageFile(const char* file) {
     MessageDictionary& dictionary = MessageDictionary::globalDictionary();
     MessageReader reader(&dictionary);
     try {
-        logger.info(MSG_RDLOCMES, file);
+        logger.info(MSG_RDLOCMES).arg(file);
         reader.readFile(file, MessageReader::REPLACE);
 
         // File successfully read, list the duplicates
@@ -70,7 +72,7 @@ readLocalMessageFile(const char* file) {
         for (MessageReader::MessageIDCollection::const_iterator
             i = unknown.begin(); i != unknown.end(); ++i) {
             string message_id = boost::lexical_cast<string>(*i);
-                logger.warn(MSG_IDNOTFND, message_id.c_str());
+                logger.warn(MSG_IDNOTFND).arg(message_id);
         }
     }
     catch (MessageException& e) {
@@ -82,11 +84,15 @@ readLocalMessageFile(const char* file) {
             break;
 
         case 1:
-            logger.error(ident, args[0].c_str());
+            logger.error(ident).arg(args[0]);
             break;
 
-        default:    // 2 or more (2 should be the maximum)
-            logger.error(ident, args[0].c_str(), args[1].c_str());
+        case 2:
+            logger.error(ident).arg(args[0]).arg(args[1]);
+            break;
+
+        default:    // 3 or more (3 should be the maximum)
+            logger.error(ident).arg(args[0]).arg(args[1]).arg(args[2]);
         }
     }
 }
@@ -117,7 +123,7 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
         vector<string>::iterator new_end =
             unique(duplicates.begin(), duplicates.end());
         for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
-            logger.warn(MSG_DUPMSGID, i->c_str());
+            logger.warn(MSG_DUPMSGID).arg(*i);
         }
 
     }
@@ -128,5 +134,76 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
     }
 }
 
+/// Logger Run-Time Initialization via Environment Variables
+void initLogger() {
+
+    // Root logger name is defined by the environment variable B10_LOGGER_ROOT.
+    // If not present, the name is "b10root".
+    const char* DEFAULT_ROOT = "b10root";
+    const char* root = getenv("B10_LOGGER_ROOT");
+    if (! root) {
+        root = DEFAULT_ROOT;
+    }
+
+    // Set the logging severity.  The environment variable is
+    // B10_LOGGER_SEVERITY, and can be one of "DEBUG", "INFO", "WARN", "ERROR"
+    // of "FATAL".  Note that the string must be in upper case with no leading
+    // of trailing blanks.
+    isc::log::Severity severity = isc::log::DEFAULT;
+    const char* sev_char = getenv("B10_LOGGER_SEVERITY");
+    if (sev_char) {
+        string sev_string(sev_char);
+        if (sev_string == "DEBUG") {
+            severity = isc::log::DEBUG;
+        } else if (sev_string == "INFO") {
+            severity = isc::log::INFO;
+        } else if (sev_string == "WARN") {
+            severity = isc::log::WARN;
+        } else if (sev_string == "ERROR") {
+            severity = isc::log::ERROR;
+        } else if (sev_string == "FATAL") {
+            severity = isc::log::FATAL;
+        } else {
+            std::cerr << "**ERROR** unrecognised logger severity of '"
+                      << sev_string << "' - default severity will be used\n";
+        }
+    }
+
+    // If the severity is debug, get the debug level (environment variable
+    // B10_LOGGER_DBGLEVEL), which should be in the range 0 to 99.
+    int dbglevel = 0;
+    if (severity == isc::log::DEBUG) {
+        const char* dbg_char = getenv("B10_LOGGER_DBGLEVEL");
+        if (dbg_char) {
+            int level = 0;
+            try {
+                level = boost::lexical_cast<int>(dbg_char);
+                if (level < MIN_DEBUG_LEVEL) {
+                    std::cerr << "**ERROR** debug level of " << level
+                              << " is invalid - a value of " << MIN_DEBUG_LEVEL
+                              << " will be used\n";
+                    level = MIN_DEBUG_LEVEL;
+                } else if (level > MAX_DEBUG_LEVEL) {
+                    std::cerr << "**ERROR** debug level of " << level
+                              << " is invalid - a value of " << MAX_DEBUG_LEVEL
+                              << " will be used\n";
+                    level = MAX_DEBUG_LEVEL;
+                }
+            } catch (...) {
+                // Error, but not fatal to the test
+                std::cerr << "**ERROR** Unable to translate "
+                             "B10_LOGGER_DBGLEVEL - a value of 0 will be used\n";
+            }
+            dbglevel = level;
+        }
+    }
+
+    /// Set the local message file
+    const char* localfile = getenv("B10_LOGGER_LOCALMSG");
+
+    // Initialize logging
+    initLogger(root, severity, dbglevel, localfile);
+}
+
 } // namespace log
 } // namespace isc
diff --git a/src/lib/log/logger_support.h b/src/lib/log/logger_support.h
index 6b5fdec..f4861b2 100644
--- a/src/lib/log/logger_support.h
+++ b/src/lib/log/logger_support.h
@@ -39,6 +39,37 @@ namespace log {
 void initLogger(const std::string& root, isc::log::Severity severity,
     int dbglevel, const char* file);
 
+
+/// \brief Run-Time Initialization from Environment
+///
+/// Performs run-time initialization of the logger via the setting of
+/// environment variables.  These are:
+///
+/// B10_LOGGER_ROOT
+/// Name of the root logger.  If not given, the string "b10root" will be used.
+///
+/// B10_LOGGER_SEVERITY
+/// Severity of messages that will be logged.  This must be one of the strings
+/// "DEBUG", "INFO", "WARN", "ERROR", "FATAL". (Must be upper case and must
+/// not contain leading or trailing spaces.)  If not specified (or if
+/// specified but incorrect), the default for the logging system will be used
+/// (currently INFO).
+///
+/// B10_LOGGER_DBGLEVEL
+/// Ignored if the level is not DEBUG, this should be a number between 0 and
+/// 99 indicating the logging severity.  The default is 0.  If outside these
+/// limits or if not a number, a value of 0 is used.
+///
+/// B10_LOGGER_LOCALMSG
+/// If defined, the path specification of a file that contains message
+/// definitions replacing ones in the default dictionary.
+///
+/// Any errors in the settings cause messages to be output to stderr.
+///
+/// This function is most likely to be called from unit test programs.
+
+void initLogger();
+
 } // namespace log
 } // namespace isc
 
diff --git a/src/lib/log/macros.h b/src/lib/log/macros.h
new file mode 100644
index 0000000..3128131
--- /dev/null
+++ b/src/lib/log/macros.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LOG_MACROS_H
+#define __LOG_MACROS_H
+
+#include <log/logger.h>
+
+/// \brief Macro to conveniently test debug output and log it
+#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE) \
+    if (!(LOGGER).isDebugEnabled((LEVEL))) { \
+    } else \
+        (LOGGER).debug((LEVEL), (MESSAGE))
+
+/// \brief Macro to conveniently test info output and log it
+#define LOG_INFO(LOGGER, MESSAGE) \
+    if (!(LOGGER).isInfoEnabled()) { \
+    } else \
+        (LOGGER).info((MESSAGE))
+
+/// \brief Macro to conveniently test warn output and log it
+#define LOG_WARN(LOGGER, MESSAGE) \
+    if (!(LOGGER).isWarnEnabled()) { \
+    } else \
+        (LOGGER).warn((MESSAGE))
+
+/// \brief Macro to conveniently test error output and log it
+#define LOG_ERROR(LOGGER, MESSAGE) \
+    if (!(LOGGER).isErrorEnabled()) { \
+    } else \
+        (LOGGER).error((MESSAGE))
+
+/// \brief Macro to conveniently test fatal output and log it
+#define LOG_FATAL(LOGGER, MESSAGE) \
+    if (!(LOGGER).isFatalEnabled()) { \
+    } else \
+        (LOGGER).fatal((MESSAGE))
+
+#endif
diff --git a/src/lib/log/message_exception.cc b/src/lib/log/message_exception.cc
deleted file mode 100644
index 1a69ca5..0000000
--- a/src/lib/log/message_exception.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-/// \brief Body of Virtual Destructor
-
-#include <log/message_exception.h>
-
-namespace isc {
-namespace log {
-
-MessageException::~MessageException() throw() {
-}
-
-} // namespace log
-} // namespace isc
diff --git a/src/lib/log/message_exception.h b/src/lib/log/message_exception.h
index 30c6618..eebee89 100644
--- a/src/lib/log/message_exception.h
+++ b/src/lib/log/message_exception.h
@@ -19,6 +19,7 @@
 #include <string>
 #include <vector>
 
+#include <boost/lexical_cast.hpp>
 #include <log/message_types.h>
 
 namespace isc {
@@ -35,33 +36,47 @@ public:
 
     /// \brief Constructor
     ///
-    /// \param id Message identification
-    MessageException(MessageID id) : id_(id)
-    {}
+    /// \param id Message identification.
+    /// \param lineno Line number on which error occurred (if > 0).
+    MessageException(MessageID id, int lineno = 0) : id_(id)
+    {
+        if (lineno > 0) {
+            args_.push_back(boost::lexical_cast<std::string>(lineno));
+        }
+    }
 
     /// \brief Constructor
     ///
-    /// \param id Message identification
-    /// \param arg1 First message argument
-    MessageException(MessageID id, const std::string& arg1) : id_(id)
+    /// \param id Message identification.
+    /// \param arg1 First message argument.
+    /// \param lineno Line number on which error occurred (if > 0).
+    MessageException(MessageID id, const std::string& arg1, int lineno = 0)
+        : id_(id)
     {
+        if (lineno > 0) {
+            args_.push_back(boost::lexical_cast<std::string>(lineno));
+        }
         args_.push_back(arg1);
     }
 
     /// \brief Constructor
     ///
-    /// \param id Message identification
-    /// \param arg1 First message argument
-    /// \param arg2 Second message argument
+    /// \param id Message identification.
+    /// \param arg1 First message argument.
+    /// \param arg2 Second message argument.
+    /// \param lineno Line number on which error occurred (if > 0).
     MessageException(MessageID id, const std::string& arg1,
-        const std::string& arg2) : id_(id)
+        const std::string& arg2, int lineno = 0) : id_(id)
     {
+        if (lineno > 0) {
+            args_.push_back(boost::lexical_cast<std::string>(lineno));
+        }
         args_.push_back(arg1);
         args_.push_back(arg2);
     }
 
     /// \brief Destructor
-    virtual ~MessageException() throw();
+    ~MessageException() throw() {}
 
     /// \brief Return Message ID
     ///
diff --git a/src/lib/log/message_reader.cc b/src/lib/log/message_reader.cc
index 4402b0e..1a0b242 100644
--- a/src/lib/log/message_reader.cc
+++ b/src/lib/log/message_reader.cc
@@ -12,8 +12,10 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <cassert>
 #include <errno.h>
 #include <string.h>
+#include <iostream>
 
 #include <iostream>
 #include <fstream>
@@ -21,68 +23,74 @@
 #include <log/message_exception.h>
 #include <log/messagedef.h>
 #include <log/message_reader.h>
-#include <log/strutil.h>
+#include <util/strutil.h>
 
 using namespace std;
 
-namespace isc {
-namespace log {
-
-// Virtual destructor.
-MessageReader::~MessageReader() {
+namespace {
+const char DIRECTIVE_FLAG = '$';    // Starts each directive
+const char MESSAGE_FLAG = '%';      // Starts each message
 }
 
 
+namespace isc {
+namespace log {
+
 // Read the file.
 
 void
 MessageReader::readFile(const string& file, MessageReader::Mode mode) {
 
-    // Ensure the non-added collection is empty: this object might be
-    // being reused.
+    // Ensure the non-added collection is empty: we could be re-using this
+    // object.
     not_added_.clear();
 
-    // Open the file
+    // Open the file.
     ifstream infile(file.c_str());
     if (infile.fail()) {
-        throw MessageException(MSG_OPNMSGIN, file, strerror(errno));
+        throw MessageException(MSG_OPENIN, file, strerror(errno));
     }
 
-    // Loop round reading it.
+    // Loop round reading it.  As we process the file one line at a time,
+    // keep a track of line number of aid diagnosis of problems.
     string line;
     getline(infile, line);
+    lineno_ = 0;
+
     while (infile.good()) {
+        ++lineno_;
         processLine(line, mode);
         getline(infile, line);
     }
 
     // Why did the loop terminate?
     if (!infile.eof()) {
-        throw MessageException(MSG_MSGRDERR, file, strerror(errno));
+        throw MessageException(MSG_READERR, file, strerror(errno));
     }
     infile.close();
 }
 
-// Parse a line of the file
+// Parse a line of the file.
 
 void
 MessageReader::processLine(const string& line, MessageReader::Mode mode) {
 
     // Get rid of leading and trailing spaces
-    string text = isc::strutil::trim(line);
+    string text = isc::util::str::trim(line);
 
     if (text.empty()) {
         ;                           // Ignore blank lines
 
-    } else if ((text[0] == '#') || (text[0] == '+')) {
-        ;                           // Ignore comments or descriptions
-
-    } else if (text[0] == '$') {
+    } else if (text[0] == DIRECTIVE_FLAG) {
         parseDirective(text);       // Process directives
 
-    } else {
-        parseMessage(text, mode);   // Process other lines
 
+    } else if (text[0] == MESSAGE_FLAG) {
+        parseMessage(text, mode);   // Process message definition line
+
+    } else {
+        ;                           // Other lines are extended message
+                                    // description so are ignored
     }
 }
 
@@ -93,136 +101,168 @@ MessageReader::parseDirective(const std::string& text) {
 
 
     // Break into tokens
-    vector<string> tokens = isc::strutil::tokens(text);
+    vector<string> tokens = isc::util::str::tokens(text);
 
     // Uppercase directive and branch on valid ones
-    isc::strutil::uppercase(tokens[0]);
+    isc::util::str::uppercase(tokens[0]);
     if (tokens[0] == string("$PREFIX")) {
         parsePrefix(tokens);
+
     } else if (tokens[0] == string("$NAMESPACE")) {
         parseNamespace(tokens);
+
     } else {
-        throw MessageException(MSG_UNRECDIR, tokens[0]);
+
+        // Unrecognised directive
+        throw MessageException(MSG_UNRECDIR, tokens[0], lineno_);
     }
 }
 
 // Process $PREFIX
-
 void
 MessageReader::parsePrefix(const vector<string>& tokens) {
 
-    // Check argument count
-
-    static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-    if (tokens.size() < 2) {
-        throw MessageException(MSG_PRFNOARG);
-    } else if (tokens.size() > 2) {
-        throw MessageException(MSG_PRFEXTRARG);
-
-    }
+    // Should not get here unless there is something in the tokens array.
+    assert(tokens.size() > 0);
 
-    // As a style, we are going to have the symbols in uppercase
-    string prefix = tokens[1];
-    isc::strutil::uppercase(prefix);
+    // Process $PREFIX.  With no arguments, the prefix is set to the empty
+    // string.  One argument sets the prefix to the to its value and more than
+    // one argument is invalid.
+    if (tokens.size() == 1) {
+        prefix_ = "";
 
-    // Token is potentially valid providing it only contains alphabetic
-    // and numeric characters (and underscores) and does not start with a
-    // digit.
-    if ((prefix.find_first_not_of(valid) != string::npos) ||
-        (std::isdigit(prefix[0]))) {
+    } else if (tokens.size() == 2) {
+        prefix_ = tokens[1];
 
-        // Invalid character in string or it starts with a digit.
-        throw MessageException(MSG_PRFINVARG, tokens[1]);
-    }
+        // Token is potentially valid providing it only contains alphabetic
+        // and numeric characters (and underscores) and does not start with a
+        // digit.
+        if (invalidSymbol(prefix_)) {
+            throw MessageException(MSG_PRFINVARG, prefix_, lineno_);
+        }
 
-    // All OK - unless the prefix has already been set.
+    } else {
 
-    if (prefix_.size() != 0) {
-        throw MessageException(MSG_DUPLPRFX);
+        // Too many arguments
+        throw MessageException(MSG_PRFEXTRARG, lineno_);
     }
+}
 
-    // Prefix has not been set, so set it and return success.
-
-    prefix_ = prefix;
+// Check if string is an invalid C++ symbol.  It is valid if comprises only
+// alphanumeric characters and underscores, and does not start with a digit.
+// (Owing to the logic of the rest of the code, we check for its invalidity,
+// not its validity.)
+bool
+MessageReader::invalidSymbol(const string& symbol) {
+    static const string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                      "abcdefghijklmnopqrstuvwxyz"
+                                      "0123456789_";
+    return ( symbol.empty() ||
+            (symbol.find_first_not_of(valid_chars) != string::npos) ||
+            (std::isdigit(symbol[0])));
 }
 
 // Process $NAMESPACE.  A lot of the processing is similar to that of $PREFIX,
 // except that only limited checks will be done on the namespace (to avoid a
-// lot of parsing and separating out of the namespace components.)
+// lot of parsing and separating out of the namespace components.)  Also, unlike
+// $PREFIX, there can only be one $NAMESPACE in a file.
 
 void
 MessageReader::parseNamespace(const vector<string>& tokens) {
 
     // Check argument count
-
-    static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:"
-        "abcdefghijklmnopqrstuvwxyz";
-
     if (tokens.size() < 2) {
-        throw MessageException(MSG_NSNOARG);
+        throw MessageException(MSG_NSNOARG, lineno_);
 
     } else if (tokens.size() > 2) {
-        throw MessageException(MSG_NSEXTRARG);
+        throw MessageException(MSG_NSEXTRARG, lineno_);
 
     }
 
     // Token is potentially valid providing it only contains alphabetic
-    // and numeric characters (and underscores and colons).
-    if (tokens[1].find_first_not_of(valid) != string::npos) {
-
-        // Invalid character in string or it starts with a digit.
-        throw MessageException(MSG_NSINVARG, tokens[1]);
+    // and numeric characters (and underscores and colons).  As noted above,
+    // we won't be exhaustive - after all, and code containing the resultant
+    // namespace will have to be compiled, and the compiler will catch errors.
+    static const string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                      "abcdefghijklmnopqrstuvwxyz"
+                                      "0123456789_:";
+    if (tokens[1].find_first_not_of(valid_chars) != string::npos) {
+        throw MessageException(MSG_NSINVARG, tokens[1], lineno_);
     }
 
     // All OK - unless the namespace has already been set.
     if (ns_.size() != 0) {
-        throw MessageException(MSG_DUPLNS);
+        throw MessageException(MSG_DUPLNS, lineno_);
     }
 
     // Prefix has not been set, so set it and return success.
-
     ns_ = tokens[1];
 }
 
 // Process message.  By the time this method is called, the line has been
-// stripped of leading and trailing spaces, and we believe that it is a line
-// defining a message.  The first token on the line is converted to uppercase
-// and becomes the message ID; the rest of the line is the message text.
+// stripped of leading and trailing spaces.  The first character of the string
+// is the message introducer, so we can get rid of that.  The remainder is
+// a line defining a message.
+//
+// The first token on the line, when concatenated to the prefix and converted to
+// upper-case, is the message ID.  The first of the line from the next token
+// on is the message text.
 
 void
 MessageReader::parseMessage(const std::string& text, MessageReader::Mode mode) {
 
     static string delimiters("\t\n ");   // Delimiters
 
+    // The line passed should be at least one character long and start with the
+    // message introducer (else we should not have got here).
+    assert((text.size() >= 1) && (text[0] == MESSAGE_FLAG));
+
+    // A line comprising just the message introducer is not valid.
+    if (text.size() == 1) {
+        throw MessageException(MSG_NOMSGID, text, lineno_);
+    }
+
+    // Strip off the introducer and any leading space after that.
+    string message_line = isc::util::str::trim(text.substr(1));
+
     // Look for the first delimiter.
-    size_t first_delim = text.find_first_of(delimiters);
+    size_t first_delim = message_line.find_first_of(delimiters);
     if (first_delim == string::npos) {
 
         // Just a single token in the line - this is not valid
-        throw MessageException(MSG_NOMSGTXT, text);
+        throw MessageException(MSG_NOMSGTXT, message_line, lineno_);
     }
 
-    // Extract the first token into the message ID
-    string ident = text.substr(0, first_delim);
+    // Extract the first token into the message ID, preceding it with the
+    // current prefix, then convert to upper-case.  If the prefix is not set,
+    // perform the valid character check now - the string will become a C++
+    // symbol so we may as well identify problems early.
+    string ident = prefix_ + message_line.substr(0, first_delim);
+    if (prefix_.empty()) {
+        if (invalidSymbol(ident)) {
+            throw MessageException(MSG_INVMSGID, ident, lineno_);
+        }
+    }
+    isc::util::str::uppercase(ident);
 
     // Locate the start of the message text
-    size_t first_text = text.find_first_not_of(delimiters, first_delim);
+    size_t first_text = message_line.find_first_not_of(delimiters, first_delim);
     if (first_text == string::npos) {
 
         // ?? This happens if there are trailing delimiters, which should not
         // occur as we have stripped trailing spaces off the line.  Just treat
         // this as a single-token error for simplicity's sake.
-        throw MessageException(MSG_NOMSGTXT, text);
+        throw MessageException(MSG_NOMSGTXT, message_line, lineno_);
     }
 
     // Add the result to the dictionary and to the non-added list if the add to
     // the dictionary fails.
     bool added;
     if (mode == ADD) {
-        added = dictionary_->add(ident, text.substr(first_text));
+        added = dictionary_->add(ident, message_line.substr(first_text));
     }
     else {
-        added = dictionary_->replace(ident, text.substr(first_text));
+        added = dictionary_->replace(ident, message_line.substr(first_text));
     }
     if (!added) {
         not_added_.push_back(ident);
diff --git a/src/lib/log/message_reader.h b/src/lib/log/message_reader.h
index d07c7f2..eded9c6 100644
--- a/src/lib/log/message_reader.h
+++ b/src/lib/log/message_reader.h
@@ -64,10 +64,9 @@ public:
         dictionary_(dictionary)
     {}
 
-
     /// \brief Virtual Destructor
-    virtual ~MessageReader();
-
+    virtual ~MessageReader()
+    {}
 
     /// \brief Get Dictionary
     ///
@@ -188,10 +187,24 @@ private:
     /// \param tokens $NAMESPACE line split into tokens
     void parseNamespace(const std::vector<std::string>& tokens);
 
+    /// \brief Check for invalid C++ symbol name
+    ///
+    /// The message ID (or concatenation of prefix and message ID) will be used
+    /// as the name of a symbol in C++ code.  This function checks if the name
+    /// is invalid (contains anything other than alphanumeric characters or
+    /// underscores, or starts with a digit).
+    ///
+    /// \param symbol name to check to see if it is an invalid C++ symbol.
+    ///
+    /// \return true if the name is invalid, false if it is valid.
+    bool invalidSymbol(const std::string& symbol);
+
+
 
     /// Attributes
     MessageDictionary*  dictionary_;    ///< Dictionary to add messages to
     MessageIDCollection not_added_;     ///< List of IDs not added
+    int                 lineno_;        ///< Number of last line read
     std::string         prefix_;        ///< Argument of $PREFIX statement
     std::string         ns_;            ///< Argument of $NAMESPACE statement
 };
diff --git a/src/lib/log/messagedef.cc b/src/lib/log/messagedef.cc
index f680a74..5cc89b3 100644
--- a/src/lib/log/messagedef.cc
+++ b/src/lib/log/messagedef.cc
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Mon May  9 13:52:54 2011
 
 #include <cstddef>
 #include <log/message_types.h>
@@ -7,23 +7,23 @@
 namespace isc {
 namespace log {
 
-extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
-extern const isc::log::MessageID MSG_DUPLPRFX = "DUPLPRFX";
-extern const isc::log::MessageID MSG_DUPMSGID = "DUPMSGID";
-extern const isc::log::MessageID MSG_IDNOTFND = "IDNOTFND";
-extern const isc::log::MessageID MSG_MSGRDERR = "MSGRDERR";
-extern const isc::log::MessageID MSG_MSGWRTERR = "MSGWRTERR";
-extern const isc::log::MessageID MSG_NOMSGTXT = "NOMSGTXT";
-extern const isc::log::MessageID MSG_NSEXTRARG = "NSEXTRARG";
-extern const isc::log::MessageID MSG_NSINVARG = "NSINVARG";
-extern const isc::log::MessageID MSG_NSNOARG = "NSNOARG";
-extern const isc::log::MessageID MSG_OPNMSGIN = "OPNMSGIN";
-extern const isc::log::MessageID MSG_OPNMSGOUT = "OPNMSGOUT";
-extern const isc::log::MessageID MSG_PRFEXTRARG = "PRFEXTRARG";
-extern const isc::log::MessageID MSG_PRFINVARG = "PRFINVARG";
-extern const isc::log::MessageID MSG_PRFNOARG = "PRFNOARG";
-extern const isc::log::MessageID MSG_RDLOCMES = "RDLOCMES";
-extern const isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
+extern const isc::log::MessageID MSG_DUPLNS = "MSG_DUPLNS";
+extern const isc::log::MessageID MSG_DUPMSGID = "MSG_DUPMSGID";
+extern const isc::log::MessageID MSG_IDNOTFND = "MSG_IDNOTFND";
+extern const isc::log::MessageID MSG_INVMSGID = "MSG_INVMSGID";
+extern const isc::log::MessageID MSG_NOMSGID = "MSG_NOMSGID";
+extern const isc::log::MessageID MSG_NOMSGTXT = "MSG_NOMSGTXT";
+extern const isc::log::MessageID MSG_NSEXTRARG = "MSG_NSEXTRARG";
+extern const isc::log::MessageID MSG_NSINVARG = "MSG_NSINVARG";
+extern const isc::log::MessageID MSG_NSNOARG = "MSG_NSNOARG";
+extern const isc::log::MessageID MSG_OPENIN = "MSG_OPENIN";
+extern const isc::log::MessageID MSG_OPENOUT = "MSG_OPENOUT";
+extern const isc::log::MessageID MSG_PRFEXTRARG = "MSG_PRFEXTRARG";
+extern const isc::log::MessageID MSG_PRFINVARG = "MSG_PRFINVARG";
+extern const isc::log::MessageID MSG_RDLOCMES = "MSG_RDLOCMES";
+extern const isc::log::MessageID MSG_READERR = "MSG_READERR";
+extern const isc::log::MessageID MSG_UNRECDIR = "MSG_UNRECDIR";
+extern const isc::log::MessageID MSG_WRITERR = "MSG_WRITERR";
 
 } // namespace log
 } // namespace isc
@@ -31,23 +31,23 @@ extern const isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
 namespace {
 
 const char* values[] = {
-    "DUPLNS", "duplicate $NAMESPACE directive found",
-    "DUPLPRFX", "duplicate $PREFIX directive found",
-    "DUPMSGID", "duplicate message ID (%s) in compiled code",
-    "IDNOTFND", "could not replace message for '%s': no such message identification",
-    "MSGRDERR", "error reading from message file %s: %s",
-    "MSGWRTERR", "error writing to %s: %s",
-    "NOMSGTXT", "a line containing a message ID ('%s') and nothing else was found",
-    "NSEXTRARG", "$NAMESPACE directive has too many arguments",
-    "NSINVARG", "$NAMESPACE directive has an invalid argument ('%s')",
-    "NSNOARG", "no arguments were given to the $NAMESPACE directive",
-    "OPNMSGIN", "unable to open message file %s for input: %s",
-    "OPNMSGOUT", "unable to open %s for output: %s",
-    "PRFEXTRARG", "$PREFIX directive has too many arguments",
-    "PRFINVARG", "$PREFIX directive has an invalid argument ('%s')",
-    "PRFNOARG", "no arguments were given to the $PREFIX directive",
-    "RDLOCMES", "reading local message file %s",
-    "UNRECDIR", "unrecognised directive '%s'",
+    "MSG_DUPLNS", "line %1: duplicate $NAMESPACE directive found",
+    "MSG_DUPMSGID", "duplicate message ID (%1) in compiled code",
+    "MSG_IDNOTFND", "could not replace message text for '%1': no such message",
+    "MSG_INVMSGID", "line %1: invalid message identification '%2'",
+    "MSG_NOMSGID", "line %1: message definition line found without a message ID",
+    "MSG_NOMSGTXT", "line %1: line found containing a message ID ('%2') and no text",
+    "MSG_NSEXTRARG", "line %1: $NAMESPACE directive has too many arguments",
+    "MSG_NSINVARG", "line %1: $NAMESPACE directive has an invalid argument ('%2')",
+    "MSG_NSNOARG", "line %1: no arguments were given to the $NAMESPACE directive",
+    "MSG_OPENIN", "unable to open message file %1 for input: %2",
+    "MSG_OPENOUT", "unable to open %1 for output: %2",
+    "MSG_PRFEXTRARG", "line %1: $PREFIX directive has too many arguments",
+    "MSG_PRFINVARG", "line %1: $PREFIX directive has an invalid argument ('%2')",
+    "MSG_RDLOCMES", "reading local message file %1",
+    "MSG_READERR", "error reading from message file %1: %2",
+    "MSG_UNRECDIR", "line %1: unrecognised directive '%2'",
+    "MSG_WRITERR", "error writing to %1: %2",
     NULL
 };
 
diff --git a/src/lib/log/messagedef.h b/src/lib/log/messagedef.h
index eb8f4ea..79c8bab 100644
--- a/src/lib/log/messagedef.h
+++ b/src/lib/log/messagedef.h
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Mon May  9 13:52:54 2011
 
 #ifndef __MESSAGEDEF_H
 #define __MESSAGEDEF_H
@@ -9,22 +9,22 @@ namespace isc {
 namespace log {
 
 extern const isc::log::MessageID MSG_DUPLNS;
-extern const isc::log::MessageID MSG_DUPLPRFX;
 extern const isc::log::MessageID MSG_DUPMSGID;
 extern const isc::log::MessageID MSG_IDNOTFND;
-extern const isc::log::MessageID MSG_MSGRDERR;
-extern const isc::log::MessageID MSG_MSGWRTERR;
+extern const isc::log::MessageID MSG_INVMSGID;
+extern const isc::log::MessageID MSG_NOMSGID;
 extern const isc::log::MessageID MSG_NOMSGTXT;
 extern const isc::log::MessageID MSG_NSEXTRARG;
 extern const isc::log::MessageID MSG_NSINVARG;
 extern const isc::log::MessageID MSG_NSNOARG;
-extern const isc::log::MessageID MSG_OPNMSGIN;
-extern const isc::log::MessageID MSG_OPNMSGOUT;
+extern const isc::log::MessageID MSG_OPENIN;
+extern const isc::log::MessageID MSG_OPENOUT;
 extern const isc::log::MessageID MSG_PRFEXTRARG;
 extern const isc::log::MessageID MSG_PRFINVARG;
-extern const isc::log::MessageID MSG_PRFNOARG;
 extern const isc::log::MessageID MSG_RDLOCMES;
+extern const isc::log::MessageID MSG_READERR;
 extern const isc::log::MessageID MSG_UNRECDIR;
+extern const isc::log::MessageID MSG_WRITERR;
 
 } // namespace log
 } // namespace isc
diff --git a/src/lib/log/messagedef.mes b/src/lib/log/messagedef.mes
index 3599388..51c04fa 100644
--- a/src/lib/log/messagedef.mes
+++ b/src/lib/log/messagedef.mes
@@ -12,108 +12,108 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-$PREFIX MSG_
-$NAMESPACE isc::log
-
 # \brief Message Utility Message File
 #
-# This is the source of the set of messages generated by the message and logging
-# components.  The associated .h and .cc files are created by hand from this
-# file though and are not built during the build process; this is to avoid the
-# chicken-and-egg situation where we need the files to build the message
+# This is the source of the set of messages generated by the message and
+# logging components.  The associated .h and .cc files are created by hand from
+# this file though and are not built during the build process; this is to avoid
+# the chicken-and-egg situation where we need the files to build the message
 # compiler, yet we need the compiler to build the files.
 
-DUPMSGID  duplicate message ID (%s) in compiled code
-+ Indicative of a programming error, when it started up, BIND10 detected that
-+ the given message ID had been registered by one or more modules.  (All message
-+ IDs should be unique throughout BIND10.)  This has no impact on the operation
-+ of the server other that erroneous messages may be logged.  (When BIND10 loads
-+ the message IDs (and their associated text), if a duplicate ID is found it is
-+ discarded.  However, when the module that supplied the duplicate ID logs that
-+ particular message, the text supplied by the module that added the original
-+ ID will be output - something that may bear no relation to the condition being
-+ logged.
-
-DUPLNS    duplicate $NAMESPACE directive found
-+ When reading a message file, more than one $NAMESPACE directive was found.  In
-+ this version of the code, such a condition is regarded as an error and the
-+ read will be abandoned.
-
-DUPLPRFX    duplicate $PREFIX directive found
-+ When reading a message file, more than one $PREFIX directive was found.  In
-+ this version of the code, such a condition is regarded as an error and the
-+ read will be abandoned.
-
-IDNOTFND    could not replace message for '%s': no such message identification
-+ During start-up a local message file was read.  A line with the listed
-+ message identification was found in the file, but the identification is not
-+ one contained in the compiled-in message dictionary.  Either the message
-+ identification has been mis-spelled in the file, or the local file was used
-+ for an earlier version of the software and the message with that
-+ identification has been removed.
-+
-+ This message may appear a number of times in the file, once for every such
-+ unknown message identification.
-
-MSGRDERR    error reading from message file %s: %s
-+ The specified error was encountered reading from the named message file.
-
-MSGWRTERR   error writing to %s: %s
-+ The specified error was encountered by the message compiler when writing to
-+ the named output file.
-
-NSEXTRARG  $NAMESPACE directive has too many arguments
-+ The $NAMESPACE directive takes a single argument, a namespace in which all the
-+ generated symbol names are placed.  This error is generated when the
-+ compiler finds a $NAMESPACE directive with more than one argument.
-
-NSINVARG    $NAMESPACE directive has an invalid argument ('%s')
-+ The $NAMESPACE argument should be a valid C++ namespace.  The reader does a
-+ cursory check on its validity, checking that the characters in the namespace
-+ are correct.  The error is generated when the reader finds an invalid
-+ character. (Valid are alphanumeric characters, underscores and colons.)
-
-NOMSGTXT    a line containing a message ID ('%s') and nothing else was found
-+ Message definitions comprise lines starting with a message identification (a
-+ symbolic name for the message) and followed by the text of the message.  This
-+ error is generated when a line is found in the message file that contains just
-+ the message identification and no text.
-
-NSNOARG     no arguments were given to the $NAMESPACE directive
-+ The $NAMESPACE directive takes a single argument, a namespace in which all the
-+ generated symbol names are placed.  This error is generated when the
-+ compiler finds a $NAMESPACE directive with no arguments.
-
-OPNMSGIN     unable to open message file %s for input: %s
-+ The program was not able to open the specified input message file for the
-+ reason given.
-
-OPNMSGOUT   unable to open %s for output: %s
-+ The program was not able to open the specified output file for the reason
-+ given.
-
-PRFEXTRARG  $PREFIX directive has too many arguments
-+ The $PREFIX directive takes a single argument, a prefix to be added to the
-+ symbol names when a C++ .h file is created.  This error is generated when the
-+ compiler finds a $PREFIX directive with more than one argument.
-
-PRFINVARG   $PREFIX directive has an invalid argument ('%s')
-+ The $PREFIX argument is used in a symbol name in a C++ header file.  As such,
-+ it must adhere to restrictions on C++ symbol names (e.g. may only contain
-+ alphanumeric characters or underscores, and may nor start with a digit).  A
-+ $PREFIX directive was found with an argument (given in the message) that
-+ violates those restictions.
-
-PRFNOARG    no arguments were given to the $PREFIX directive
-+ The $PREFIX directive takes a single argument, a prefix to be added to the
-+ symbol names when a C++ .h file is created.  This error is generated when the
-+ compiler finds a $PREFIX directive with no arguments.
-
-RDLOCMES    reading local message file %s
-+ This is an informational message output by BIND10 when it starts to read a
-+ local message file.  (A local message file may replace the text of one of more
-+ messages; the ID of the message will not be changed though.)
-
-UNRECDIR    unrecognised directive '%s'
-+ A line starting with a dollar symbol was found, but the first word on the line
-+ (shown in the message) was not a recognised message compiler directive.
+$PREFIX MSG_
+$NAMESPACE isc::log
+
+% DUPMSGID      duplicate message ID (%1) in compiled code
+Indicative of a programming error, when it started up, BIND10 detected that
+the given message ID had been registered by one or more modules.  (All message
+IDs should be unique throughout BIND10.)  This has no impact on the operation
+of the server other that erroneous messages may be logged.  (When BIND10 loads
+the message IDs (and their associated text), if a duplicate ID is found it is
+discarded.  However, when the module that supplied the duplicate ID logs that
+particular message, the text supplied by the module that added the original
+ID will be output - something that may bear no relation to the condition being
+logged.
+
+% DUPLNS        line %1: duplicate $NAMESPACE directive found
+When reading a message file, more than one $NAMESPACE directive was found.  In
+this version of the code, such a condition is regarded as an error and the
+read will be abandoned.
+
+% IDNOTFND      could not replace message text for '%1': no such message
+During start-up a local message file was read.  A line with the listed
+message identification was found in the file, but the identification is not
+one contained in the compiled-in message dictionary.  Either the message
+identification has been mis-spelled in the file, or the local file was used
+for an earlier version of the software and the message with that
+identification has been removed.
+
+This message may appear a number of times in the file, once for every such
+unknown message identification.
+
+% INVMSGID      line %1: invalid message identification '%2'
+The concatenation of the prefix and the message identification is used as
+a symbol in the C++ module; as such it may only contain 
+
+% NOMSGID       line %1: message definition line found without a message ID
+Message definition lines are lines starting with a "%".  The rest of the line
+should comprise the message ID and text describing the message.  This error
+indicates the message compiler found a line in the message file comprising
+just the "%" and nothing else.
+
+% NOMSGTXT      line %1: line found containing a message ID ('%2') and no text
+Message definition lines are lines starting with a "%".  The rest of the line
+should comprise the message ID and text describing the message.  This error
+is generated when a line is found in the message file that contains the
+leading "%" and the message identification but no text.
+
+% NSEXTRARG     line %1: $NAMESPACE directive has too many arguments
+The $NAMESPACE directive takes a single argument, a namespace in which all the
+generated symbol names are placed.  This error is generated when the
+compiler finds a $NAMESPACE directive with more than one argument.
+
+% NSINVARG      line %1: $NAMESPACE directive has an invalid argument ('%2')
+The $NAMESPACE argument should be a valid C++ namespace.  The reader does a
+cursory check on its validity, checking that the characters in the namespace
+are correct.  The error is generated when the reader finds an invalid
+character. (Valid are alphanumeric characters, underscores and colons.)
+
+% NSNOARG       line %1: no arguments were given to the $NAMESPACE directive
+The $NAMESPACE directive takes a single argument, a namespace in which all the
+generated symbol names are placed.  This error is generated when the
+compiler finds a $NAMESPACE directive with no arguments.
+
+% OPENIN        unable to open message file %1 for input: %2
+The program was not able to open the specified input message file for the
+reason given.
+
+% OPENOUT       unable to open %1 for output: %2
+The program was not able to open the specified output file for the reason
+given.
+
+% PRFEXTRARG    line %1: $PREFIX directive has too many arguments
+The $PREFIX directive takes a single argument, a prefix to be added to the
+symbol names when a C++ .h file is created.  This error is generated when the
+compiler finds a $PREFIX directive with more than one argument.
+
+% PRFINVARG     line %1: $PREFIX directive has an invalid argument ('%2')
+The $PREFIX argument is used in a symbol name in a C++ header file.  As such,
+it must adhere to restrictions on C++ symbol names (e.g. may only contain
+alphanumeric characters or underscores, and may nor start with a digit).
+A $PREFIX directive was found with an argument (given in the message) that
+violates those restictions.
+
+% RDLOCMES      reading local message file %1
+This is an informational message output by BIND10 when it starts to read a
+local message file.  (A local message file may replace the text of one of more
+messages; the ID of the message will not be changed though.)
+
+% READERR       error reading from message file %1: %2
+The specified error was encountered reading from the named message file.
+
+% WRITERR       error writing to %1: %2
+The specified error was encountered by the message compiler when writing to
+the named output file.
+
+% UNRECDIR      line %1: unrecognised directive '%2'
+A line starting with a dollar symbol was found, but the first word on the line
+(shown in the message) was not a recognised message compiler directive.
diff --git a/src/lib/log/strutil.cc b/src/lib/log/strutil.cc
deleted file mode 100644
index 65fb0cd..0000000
--- a/src/lib/log/strutil.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <numeric>
-
-#include <string.h>
-#include <strutil.h>
-
-using namespace std;
-
-namespace isc {
-namespace strutil {
-
-// Normalize slashes
-
-void
-normalizeSlash(std::string& name) {
-    if (!name.empty()) {
-        size_t pos = 0;
-        while ((pos = name.find('\\', pos)) != std::string::npos) {
-            name[pos] = '/';
-        }
-    }
-}
-
-// Trim String
-
-string
-trim(const string& instring) {
-    static const char* blanks = " \t\n";
-
-    string retstring = "";
-    if (!instring.empty()) {
-
-        // Search for first non-blank character in the string
-        size_t first = instring.find_first_not_of(blanks);
-        if (first != string::npos) {
-
-            // String not all blanks, so look for last character
-            size_t last = instring.find_last_not_of(blanks);
-
-            // Extract the trimmed substring
-            retstring = instring.substr(first, (last - first + 1));
-        }
-    }
-
-    return (retstring);
-}
-
-// Tokenise string.  As noted in the header, this is locally written to avoid
-// another dependency on a Boost library.
-
-vector<string>
-tokens(const std::string& text, const std::string& delim) {
-    vector<string> result;
-
-    // Search for the first non-delimiter character
-    size_t start = text.find_first_not_of(delim);
-    while (start != string::npos) {
-
-        // Non-delimiter found, look for next delimiter
-        size_t end = text.find_first_of(delim, start);
-        if (end != string::npos) {
-
-            // Delimiter found, so extract string & search for start of next
-            // non-delimiter segment.
-            result.push_back(text.substr(start, (end - start)));
-            start = text.find_first_not_of(delim, end);
-
-        } else {
-
-            // End of string found, extract rest of string and flag to exit
-            result.push_back(text.substr(start));
-            start = string::npos;
-        }
-    }
-
-    return (result);
-}
-
-// Local function to pass to accumulate() for summing up string lengths.
-
-namespace {
-
-size_t
-lengthSum(string::size_type curlen, const string& cur_string) {
-    return (curlen + cur_string.size());
-}
-
-}
-
-// Provide printf-style formatting.
-
-std::string
-format(const std::string& format, const std::vector<std::string>& args) {
-
-    static const string flag = "%s";
-
-    // Initialize return string.  To speed things up, we'll reserve an
-    // appropriate amount of space - current string size, plus length of all
-    // the argument strings, less two characters for each argument (the %s in
-    // the format string is being replaced).
-    string result;
-    size_t length = accumulate(args.begin(), args.end(), format.size(),
-        lengthSum) - (args.size() * flag.size());
-    result.reserve(length);
-
-    // Iterate through replacing all tokens
-    result = format;
-    size_t tokenpos = 0;    // Position of last token replaced
-    int i = 0;              // Index into argument array
-
-    while ((i < args.size()) && (tokenpos != string::npos)) {
-        tokenpos = result.find(flag, tokenpos);
-        if (tokenpos != string::npos) {
-            result.replace(tokenpos, flag.size(), args[i++]);
-        }
-    }
-
-    return (result);
-}
-
-} // namespace log
-} // namespace isc
diff --git a/src/lib/log/strutil.h b/src/lib/log/strutil.h
deleted file mode 100644
index 087410f..0000000
--- a/src/lib/log/strutil.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __STRUTIL_H
-#define __STRUTIL_H
-
-#include <algorithm>
-#include <cctype>
-#include <string>
-#include <vector>
-
-namespace isc {
-namespace strutil {
-
-/// \brief A Set of C++ Utilities for Manipulating Strings
-
-/// \brief Normalize Backslash
-///
-/// Only relevant to Windows, this replaces all "\" in a string with "/" and
-/// returns the result.  On other systems it is a no-op.  Note that Windows does
-/// recognise file names with the "\" replaced by "/" (at least in system calls,
-/// if not the command line).
-///
-/// \param name Name to be substituted
-void normalizeSlash(std::string& name);
-
-
-/// \brief Trim Leading and Trailing Spaces
-///
-/// Returns a copy of the input string but with any leading or trailing spaces
-/// or tabs removed.
-///
-/// \param instring Input string to modify
-///
-/// \return String with leading and trailing spaces removed
-std::string trim(const std::string& instring);
-
-
-/// \brief Split String into Tokens
-///
-/// Splits a string into tokens (the tokens being delimited by one or more of
-/// the delimiter characters) and returns the tokens in a vector array. Note
-/// that adjacent delimiters are considered to be a single delimiter.
-///
-/// Special cases are:
-/// -# The empty string is considered to be zero tokens.
-/// -# A string comprising nothing but delimiters is considered to be zero
-///    tokens.
-///
-/// The reasoning behind this is that the string can be thought of as having
-/// invisible leading and trailing delimiter characters.  Therefore both cases
-/// reduce to a set of contiguous delimiters, which are considered a single
-/// delimiter (so getting rid of the string).
-///
-/// We could use Boost for this, but this (simple) function eliminates one
-/// dependency in the code.
-///
-/// \param text String to be split.  Passed by value as the internal copy is
-/// altered during the processing.
-/// \param delim Delimiter characters
-///
-/// \return Vector of tokens.
-std::vector<std::string> tokens(const std::string& text,
-        const std::string& delim = std::string(" \t\n"));
-
-
-/// \brief Uppercase Character
-///
-/// Used in uppercase() to pass as an argument to std::transform().  The
-/// function std::toupper() can't be used as it takes an "int" as its argument;
-/// this confuses the template expansion mechanism because dereferencing a
-/// string::iterator returns a char.
-///
-/// \param chr Character to be upper-cased.
-///
-/// \return Uppercase version of the argument
-inline char toUpper(char chr) {
-    return (static_cast<char>(std::toupper(static_cast<int>(chr))));
-}
-
-
-/// \brief Uppercase String
-///
-/// A convenience function to uppercase a string.
-///
-/// \param text String to be upper-cased.
-inline void uppercase(std::string& text) {
-    std::transform(text.begin(), text.end(), text.begin(),
-        isc::strutil::toUpper);
-}
-
-/// \brief Lowercase Character
-///
-/// Used in lowercase() to pass as an argument to std::transform().  The
-/// function std::tolower() can't be used as it takes an "int" as its argument;
-/// this confuses the template expansion mechanism because dereferencing a
-/// string::iterator returns a char.
-///
-/// \param chr Character to be lower-cased.
-///
-/// \return Lowercase version of the argument
-inline char toLower(char chr) {
-    return (static_cast<char>(std::tolower(static_cast<int>(chr))));
-}
-
-/// \brief Lowercase String
-///
-/// A convenience function to lowercase a string
-///
-/// \param text String to be lower-cased.
-inline void lowercase(std::string& text) {
-    std::transform(text.begin(), text.end(), text.begin(),
-        isc::strutil::toLower);
-}
-
-
-/// \brief Apply Formatting
-///
-/// Given a printf-style format string containing only "%s" place holders
-/// (others are ignored) and a vector of strings, this produces a single string
-/// with the placeholders replaced.
-///
-/// \param format Format string
-/// \param args Vector of argument strings
-///
-/// \return Resultant string
-std::string format(const std::string& format,
-    const std::vector<std::string>& args);
-
-
-} // namespace strutil
-} // namespace isc
-
-#endif // __STRUTIL_H
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index 1845706..46065e8 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = .
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 if USE_STATIC_LINK
@@ -15,20 +16,20 @@ TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = root_logger_name_unittest.cc
-run_unittests_SOURCES += filename_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += message_dictionary_unittest.cc
 run_unittests_SOURCES += message_reader_unittest.cc
 run_unittests_SOURCES += message_initializer_unittest.cc
 run_unittests_SOURCES += message_initializer_unittest_2.cc
-run_unittests_SOURCES += strutil_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
+run_unittests_SOURCES += log_formatter_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 endif
 
 TESTS += logger_support_test
@@ -36,6 +37,7 @@ logger_support_test_SOURCES = logger_support_test.cc
 logger_support_test_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 logger_support_test_LDFLAGS = $(AM_LDFLAGS)
 logger_support_test_LDADD  = $(top_builddir)/src/lib/log/liblog.la
+logger_support_test_LDADD += $(top_builddir)/src/lib/util/libutil.la
 
 noinst_PROGRAMS = $(TESTS)
 
diff --git a/src/lib/log/tests/filename_unittest.cc b/src/lib/log/tests/filename_unittest.cc
deleted file mode 100644
index f3032eb..0000000
--- a/src/lib/log/tests/filename_unittest.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <log/filename.h>
-
-using namespace isc;
-using namespace isc::log;
-using namespace std;
-
-class FilenameTest : public ::testing::Test {
-protected:
-    FilenameTest()
-    {
-    }
-};
-
-
-// Check that the name can be changed
-
-TEST_F(FilenameTest, SetName) {
-    Filename fname("/a/b/c.d");
-    EXPECT_EQ("/a/b/c.d", fname.fullName());
-
-    fname.setName("test.txt");
-    EXPECT_EQ("test.txt", fname.fullName());
-}
-
-
-// Check that the components are split correctly.  This is a check of the
-// private member split() method.
-
-TEST_F(FilenameTest, Components) {
-
-    // Complete name
-    Filename fname("/alpha/beta/gamma.delta");
-    EXPECT_EQ("/alpha/beta/", fname.directory());
-    EXPECT_EQ("gamma", fname.name());
-    EXPECT_EQ(".delta", fname.extension());
-
-    // Directory only
-    fname.setName("/gamma/delta/");
-    EXPECT_EQ("/gamma/delta/", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // Filename only
-    fname.setName("epsilon");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("epsilon", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // Extension only
-    fname.setName(".zeta");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ(".zeta", fname.extension());
-
-    // Missing directory
-    fname.setName("eta.theta");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("eta", fname.name());
-    EXPECT_EQ(".theta", fname.extension());
-
-    // Missing filename
-    fname.setName("/iota/.kappa");
-    EXPECT_EQ("/iota/", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ(".kappa", fname.extension());
-
-    // Missing extension
-    fname.setName("lambda/mu/nu");
-    EXPECT_EQ("lambda/mu/", fname.directory());
-    EXPECT_EQ("nu", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // Check that the decomposition can occur in the presence of leading and
-    // trailing spaces
-    fname.setName("  lambda/mu/nu\t  ");
-    EXPECT_EQ("lambda/mu/", fname.directory());
-    EXPECT_EQ("nu", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // Empty string
-    fname.setName("");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // ... and just spaces
-    fname.setName("  ");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    // Check corner cases - where separators are present, but strings are
-    // absent.
-    fname.setName("/");
-    EXPECT_EQ("/", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ("", fname.extension());
-
-    fname.setName(".");
-    EXPECT_EQ("", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ(".", fname.extension());
-
-    fname.setName("/.");
-    EXPECT_EQ("/", fname.directory());
-    EXPECT_EQ("", fname.name());
-    EXPECT_EQ(".", fname.extension());
-
-    // Note that the space is a valid filename here; only leading and trailing
-    // spaces should be trimmed.
-    fname.setName("/ .");
-    EXPECT_EQ("/", fname.directory());
-    EXPECT_EQ(" ", fname.name());
-    EXPECT_EQ(".", fname.extension());
-
-    fname.setName(" / . ");
-    EXPECT_EQ("/", fname.directory());
-    EXPECT_EQ(" ", fname.name());
-    EXPECT_EQ(".", fname.extension());
-}
-
-// Check that the expansion with a default works.
-
-TEST_F(FilenameTest, ExpandWithDefault) {
-    Filename fname("a.b");
-
-    // These tests also check that the trimming of the default component is
-    // done properly.
-    EXPECT_EQ("/c/d/a.b", fname.expandWithDefault(" /c/d/  "));
-    EXPECT_EQ("/c/d/a.b", fname.expandWithDefault("/c/d/e.f"));
-    EXPECT_EQ("a.b", fname.expandWithDefault("e.f"));
-
-    fname.setName("/a/b/c");
-    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault(".d"));
-    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("x.d"));
-    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("/s/t/u.d"));
-    EXPECT_EQ("/a/b/c", fname.expandWithDefault("/s/t/u"));
-
-    fname.setName(".h");
-    EXPECT_EQ("/a/b/c.h", fname.expandWithDefault("/a/b/c.msg"));
-}
-
-// Check that we can use this as a default in expanding a filename
-
-TEST_F(FilenameTest, UseAsDefault) {
-
-    Filename fname("a.b");
-
-    // These tests also check that the trimming of the default component is
-    // done properly.
-    EXPECT_EQ("/c/d/a.b", fname.useAsDefault(" /c/d/  "));
-    EXPECT_EQ("/c/d/e.f", fname.useAsDefault("/c/d/e.f"));
-    EXPECT_EQ("e.f", fname.useAsDefault("e.f"));
-
-    fname.setName("/a/b/c");
-    EXPECT_EQ("/a/b/c.d", fname.useAsDefault(".d"));
-    EXPECT_EQ("/a/b/x.d", fname.useAsDefault("x.d"));
-    EXPECT_EQ("/s/t/u.d", fname.useAsDefault("/s/t/u.d"));
-    EXPECT_EQ("/s/t/u", fname.useAsDefault("/s/t/u"));
-    EXPECT_EQ("/a/b/c", fname.useAsDefault(""));
-}
diff --git a/src/lib/log/tests/log_formatter_unittest.cc b/src/lib/log/tests/log_formatter_unittest.cc
new file mode 100644
index 0000000..b67831a
--- /dev/null
+++ b/src/lib/log/tests/log_formatter_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <log/log_formatter.h>
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+namespace {
+
+class FormatterTest : public ::testing::Test {
+protected:
+    typedef pair<const char*, string> Output;
+    typedef isc::log::Formatter<FormatterTest> Formatter;
+    vector<Output> outputs;
+public:
+    void output(const char* prefix, const string& message) {
+        outputs.push_back(Output(prefix, message));
+    }
+    // Just shortcut for new string
+    string* s(const char* text) {
+        return (new string(text));
+    }
+};
+
+// Create an inactive formatter and check it doesn't produce any output
+TEST_F(FormatterTest, inactive) {
+    Formatter();
+    EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and check it produces output. Does no arg
+// substitution yet
+TEST_F(FormatterTest, active) {
+    Formatter("TEST", s("Text of message"), this);
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("Text of message", outputs[0].second);
+}
+
+// No output even when we have an arg on the inactive formatter
+TEST_F(FormatterTest, inactiveArg) {
+    Formatter().arg("Hello");
+    EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and replace a placeholder with string
+TEST_F(FormatterTest, stringArg) {
+    {
+        SCOPED_TRACE("C++ string");
+        Formatter("TEST", s("Hello %1"), this).arg(string("World"));
+        ASSERT_EQ(1, outputs.size());
+        EXPECT_STREQ("TEST", outputs[0].first);
+        EXPECT_EQ("Hello World", outputs[0].second);
+    }
+    {
+        SCOPED_TRACE("C++ string");
+        Formatter("TEST", s("Hello %1"), this).arg(string("Internet"));
+        ASSERT_EQ(2, outputs.size());
+        EXPECT_STREQ("TEST", outputs[1].first);
+        EXPECT_EQ("Hello Internet", outputs[1].second);
+    }
+}
+
+// Can convert to string
+TEST_F(FormatterTest, intArg) {
+    Formatter("TEST", s("The answer is %1"), this).arg(42);
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("The answer is 42", outputs[0].second);
+}
+
+// Can use multiple arguments at different places
+TEST_F(FormatterTest, multiArg) {
+    Formatter("TEST", s("The %2 are %1"), this).arg("switched").
+        arg("arguments");
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("The arguments are switched", outputs[0].second);
+}
+
+// Can survive and complains if placeholder is missing
+TEST_F(FormatterTest, missingPlace) {
+    EXPECT_NO_THROW(Formatter("TEST", s("Missing the first %2"), this).
+                    arg("missing").arg("argument"));
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("Missing the first argument "
+              "@@Missing placeholder %1 for 'missing'@@", outputs[0].second);
+}
+
+// Can replace multiple placeholders
+TEST_F(FormatterTest, multiPlaceholder) {
+    Formatter("TEST", s("The %1 is the %1"), this).
+        arg("first rule of tautology club");
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("The first rule of tautology club is "
+              "the first rule of tautology club", outputs[0].second);
+}
+
+// Test we can cope with replacement containing the placeholder
+TEST_F(FormatterTest, noRecurse) {
+    // If we recurse, this will probably eat all the memory and crash
+    Formatter("TEST", s("%1"), this).arg("%1 %1");
+    ASSERT_EQ(1, outputs.size());
+    EXPECT_STREQ("TEST", outputs[0].first);
+    EXPECT_EQ("%1 %1", outputs[0].second);
+}
+
+}
diff --git a/src/lib/log/tests/logger_support_test.cc b/src/lib/log/tests/logger_support_test.cc
index 4d8863e..0a2338b 100644
--- a/src/lib/log/tests/logger_support_test.cc
+++ b/src/lib/log/tests/logger_support_test.cc
@@ -23,6 +23,7 @@
 #include <iostream>
 
 #include <log/logger.h>
+#include <log/macros.h>
 #include <log/logger_support.h>
 #include <log/root_logger_name.h>
 
@@ -92,13 +93,14 @@ int main(int argc, char** argv) {
     initLogger("alpha", severity, dbglevel, localfile);
 
     // Log a few messages
-    logger_ex.fatal(MSG_MSGWRTERR, "test1", "42");
-    logger_ex.error(MSG_UNRECDIR, "false");
-    logger_dlm.warn(MSG_MSGRDERR, "a.txt", "dummy test");
-    logger_dlm.info(MSG_OPNMSGIN, "example.msg", "dummy test");
-    logger_ex.debug(0, MSG_UNRECDIR, "[abc]");
-    logger_ex.debug(24, MSG_UNRECDIR, "[24]");
-    logger_ex.debug(25, MSG_UNRECDIR, "[25]");
-    logger_ex.debug(26, MSG_UNRECDIR, "[26]");
+    LOG_FATAL(logger_ex, MSG_WRITERR).arg("test1").arg("42");
+    LOG_ERROR(logger_ex, MSG_RDLOCMES).arg("dummy/file");
+    LOG_WARN(logger_dlm, MSG_READERR).arg("a.txt").arg("dummy reason");
+    LOG_INFO(logger_dlm, MSG_OPENIN).arg("example.msg").arg("dummy reason");
+    LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("dummy/0");
+    LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("dummy/24");
+    LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("dummy/25");
+    LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("dummy/26");
+
     return (0);
 }
diff --git a/src/lib/log/tests/message_dictionary_unittest.cc b/src/lib/log/tests/message_dictionary_unittest.cc
index a92585c..ba33820 100644
--- a/src/lib/log/tests/message_dictionary_unittest.cc
+++ b/src/lib/log/tests/message_dictionary_unittest.cc
@@ -29,7 +29,7 @@ using namespace std;
 // and the latter should be present.
 
 static const char* values[] = {
-    "DUPLNS", "duplicate $NAMESPACE directive found",
+    "MSG_DUPLNS", "duplicate $NAMESPACE directive found",
     "NEWSYM", "new symbol added",
     NULL
 };
@@ -190,7 +190,7 @@ TEST_F(MessageDictionaryTest, GlobalTest) {
 TEST_F(MessageDictionaryTest, GlobalLoadTest) {
     vector<string>& duplicates = MessageInitializer::getDuplicates();
     ASSERT_EQ(1, duplicates.size());
-    EXPECT_EQ(string("DUPLNS"), duplicates[0]);
+    EXPECT_EQ(string("MSG_DUPLNS"), duplicates[0]);
 
     string text = MessageDictionary::globalDictionary().getText("NEWSYM");
     EXPECT_EQ(string("new symbol added"), text);
diff --git a/src/lib/log/tests/message_reader_unittest.cc b/src/lib/log/tests/message_reader_unittest.cc
index 36288f2..7b3ba5f 100644
--- a/src/lib/log/tests/message_reader_unittest.cc
+++ b/src/lib/log/tests/message_reader_unittest.cc
@@ -68,8 +68,8 @@ TEST_F(MessageReaderTest, BlanksAndComments) {
     EXPECT_NO_THROW(reader_.processLine(" \n "));
     EXPECT_NO_THROW(reader_.processLine("# This is a comment"));
     EXPECT_NO_THROW(reader_.processLine("\t\t # Another comment"));
-    EXPECT_NO_THROW(reader_.processLine("  + A description line"));
-    EXPECT_NO_THROW(reader_.processLine("#+ A comment"));
+    EXPECT_NO_THROW(reader_.processLine("  A description line"));
+    EXPECT_NO_THROW(reader_.processLine("# A comment"));
     EXPECT_NO_THROW(reader_.processLine("  +# A description line"));
 
     // ... and (b) nothing gets added to either the map or the not-added section.
@@ -97,6 +97,15 @@ processLineException(MessageReader& reader, const char* what,
     }
 }
 
+// Check that it recognises invalid directives
+
+TEST_F(MessageReaderTest, InvalidDirectives) {
+
+    // Check that a "$" with nothing else generates an error
+    processLineException(reader_, "$", MSG_UNRECDIR);
+    processLineException(reader_, "$xyz", MSG_UNRECDIR);
+}
+
 // Check that it can parse a prefix
 
 TEST_F(MessageReaderTest, Prefix) {
@@ -104,8 +113,8 @@ TEST_F(MessageReaderTest, Prefix) {
     // Check that no $PREFIX is present
     EXPECT_EQ(string(""), reader_.getPrefix());
 
-    // Check that a $PREFIX directive with no argument generates an error.
-    processLineException(reader_, "$PREFIX", MSG_PRFNOARG);
+    // Check that a $PREFIX directive with no argument is OK
+    EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
 
     // Check a $PREFIX with multiple arguments is invalid
     processLineException(reader_, "$prefix A B", MSG_PRFEXTRARG);
@@ -118,17 +127,19 @@ TEST_F(MessageReaderTest, Prefix) {
 
     // A valid prefix should be accepted
     EXPECT_NO_THROW(reader_.processLine("$PREFIX   dlm__"));
-    EXPECT_EQ(string("DLM__"), reader_.getPrefix());
+    EXPECT_EQ(string("dlm__"), reader_.getPrefix());
 
     // And check that the parser fails on invalid prefixes...
     processLineException(reader_, "$prefix 1ABC", MSG_PRFINVARG);
 
-    // ... and rejects another valid one
-    processLineException(reader_, "$PREFIX ABC", MSG_DUPLPRFX);
-
     // Check that we can clear the prefix as well
     reader_.clearPrefix();
     EXPECT_EQ(string(""), reader_.getPrefix());
+
+    EXPECT_NO_THROW(reader_.processLine("$PREFIX   dlm__"));
+    EXPECT_EQ(string("dlm__"), reader_.getPrefix());
+    EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
+    EXPECT_EQ(string(""), reader_.getPrefix());
 }
 
 // Check that it can parse a namespace
@@ -173,8 +184,8 @@ TEST_F(MessageReaderTest, Namespace) {
 TEST_F(MessageReaderTest, ValidMessageAddDefault) {
 
     // Add a couple of valid messages
-    reader_.processLine("GLOBAL1\t\tthis is message global one\n");
-    reader_.processLine("GLOBAL2 this is message global two");
+    reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
+    reader_.processLine("%GLOBAL2 this is message global two");
 
     // ... and check them
     EXPECT_EQ(string("this is message global one"),
@@ -191,9 +202,9 @@ TEST_F(MessageReaderTest, ValidMessageAddDefault) {
 TEST_F(MessageReaderTest, ValidMessageAdd) {
 
     // Add a couple of valid messages
-    reader_.processLine("GLOBAL1\t\tthis is message global one\n",
+    reader_.processLine("%GLOBAL1\t\tthis is message global one\n",
         MessageReader::ADD);
-    reader_.processLine("GLOBAL2 this is message global two",
+    reader_.processLine("% GLOBAL2 this is message global two",
         MessageReader::ADD);
 
     // ... and check them
@@ -214,9 +225,9 @@ TEST_F(MessageReaderTest, ValidMessageReplace) {
     dictionary_->add("GLOBAL2", "original global2 message");
 
     // Replace a couple of valid messages
-    reader_.processLine("GLOBAL1\t\tthis is message global one\n",
+    reader_.processLine("% GLOBAL1\t\tthis is message global one\n",
         MessageReader::REPLACE);
-    reader_.processLine("GLOBAL2 this is message global two",
+    reader_.processLine("% GLOBAL2 this is message global two",
         MessageReader::REPLACE);
 
     // ... and check them
@@ -237,14 +248,14 @@ TEST_F(MessageReaderTest, ValidMessageReplace) {
 TEST_F(MessageReaderTest, Overflows) {
 
     // Add a couple of valid messages
-    reader_.processLine("GLOBAL1\t\tthis is message global one\n");
-    reader_.processLine("GLOBAL2 this is message global two");
+    reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
+    reader_.processLine("% GLOBAL2 this is message global two");
 
     // Add a duplicate in ADD mode.
-    reader_.processLine("GLOBAL1\t\tthis is a replacement for global one");
+    reader_.processLine("% GLOBAL1\t\tthis is a replacement for global one");
 
     // Replace a non-existent one in REPLACE mode
-    reader_.processLine("LOCAL\t\tthis is a new message",
+    reader_.processLine("% LOCAL\t\tthis is a new message",
         MessageReader::REPLACE);
 
     // Check what is in the dictionary.
diff --git a/src/lib/log/tests/run_time_init_test.sh.in b/src/lib/log/tests/run_time_init_test.sh.in
index e2bdf6f..e48a781 100755
--- a/src/lib/log/tests/run_time_init_test.sh.in
+++ b/src/lib/log/tests/run_time_init_test.sh.in
@@ -29,48 +29,49 @@ passfail() {
 # Create the local message file for testing
 
 cat > $localmes << .
-NOTHERE     this message is not in the global dictionary
-MSGRDERR    replacement read error, parameters: '%s' and '%s'
-UNRECDIR    replacement unrecognised directive message, parameter is '%s'
+\$PREFIX MSG_
+% NOTHERE     this message is not in the global dictionary
+% READERR     replacement read error, parameters: '%1' and '%2'
+% RDLOCMES    replacement read local message file, parameter is '%1'
 .
 
 echo -n "1. runInitTest default parameters: "
 cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
-WARN  [alpha.dlm] MSGRDERR, error reading from message file a.txt: dummy test
-INFO  [alpha.dlm] OPNMSGIN, unable to open message file example.msg for input: dummy test
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
+WARN  [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO  [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
 .
 ./logger_support_test | cut -d' ' -f3- | diff $tempfile -
 passfail $?
 
 echo -n "2. Severity filter: "
 cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
 .
 ./logger_support_test -s error | cut -d' ' -f3- | diff $tempfile -
 passfail $?
 
 echo -n "3. Debug level: "
 cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
-WARN  [alpha.dlm] MSGRDERR, error reading from message file a.txt: dummy test
-INFO  [alpha.dlm] OPNMSGIN, unable to open message file example.msg for input: dummy test
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[abc]'
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[24]'
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[25]'
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
+WARN  [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO  [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/0
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/24
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/25
 .
 ./logger_support_test -s debug -d 25 | cut -d' ' -f3- | diff $tempfile -
 passfail $?
 
 echo -n "4. Local message replacement: "
 cat > $tempfile << .
-WARN  [alpha.log] IDNOTFND, could not replace message for 'NOTHERE': no such message identification
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, replacement unrecognised directive message, parameter is 'false'
-WARN  [alpha.dlm] MSGRDERR, replacement read error, parameters: 'a.txt' and 'dummy test'
+WARN  [alpha.log] MSG_IDNOTFND, could not replace message text for 'MSG_NOTHERE': no such message
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, replacement read local message file, parameter is 'dummy/file'
+WARN  [alpha.dlm] MSG_READERR, replacement read error, parameters: 'a.txt' and 'dummy reason'
 .
 ./logger_support_test -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
 passfail $?
diff --git a/src/lib/log/tests/strutil_unittest.cc b/src/lib/log/tests/strutil_unittest.cc
deleted file mode 100644
index b3fceef..0000000
--- a/src/lib/log/tests/strutil_unittest.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <log/strutil.h>
-
-using namespace isc;
-using namespace std;
-
-class StringUtilTest : public ::testing::Test {
-protected:
-    StringUtilTest()
-    {
-    }
-};
-
-
-// Check for slash replacement
-
-TEST_F(StringUtilTest, Slash) {
-
-    string instring = "";
-    isc::strutil::normalizeSlash(instring);
-    EXPECT_EQ("", instring);
-
-    instring = "C:\\A\\B\\C.D";
-    isc::strutil::normalizeSlash(instring);
-    EXPECT_EQ("C:/A/B/C.D", instring);
-
-    instring = "// \\ //";
-    isc::strutil::normalizeSlash(instring);
-    EXPECT_EQ("// / //", instring);
-}
-
-// Check that leading and trailing space trimming works
-
-TEST_F(StringUtilTest, Trim) {
-
-    // Empty and full string.
-    EXPECT_EQ("", isc::strutil::trim(""));
-    EXPECT_EQ("abcxyz", isc::strutil::trim("abcxyz"));
-
-    // Trim right-most blanks
-    EXPECT_EQ("ABC", isc::strutil::trim("ABC   "));
-    EXPECT_EQ("ABC", isc::strutil::trim("ABC\t\t  \n\t"));
-
-    // Left-most blank trimming
-    EXPECT_EQ("XYZ", isc::strutil::trim("  XYZ"));
-    EXPECT_EQ("XYZ", isc::strutil::trim("\t\t  \tXYZ"));
-
-    // Right and left, with embedded spaces
-    EXPECT_EQ("MN \t OP", isc::strutil::trim("\t\tMN \t OP \t"));
-}
-
-// Check tokenization.  Note that ASSERT_EQ is used to check the size of the
-// returned vector; if not as expected, the following references may be invalid
-// so should not be used.
-
-TEST_F(StringUtilTest, Tokens) {
-    vector<string>  result;
-
-    // Default delimiters
-
-    // Degenerate cases
-    result = isc::strutil::tokens("");          // Empty string
-    EXPECT_EQ(0, result.size());
-
-    result = isc::strutil::tokens(" \n ");      // String is all delimiters
-    EXPECT_EQ(0, result.size());
-
-    result = isc::strutil::tokens("abc");       // String has no delimiters
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("abc"), result[0]);
-
-    // String containing leading and/or trailing delimiters, no embedded ones.
-    result = isc::strutil::tokens("\txyz");     // One leading delimiter
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("xyz"), result[0]);
-
-    result = isc::strutil::tokens("\t \nxyz");  // Multiple leading delimiters
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("xyz"), result[0]);
-
-    result = isc::strutil::tokens("xyz\n");     // One trailing delimiter
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("xyz"), result[0]);
-
-    result = isc::strutil::tokens("xyz  \t");   // Multiple trailing
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("xyz"), result[0]);
-
-    result = isc::strutil::tokens("\t xyz \n"); // Leading and trailing
-    ASSERT_EQ(1, result.size());
-    EXPECT_EQ(string("xyz"), result[0]);
-
-    // Embedded delimiters
-    result = isc::strutil::tokens("abc\ndef");  // 2 tokens, one separator
-    ASSERT_EQ(2, result.size());
-    EXPECT_EQ(string("abc"), result[0]);
-    EXPECT_EQ(string("def"), result[1]);
-
-    result = isc::strutil::tokens("abc\t\t\ndef");  // 2 tokens, 3 separators
-    ASSERT_EQ(2, result.size());
-    EXPECT_EQ(string("abc"), result[0]);
-    EXPECT_EQ(string("def"), result[1]);
-
-    result = isc::strutil::tokens("abc\n  \tdef\t\tghi");
-    ASSERT_EQ(3, result.size());                // Multiple tokens, many delims
-    EXPECT_EQ(string("abc"), result[0]);
-    EXPECT_EQ(string("def"), result[1]);
-    EXPECT_EQ(string("ghi"), result[2]);
-
-    // Embedded and non-embedded delimiters
-
-    result = isc::strutil::tokens("\t\t  \nabc\n  \tdef\t\tghi   \n\n");
-    ASSERT_EQ(3, result.size());                // Multiple tokens, many delims
-    EXPECT_EQ(string("abc"), result[0]);
-    EXPECT_EQ(string("def"), result[1]);
-    EXPECT_EQ(string("ghi"), result[2]);
-
-    // Non-default delimiter
-    result = isc::strutil::tokens("alpha/beta/ /gamma//delta/epsilon/", "/");
-    ASSERT_EQ(6, result.size());
-    EXPECT_EQ(string("alpha"), result[0]);
-    EXPECT_EQ(string("beta"), result[1]);
-    EXPECT_EQ(string(" "), result[2]);
-    EXPECT_EQ(string("gamma"), result[3]);
-    EXPECT_EQ(string("delta"), result[4]);
-    EXPECT_EQ(string("epsilon"), result[5]);
-
-    // Non-default delimiters (plural)
-    result = isc::strutil::tokens("+*--alpha*beta+ -gamma**delta+epsilon-+**",
-        "*+-");
-    ASSERT_EQ(6, result.size());
-    EXPECT_EQ(string("alpha"), result[0]);
-    EXPECT_EQ(string("beta"), result[1]);
-    EXPECT_EQ(string(" "), result[2]);
-    EXPECT_EQ(string("gamma"), result[3]);
-    EXPECT_EQ(string("delta"), result[4]);
-    EXPECT_EQ(string("epsilon"), result[5]);
-}
-
-// Changing case
-
-TEST_F(StringUtilTest, ChangeCase) {
-    string mixed("abcDEFghiJKLmno123[]{=+--+]}");
-    string upper("ABCDEFGHIJKLMNO123[]{=+--+]}");
-    string lower("abcdefghijklmno123[]{=+--+]}");
-
-    string test = mixed;
-    isc::strutil::lowercase(test);
-    EXPECT_EQ(lower, test);
-
-    test = mixed;
-    isc::strutil::uppercase(test);
-    EXPECT_EQ(upper, test);
-}
-
-// Formatting
-
-TEST_F(StringUtilTest, Formatting) {
-
-    vector<string> args;
-    args.push_back("arg1");
-    args.push_back("arg2");
-    args.push_back("arg3");
-
-    string format1 = "This is a string with no tokens";
-    EXPECT_EQ(format1, isc::strutil::format(format1, args));
-
-    string format2 = "";    // Empty string
-    EXPECT_EQ(format2, isc::strutil::format(format2, args));
-
-    string format3 = "   ";    // Empty string
-    EXPECT_EQ(format3, isc::strutil::format(format3, args));
-
-    string format4 = "String with %d non-string tokens %lf";
-    EXPECT_EQ(format4, isc::strutil::format(format4, args));
-
-    string format5 = "String with %s correct %s number of tokens %s";
-    string result5 = "String with arg1 correct arg2 number of tokens arg3";
-    EXPECT_EQ(result5, isc::strutil::format(format5, args));
-
-    string format6 = "String with %s too %s few tokens";
-    string result6 = "String with arg1 too arg2 few tokens";
-    EXPECT_EQ(result6, isc::strutil::format(format6, args));
-
-    string format7 = "String with %s too %s many %s tokens %s !";
-    string result7 = "String with arg1 too arg2 many arg3 tokens %s !";
-    EXPECT_EQ(result7, isc::strutil::format(format7, args));
-
-    string format8 = "String with embedded%s%s%stokens";
-    string result8 = "String with embeddedarg1arg2arg3tokens";
-    EXPECT_EQ(result8, isc::strutil::format(format8, args));
-
-    // Handle an empty vector
-    args.clear();
-    string format9 = "%s %s";
-    EXPECT_EQ(format9, isc::strutil::format(format9, args));
-}
diff --git a/src/lib/nsas/Makefile.am b/src/lib/nsas/Makefile.am
index 43300f6..3ecbca7 100644
--- a/src/lib/nsas/Makefile.am
+++ b/src/lib/nsas/Makefile.am
@@ -3,40 +3,61 @@ SUBDIRS = . tests
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
 AM_CPPFLAGS += $(SQLITE_CFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
-# Some versions of GCC warn about some versions of Boost regarding
-# missing initializer for members in its posix_time.
+# Some versions of GCC warn about some versions of Boost regarding missing
+# initializer for members in its posix_time.
 # https://svn.boost.org/trac/boost/ticket/3477
 # But older GCC compilers don't have the flag.
 AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 
-if USE_CLANGPP
 # clang++ complains about unused function parameters in some boost header
 # files.
+if USE_CLANGPP
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 
+# Define rule to build logging source files from message file
+nsasdef.h nsasdef.cc: nsasdef.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/nsas/nsasdef.mes
+
+# What is being built.
 lib_LTLIBRARIES = libnsas.la
+
+# Tell Automake that the nsasdef.{cc,h} source files are created in the build
+# process, so it must create these before doing anything else.  Although they
+# are a dependency of the library (so will be created from the message file
+# anyway), there is no guarantee as to exactly _when_ in the build they will be
+# created.  As the .h file is included in other sources file (so must be
+# present when they are compiled), the safest option is to create it first.
+BUILT_SOURCES = nsasdef.h nsasdef.cc
+
+# Library sources. The generated files will not be in the distribution.
 libnsas_la_SOURCES  = address_entry.h address_entry.cc
 libnsas_la_SOURCES += asiolink.h
 libnsas_la_SOURCES += hash.cc hash.h
 libnsas_la_SOURCES += hash_deleter.h
 libnsas_la_SOURCES += hash_key.cc hash_key.h
-libnsas_la_SOURCES += locks.h
 libnsas_la_SOURCES += hash_table.h
-libnsas_la_SOURCES += lru_list.h
 libnsas_la_SOURCES += nameserver_address_store.cc nameserver_address_store.h
 libnsas_la_SOURCES += nameserver_address.h nameserver_address.cc
 libnsas_la_SOURCES += nameserver_entry.cc nameserver_entry.h
 libnsas_la_SOURCES += nsas_entry_compare.h
 libnsas_la_SOURCES += nsas_entry.h nsas_types.h
+libnsas_la_SOURCES += nsas_log.cc nsas_log.h
 libnsas_la_SOURCES += zone_entry.cc zone_entry.h
 libnsas_la_SOURCES += fetchable.h
 libnsas_la_SOURCES += address_request_callback.h
-libnsas_la_SOURCES += random_number_generator.h
 libnsas_la_SOURCES += glue_hints.h glue_hints.cc
 
-CLEANFILES = *.gcno *.gcda
+nodist_libnsas_la_SOURCES  = nsasdef.h nsasdef.cc
+
+# The message file should be in the distribution.
+EXTRA_DIST = nsasdef.mes
+
+# Make sure that the generated files are got rid of in a clean operation
+CLEANFILES = *.gcno *.gcda nsasdef.h nsasdef.cc
diff --git a/src/lib/nsas/glue_hints.cc b/src/lib/nsas/glue_hints.cc
index d4c653a..02c27ee 100644
--- a/src/lib/nsas/glue_hints.cc
+++ b/src/lib/nsas/glue_hints.cc
@@ -58,7 +58,7 @@ namespace {
         const std::string ns_name = rrset->getName().toText();
         RdataIteratorPtr rdi = rrset->getRdataIterator();
         while (!rdi->isLast()) {
-            AddressEntry entry(asiolink::IOAddress(rdi->getCurrent().toText()));
+            AddressEntry entry(isc::asiolink::IOAddress(rdi->getCurrent().toText()));
             boost::shared_ptr<NameserverEntry> ns_entry(new NameserverEntry(ns_name, rrset->getClass()));
             NameserverAddress ns_address(ns_entry, entry, V4_ONLY);
             addresses.push_back(ns_address);
diff --git a/src/lib/nsas/hash_deleter.h b/src/lib/nsas/hash_deleter.h
index 29a32d7..27f066e 100644
--- a/src/lib/nsas/hash_deleter.h
+++ b/src/lib/nsas/hash_deleter.h
@@ -16,8 +16,9 @@
 #define __HASH_DELETER_H
 
 #include <boost/shared_ptr.hpp>
+#include <util/lru_list.h>
+
 #include "hash_table.h"
-#include "lru_list.h"
 
 namespace isc {
 namespace nsas {
@@ -31,7 +32,7 @@ namespace nsas {
 /// hash table without the need to be declared as "friend" or the need
 /// to define accessor methods.
 template <typename T>
-class HashDeleter : public LruList<T>::Dropped {
+class HashDeleter : public isc::util::LruList<T>::Dropped {
 public:
 
     /// \brief Constructor
diff --git a/src/lib/nsas/hash_table.h b/src/lib/nsas/hash_table.h
index c4a9913..c028fa4 100644
--- a/src/lib/nsas/hash_table.h
+++ b/src/lib/nsas/hash_table.h
@@ -19,7 +19,8 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include "locks.h"
+#include <util/locks.h>
+
 #include "hash.h"
 #include "hash_key.h"
 
@@ -47,7 +48,7 @@ struct HashTableSlot {
     typedef typename std::list<boost::shared_ptr<T> >::iterator  iterator;
                                     ///< Iterator over elements with same hash
 
-    typedef isc::locks::upgradable_mutex mutex_type;
+    typedef isc::util::locks::upgradable_mutex mutex_type;
                                     ///< Mutex protecting this slot
     //@}
 
@@ -114,11 +115,11 @@ public:
     ///
     //@{
     typedef typename
-    isc::locks::sharable_lock<typename HashTableSlot<T>::mutex_type>
+    isc::util::locks::sharable_lock<typename HashTableSlot<T>::mutex_type>
     sharable_lock;                  ///< Type for a scope-limited read-lock
 
     typedef typename
-    isc::locks::scoped_lock<typename HashTableSlot<T>::mutex_type>
+    isc::util::locks::scoped_lock<typename HashTableSlot<T>::mutex_type>
     scoped_lock;                    ///< Type for a scope-limited write-lock
     //@}
 
diff --git a/src/lib/nsas/locks.h b/src/lib/nsas/locks.h
deleted file mode 100644
index 98197c3..0000000
--- a/src/lib/nsas/locks.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-/// This file (right now) provides dummy locks
-/// It also contains code to use boost/threads locks:
-///
-/// if USE_BOOST_THREADS is defined, we typedef the relevant classes
-/// and derive from the relevant templates so our dummy locks are
-/// replaced by the boost locks (--enable-boost-threads)
-///
-/// If USE_BOOST_THREADS is NOT defined, all locks are dummy classes
-/// that don't actually do anything. At this moment, only the very
-/// minimal set of methods that we actually use is defined.
-///
-/// Note that we need to include <config.h> in our .cc files for that
-/// to be set. we might want to enfore this at compile time with a check
-/// (TODO)
-/// Note that this also contains a workaround for Sunstudio; which
-/// probably won't completely work right now (that is, if the TODO
-/// above is completed), since that would also require some changes
-/// in most (at first glance unrelated) Makefiles
-/// (TODO2)
-
-#ifndef __LOCKS_
-#define __LOCKS_
-
-#ifndef USE_BOOST_THREADS
-
-namespace isc {
-namespace locks {
-
-class mutex {
-};
-
-class recursive_mutex {
-};
-
-class upgradable_mutex {
-};
-
-template <typename T>
-class sharable_lock {
-public:
-    sharable_lock(T) { }
-};
-
-template <typename T>
-class scoped_lock {
-public:
-    scoped_lock(T) { }
-
-    void lock() {}
-    void unlock() {}
-};
-
-}
-}
-
-#else // USE_BOOST_THREADS
-
-// Workaround for a problem with boost and sunstudio 5.10
-// There is a version check in there that appears wrong,
-// which makes including boost/thread.hpp fail
-// This will probably be fixed in a future version of boost,
-// in which case this part can be removed then
-#ifdef NEED_SUNPRO_WORKAROUND
-#if defined(__SUNPRO_CC) && __SUNPRO_CC == 0x5100
-#undef __SUNPRO_CC
-#define __SUNPRO_CC 0x5090
-#endif
-#endif // NEED_SUNPRO_WORKAROUND
-
-#include <boost/thread.hpp>
-#include <boost/interprocess/sync/sharable_lock.hpp>
-#include <boost/interprocess/sync/scoped_lock.hpp>
-#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
-#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
-
-namespace isc {
-namespace locks {
-
-typedef boost::mutex mutex;
-typedef boost::interprocess::interprocess_upgradable_mutex upgradable_mutex;
-typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex;
-
-template <typename T>
-struct sharable_lock : public boost::interprocess::sharable_lock<T> {
-public:
-    sharable_lock(T&  mtype) : boost::interprocess::sharable_lock<T>(mtype) {}
-};
-
-
-template <class T>
-struct scoped_lock : public boost::interprocess::scoped_lock<T> {
-public:
-    scoped_lock(T& mtype) : boost::interprocess::scoped_lock<T>(mtype) { }
-};
-
-}
-}
-
-
-#endif // USE_BOOST_THREADS
-
-#endif // __LOCKS_
diff --git a/src/lib/nsas/lru_list.h b/src/lib/nsas/lru_list.h
deleted file mode 100644
index b057baf..0000000
--- a/src/lib/nsas/lru_list.h
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __LRU_LIST_H
-#define __LRU_LIST_H
-
-#include <list>
-#include <string>
-
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include "locks.h"
-
-namespace isc {
-namespace nsas {
-
-/// \brief LRU List
-///
-/// Provides the LRU list for the zone and nameserver objects.  The list is
-/// created with a specific size.  Entries are added to the back of the list
-/// and removed from the front.  It is also possible to pull an element out
-/// of the middle of the list and add it to the end of the list, an action that
-/// should be done when the element is referenced.
-///
-/// It is not intended that the class be copied, and the derivation from
-/// boost::noncopyable enforces this.
-template <typename T>
-class LruList : boost::noncopyable {
-public:
-    typedef typename std::list<boost::shared_ptr<T> > lru_list;
-    typedef typename lru_list::iterator               iterator;
-
-    /// \brief Dropped Operation
-    ///
-    /// When an object is dropped from the LRU list because it has not been
-    /// accessed for some time, it is possible that the action should trigger
-    /// some other functions.  For this reason, it is possible to register
-    /// a list-wide functor object to execute in this casee.
-    ///
-    /// Note that the function does not execute as the result of a call to
-    /// remove() - that is an explicit call and it is assumed that the caller
-    /// will handle any additional operations needed.
-    class Dropped {
-    public:
-        /// \brief Constructor
-        Dropped(){}
-
-        /// \brief Virtual Destructor
-        virtual ~Dropped(){}
-
-        /// \brief Dropped Object Handler
-        ///
-        /// Function object called when the object drops off the end of the
-        /// LRU list.
-        ///
-        /// \param drop Object being dropped.
-        virtual void operator()(T* drop) const = 0;
-    };
-
-    /// \brief Constructor
-    ///
-    /// \param max_size Maximum size of the list before elements are dropped.
-    /// \param dropped Pointer to a function object that will get called as
-    /// elements are dropped.  This object will be stored using a shared_ptr,
-    /// so should be allocated with new().
-    LruList(uint32_t max_size = 1000, Dropped* dropped = NULL) :
-        max_size_(max_size), count_(0), dropped_(dropped)
-    {}
-
-    /// \brief Virtual Destructor
-    virtual ~LruList()
-    {}
-
-    /// \brief Add Element
-    ///
-    /// Add a new element to the end of the list.
-    ///
-    /// \param element Reference to the element to add.
-    ///
-    /// \return Handle describing the element in the LRU list.
-    virtual void add(boost::shared_ptr<T>& element);
-
-    /// \brief Remove Element
-    ///
-    /// Removes an element from the list.  If the element is not present (i.e.
-    /// its internal list pointer is invalid), this is a no-op.
-    ///
-    /// \param element Reference to the element to remove.
-    virtual void remove(boost::shared_ptr<T>& element);
-
-    /// \brief Touch Element
-    ///
-    /// The name comes from the Unix "touch" command.  All this does is to
-    /// move the specified entry from the middle of the list to the end of
-    /// the list.
-    ///
-    /// \param element Reference to the element to touch.
-    virtual void touch(boost::shared_ptr<T>& element);
-
-    /// \brief Drop All the Elements in the List .
-    ///
-    /// All the elements will be dropped from the list container, and their
-    /// drop handler(if there is one) will be called, when done, the size of
-    /// of list will be 0.
-    virtual void clear();
-
-    /// \brief Return Size of the List
-    ///
-    /// An independent count is kept of the list size, as list.size() may take
-    /// some time if the list is big.
-    ///
-    /// \return Number of elements in the list
-    virtual uint32_t size() const {
-
-        // Don't bother to lock the mutex.  If an update is in progress, we
-        // receive either the value just before the update or just after it.
-        // Either way, this call could have come just before or just after
-        // that operation, so the value would have been just as uncertain.
-        return count_;
-    }
-
-    /// \brief Return Maximum Size
-    ///
-    /// \return Maximum size of the list
-    virtual uint32_t getMaxSize() const {
-        return max_size_;
-    }
-
-    /// \brief Set Maximum Size
-    ///
-    /// \param max_size New maximum list size
-    virtual void setMaxSize(uint32_t max_size) {
-        max_size_ = max_size;
-    }
-
-private:
-    isc::locks::mutex                   mutex_;     ///< List protection
-    std::list<boost::shared_ptr<T> >    lru_;       ///< The LRU list itself
-    uint32_t                            max_size_;  ///< Max size of the list
-    uint32_t                            count_;     ///< Count of elements
-    boost::shared_ptr<Dropped>          dropped_;   ///< Dropped object
-};
-
-// Add entry to the list
-template <typename T>
-void LruList<T>::add(boost::shared_ptr<T>& element) {
-
-    // Protect list against concurrent access
-    isc::locks::scoped_lock<isc::locks::mutex> lock(mutex_);
-
-    // Add the entry and set its pointer field to point into the list.
-    // insert() is used to get the pointer.
-    element->setLruIterator(lru_.insert(lru_.end(), element));
-
-    // ... and update the count while we have the mutex.
-    ++count_;
-
-    // If the count takes us above the maximum size of the list, remove elements
-    // from the front.  The current list size could be more than one above the
-    // maximum size of the list if the maximum size was changed after
-    // construction.
-    while (count_ > max_size_) {
-        if (!lru_.empty()) {
-
-            // Run the drop handler (if there is one) on the
-
-            // to-be-dropped object.
-            if (dropped_) {
-                (*dropped_)(lru_.begin()->get());
-            }
-
-            // ... and get rid of it from the list
-            lru_.pop_front();
-            --count_;
-        }
-        else {
-
-            // TODO: Log this condition (count_ > 0 when list empty) -
-            // it should not happen
-            count_ = 0;
-            break;
-        }
-    }
-}
-
-// Remove an element from the list
-template <typename T>
-void LruList<T>::remove(boost::shared_ptr<T>& element) {
-
-    // An element can only be removed it its internal pointer is valid.
-    // If it is, the pointer can be used to access the list because no matter
-    // what other elements are added or removed, the pointer remains valid.
-    //
-    // If the pointer is not valid, this is a no-op.
-    if (element->iteratorValid()) {
-
-        // Is valid, so protect list against concurrent access
-        isc::locks::scoped_lock<isc::locks::mutex> lock(mutex_);
-
-        lru_.erase(element->getLruIterator());  // Remove element from list
-        element->invalidateIterator();          // Invalidate pointer
-        --count_;                               // One less element
-    }
-}
-
-// Touch an element - remove it from the list and add to the end
-template <typename T>
-void LruList<T>::touch(boost::shared_ptr<T>& element) {
-
-    // As before, if the pointer is not valid, this is a no-op.
-    if (element->iteratorValid()) {
-
-        // Protect list against concurrent access
-        isc::locks::scoped_lock<isc::locks::mutex> lock(mutex_);
-
-        // Move the element to the end of the list.
-        lru_.splice(lru_.end(), lru_, element->getLruIterator());
-
-        // Update the iterator in the element to point to it.  We can
-        // offset from end() as a list has a bidirectional iterator.
-        iterator i = lru_.end();
-        element->setLruIterator(--i);
-    }
-}
-
-// Clear the list-  when done, the size of list will be 0.
-template <typename T>
-void LruList<T>::clear() {
-    // Protect list against concurrent access
-    isc::locks::scoped_lock<isc::locks::mutex> lock(mutex_);
-
-    // ... and update the count while we have the mutex.
-    count_ = 0;
-    typename std::list<boost::shared_ptr<T> >::iterator iter;
-    if (dropped_) {
-        for (iter = lru_.begin(); iter != lru_.end(); ++iter) {
-            // Call the drop handler.
-            (*dropped_)(iter->get());
-        }
-    }
-
-    lru_.clear();
-}
-
-}   // namespace nsas
-}   // namespace isc
-
-#endif // __LRU_LIST_H
diff --git a/src/lib/nsas/nameserver_address_store.cc b/src/lib/nsas/nameserver_address_store.cc
index e92c177..ac55409 100644
--- a/src/lib/nsas/nameserver_address_store.cc
+++ b/src/lib/nsas/nameserver_address_store.cc
@@ -20,10 +20,11 @@
 
 #include <config.h>
 #include <dns/rdataclass.h>
+#include <util/locks.h>
+#include <util/lru_list.h>
+#include <log/logger.h>
 
-#include "locks.h"
 #include "hash_table.h"
-#include "lru_list.h"
 #include "hash_deleter.h"
 #include "nsas_entry_compare.h"
 #include "nameserver_entry.h"
@@ -31,6 +32,8 @@
 #include "zone_entry.h"
 #include "glue_hints.h"
 #include "address_request_callback.h"
+#include "nsasdef.h"
+#include "nsas_log.h"
 
 using namespace isc::dns;
 using namespace std;
@@ -50,9 +53,9 @@ NameserverAddressStore::NameserverAddressStore(
         zonehashsize)),
     nameserver_hash_(new HashTable<NameserverEntry>(
         new NsasEntryCompare<NameserverEntry>, nshashsize)),
-    zone_lru_(new LruList<ZoneEntry>((3 * zonehashsize),
+    zone_lru_(new isc::util::LruList<ZoneEntry>((3 * zonehashsize),
         new HashDeleter<ZoneEntry>(*zone_hash_))),
-    nameserver_lru_(new LruList<NameserverEntry>((3 * nshashsize),
+    nameserver_lru_(new isc::util::LruList<NameserverEntry>((3 * nshashsize),
         new HashDeleter<NameserverEntry>(*nameserver_hash_))),
     resolver_(resolver.get())
 { }
@@ -70,7 +73,7 @@ newZone(
     isc::resolve::ResolverInterface* resolver,
     const string* zone, const RRClass* class_code,
     const boost::shared_ptr<HashTable<NameserverEntry> >* ns_hash,
-    const boost::shared_ptr<LruList<NameserverEntry> >* ns_lru)
+    const boost::shared_ptr<isc::util::LruList<NameserverEntry> >* ns_lru)
 {
     boost::shared_ptr<ZoneEntry> result(new ZoneEntry(resolver, *zone, *class_code,
         *ns_hash, *ns_lru));
@@ -84,6 +87,8 @@ NameserverAddressStore::lookup(const string& zone, const RRClass& class_code,
     boost::shared_ptr<AddressRequestCallback> callback, AddressFamily family,
     const GlueHints& glue_hints)
 {
+    LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_LOOKUPZONE).arg(zone);
+
     pair<bool, boost::shared_ptr<ZoneEntry> > zone_obj(
         zone_hash_->getOrAdd(HashKey(zone, class_code),
                              boost::bind(newZone, resolver_, &zone, &class_code,
@@ -103,6 +108,8 @@ NameserverAddressStore::cancel(const string& zone,
     const boost::shared_ptr<AddressRequestCallback>& callback,
     AddressFamily family)
 {
+    LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_LOOKUPCANCEL).arg(zone);
+
     boost::shared_ptr<ZoneEntry> entry(zone_hash_->get(HashKey(zone,
                                                                class_code)));
     if (entry) {
diff --git a/src/lib/nsas/nameserver_address_store.h b/src/lib/nsas/nameserver_address_store.h
index d54be84..87845c9 100644
--- a/src/lib/nsas/nameserver_address_store.h
+++ b/src/lib/nsas/nameserver_address_store.h
@@ -32,11 +32,13 @@ namespace dns {
 class RRClass;
 }
 
+namespace util {
+template<class T> class LruList;
+}
+
 namespace nsas {
 
-class ResolverInterface;
 template<class T> class HashTable;
-template<class T> class LruList;
 class ZoneEntry;
 class NameserverEntry;
 class AddressRequestCallback;
@@ -112,8 +114,8 @@ protected:
     boost::shared_ptr<HashTable<NameserverEntry> > nameserver_hash_;
 
     // ... and the LRU lists
-    boost::shared_ptr<LruList<ZoneEntry> > zone_lru_;
-    boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru_;
+    boost::shared_ptr<isc::util::LruList<ZoneEntry> > zone_lru_;
+    boost::shared_ptr<isc::util::LruList<NameserverEntry> > nameserver_lru_;
     // The resolver we use
 private:
     isc::resolve::ResolverInterface* resolver_;
diff --git a/src/lib/nsas/nameserver_entry.cc b/src/lib/nsas/nameserver_entry.cc
index 40d5cd7..65b2ec2 100644
--- a/src/lib/nsas/nameserver_entry.cc
+++ b/src/lib/nsas/nameserver_entry.cc
@@ -40,8 +40,9 @@
 #include "address_entry.h"
 #include "nameserver_address.h"
 #include "nameserver_entry.h"
+#include "nsas_log.h"
 
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace isc::nsas;
 using namespace isc::dns;
 using namespace std;
@@ -52,7 +53,7 @@ namespace nsas {
 namespace {
 
 // Just shorter type alias
-typedef isc::locks::scoped_lock<isc::locks::recursive_mutex> Lock;
+typedef isc::util::locks::scoped_lock<isc::util::locks::recursive_mutex> Lock;
 
 }
 
@@ -178,6 +179,9 @@ NameserverEntry::updateAddressRTTAtIndex(uint32_t rtt, size_t index,
         new_rtt = 1;
     }
     addresses_[family][index].setRTT(new_rtt);
+    LOG_DEBUG(nsas_logger, NSAS_DBG_RTT, NSAS_SETRTT)
+              .arg(addresses_[family][index].getAddress().toText())
+              .arg(old_rtt).arg(new_rtt);
 }
 
 void
@@ -203,7 +207,7 @@ NameserverEntry::setAddressUnreachable(const IOAddress& address) {
  * \short A callback into the resolver.
  *
  * Whenever we ask the resolver something, this is created and the answer is
- * fed back trough this. It holds a shared pointer to the entry so it is not
+ * fed back through this. It holds a shared pointer to the entry so it is not
  * destroyed too soon.
  */
 class NameserverEntry::ResolverCallback :
@@ -230,6 +234,7 @@ class NameserverEntry::ResolverCallback :
             if (!response_message ||
                 response_message->getRcode() != isc::dns::Rcode::NOERROR() ||
                 response_message->getRRCount(isc::dns::Message::SECTION_ANSWER) == 0) {
+                LOG_ERROR(nsas_logger, NSAS_INVRESPSTR).arg(entry_->getName());
                 failureInternal(lock);
                 return;
             }
@@ -243,7 +248,12 @@ class NameserverEntry::ResolverCallback :
             if (response->getType() != type_ ||
                 response->getClass() != RRClass(entry_->getClass()))
             {
-                // TODO Log we got answer of different type
+                // Invalid response type or class
+                LOG_ERROR(nsas_logger, NSAS_INVRESPTC)
+                          .arg(entry_->getName()).arg(type_)
+                          .arg(entry_->getClass()).arg(response->getType())
+                          .arg(response->getClass());
+
                 failureInternal(lock);
                 return;
             }
@@ -264,8 +274,10 @@ class NameserverEntry::ResolverCallback :
                     }
                 }
                 // If we found it, use it. If not, create a new one.
-                entries.push_back(found ? *found : AddressEntry(IOAddress(
-                    i->getCurrent().toText()), 1));
+                entries.push_back(found ? *found : AddressEntry(
+                                                   IOAddress(address), 1));
+                LOG_DEBUG(nsas_logger, NSAS_DBG_RESULTS, NSAS_NSLKUPSUCC)
+                          .arg(address).arg(entry_->getName());
             }
 
             // We no longer need the previous set of addresses, we have
@@ -310,6 +322,8 @@ class NameserverEntry::ResolverCallback :
          * So mark the current address family as unreachable.
          */
         virtual void failure() {
+            LOG_DEBUG(nsas_logger, NSAS_DBG_RESULTS, NSAS_NSLKUPFAIL)
+                      .arg(type_).arg(entry_->getName());
             Lock lock(entry_->mutex_);
             failureInternal(lock);
         }
@@ -422,6 +436,8 @@ NameserverEntry::askIP(isc::resolve::ResolverInterface* resolver,
         // Ask for both types of addresses
         // We are unlocked here, as the callback from that might want to lock
         lock.unlock();
+
+        LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_NSADDR).arg(getName());
         askIP(resolver, RRType::A(), V4_ONLY);
         askIP(resolver, RRType::AAAA(), V6_ONLY);
         // Make sure we end the routine when we are not locked
diff --git a/src/lib/nsas/nameserver_entry.h b/src/lib/nsas/nameserver_entry.h
index 99d7ff5..0f214c6 100644
--- a/src/lib/nsas/nameserver_entry.h
+++ b/src/lib/nsas/nameserver_entry.h
@@ -25,11 +25,12 @@
 
 #include <resolve/resolver_interface.h>
 
+#include <util/lru_list.h>
+
 #include "address_entry.h"
 #include "asiolink.h"
 #include "nsas_types.h"
 #include "hash_key.h"
-#include "lru_list.h"
 #include "fetchable.h"
 #include "nsas_entry.h"
 #include "nameserver_address.h"
@@ -246,7 +247,7 @@ public:
     //@}
 
 private:
-    mutable isc::locks::recursive_mutex    mutex_;///< Mutex protecting this object
+    mutable isc::util::locks::recursive_mutex    mutex_;///< Mutex protecting this object
     std::string     name_;              ///< Canonical name of the nameserver
     isc::dns::RRClass classCode_;       ///< Class of the nameserver
     /**
diff --git a/src/lib/nsas/nsas_entry.h b/src/lib/nsas/nsas_entry.h
index f739e8d..9cbed11 100644
--- a/src/lib/nsas/nsas_entry.h
+++ b/src/lib/nsas/nsas_entry.h
@@ -19,10 +19,10 @@
 #include <iostream>
 
 #include <exceptions/exceptions.h>
+#include <util/lru_list.h>
 
 #include "hash_key.h"
 #include "hash_table.h"
-#include "lru_list.h"
 
 namespace isc {
 namespace nsas {
@@ -66,7 +66,7 @@ public:
 /// This class is inherited from boost::enable_shared_from_this class
 /// So within a member function a shared_ptr to current object can be obtained
 template <typename T>
-class NsasEntry : public boost::enable_shared_from_this <T>  {
+class NsasEntry : public boost::enable_shared_from_this <T> {
 public:
 
     /// \brief Default Constructor
@@ -93,7 +93,7 @@ public:
     /// Sets the iterator of an object and, as a side effect, marks it as valid.
     ///
     /// \param iterator Iterator of this element in the list
-    virtual void setLruIterator(typename LruList<T>::iterator iterator) {
+    virtual void setLruIterator(typename isc::util::LruList<T>::iterator iterator) {
         iterator_ = iterator;
         valid_ = true;
     }
@@ -103,7 +103,7 @@ public:
     /// \return iterator Iterator of this element in the list.
     ///
     /// \exception InvalidLruIterator Thrown if the iterator is not valid.
-    virtual typename LruList<T>::iterator getLruIterator() const {
+    virtual typename isc::util::LruList<T>::iterator getLruIterator() const {
         if (! valid_) {
             isc_throw(InvalidLruIterator,
                 "pointer of element into LRU list was not valid");
@@ -127,7 +127,7 @@ public:
     }
 
 private:
-    typename LruList<T>::iterator  iterator_;  ///< Handle into the LRU List
+    typename isc::util::LruList<T>::iterator  iterator_;  ///< Handle into the LRU List
     bool                           valid_;     ///< true if handle is valid
 };
 
diff --git a/src/lib/nsas/nsas_log.cc b/src/lib/nsas/nsas_log.cc
new file mode 100644
index 0000000..931b131
--- /dev/null
+++ b/src/lib/nsas/nsas_log.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// Defines the logger used by the NSAS
+
+#include "nsas/nsas_log.h"
+
+namespace isc {
+namespace nsas {
+
+isc::log::Logger nsas_logger("nsas");
+
+} // namespace nsas
+} // namespace isc
+
diff --git a/src/lib/nsas/nsas_log.h b/src/lib/nsas/nsas_log.h
new file mode 100644
index 0000000..9631988
--- /dev/null
+++ b/src/lib/nsas/nsas_log.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __NSAS_LOG__H
+#define __NSAS_LOG__H
+
+#include <log/macros.h>
+#include "nsasdef.h"
+
+namespace isc {
+namespace nsas {
+
+/// \brief NSAS Logging
+///
+/// Defines the levels used to output debug messages in the NSAS.  Note that
+/// higher numbers equate to more verbose (and detailed) output.
+
+// The first level traces normal operations - asking the NSAS for an address,
+// and cancelling a lookup.  It also records when the NSAS calls back to the
+// resolver to resolve something.
+const int NSAS_DBG_TRACE = 10;
+
+// The next level extends the normal operations and records the results of the
+// lookups.
+const int NSAS_DBG_RESULTS = 20;
+
+// Additional information on the usage of the names - the RTT values obtained
+// when queries were done.
+const int NSAS_DBG_RTT = 30;
+
+
+/// \brief NSAS Logger
+///
+/// Define the logger used to log messages.  We could define it in multiple
+/// modules, but defining in a single module and linking to it saves time and
+/// space.
+extern isc::log::Logger nsas_logger;    // isc::nsas::logger is the NSAS logger
+
+} // namespace nsas
+} // namespace isc
+
+#endif // __NSAS_LOG__H
diff --git a/src/lib/nsas/nsasdef.mes b/src/lib/nsas/nsasdef.mes
new file mode 100644
index 0000000..0f32d09
--- /dev/null
+++ b/src/lib/nsas/nsasdef.mes
@@ -0,0 +1,61 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX NSAS_
+$NAMESPACE isc::nsas
+
+% INVRESPSTR      queried for %1 but got invalid response
+This message indicates an internal error in the nameserver address store
+component (NSAS) of the resolver.  The NSAS made a query for a RR for the
+specified nameserver but received an invalid response.  Either the success
+function was called without a DNS message or the message was invalid on some
+way. (In the latter case, the error should have been picked up elsewhere in
+the processing logic, hence the raising of the error here.)
+
+% INVRESPTC       queried for %1 RR of type/class %2/%3, received response %4/%5
+This message indicates an internal error in the nameserver address store
+component (NSAS) of the resolver.  The NSAS made a query for the given RR
+type and class, but instead received an answer with the given type and class.
+
+% LOOKUPCANCEL    lookup for zone %1 has been cancelled
+A debug message, this is output when a NSAS (nameserver address store -
+part of the resolver) lookup for a zone has been cancelled.
+
+% LOOKUPZONE      searching NSAS for nameservers for zone %1
+A debug message, this is output when a call is made to the nameserver address
+store (part of the resolver) to obtain the nameservers for the specified zone.
+
+% NSADDR          asking resolver to obtain A and AAAA records for %1
+A debug message, the NSAS (nameserver address store - part of the resolver) is
+making a callback into the resolver to retrieve the address records for the
+specified nameserver.
+
+% NSLKUPFAIL      failed to lookup any %1 for %2
+A debug message, the NSAS (nameserver address store - part of the resolver)
+has been unable to retrieve the specified resource record for the specified
+nameserver.  This is not necessarily a problem - the nameserver may be
+unreachable, in which case the NSAS will try other nameservers in the zone.
+
+% NSLKUPSUCC      found address %1 for %2
+A debug message, the NSAS (nameserver address store - part of the resolver)
+has retrieved the given address for the specified nameserver through an
+external query.
+
+% SETRTT          reporting RTT for %1 as %2; new value is now %3
+A NSAS (nameserver address store - part of the resolver) debug message
+reporting the round-trip time (RTT) for a query made to the specified
+nameserver.  The RTT has been updated using the value given and the new RTT is
+displayed.  (The RTT is subject to a calculation that damps out sudden
+changes.  As a result, the new RTT is not necessarily equal to the RTT
+reported.)
diff --git a/src/lib/nsas/random_number_generator.h b/src/lib/nsas/random_number_generator.h
deleted file mode 100644
index 8884d0e..0000000
--- a/src/lib/nsas/random_number_generator.h
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __NSAS_RANDOM_NUMBER_GENERATOR_H
-#define __NSAS_RANDOM_NUMBER_GENERATOR_H
-
-#include <algorithm>
-#include <cmath>
-#include <numeric>
-
-#include <exceptions/exceptions.h>
-
-#include <boost/random/mersenne_twister.hpp>
-#include <boost/random/uniform_int.hpp>
-#include <boost/random/uniform_real.hpp>
-#include <boost/random/variate_generator.hpp>
-
-namespace isc {
-namespace nsas {
-
-class InvalidLimits : public isc::BadValue {
-public:
-    InvalidLimits(const char* file, size_t line, const char* what) :
-        isc::BadValue(file, line, what) {}
-};
-
-class SumNotOne : public isc::BadValue {
-public:
-    SumNotOne(const char* file, size_t line, const char* what) :
-        isc::BadValue(file, line, what) {}
-};
-
-class InvalidProbValue : public isc::BadValue {
-public:
-    InvalidProbValue(const char* file, size_t line, const char* what) :
-        isc::BadValue(file, line, what) {}
-};
-
-
-
-/// \brief Uniform random integer generator
-///
-/// Generate uniformly distributed integers in range of [min, max]
-class UniformRandomIntegerGenerator{
-public:
-    /// \brief Constructor
-    ///
-    /// \param min The minimum number in the range
-    /// \param max The maximum number in the range
-    UniformRandomIntegerGenerator(int min, int max):
-        min_(std::min(min, max)), max_(std::max(min, max)),
-        dist_(min_, max_), generator_(rng_, dist_)
-    {
-        // To preserve the restriction of the underlying uniform_int class (and
-        // to retain compatibility with earlier versions of the class), we will
-        // abort if the minimum and maximum given are the wrong way round.
-        if (min > max) {
-            isc_throw(InvalidLimits, "minimum limit is greater than maximum "
-                      "when initializing UniformRandomIntegerGenerator");
-        }
-
-        // Init with the current time
-        rng_.seed(time(NULL));
-    }
-
-    /// \brief Generate uniformly distributed integer
-    int operator()() { return generator_(); }
-private:
-    /// Hide default and copy constructor
-    UniformRandomIntegerGenerator();///< Default constructor
-    UniformRandomIntegerGenerator(const UniformRandomIntegerGenerator&); ///< Copy constructor
-
-    int min_;                       ///< The minimum integer that can generate
-    int max_;                       ///< The maximum integer that can generate
-    boost::uniform_int<> dist_;     ///< Distribute uniformly.
-    boost::mt19937 rng_;            ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator
-    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_; ///< Uniform generator
-};
-
-/// \brief Weighted random integer generator
-///
-/// Generate random integers according different probabilities
-class WeightedRandomIntegerGenerator {
-public:
-    /// \brief Constructor
-    ///
-    /// \param probabilities The probabies for all the integers, the probability must be 
-    /// between 0 and 1.0, the sum of probabilities must be equal to 1.
-    /// For example, if the probabilities contains the following values:
-    /// 0.5 0.3 0.2, the 1st integer will be generated more frequently than the
-    /// other integers and the probability is proportional to its value.
-    /// \param min The minimum integer that generated, other integers will be 
-    /// min, min + 1, ..., min + probabilities.size() - 1
-    WeightedRandomIntegerGenerator(const std::vector<double>& probabilities,
-        size_t min = 0):
-        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min)
-    {
-        // The probabilities must be valid.  Checking is quite an expensive
-        // operation, so is only done in a debug build.
-        assert(areProbabilitiesValid(probabilities));
-
-        // Calculate the partial sum of probabilities
-        std::partial_sum(probabilities.begin(), probabilities.end(),
-                                     std::back_inserter(cumulative_));
-        // Init with the current time
-        rng_.seed(time(NULL));
-    }
-
-    /// \brief Default constructor
-    ///
-    WeightedRandomIntegerGenerator():
-        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0)
-    {
-    }
-
-    /// \brief Reset the probabilities
-    ///
-    /// Change the weights of each integers
-    /// \param probabilities The probabies for all the integers
-    /// \param min The minimum integer that generated
-    void reset(const std::vector<double>& probabilities, size_t min = 0)
-    {
-        // The probabilities must be valid.
-        assert(areProbabilitiesValid(probabilities));
-
-        // Reset the cumulative sum
-        cumulative_.clear();
-
-        // Calculate the partial sum of probabilities
-        std::partial_sum(probabilities.begin(), probabilities.end(),
-                                     std::back_inserter(cumulative_));
-
-        // Reset the minimum integer
-        min_ = min;
-    }
-
-    /// \brief Generate weighted random integer
-    size_t operator()()
-    {
-        return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_()) 
-            - cumulative_.begin() + min_;
-    }
-
-private:
-    /// \brief Check the validation of probabilities vector
-    ///
-    /// The probability must be in range of [0, 1.0] and the sum must be equal
-    /// to 1.0.  Empty probabilities are also valid.
-    ///
-    /// Checking the probabilities is quite an expensive operation, so it is
-    /// only done during a debug build (via a call through assert()).  However,
-    /// instead of letting assert() call abort(), if this method encounters an
-    /// error, an exception is thrown.  This makes unit testing somewhat easier.
-    ///
-    /// \param probabilities Vector of probabilities.
-    bool areProbabilitiesValid(const std::vector<double>& probabilities) const
-    {
-        typedef std::vector<double>::const_iterator Iterator;
-        double sum = probabilities.empty() ? 1.0 : 0.0;
-        for(Iterator it = probabilities.begin(); it != probabilities.end(); ++it){
-            //The probability must be in [0, 1.0]
-            if(*it < 0.0 || *it > 1.0) {
-                isc_throw(InvalidProbValue,
-                          "probability must be in the range 0..1");
-            }
-
-            sum += *it;
-        }
-
-        double epsilon = 0.0001;
-        // The sum must be equal to 1
-       if (std::fabs(sum - 1.0) >= epsilon) {
-           isc_throw(SumNotOne, "Sum of probabilities is not equal to 1");
-       }
-
-       return true;
-    }
-
-    std::vector<double> cumulative_;    ///< Partial sum of the probabilities
-    boost::mt19937 rng_;                ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator 
-    boost::uniform_real<> dist_;        ///< Uniformly distributed real numbers
-
-    // Shortcut typedef
-    // This typedef is placed directly before its use, as the sunstudio
-    // compiler could not handle it being anywhere else (don't know why)
-    typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator;
-    UniformRealGenerator uniform_real_gen_;     ///< Uniformly distributed random real numbers generator
-
-    size_t min_;                                ///< The minimum integer that will be generated
-};
-
-}   // namespace dns
-}   // namespace isc
-
-
-#endif//__NSAS_RANDOM_NUMBER_GENERATOR_H
diff --git a/src/lib/nsas/tests/Makefile.am b/src/lib/nsas/tests/Makefile.am
index 9d9e61c..e9235ba 100644
--- a/src/lib/nsas/tests/Makefile.am
+++ b/src/lib/nsas/tests/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = .
 AM_CPPFLAGS  = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
@@ -33,7 +34,6 @@ run_unittests_SOURCES += hash_deleter_unittest.cc
 run_unittests_SOURCES += hash_key_unittest.cc
 run_unittests_SOURCES += hash_table_unittest.cc
 run_unittests_SOURCES += hash_unittest.cc
-run_unittests_SOURCES += lru_list_unittest.cc
 run_unittests_SOURCES += nameserver_address_unittest.cc
 run_unittests_SOURCES += nameserver_address_store_unittest.cc
 run_unittests_SOURCES += nameserver_entry_unittest.cc
@@ -41,7 +41,6 @@ run_unittests_SOURCES += nsas_entry_compare_unittest.cc
 run_unittests_SOURCES += nsas_test.h
 run_unittests_SOURCES += zone_entry_unittest.cc
 run_unittests_SOURCES += fetchable_unittest.cc
-run_unittests_SOURCES += random_number_generator_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -53,6 +52,8 @@ run_unittests_LDADD += -lboost_thread
 endif
 
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/nsas/tests/address_entry_unittest.cc b/src/lib/nsas/tests/address_entry_unittest.cc
index 02fef51..60aa3cc 100644
--- a/src/lib/nsas/tests/address_entry_unittest.cc
+++ b/src/lib/nsas/tests/address_entry_unittest.cc
@@ -32,7 +32,7 @@ static std::string V4B_TEXT("5.6.7.8");
 static std::string V6A_TEXT("2001:dead:beef::");
 static std::string V6B_TEXT("1984:1985::1986:1987");
 
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace std;
 using namespace isc::nsas;
 
diff --git a/src/lib/nsas/tests/hash_deleter_unittest.cc b/src/lib/nsas/tests/hash_deleter_unittest.cc
index 97fecbe..c370857 100644
--- a/src/lib/nsas/tests/hash_deleter_unittest.cc
+++ b/src/lib/nsas/tests/hash_deleter_unittest.cc
@@ -22,11 +22,11 @@
 #include <boost/lexical_cast.hpp>
 
 #include <dns/rrclass.h>
+#include <util/lru_list.h>
 
 #include "../nsas_entry.h"
 #include "../hash_table.h"
 #include "../hash_key.h"
-#include "../lru_list.h"
 #include "../hash_deleter.h"
 
 #include "nsas_test.h"
@@ -34,6 +34,7 @@
 
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace isc {
 namespace nsas {
diff --git a/src/lib/nsas/tests/lru_list_unittest.cc b/src/lib/nsas/tests/lru_list_unittest.cc
deleted file mode 100644
index e286826..0000000
--- a/src/lib/nsas/tests/lru_list_unittest.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <iostream>
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-#include <boost/lexical_cast.hpp>
-
-#include "../nsas_entry.h"
-#include "../lru_list.h"
-
-#include "nsas_test.h"
-
-using namespace std;
-
-namespace isc {
-namespace nsas {
-
-/// \brief Dropped Functor Class
-///
-/// Functor object is called when an object is dropped from the LRU list.
-/// To prove that it has run, this function does nothing more than set the
-/// MS bit on the 16-bit class value.
-class Dropped : public LruList<TestEntry>::Dropped {
-public:
-    virtual void operator()(TestEntry* entry) const {
-        entry->setClass(RRClass(entry->getClass().getCode() | 0x8000));
-    }
-};
-
-
-/// \brief Text Fixture Class
-class LruListTest : public ::testing::Test {
-protected:
-    LruListTest() :
-        entry1_(new TestEntry("alpha", RRClass::IN())),
-        entry2_(new TestEntry("beta", RRClass::CH())),
-        entry3_(new TestEntry("gamma", RRClass::HS())),
-        entry4_(new TestEntry("delta", RRClass::IN())),
-        entry5_(new TestEntry("epsilon", RRClass::HS())),
-        entry6_(new TestEntry("zeta", RRClass::CH())),
-        entry7_(new TestEntry("eta", RRClass::IN()))
-    {}
-
-    virtual ~LruListTest() 
-    {}
-
-    boost::shared_ptr<TestEntry>    entry1_;
-    boost::shared_ptr<TestEntry>    entry2_;
-    boost::shared_ptr<TestEntry>    entry3_;
-    boost::shared_ptr<TestEntry>    entry4_;
-    boost::shared_ptr<TestEntry>    entry5_;
-    boost::shared_ptr<TestEntry>    entry6_;
-    boost::shared_ptr<TestEntry>    entry7_;
-};
-
-
-// Test of the constructor
-TEST_F(LruListTest, Constructor) {
-    LruList<TestEntry>  lru(100);
-    EXPECT_EQ(100, lru.getMaxSize());
-    EXPECT_EQ(0, lru.size());
-}
-
-// Test of Get/Set the maximum number of entrys
-TEST_F(LruListTest, GetSet) {
-    LruList<TestEntry>  lru(100);
-    EXPECT_EQ(100, lru.getMaxSize());
-    lru.setMaxSize(42);
-    EXPECT_EQ(42, lru.getMaxSize());
-}
-
-// Test that adding an entry really does add an entry
-TEST_F(LruListTest, Add) {
-    LruList<TestEntry>  lru(100);
-    EXPECT_EQ(0, lru.size());
-
-    lru.add(entry1_);
-    EXPECT_EQ(1, lru.size());
-
-    lru.add(entry2_);
-    EXPECT_EQ(2, lru.size());
-}
-
-// Test that removing an entry really does remove it.
-TEST_F(LruListTest, Remove) {
-    LruList<TestEntry>  lru(100);
-    EXPECT_EQ(0, lru.size());
-
-    EXPECT_FALSE(entry1_->iteratorValid());
-    lru.add(entry1_);
-    EXPECT_TRUE(entry1_->iteratorValid());
-    EXPECT_EQ(1, lru.size());
-
-    EXPECT_FALSE(entry2_->iteratorValid());
-    lru.add(entry2_);
-    EXPECT_TRUE(entry2_->iteratorValid());
-    EXPECT_EQ(2, lru.size());
-
-    lru.remove(entry1_);
-    EXPECT_FALSE(entry1_->iteratorValid());
-    EXPECT_EQ(1, lru.size());
-}
-
-// Check that adding a new entry to a limited size list does delete the
-// oldest entry from the list.
-TEST_F(LruListTest, SizeLimit) {
-    LruList<TestEntry>  lru(3);
-    EXPECT_EQ(0, lru.size());
-
-    // Add first entry and check that the shared pointer's reference count
-    // has increased.  There will be two references: one from the "entry1_"
-    // member in the test fixture class, and one from the list.
-    EXPECT_EQ(1, entry1_.use_count());
-    lru.add(entry1_);
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(1, lru.size());
-
-    // Same for entry 2.
-    EXPECT_EQ(1, entry2_.use_count());
-    lru.add(entry2_);
-    EXPECT_EQ(2, entry2_.use_count());
-    EXPECT_EQ(2, lru.size());
-
-    // Same for entry 3.
-    EXPECT_EQ(1, entry3_.use_count());
-    lru.add(entry3_);
-    EXPECT_EQ(2, entry3_.use_count());
-    EXPECT_EQ(3, lru.size());
-
-    // Adding entry 4 should remove entry 1 from the list.  This will
-    // delete the list's shared pointer to the entry and will therefore
-    // drop the reference count back to one (from the "entry1_" member in
-    // the text fixture class).
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(1, entry4_.use_count());
-    lru.add(entry4_);
-    EXPECT_EQ(1, entry1_.use_count());
-    EXPECT_EQ(2, entry4_.use_count());
-    EXPECT_EQ(3, lru.size());
-
-    // Adding entry 5 should remove entry 2 from the list.
-    EXPECT_EQ(2, entry2_.use_count());
-    EXPECT_EQ(1, entry5_.use_count());
-    lru.add(entry5_);
-    EXPECT_EQ(1, entry2_.use_count());
-    EXPECT_EQ(2, entry5_.use_count());
-    EXPECT_EQ(3, lru.size());
-}
-
-// Check that "touching" an entry adds it to the back of the list.
-TEST_F(LruListTest, Touch) {
-
-    // Create the list
-    LruList<TestEntry>  lru(3);
-    EXPECT_EQ(0, lru.size());
-    lru.add(entry1_);
-    lru.add(entry2_);
-    lru.add(entry3_);
-
-    // Check the reference counts of the entrys and the list size
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(2, entry2_.use_count());
-    EXPECT_EQ(2, entry3_.use_count());
-    EXPECT_EQ(1, entry4_.use_count());
-    EXPECT_EQ(1, entry5_.use_count());
-    EXPECT_EQ(1, entry6_.use_count());
-    EXPECT_EQ(1, entry7_.use_count());
-    EXPECT_EQ(3, lru.size());
-
-    // "Touch" the first entry
-    lru.touch(entry1_);
-
-    // Adding two more entries should not remove the touched entry.
-    lru.add(entry4_);
-    lru.add(entry5_);
-
-    // Check the status of the entrys and the list.
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(1, entry2_.use_count());
-    EXPECT_EQ(1, entry3_.use_count());
-    EXPECT_EQ(2, entry4_.use_count());
-    EXPECT_EQ(2, entry5_.use_count());
-    EXPECT_EQ(1, entry6_.use_count());
-    EXPECT_EQ(1, entry7_.use_count());
-    EXPECT_EQ(3, lru.size());
-
-    // Now touch the entry agin to move it to the back of the list.
-    // This checks that the iterator stored in the entry as a result of the
-    // last touch operation is valid.
-    lru.touch(entry1_);
-
-    // Check this by adding two more entrys and checking reference counts
-    // to see what is stored.
-    lru.add(entry6_);
-    lru.add(entry7_);
-
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(1, entry2_.use_count());
-    EXPECT_EQ(1, entry3_.use_count());
-    EXPECT_EQ(1, entry4_.use_count());
-    EXPECT_EQ(1, entry5_.use_count());
-    EXPECT_EQ(2, entry6_.use_count());
-    EXPECT_EQ(2, entry7_.use_count());
-    EXPECT_EQ(3, lru.size());
-}
-
-// Dropped functor tests: tests that the function object is called when an
-// object expires from the list.
-TEST_F(LruListTest, Dropped) {
-
-    // Create an object with an expiration handler.
-    LruList<TestEntry> lru(3, new Dropped());
-
-    // Fill the list
-    lru.add(entry1_);
-    lru.add(entry2_);
-    lru.add(entry3_);
-
-    EXPECT_EQ(RRClass::IN(), entry1_->getClass());
-    EXPECT_EQ(RRClass::CH(), entry2_->getClass());
-
-    // Add another entry and check that the handler runs.
-    EXPECT_EQ(0, (entry1_->getClass().getCode() & 0x8000));
-    lru.add(entry4_);
-    EXPECT_NE(0, (entry1_->getClass().getCode() & 0x8000));
-
-    EXPECT_EQ(0, (entry2_->getClass().getCode() & 0x8000));
-    lru.add(entry5_);
-    EXPECT_NE(0, (entry2_->getClass().getCode() & 0x8000));
-
-    // Delete an entry and check that the handler does not run. 
-    EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000));
-    lru.remove(entry3_);
-    EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000));
-}
-
-// Clear functor tests: tests whether all the elements in
-// the list are dropped properly and the size of list is
-// set to 0.
-TEST_F(LruListTest, Clear) {
-    // Create an object with an expiration handler.
-    LruList<TestEntry> lru(3, new Dropped());
-
-    // Fill the list
-    lru.add(entry1_);
-    lru.add(entry2_);
-    lru.add(entry3_);
-
-    EXPECT_EQ(RRClass::IN(), entry1_->getClass());
-    EXPECT_EQ(RRClass::CH(), entry2_->getClass());
-    EXPECT_EQ(RRClass::HS(), entry3_->getClass());
-
-    EXPECT_EQ(0, (entry1_->getClass().getCode() & 0x8000));
-    EXPECT_EQ(0, (entry2_->getClass().getCode() & 0x8000));
-    EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000));
-
-    // Clear the lru list, and check the drop handler run
-    lru.clear();
-    EXPECT_NE(0, (entry1_->getClass().getCode() & 0x8000));
-    EXPECT_NE(0, (entry2_->getClass().getCode() & 0x8000));
-    EXPECT_NE(0, (entry3_->getClass().getCode() & 0x8000));
- 
-    EXPECT_EQ(0, lru.size());
-}
-
-// Miscellaneous tests - pathological conditions
-TEST_F(LruListTest, Miscellaneous) {
-
-    // Zero size list should not allow entrys to be added
-    LruList<TestEntry> lru_1(0);
-    lru_1.add(entry1_);
-    EXPECT_EQ(0, lru_1.size());
-    EXPECT_EQ(1, entry1_.use_count());
-
-    // Removing an uninserted entry should not affect the list.
-    LruList<TestEntry> lru_2(100);
-    lru_2.add(entry1_);
-    lru_2.add(entry2_);
-    lru_2.add(entry3_);
-    EXPECT_EQ(3, lru_2.size());
-
-    lru_2.remove(entry4_);
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(2, entry2_.use_count());
-    EXPECT_EQ(2, entry3_.use_count());
-    EXPECT_EQ(1, entry4_.use_count());
-    EXPECT_EQ(1, entry5_.use_count());
-    EXPECT_EQ(3, lru_2.size());
-
-    // Touching an uninserted entry should not affect the list.
-    lru_2.touch(entry5_);
-    EXPECT_EQ(2, entry1_.use_count());
-    EXPECT_EQ(2, entry2_.use_count());
-    EXPECT_EQ(2, entry3_.use_count());
-    EXPECT_EQ(1, entry4_.use_count());
-    EXPECT_EQ(1, entry5_.use_count());
-    EXPECT_EQ(3, lru_2.size());
-}
-
-}   // namespace nsas
-}   // namespace isc
diff --git a/src/lib/nsas/tests/nameserver_address_store_unittest.cc b/src/lib/nsas/tests/nameserver_address_store_unittest.cc
index 9133daf..abbac1d 100644
--- a/src/lib/nsas/tests/nameserver_address_store_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_store_unittest.cc
@@ -12,34 +12,36 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <config.h>
-
-/// \brief Test Deleter Objects
+/// \brief Nameserver Address Store Tests
 ///
-/// This file contains tests for the "deleter" classes within the nameserver
-/// address store.  These act to delete zones from the zone hash table when
-/// the element reaches the top of the LRU list.
+/// This file contains tests for the nameserver address store as a whole.
 
-#include <dns/rrttl.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
+#include <algorithm>
+#include <cassert>
+#include <string.h>
+#include <vector>
 
-#include <gtest/gtest.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
 
-#include <string.h>
-#include <cassert>
+#include <config.h>
 
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/rrttl.h>
+
+#include "../address_request_callback.h"
 #include "../nameserver_address_store.h"
-#include "../nsas_entry_compare.h"
 #include "../nameserver_entry.h"
+#include "../nsas_entry_compare.h"
 #include "../zone_entry.h"
-#include "../address_request_callback.h"
 #include "nsas_test.h"
 
 using namespace isc::dns;
+using namespace isc::util;
 using namespace std;
 
 namespace isc {
@@ -66,43 +68,62 @@ public:
     virtual ~DerivedNsas()
     {}
 
-    /// \brief Add Nameserver Entry to Hash and LRU Tables
+    /// \brief Add Nameserver Entry to hash and LRU tables
+    ///
+    /// \param entry Nameserver Entry to add.
     void AddNameserverEntry(boost::shared_ptr<NameserverEntry>& entry) {
         HashKey h = entry->hashKey();
         nameserver_hash_->add(entry, h);
         nameserver_lru_->add(entry);
     }
 
-    /// \brief Add Zone Entry to Hash and LRU Tables
+    /// \brief Add Zone Entry to hash and LRU tables
+    ///
+    /// \param entry Zone Entry to add.
     void AddZoneEntry(boost::shared_ptr<ZoneEntry>& entry) {
         HashKey h = entry->hashKey();
         zone_hash_->add(entry, h);
         zone_lru_->add(entry);
     }
-    /**
-     * \short Just wraps the common lookup
-     *
-     * It calls the lookup and provides the authority section
-     * if it is asked for by the resolver.
-     */
+
+    /// \brief Wrap the common lookup
+    ///
+    /// Calls the lookup and provides the authority section if it is asked
+    /// for by the resolver.
+    ///
+    /// \param name Name of zone for which an address is required
+    /// \param class_code Class of the zone
+    /// \param authority Pointer to authority section RRset to which NS
+    ///        records will be added.
+    /// \param callback Callback object used to pass result back to caller
     void lookupAndAnswer(const string& name, const RRClass& class_code,
-        RRsetPtr authority,
-        boost::shared_ptr<AddressRequestCallback> callback)
+                         RRsetPtr authority,
+                         boost::shared_ptr<AddressRequestCallback> callback)
     {
+        // Note how many requests are in the resolver's queue
         size_t size(resolver_->requests.size());
+
+        // Lookup the name.  This should generate a request for NS records.
         NameserverAddressStore::lookup(name, class_code, callback, ANY_OK);
-        // It asked something, the only thing it can ask is the NS list
         if (size < resolver_->requests.size()) {
+
+            // It asked something, the only thing it can ask is the NS list.
+            // Once answered, drop the request so no-one else sees it
             resolver_->provideNS(size, authority);
-            // Once answered, drop the request so noone else sees it
             resolver_->requests.erase(resolver_->requests.begin() + size);
+
         } else {
-            ADD_FAILURE() << "Not asked for NS";
+
+            // The test resolver's requests queue has not increased in size,
+            // so the lookup did not generate a request.
+            ADD_FAILURE() << "Lookup did not generate a request for NS records";
         }
     }
+
 private:
-    boost::shared_ptr<TestResolver> resolver_;
-};
+    boost::shared_ptr<TestResolver> resolver_; 
+                                ///< Resolver used to answer generated requests
+};                                              
 
 
 
@@ -110,6 +131,7 @@ private:
 class NameserverAddressStoreTest : public TestWithRdata {
 protected:
 
+    /// \brief Constructor
     NameserverAddressStoreTest() :
         authority_(new RRset(Name("example.net."), RRClass::IN(), RRType::NS(),
             RRTTL(128))),
@@ -117,8 +139,8 @@ protected:
             RRType::NS(), RRTTL(128))),
         resolver_(new TestResolver)
     {
-        // Constructor - initialize a set of nameserver and zone objects.  For
-        // convenience, these are stored in vectors.
+        // Initialize a set of nameserver and zone objects.  For convenience,
+        // these are stored in vectors.
         for (int i = 1; i <= 9; ++i) {
             std::string name = "nameserver" + boost::lexical_cast<std::string>(
                 i);
@@ -144,57 +166,70 @@ protected:
         NSASCallback::results.clear();
     }
 
+    /// \brief Internal callback object
+    ///
+    /// Callback object.  It just records whether the success() or
+    /// unreachable() methods were called and if success, a copy of the
+    /// Nameserver object. (The data is held in a static object that will
+    /// outlive the lifetime of the callback object.)
+    struct NSASCallback : public AddressRequestCallback {
+        typedef pair<bool, NameserverAddress> Result;
+        static vector<Result> results;
+
+        virtual void success(const NameserverAddress& address) {
+            results.push_back(Result(true, address));
+        }
+        virtual void unreachable() {
+            results.push_back(Result(false, NameserverAddress()));
+        }
+    };
+
+    /// \brief Return pointer to callback object
+    boost::shared_ptr<AddressRequestCallback> getCallback() {
+        return (boost::shared_ptr<AddressRequestCallback>(new NSASCallback));
+    }
+
+    // Member variables
+
     // Vector of pointers to nameserver and zone entries.
     std::vector<boost::shared_ptr<NameserverEntry> > nameservers_;
     std::vector<boost::shared_ptr<ZoneEntry> >       zones_;
 
-    RRsetPtr authority_, empty_authority_;
+    // Authority sections used in the tests
+    RRsetPtr authority_;
+    RRsetPtr empty_authority_;
 
+    // ... and the resolver
     boost::shared_ptr<TestResolver> resolver_;
-
-    class NSASCallback : public AddressRequestCallback {
-        public:
-            typedef pair<bool, NameserverAddress> Result;
-            static vector<Result> results;
-            virtual void success(const NameserverAddress& address) {
-                results.push_back(Result(true, address));
-            }
-            virtual void unreachable() {
-                results.push_back(Result(false, NameserverAddress()));
-            }
-    };
-
-    boost::shared_ptr<AddressRequestCallback> getCallback() {
-        return (boost::shared_ptr<AddressRequestCallback>(new NSASCallback));
-    }
 };
 
+/// Definition of the static results object
 vector<NameserverAddressStoreTest::NSASCallback::Result>
     NameserverAddressStoreTest::NSASCallback::results;
 
 
 /// \brief Remove Zone Entry from Hash Table
 ///
-/// Check that when an entry reaches the top of the zone LRU list, it is removed from the
-/// hash table as well.
+/// Check that when an entry reaches the top of the zone LRU list, it is removed
+/// from the hash table as well.
 TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) {
 
-    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and
-    // nameserver tables).
+    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone
+    // and nameserver tables).
     DerivedNsas nsas(resolver_, 2, 2);
 
-    // Add six entries to the tables.  After addition the reference count of each element
-    // should be 3 - one for the entry in the zones_ vector, and one each for the entries
-    // in the LRU list and hash table.
+    // Add six entries to the tables.  After addition the reference count of
+    // each element should be 3 - one for the entry in the zones_ vector, and
+    // one each for the entries in the LRU list and hash table.
     for (int i = 1; i <= 6; ++i) {
         EXPECT_EQ(1, zones_[i].use_count());
         nsas.AddZoneEntry(zones_[i]);
         EXPECT_EQ(3, zones_[i].use_count());
     }
 
-    // Adding another entry should cause the first one to drop off the LRU list, which
-    // should also trigger the deletion of the entry from the hash table.  This should
-    // reduce its use count to 1.
+    // Adding another entry should cause the first one to drop off the LRU list,
+    // which should also trigger the deletion of the entry from the hash table.
+    //  This should reduce its use count to 1.
     EXPECT_EQ(1, zones_[7].use_count());
     nsas.AddZoneEntry(zones_[7]);
     EXPECT_EQ(3, zones_[7].use_count());
@@ -205,26 +240,26 @@ TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) {
 
 /// \brief Remove Entry from Hash Table
 ///
-/// Check that when an entry reaches the top of the LRU list, it is removed from the
-/// hash table as well.
+/// Check that when an entry reaches the top of the LRU list, it is removed from
+/// the hash table as well.
 TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) {
 
-    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and
-    // nameserver tables).
+    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone
+    // and nameserver tables).
     DerivedNsas nsas(resolver_, 2, 2);
 
-    // Add six entries to the tables.  After addition the reference count of each element
-    // should be 3 - one for the entry in the nameservers_ vector, and one each for the entries
-    // in the LRU list and hash table.
+    // Add six entries to the tables.  After addition the reference count of
+    // each element should be 3 - one for the entry in the nameservers_ vector,
+    // and one each for the entries in the LRU list and hash table.
     for (int i = 1; i <= 6; ++i) {
         EXPECT_EQ(1, nameservers_[i].use_count());
         nsas.AddNameserverEntry(nameservers_[i]);
         EXPECT_EQ(3, nameservers_[i].use_count());
     }
 
-    // Adding another entry should cause the first one to drop off the LRU list, which
-    // should also trigger the deletion of the entry from the hash table.  This should
-    // reduce its use count to 1.
+    // Adding another entry should cause the first one to drop off the LRU list,
+    // which should also trigger the deletion of the entry from the hash table.
+    // This should reduce its use count to 1.
     EXPECT_EQ(1, nameservers_[7].use_count());
     nsas.AddNameserverEntry(nameservers_[7]);
     EXPECT_EQ(3, nameservers_[7].use_count());
@@ -237,14 +272,17 @@ TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) {
 /// Check if it asks correct questions and it keeps correct internal state.
 TEST_F(NameserverAddressStoreTest, emptyLookup) {
     DerivedNsas nsas(resolver_, 10, 10);
+
     // Ask it a question
     nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
         getCallback());
+
     // It should ask for IP addresses for ns.example.com.
     EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
 
     // Ask another question for the same zone
     nsas.lookup("example.net.", RRClass::IN(), getCallback());
+
     // It should ask no more questions now
     EXPECT_EQ(2, resolver_->requests.size());
 
@@ -252,6 +290,7 @@ TEST_F(NameserverAddressStoreTest, emptyLookup) {
     authority_->setName(Name("example.com."));
     nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_,
         getCallback());
+
     // It still should ask nothing
     EXPECT_EQ(2, resolver_->requests.size());
 
@@ -271,11 +310,14 @@ TEST_F(NameserverAddressStoreTest, emptyLookup) {
 /// It should not ask anything and say it is unreachable right away.
 TEST_F(NameserverAddressStoreTest, zoneWithoutNameservers) {
     DerivedNsas nsas(resolver_, 10, 10);
+
     // Ask it a question
     nsas.lookupAndAnswer("example.net.", RRClass::IN(), empty_authority_,
         getCallback());
+
     // There should be no questions, because there's nothing to ask
     EXPECT_EQ(0, resolver_->requests.size());
+
     // And there should be one "unreachable" answer for the query
     ASSERT_EQ(1, NSASCallback::results.size());
     EXPECT_FALSE(NSASCallback::results[0].first);
@@ -288,9 +330,11 @@ TEST_F(NameserverAddressStoreTest, zoneWithoutNameservers) {
 /// without further asking.
 TEST_F(NameserverAddressStoreTest, unreachableNS) {
     DerivedNsas nsas(resolver_, 10, 10);
+
     // Ask it a question
     nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
         getCallback());
+
     // It should ask for IP addresses for example.com.
     EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
 
@@ -298,6 +342,7 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) {
     authority_->setName(Name("example.com."));
     nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_,
         getCallback());
+
     // It should ask nothing more now
     EXPECT_EQ(2, resolver_->requests.size());
 
@@ -307,12 +352,14 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) {
 
     // We should have 2 answers now
     EXPECT_EQ(2, NSASCallback::results.size());
+
     // When we ask one same and one other zone with the same nameserver,
     // it should generate no questions and answer right away
     nsas.lookup("example.net.", RRClass::IN(), getCallback());
     authority_->setName(Name("example.org."));
     nsas.lookupAndAnswer("example.org.", RRClass::IN(), authority_,
         getCallback());
+
     // There should be 4 negative answers now
     EXPECT_EQ(4, NSASCallback::results.size());
     BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) {
@@ -325,18 +372,23 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) {
 /// Does some asking, on a set of zones that share some nameservers, with
 /// slower answering, evicting data, etc.
 TEST_F(NameserverAddressStoreTest, CombinedTest) {
+
     // Create small caches, so we get some evictions
     DerivedNsas nsas(resolver_, 1, 1);
+
     // Ask for example.net. It has single nameserver out of the zone
     nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
         getCallback());
+
     // It should ask for the nameserver IP addresses
     EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
     EXPECT_EQ(0, NSASCallback::results.size());
+
     // But we do not answer it right away. We create a new zone and
     // let this nameserver entry get out.
     rrns_->addRdata(rdata::generic::NS("example.cz"));
     nsas.lookupAndAnswer(EXAMPLE_CO_UK, RRClass::IN(), rrns_, getCallback());
+
     // It really should ask something, one of the nameservers
     // (or both)
     ASSERT_GT(resolver_->requests.size(), 2);
@@ -346,8 +398,8 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
     EXPECT_NO_THROW(resolver_->asksIPs(name, 2, 3));
     EXPECT_EQ(0, NSASCallback::results.size());
 
-    size_t request_count(resolver_->requests.size());
     // This should still be in the hash table, so try it asks no more questions
+    size_t request_count(resolver_->requests.size());
     nsas.lookup("example.net.", RRClass::IN(), getCallback());
     EXPECT_EQ(request_count, resolver_->requests.size());
     EXPECT_EQ(0, NSASCallback::results.size());
@@ -355,6 +407,7 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
     // We respond to one of the 3 nameservers
     EXPECT_NO_THROW(resolver_->answer(2, name, RRType::A(),
         rdata::in::A("192.0.2.1")));
+
     // That should trigger one answer
     EXPECT_EQ(1, NSASCallback::results.size());
     EXPECT_TRUE(NSASCallback::results[0].first);
@@ -362,6 +415,7 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
         NSASCallback::results[0].second.getAddress().toText());
     EXPECT_NO_THROW(resolver_->answer(3, name, RRType::AAAA(),
         rdata::in::AAAA("2001:bd8::1")));
+
     // And there should be yet another query
     ASSERT_GT(resolver_->requests.size(), 4);
     EXPECT_NE(name, resolver_->requests[4].first->getName());
@@ -379,9 +433,9 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
     EXPECT_EQ(request_count + 2, resolver_->requests.size());
     EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), request_count,
         request_count + 1));
-    // Now, we answer both queries for the same address
-    // and three (one for the original, one for this one) more answers should
-    // arrive
+
+    // Now, we answer both queries for the same address and three (one for the
+    // original, one for this one) more answers should arrive
     NSASCallback::results.clear();
     EXPECT_NO_THROW(resolver_->answer(0, Name("ns.example.com."), RRType::A(),
         rdata::in::A("192.0.2.2")));
@@ -394,5 +448,113 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
     }
 }
 
+// Check that we can update the RTT associated with nameservers successfully.
+// Also checks that we can't set the RTT to zero (which would cause problems
+// with selection algorithm).
+TEST_F(NameserverAddressStoreTest, updateRTT) {
+
+    // Initialization.
+    string  zone_name = "example.net.";
+    string  ns_name = "ns.example.com."; 
+    vector<string> address;
+    address.push_back("192.0.2.1");
+    address.push_back("192.0.2.2");
+
+    uint32_t HIGH_RTT = 10000;  // 1E4; When squared, the result fits in 32 bits
+
+    DerivedNsas nsas(resolver_, 103, 107);   // Arbitrary cache sizes
+
+    // Ensure that location holding the addresses returned is empty.  We'll
+    // be using this throughout the tests.  As the full name is a bit of a
+    // mouthful, set up an alias.
+    vector<NameserverAddressStoreTest::NSASCallback::Result>& results =
+        NameserverAddressStoreTest::NSASCallback::results;
+    results.clear();
+
+    // Initialize the test resolver with the answer for the A record query
+    // for ns.example.com (the nameserver set for example.net in the class
+    // initialization).  We'll set two addresses.
+    Name ns_example_com(ns_name);
+    RRsetPtr ns_address = boost::shared_ptr<RRset>(new RRset(
+        ns_example_com, RRClass::IN(), RRType::A(), RRTTL(300)));
+    BOOST_FOREACH(string addr, address) {
+        ns_address->addRdata(rdata::in::A(addr));
+    }
+
+    // All set.  Ask for example.net.
+    boost::shared_ptr<AddressRequestCallback> callback = getCallback();
+    nsas.lookupAndAnswer(zone_name, RRClass::IN(), authority_, getCallback());
+
+    // This should generate two requests - one for A and one for AAAA.
+    EXPECT_EQ(2, resolver_->requests.size());
+
+    // Provide an answer that has two A records.  This should generate one
+    // result.
+    EXPECT_NO_THROW(resolver_->answer(0, ns_address));
+    EXPECT_EQ(1, results.size());
+
+    // We expect the lookup to be successful.  Check that the address is one of
+    // the two we've set and that the RTT associated with this nameserver is
+    // non-zero.
+    EXPECT_EQ(true, results[0].first);
+    vector<string>::iterator addr1 = find(address.begin(), address.end(),
+                                     results[0].second.getAddress().toText());
+    EXPECT_TRUE(addr1 != address.end());
+
+    // The RTT we got should be non-zero and less than the high value we are
+    // using for the test.
+    uint32_t rtt1 = results[0].second.getAddressEntry().getRTT();
+    EXPECT_NE(0, rtt1);
+    EXPECT_LT(rtt1, HIGH_RTT);
+
+    // Update the address with a very high RTT.  Owning to the way the NSAS is
+    // written, we can update the RTT but cannot read the new value back from
+    // the new object.  
+    results[0].second.updateRTT(HIGH_RTT);
+
+    // Get another nameserver.  As the probability of returning a particular
+    // address is proporational to 1/t^2, we should get the second address
+    // since the first now has a larger RTT.  However, this is not guaranteed
+    // - this is a probability (albeit small) of getting the first again. We'll
+    // allow three chances of getting the "wrong" address before we declare
+    // an error.
+    int attempt = 0;
+    vector<string>::iterator addr2 = addr1;
+    for (attempt = 0; (attempt < 3) && (*addr1 == *addr2); ++attempt) {
+        results.clear();
+        nsas.lookup(zone_name, RRClass::IN(), 
+                             getCallback(), ANY_OK);
+        addr2 = find(address.begin(), address.end(),
+                     results[0].second.getAddress().toText());
+    }
+    EXPECT_LT(attempt, 3);
+
+    // Ensure that the RTT is non-zero.
+    // obtained earlier.
+    uint32_t rtt2 = results[0].second.getAddressEntry().getRTT();
+    EXPECT_NE(0, rtt2);
+
+    // The test has shown that the code can return the two nameservers.  Now
+    // try to set the RTT for the last one returned to zero.  As there is a
+    // smoothing effect in the calculations which damps out an abrupt change
+    // in the RTT, the underlying RTT will not be set to zero immediately.  So
+    // loop a large number of times, each time setting it to zero.
+    //
+    // Between each setting of the RTT, we have to retrieve the nameserver from
+    // the NSAS again.  This means that we _could_ occasionally get the address
+    // of the one whose RTT we have raised to HIGH_RTT.  We overcome this by
+    // looping a _very_ large number of times.  Ultimately the RTT of both
+    // addresses should decay to a small value.
+    for (int i = 0; i < 2000; ++i) {   // 1000 times for each nameserver
+        results.clear();
+        nsas.lookup(zone_name, RRClass::IN(), getCallback(), ANY_OK);
+        EXPECT_EQ(1, results.size());
+        uint32_t rtt3 = results[0].second.getAddressEntry().getRTT();
+        EXPECT_NE(0, rtt3);
+        results[0].second.updateRTT(0);
+    }
+}
+
+
 } // namespace nsas
 } // namespace isc
diff --git a/src/lib/nsas/tests/nameserver_address_unittest.cc b/src/lib/nsas/tests/nameserver_address_unittest.cc
index 457e61c..1b211e9 100644
--- a/src/lib/nsas/tests/nameserver_address_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_unittest.cc
@@ -51,14 +51,15 @@ public:
         ns_.reset(new NameserverEntry(name_.toText(), RRClass::IN()));
         ns_->askIP(resolver_.get(), boost::shared_ptr<Callback>(new Callback), ANY_OK);
         resolver_->asksIPs(name_, 0, 1);
-        resolver_->requests[0].second->success(createResponseMessage(rrv4_));
+        resolver_->requests[0].second->success(
+            isc::util::unittests::createResponseMessage(rrv4_));
     }
 
     // Return the sample NameserverEntry
     boost::shared_ptr<NameserverEntry>& getNameserverEntry() { return ns_; }
 
     // Return the IOAddress corresponding to the index in rrv4_
-    asiolink::IOAddress getAddressAtIndex(uint32_t index) {
+    isc::asiolink::IOAddress getAddressAtIndex(uint32_t index) {
         return ns_.get()->getAddressAtIndex(index, V4_ONLY);
     }
 
@@ -107,7 +108,7 @@ TEST_F(NameserverAddressTest, Address) {
     boost::shared_ptr<NameserverEntry> empty_ne((NameserverEntry*)NULL);
     // It will throw an NullNameserverEntryPointer exception with the empty NameserverEntry shared pointer
     ASSERT_THROW({NameserverAddress empty_ns_address(empty_ne,
-        asiolink::IOAddress("127.0.0.1"), V4_ONLY);},
+        isc::asiolink::IOAddress("127.0.0.1"), V4_ONLY);},
         NullNameserverEntryPointer);
 }
 
diff --git a/src/lib/nsas/tests/nameserver_entry_unittest.cc b/src/lib/nsas/tests/nameserver_entry_unittest.cc
index 4225e87..3435d26 100644
--- a/src/lib/nsas/tests/nameserver_entry_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_entry_unittest.cc
@@ -39,7 +39,7 @@
 #include "nsas_test.h"
 
 using namespace isc::nsas;
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace std;
 using namespace isc::dns;
 using namespace rdata;
@@ -72,7 +72,8 @@ private:
         RRsetPtr set)
     {
         if (set) {
-            resolver->requests[index].second->success(createResponseMessage(set));
+            resolver->requests[index].second->success(
+                isc::util::unittests::createResponseMessage(set));
         } else {
             resolver->requests[index].second->failure();
         }
@@ -513,6 +514,11 @@ TEST_F(NameserverEntryTest, UpdateRTT) {
 
     // The rtt should be close to stable rtt value
     EXPECT_TRUE((stable_rtt - new_rtt) < (new_rtt - init_rtt));
+
+    // Finally, try updating the RTT to a very large value (large enough for
+    // RTT^2 - used in the internal calculation - to exceed a 32-bit value).
+    EXPECT_NO_THROW(vec[0].updateRTT(1000000000));  // 10^9
+
 }
 
 }   // namespace
diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h
index 7500fc7..2dd95ef 100644
--- a/src/lib/nsas/tests/nsas_test.h
+++ b/src/lib/nsas/tests/nsas_test.h
@@ -26,8 +26,9 @@
 
 #include <config.h>
 
+#include <util/buffer.h>
+#include <util/unittests/resolver.h>
 #include <dns/message.h>
-#include <dns/buffer.h>
 #include <dns/rdata.h>
 #include <dns/rrtype.h>
 #include <dns/rrttl.h>
@@ -35,23 +36,12 @@
 #include <dns/rcode.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdataclass.h>
-#include <resolve/resolver_interface.h>
 #include "../nsas_entry.h"
 
 using namespace isc::dns::rdata;
 using namespace isc::dns;
-
-namespace {
-    MessagePtr
-    createResponseMessage(RRsetPtr answer_rrset)
-    {
-        MessagePtr response(new Message(Message::RENDER));
-        response->setOpcode(Opcode::QUERY());
-        response->setRcode(Rcode::NOERROR());
-        response->addRRset(Message::SECTION_ANSWER, answer_rrset);
-        return response;
-    }
-}
+using namespace isc::util;
+using isc::util::unittests::TestResolver;
 
 namespace isc {
 namespace dns {
@@ -124,7 +114,7 @@ public:
     virtual void toWire(OutputBuffer& buffer) const;
 
     /// \brief render the \Rdata in the wire format to a \c MessageRenderer
-    virtual void toWire(MessageRenderer& renderer) const;
+    virtual void toWire(AbstractMessageRenderer& renderer) const;
     
     /// \brief Comparison Method
     virtual int compare(const Rdata& other) const;
@@ -140,7 +130,7 @@ void RdataTest<T>::toWire(OutputBuffer&) const {
 }
 
 template <typename T>
-void RdataTest<T>::toWire(MessageRenderer&) const {
+void RdataTest<T>::toWire(AbstractMessageRenderer&) const {
 }
 
 template <typename T>
@@ -222,133 +212,6 @@ private:
 
 static const uint32_t HASHTABLE_DEFAULT_SIZE = 1009; ///< First prime above 1000
 
-using namespace std;
-
-/*
- * This pretends to be a resolver. It stores the queries and
- * they can be answered.
- */
-class TestResolver : public isc::resolve::ResolverInterface {
-    private:
-        bool checkIndex(size_t index) {
-            return (requests.size() > index);
-        }
-
-        typedef std::map<isc::dns::Question, RRsetPtr >
-            PresetAnswers;
-        PresetAnswers answers_;
-    public:
-        typedef pair<QuestionPtr, CallbackPtr> Request;
-        vector<Request> requests;
-
-        /// \brief Destructor
-        ///
-        /// This is important.  All callbacks in the requests vector must be
-        /// called to remove them from internal loops.  Without this, destroying
-        /// the NSAS object will leave memory assigned.
-        ~TestResolver() {
-            for (size_t i = 0; i < requests.size(); ++i) {
-                requests[i].second->failure();
-            }
-        }
-
-        virtual void resolve(const QuestionPtr& q, const CallbackPtr& c) {
-            PresetAnswers::iterator it(answers_.find(*q));
-            if (it == answers_.end()) {
-                requests.push_back(Request(q, c));
-            } else {
-                if (it->second) {
-                    c->success(createResponseMessage(it->second));
-                } else {
-                    c->failure();
-                }
-            }
-        }
-
-        /*
-         * Add a preset answer. If shared_ptr() is passed (eg. NULL),
-         * it will generate failure. If the question is not preset,
-         * it goes to requests and you can answer later.
-         */
-        void addPresetAnswer(const isc::dns::Question& question,
-            RRsetPtr answer)
-        {
-            answers_[question] = answer;
-        }
-
-        // Thrown if the query at the given index does not exist.
-        class NoSuchRequest : public std::exception { };
-
-        // Thrown if the answer does not match the query
-        class DifferentRequest : public std::exception { };
-
-        QuestionPtr operator[](size_t index) {
-            if (index >= requests.size()) {
-                throw NoSuchRequest();
-            }
-            return (requests[index].first);
-        }
-        /*
-         * Looks if the two provided requests in resolver are A and AAAA.
-         * Sorts them so index1 is A.
-         *
-         * Returns false if there aren't enough elements
-         */
-        bool asksIPs(const Name& name, size_t index1, size_t index2) {
-            size_t max = (index1 < index2) ? index2 : index1;
-            if (!checkIndex(max)) {
-                return false;
-            }
-            EXPECT_EQ(name, (*this)[index1]->getName());
-            EXPECT_EQ(name, (*this)[index2]->getName());
-            EXPECT_EQ(RRClass::IN(), (*this)[index1]->getClass());
-            EXPECT_EQ(RRClass::IN(), (*this)[index2]->getClass());
-            // If they are the other way around, swap
-            if ((*this)[index1]->getType() == RRType::AAAA() &&
-                (*this)[index2]->getType() == RRType::A())
-            {
-                TestResolver::Request tmp((*this).requests[index1]);
-                (*this).requests[index1] =
-                    (*this).requests[index2];
-                (*this).requests[index2] = tmp;
-            }
-            // Check the correct addresses
-            EXPECT_EQ(RRType::A(), (*this)[index1]->getType());
-            EXPECT_EQ(RRType::AAAA(), (*this)[index2]->getType());
-            return (true);
-        }
-
-        /*
-         * Sends a simple answer to a query.
-         * Provide index of a query and the address to pass.
-         */
-        void answer(size_t index, const Name& name, const RRType& type,
-            const rdata::Rdata& rdata, size_t TTL = 100)
-        {
-            if (index >= requests.size()) {
-                throw NoSuchRequest();
-            }
-            RRsetPtr set(new RRset(name, RRClass::IN(),
-                type, RRTTL(TTL)));
-            set->addRdata(rdata);
-            requests[index].second->success(createResponseMessage(set));
-        }
-
-        void provideNS(size_t index,
-            RRsetPtr nameservers)
-        {
-            if (index >= requests.size()) {
-                throw NoSuchRequest();
-            }
-            if (requests[index].first->getName() != nameservers->getName() ||
-                requests[index].first->getType() != RRType::NS())
-            {
-                throw DifferentRequest();
-            }
-            requests[index].second->success(createResponseMessage(nameservers));
-        }
-};
-
 // String constants.  These should end in a dot.
 static const std::string EXAMPLE_CO_UK("example.co.uk.");
 static const std::string EXAMPLE_NET("example.net.");
diff --git a/src/lib/nsas/tests/random_number_generator_unittest.cc b/src/lib/nsas/tests/random_number_generator_unittest.cc
deleted file mode 100644
index 85cbcbf..0000000
--- a/src/lib/nsas/tests/random_number_generator_unittest.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <gtest/gtest.h>
-#include <boost/shared_ptr.hpp>
-
-#include <algorithm>
-#include <iostream>
-#include <vector>
-
-#include "random_number_generator.h"
-
-namespace isc {
-namespace nsas {
-
-using namespace std;
-
-/// \brief Test Fixture Class for uniform random number generator
-///
-/// The hard part for this test is how to test that the number is random?
-/// and how to test that the number is uniformly distributed? 
-/// Or maybe we can trust the boost implementation
-class UniformRandomIntegerGeneratorTest : public ::testing::Test {
-public:
-    UniformRandomIntegerGeneratorTest():
-        gen_(min_, max_)
-    {
-    }
-    virtual ~UniformRandomIntegerGeneratorTest(){}
-
-    int gen() { return gen_(); }
-    int max() const { return max_; }
-    int min() const { return min_; }
-
-private:
-    UniformRandomIntegerGenerator gen_;
-
-    const static int min_ = 1;
-    const static int max_ = 10;
-};
-
-// Some validation tests will incur performance penalty, so the tests are
-// made only in "debug" version with assert(). But if NDEBUG is defined
-// the tests will be failed since assert() is non-op in non-debug version.
-// The "#ifndef NDEBUG" is added to make the tests be performed only in
-// non-debug environment.
-// Note: the death test is not supported by all platforms.  We need to
-// compile tests using it selectively.
-#if !defined(NDEBUG)
-// Test of the constructor
-TEST_F(UniformRandomIntegerGeneratorTest, Constructor) {
-    // The range must be min<=max
-    ASSERT_THROW(UniformRandomIntegerGenerator(3, 2), InvalidLimits);
-}
-#endif
-
-// Test of the generated integers are in the range [min, max]
-TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) {
-    vector<int> numbers;
-
-    // Generate a lot of random integers
-    for (int i = 0; i < max()*10; ++i) {
-        numbers.push_back(gen());
-    }
-
-    // Remove the duplicated values
-    sort(numbers.begin(), numbers.end());
-    vector<int>::iterator it = unique(numbers.begin(), numbers.end());
-
-    // make sure the numbers are in range [min, max]
-    ASSERT_EQ(it - numbers.begin(), max() - min() + 1); 
-}
-
-/// \brief Test Fixture Class for weighted random number generator
-class WeightedRandomIntegerGeneratorTest : public ::testing::Test {
-public:
-    WeightedRandomIntegerGeneratorTest()
-    { }
-
-    virtual ~WeightedRandomIntegerGeneratorTest()
-    { }
-};
-
-// Test of the weighted random number generator constructor
-TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) {
-    vector<double> probabilities;
-
-    // If no probabilities is provided, the smallest integer will always be generated
-    WeightedRandomIntegerGenerator gen(probabilities, 123);
-    for (int i = 0; i < 100; ++i) {
-        ASSERT_EQ(gen(), 123);
-    }
-
-/// Some validation tests will incur performance penalty, so the tests are
-/// made only in "debug" version with assert(). But if NDEBUG is defined
-/// the tests will be failed since assert() is non-op in non-debug version.
-/// The "#ifndef NDEBUG" is added to make the tests be performed only in
-/// non-debug environment.
-#if !defined(NDEBUG)
-    //The probability must be >= 0
-    probabilities.push_back(-0.1);
-    probabilities.push_back(1.1);
-    ASSERT_THROW(WeightedRandomIntegerGenerator gen2(probabilities),
-                 InvalidProbValue);
-
-    //The probability must be <= 1.0
-    probabilities.clear();
-    probabilities.push_back(0.1);
-    probabilities.push_back(1.1);
-    ASSERT_THROW(WeightedRandomIntegerGenerator gen3(probabilities),
-                 InvalidProbValue);
-
-    //The sum must be equal to 1.0
-    probabilities.clear();
-    probabilities.push_back(0.2);
-    probabilities.push_back(0.9);
-    ASSERT_THROW(WeightedRandomIntegerGenerator gen4(probabilities), SumNotOne);
-
-    //The sum must be equal to 1.0
-    probabilities.clear();
-    probabilities.push_back(0.3);
-    probabilities.push_back(0.2);
-    probabilities.push_back(0.1);
-    ASSERT_THROW(WeightedRandomIntegerGenerator gen5(probabilities), SumNotOne);
-#endif
-}
-
-// Test the randomization of the generator
-TEST_F(WeightedRandomIntegerGeneratorTest, WeightedRandomization) {
-    const int repeats = 100000;
-    // We repeat the simulation for N=repeats times
-    // for each probability p, its average is mu = N*p
-    // variance sigma^2 = N * p * (1-p)
-    // sigma = sqrt(N*2/9)
-    // we should make sure that mu - 4sigma < count < mu + 4sigma
-    // which means for 99.99366% of the time this should be true
-    {
-        double p = 0.5;
-        vector<double> probabilities;
-        probabilities.push_back(p);
-        probabilities.push_back(p);
-
-        // Uniformly generated integers
-        WeightedRandomIntegerGenerator gen(probabilities);
-        int c1 = 0;
-        int c2 = 0;
-        for (int i = 0; i < repeats; ++i){
-            int n = gen();
-            if (n == 0) {
-                ++c1;
-            } else if (n == 1) {
-                ++c2;
-            }
-        }
-        double mu = repeats * p;
-        double sigma = sqrt(repeats * p * (1 - p));
-        ASSERT_TRUE(fabs(c1 - mu) < 4*sigma);
-        ASSERT_TRUE(fabs(c2 - mu) < 4*sigma);
-    }
-
-    {
-        vector<double> probabilities;
-        int c1 = 0;
-        int c2 = 0;
-        double p1 = 0.2;
-        double p2 = 0.8;
-        probabilities.push_back(p1);
-        probabilities.push_back(p2);
-        WeightedRandomIntegerGenerator gen(probabilities);
-        for (int i = 0; i < repeats; ++i) {
-            int n = gen();
-            if (n == 0) {
-                ++c1;
-            } else if (n == 1) {
-                ++c2;
-            }
-        }
-        double mu1 = repeats * p1;
-        double mu2 = repeats * p2;
-        double sigma1 = sqrt(repeats * p1 * (1 - p1));
-        double sigma2 = sqrt(repeats * p2 * (1 - p2));
-        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
-        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
-    }
-
-    {
-        vector<double> probabilities;
-        int c1 = 0;
-        int c2 = 0;
-        double p1 = 0.8;
-        double p2 = 0.2;
-        probabilities.push_back(p1);
-        probabilities.push_back(p2);
-        WeightedRandomIntegerGenerator gen(probabilities);
-        for (int i = 0; i < repeats; ++i) {
-            int n = gen();
-            if (n == 0) {
-                ++c1;
-            } else if (n == 1) {
-                ++c2;
-            }
-        }
-        double mu1 = repeats * p1;
-        double mu2 = repeats * p2;
-        double sigma1 = sqrt(repeats * p1 * (1 - p1));
-        double sigma2 = sqrt(repeats * p2 * (1 - p2));
-        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
-        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
-    }
-
-    {
-        vector<double> probabilities;
-        int c1 = 0;
-        int c2 = 0;
-        int c3 = 0;
-        double p1 = 0.5;
-        double p2 = 0.25;
-        double p3 = 0.25;
-        probabilities.push_back(p1);
-        probabilities.push_back(p2);
-        probabilities.push_back(p3);
-        WeightedRandomIntegerGenerator gen(probabilities);
-        for (int i = 0; i < repeats; ++i){
-            int n = gen();
-            if (n == 0) {
-                ++c1;
-            } else if (n == 1) {
-                ++c2;
-            } else if (n == 2) {
-                ++c3;
-            }
-        }
-        double mu1 = repeats * p1;
-        double mu2 = repeats * p2;
-        double mu3 = repeats * p3;
-        double sigma1 = sqrt(repeats * p1 * (1 - p1));
-        double sigma2 = sqrt(repeats * p2 * (1 - p2));
-        double sigma3 = sqrt(repeats * p3 * (1 - p3));
-        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
-        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
-        ASSERT_TRUE(fabs(c3 - mu3) < 4*sigma3);
-    }
-}
-
-// Test the reset function of generator
-TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) {
-    const int repeats = 100000;
-    vector<double> probabilities;
-    int c1 = 0;
-    int c2 = 0;
-    double p1 = 0.8;
-    double p2 = 0.2;
-    probabilities.push_back(p1);
-    probabilities.push_back(p2);
-    WeightedRandomIntegerGenerator gen(probabilities);
-    for (int i = 0; i < repeats; ++i) {
-        int n = gen();
-        if (n == 0) {
-            ++c1;
-        } else if (n == 1) {
-            ++c2;
-        }
-    }
-    double mu1 = repeats * p1;
-    double mu2 = repeats * p2;
-    double sigma1 = sqrt(repeats * p1 * (1 - p1));
-    double sigma2 = sqrt(repeats * p2 * (1 - p2));
-    ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
-    ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
-
-    // Reset the probabilities
-    probabilities.clear();
-    c1 = c2 = 0;
-    p1 = 0.2;
-    p2 = 0.8;
-    probabilities.push_back(p1);
-    probabilities.push_back(p2);
-    gen.reset(probabilities);
-    for (int i = 0; i < repeats; ++i) {
-        int n = gen();
-        if (n == 0) {
-            ++c1;
-        } else if (n == 1) {
-            ++c2;
-        }
-    }
-    mu1 = repeats * p1;
-    mu2 = repeats * p2;
-    sigma1 = sqrt(repeats * p1 * (1 - p1));
-    sigma2 = sqrt(repeats * p2 * (1 - p2));
-    ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
-    ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
-}
-
-} // namespace nsas
-} // namespace isc
diff --git a/src/lib/nsas/tests/run_unittests.cc b/src/lib/nsas/tests/run_unittests.cc
index d1277ad..bc672d0 100644
--- a/src/lib/nsas/tests/run_unittests.cc
+++ b/src/lib/nsas/tests/run_unittests.cc
@@ -13,14 +13,23 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
+#include <stdlib.h>
+
+#include <string>
+#include <boost/lexical_cast.hpp>
 
 #include <gtest/gtest.h>
 
 #include <dns/tests/unittest_util.h>
+#include <log/logger_support.h>
+
+using namespace std;
 
 int
 main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
 
+    isc::log::initLogger();
+
     return (RUN_ALL_TESTS());
 }
diff --git a/src/lib/nsas/tests/zone_entry_unittest.cc b/src/lib/nsas/tests/zone_entry_unittest.cc
index 34f995c..1982299 100644
--- a/src/lib/nsas/tests/zone_entry_unittest.cc
+++ b/src/lib/nsas/tests/zone_entry_unittest.cc
@@ -33,9 +33,10 @@
 #include "nsas_test.h"
 
 using namespace isc::nsas;
-using namespace asiolink;
+using namespace isc::asiolink;
 using namespace std;
 using namespace isc::dns;
+using namespace isc::util;
 
 namespace {
 
diff --git a/src/lib/nsas/zone_entry.cc b/src/lib/nsas/zone_entry.cc
index 3af70a8..1c5df03 100644
--- a/src/lib/nsas/zone_entry.cc
+++ b/src/lib/nsas/zone_entry.cc
@@ -31,7 +31,9 @@ using namespace std;
 
 namespace isc {
 
-using namespace dns;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::random;
 
 namespace nsas {
 
@@ -51,7 +53,7 @@ ZoneEntry::ZoneEntry(
 
 namespace {
 // Shorter aliases for frequently used types
-typedef isc::locks::scoped_lock<isc::locks::recursive_mutex> Lock; // Local lock, nameservers not locked
+typedef isc::util::locks::scoped_lock<isc::util::locks::recursive_mutex> Lock; // Local lock, nameservers not locked
 typedef boost::shared_ptr<AddressRequestCallback> CallbackPtr;
 
 /*
diff --git a/src/lib/nsas/zone_entry.h b/src/lib/nsas/zone_entry.h
index 92ac75a..f772784 100644
--- a/src/lib/nsas/zone_entry.h
+++ b/src/lib/nsas/zone_entry.h
@@ -25,13 +25,14 @@
 
 #include <resolve/resolver_interface.h>
 
-#include "locks.h"
+#include <util/locks.h>
+#include <util/random/random_number_generator.h>
+
 #include "hash_key.h"
 #include "nsas_entry.h"
 #include "asiolink.h"
 #include "fetchable.h"
 #include "nsas_types.h"
-#include "random_number_generator.h"
 #include "glue_hints.h"
 
 namespace isc {
@@ -72,7 +73,7 @@ public:
     ZoneEntry(isc::resolve::ResolverInterface* resolver,
         const std::string& name, const isc::dns::RRClass& class_code,
         boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table,
-        boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru);
+        boost::shared_ptr<isc::util::LruList<NameserverEntry> > nameserver_lru);
 
     /// \return Name of the zone
     std::string getName() const {
@@ -132,7 +133,7 @@ protected:
     time_t          expiry_;    ///< Expiry time of this entry, 0 means not set
     //}@
 private:
-    mutable isc::locks::recursive_mutex    mutex_;///< Mutex protecting this zone entry
+    mutable isc::util::locks::recursive_mutex    mutex_;///< Mutex protecting this zone entry
     std::string     name_;      ///< Canonical zone name
     isc::dns::RRClass        class_code_; ///< Class code
     /**
@@ -161,7 +162,7 @@ private:
     // We store the nameserver table and lru, so we can look up when there's
     // update
     boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table_;
-    boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru_;
+    boost::shared_ptr<isc::util::LruList<NameserverEntry> > nameserver_lru_;
     // Resolver callback class, documentation with the class declaration
     class ResolverCallback;
     // It has direct access to us
@@ -182,7 +183,7 @@ private:
     void insertCallback(NameserverPtr nameserver, AddressFamily family);
     // A random generator for this zone entry
     // TODO: A more global one? Per thread one?
-    WeightedRandomIntegerGenerator address_selector;
+    isc::util::random::WeightedRandomIntegerGenerator address_selector;
 };
 
 } // namespace nsas
diff --git a/src/lib/python/Makefile.am b/src/lib/python/Makefile.am
index f7eb333..75e5afb 100644
--- a/src/lib/python/Makefile.am
+++ b/src/lib/python/Makefile.am
@@ -1,6 +1,7 @@
 SUBDIRS = isc
 
 python_PYTHON =	bind10_config.py
+pythondir = $(pyexecdir)
 
 # Explicitly define DIST_COMMON so ${python_PYTHON} is not included
 # as we don't want the generated file included in distributed tarfile.
diff --git a/src/lib/python/bind10_config.py.in b/src/lib/python/bind10_config.py.in
index 3f2947d..4a38903 100644
--- a/src/lib/python/bind10_config.py.in
+++ b/src/lib/python/bind10_config.py.in
@@ -17,7 +17,37 @@
 # variables to python scripts and libraries.
 import os
 
-BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
-                                       "@PACKAGE_NAME@",
-                                       "msgq_socket").replace("${prefix}",
-                                                              "@prefix@")
+def reload():
+    # In a function, for testing purposes
+    global BIND10_MSGQ_SOCKET_FILE
+    global DATA_PATH
+    global PLUGIN_PATHS
+    global PREFIX
+    BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
+                                           "@PACKAGE_NAME@",
+                                           "msgq_socket").replace("${prefix}",
+                                                                  "@prefix@")
+    PREFIX = "@prefix@"
+
+    # If B10_FROM_SOURCE is set in the environment, we use data files
+    # from a directory relative to the value of that variable, or, if defined,
+    # relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR.  Otherwise
+    # we use the ones installed on the system.
+    # B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
+    # tests where we want to use variuos types of configuration within the test
+    # environment.  (We may want to make it even more generic so that the path is
+    # passed from the boss process)
+    if "B10_FROM_SOURCE" in os.environ:
+        if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+            DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+        else:
+            DATA_PATH = os.environ["B10_FROM_SOURCE"]
+        PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
+    else:
+        DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
+        PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
+    # For testing the plugins so they can find their own spec files
+    if "B10_TEST_PLUGIN_DIR" in os.environ:
+        PLUGIN_PATHS = os.environ["B10_TEST_PLUGIN_DIR"].split(':')
+
+reload()
diff --git a/src/lib/python/isc/config/ccsession.py b/src/lib/python/isc/config/ccsession.py
index 942bf79..226c6ba 100644
--- a/src/lib/python/isc/config/ccsession.py
+++ b/src/lib/python/isc/config/ccsession.py
@@ -151,6 +151,9 @@ class ModuleCCSession(ConfigData):
         self._remote_module_configs = {}
 
     def __del__(self):
+        # If the CC Session obejct has been closed, it returns
+        # immediately.
+        if self._session._closed: return
         self._session.group_unsubscribe(self._module_name, "*")
         for module_name in self._remote_module_configs:
             self._session.group_unsubscribe(module_name)
diff --git a/src/lib/python/isc/config/cfgmgr.py b/src/lib/python/isc/config/cfgmgr.py
index 8561378..88a93e1 100644
--- a/src/lib/python/isc/config/cfgmgr.py
+++ b/src/lib/python/isc/config/cfgmgr.py
@@ -170,6 +170,10 @@ class ConfigManager:
         self.data_path = data_path
         self.database_filename = database_filename
         self.module_specs = {}
+        # Virtual modules are the ones which have no process running. The
+        # checking of validity is done by functions presented here instead
+        # of some other process
+        self.virtual_modules = {}
         self.config = ConfigManagerData(data_path, database_filename)
         if session:
             self.cc = session
@@ -187,11 +191,20 @@ class ConfigManager:
         """Adds a ModuleSpec"""
         self.module_specs[spec.get_module_name()] = spec
 
+    def set_virtual_module(self, spec, check_func):
+        """Adds a virtual module with its spec and checking function."""
+        self.module_specs[spec.get_module_name()] = spec
+        self.virtual_modules[spec.get_module_name()] = check_func
+
     def remove_module_spec(self, module_name):
         """Removes the full ModuleSpec for the given module_name.
+           Also removes the virtual module check function if it
+           was present.
            Does nothing if the module was not present."""
         if module_name in self.module_specs:
             del self.module_specs[module_name]
+        if module_name in self.virtual_modules:
+            del self.virtual_modules[module_name]
 
     def get_module_spec(self, module_name = None):
         """Returns the full ModuleSpec for the module with the given
@@ -299,24 +312,48 @@ class ConfigManager:
         # todo: use api (and check the data against the definition?)
         old_data = copy.deepcopy(self.config.data)
         conf_part = data.find_no_exc(self.config.data, module_name)
+        update_cmd = None
+        use_part = None
         if conf_part:
             data.merge(conf_part, cmd)
-            update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
-                                                  conf_part)
-            seq = self.cc.group_sendmsg(update_cmd, module_name)
-            try:
-                answer, env = self.cc.group_recvmsg(False, seq)
-            except isc.cc.SessionTimeout:
-                answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
+            use_part = conf_part
         else:
             conf_part = data.set(self.config.data, module_name, {})
             data.merge(conf_part[module_name], cmd)
-            # send out changed info
-            update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
-                                                  conf_part[module_name])
+            use_part = conf_part[module_name]
+
+        # The command to send
+        update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
+                                              use_part)
+
+        # TODO: This design might need some revisiting. We might want some
+        # polymorphism instead of branching. But it just might turn out it
+        # will get solved by itself when we move everything to virtual modules
+        # (which is possible solution to the offline configuration problem)
+        # or when we solve the incorect behaviour here when a config is
+        # rejected (spying modules don't know it was rejected and some modules
+        # might have been commited already).
+        if module_name in self.virtual_modules:
+            # The module is virtual, so call it to get the answer
+            try:
+                error = self.virtual_modules[module_name](use_part)
+                if error is None:
+                    answer = ccsession.create_answer(0)
+                    # OK, it is successful, send the notify, but don't wait
+                    # for answer
+                    seq = self.cc.group_sendmsg(update_cmd, module_name)
+                else:
+                    answer = ccsession.create_answer(1, error)
+            # Make sure just a validating plugin don't kill the whole manager
+            except Exception as excp:
+                # Provide answer
+                answer = ccsession.create_answer(1, "Exception: " + str(excp))
+        else:
+            # Real module, send it over the wire to it
+            # send out changed info and wait for answer
             seq = self.cc.group_sendmsg(update_cmd, module_name)
-            # replace 'our' answer with that of the module
             try:
+                # replace 'our' answer with that of the module
                 answer, env = self.cc.group_recvmsg(False, seq)
             except isc.cc.SessionTimeout:
                 answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
diff --git a/src/lib/python/isc/config/config_data.py b/src/lib/python/isc/config/config_data.py
index 582c11c..cc3f484 100644
--- a/src/lib/python/isc/config/config_data.py
+++ b/src/lib/python/isc/config/config_data.py
@@ -213,6 +213,15 @@ class ConfigData:
             return spec['item_default'], True
         return None, False
 
+    def get_default_value(self, identifier):
+        """Returns the default from the specification, or None if there
+           is no default"""
+        spec = find_spec_part(self.specification.get_config_spec(), identifier)
+        if spec and 'item_default' in spec:
+            return spec['item_default']
+        else:
+            return None
+
     def get_module_spec(self):
         """Returns the ModuleSpec object associated with this ConfigData"""
         return self.specification
@@ -461,8 +470,8 @@ class MultiConfigData:
                 spec_part_list = spec_part['list_item_spec']
                 list_value, status = self.get_value(identifier)
                 if list_value is None:
-                    print("Error: identifier '%s' not found" % identifier)
-                    return
+                    raise isc.cc.data.DataNotFoundError(identifier)
+
                 if type(list_value) != list:
                     # the identifier specified a single element
                     self._append_value_item(result, spec_part_list, identifier, all)
diff --git a/src/lib/python/isc/config/tests/ccsession_test.py b/src/lib/python/isc/config/tests/ccsession_test.py
index 2ae37f5..4edc559 100644
--- a/src/lib/python/isc/config/tests/ccsession_test.py
+++ b/src/lib/python/isc/config/tests/ccsession_test.py
@@ -234,7 +234,18 @@ class TestModuleCCSession(unittest.TestCase):
         fake_session = FakeModuleCCSession()
         mccs = self.create_session("spec1.spec", None, None, fake_session)
         mccs.close()
-        self.assertEqual("closed", fake_session._socket)
+        self.assertEqual(None, fake_session._socket)
+
+    def test_del_opened(self):
+        fake_session = FakeModuleCCSession()
+        mccs = self.create_session("spec1.spec", None, None, fake_session)
+        mccs.__del__() # with opened fake_session
+
+    def test_del_closed(self):
+        fake_session = FakeModuleCCSession()
+        mccs = self.create_session("spec1.spec", None, None, fake_session)
+        fake_session.close()
+        mccs.__del__() # with closed fake_session
 
     def my_config_handler_ok(self, new_config):
         return isc.config.ccsession.create_answer(0)
diff --git a/src/lib/python/isc/config/tests/cfgmgr_test.py b/src/lib/python/isc/config/tests/cfgmgr_test.py
index 9534e14..b06db31 100644
--- a/src/lib/python/isc/config/tests/cfgmgr_test.py
+++ b/src/lib/python/isc/config/tests/cfgmgr_test.py
@@ -135,6 +135,8 @@ class TestConfigManager(unittest.TestCase):
         self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
         self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assert_(module_spec.get_module_name() not in
+                     self.cm.virtual_modules)
 
     def test_remove_module_spec(self):
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
@@ -143,6 +145,30 @@ class TestConfigManager(unittest.TestCase):
         self.assert_(module_spec.get_module_name() in self.cm.module_specs)
         self.cm.remove_module_spec(module_spec.get_module_name())
         self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assert_(module_spec.get_module_name() not in
+                     self.cm.virtual_modules)
+
+    def test_add_remove_virtual_module(self):
+        module_spec = isc.config.module_spec.module_spec_from_file(
+            self.data_path + os.sep + "spec1.spec")
+        check_func = lambda: True
+        # Make sure it's not in there before
+        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assert_(module_spec.get_module_name() not in
+                     self.cm.virtual_modules)
+        # Add it there
+        self.cm.set_virtual_module(module_spec, check_func)
+        # Check it's in there
+        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertEqual(self.cm.module_specs[module_spec.get_module_name()],
+                      module_spec)
+        self.assertEqual(self.cm.virtual_modules[module_spec.get_module_name()],
+                      check_func)
+        # Remove it again
+        self.cm.remove_module_spec(module_spec.get_module_name())
+        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assert_(module_spec.get_module_name() not in
+                     self.cm.virtual_modules)
 
     def test_get_module_spec(self):
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
@@ -312,6 +338,51 @@ class TestConfigManager(unittest.TestCase):
                                 },
                                 {'result': [0]})
 
+    def test_set_config_virtual(self):
+        """Test that if the module is virtual, we don't send it over the
+           message bus, but call the checking function.
+           """
+        # We run the same three times, with different return values
+        def single_test(value, returnFunc, expectedResult):
+            # Because closures can't assign to closed-in variables, we pass
+            # it trough self
+            self.called_with = None
+            def check_test(new_data):
+                self.called_with = new_data
+                return returnFunc()
+
+            # Register our virtual module
+            self.cm.set_virtual_module(self.spec, check_test)
+            # The fake session will throw now if it tries to read a response.
+            # Handy, we don't need to find a complicated way to check for it.
+            result = self.cm._handle_set_config_module(self.spec.
+                                                       get_module_name(),
+                                                       {'item1': value})
+            # Check the correct result is passed and our function was called
+            # With correct data
+            self.assertEqual(self.called_with['item1'], value)
+            self.assertEqual(result, {'result': expectedResult})
+            if expectedResult[0] == 0:
+                # Check it provided the correct notification
+                self.assertEqual(len(self.fake_session.message_queue), 1)
+                self.assertEqual({'command': [ 'config_update',
+                                 {'item1': value}]},
+                                 self.fake_session.get_message('Spec2', None))
+                # and the queue should now be empty again
+                self.assertEqual(len(self.fake_session.message_queue), 0)
+            else:
+                # It shouldn't send anything on error
+                self.assertEqual(len(self.fake_session.message_queue), 0)
+
+        # Success
+        single_test(5, lambda: None, [0])
+        # Graceful error
+        single_test(6, lambda: "Just error", [1, "Just error"])
+        # Exception from the checker
+        def raiser():
+            raise Exception("Just exception")
+        single_test(7, raiser, [1, "Exception: Just exception"])
+
     def test_set_config_all(self):
         my_ok_answer = { 'result': [ 0 ] }
 
diff --git a/src/lib/python/isc/config/tests/config_data_test.py b/src/lib/python/isc/config/tests/config_data_test.py
index 1aded94..48099bb 100644
--- a/src/lib/python/isc/config/tests/config_data_test.py
+++ b/src/lib/python/isc/config/tests/config_data_test.py
@@ -237,6 +237,27 @@ class TestConfigData(unittest.TestCase):
         self.assertEqual(None, value)
         self.assertEqual(False, default)
 
+    def test_get_default_value(self):
+        self.assertEqual(1, self.cd.get_default_value("item1"))
+        self.assertEqual('default', self.cd.get_default_value("item6/value1"))
+        self.assertEqual(None, self.cd.get_default_value("item6/value2"))
+
+        # set some local values to something else, and see if we
+        # still get the default
+        self.cd.set_local_config({"item1": 2, "item6": { "value1": "asdf" } })
+
+        self.assertEqual((2, False), self.cd.get_value("item1"))
+        self.assertEqual(1, self.cd.get_default_value("item1"))
+        self.assertEqual(('asdf', False), self.cd.get_value("item6/value1"))
+        self.assertEqual('default', self.cd.get_default_value("item6/value1"))
+
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.cd.get_default_value,
+                          "does_not_exist/value1")
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.cd.get_default_value,
+                          "item6/doesnotexist")
+
     def test_set_local_config(self):
         self.cd.set_local_config({"item1": 2})
         value, default = self.cd.get_value("item1")
@@ -465,8 +486,8 @@ class TestMultiConfigData(unittest.TestCase):
 
         module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec24.spec")
         self.mcd.set_specification(module_spec)
-        maps = self.mcd.get_value_maps("/Spec24/item")
-        self.assertEqual([], maps)
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.mcd.get_value_maps, "/Spec24/item", 4)
         self.mcd._set_current_config({ "Spec24": { "item": [] } })
         maps = self.mcd.get_value_maps("/Spec24/item")
         self.assertEqual([{'default': False, 'modified': False, 'name': 'Spec24/item', 'type': 'list', 'value': []}], maps)
diff --git a/src/lib/python/isc/config/tests/unittest_fakesession.py b/src/lib/python/isc/config/tests/unittest_fakesession.py
index e31b436..1641ec0 100644
--- a/src/lib/python/isc/config/tests/unittest_fakesession.py
+++ b/src/lib/python/isc/config/tests/unittest_fakesession.py
@@ -35,6 +35,7 @@ class FakeModuleCCSession:
         # the message_queue is empty when receive is called, throw
         # a SessionTimeout
         self._timeout = 0
+        self._closed = False
 
     def group_subscribe(self, group_name, instance_name = None):
         if not group_name in self.subscriptions:
@@ -43,6 +44,11 @@ class FakeModuleCCSession:
             self.subscriptions[group_name].append(instance_name)
             
     def group_unsubscribe(self, group_name, instance_name = None):
+
+        # raises SessionError if the session has been already closed.
+        if self._closed:
+            raise isc.cc.SessionError("Session has been closed.")        
+
         if group_name in self.subscriptions:
             if instance_name:
                 if len(self.subscriptions[group_name]) > 1:
@@ -94,7 +100,8 @@ class FakeModuleCCSession:
 
     def close(self):
         # need to pass along somehow that this function has been called,
-        self._socket = "closed"
+        self._socket = None
+        self._closed = True
 
     def set_timeout(self, timeout):
         self._timeout = timeout
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 43dc7af..178a983 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -142,13 +142,17 @@ class NotifyOut:
         if zone_id not in self._notify_infos:
             return
 
+        # Has no slave servers, skip it.
+        if (len(self._notify_infos[zone_id].notify_slaves) <= 0):
+            return
+
         with self._lock:
             if (self.notify_num >= _MAX_NOTIFY_NUM) or (zone_id in self._notifying_zones):
                 if zone_id not in self._waiting_zones:
                     self._waiting_zones.append(zone_id)
             else:
                 self._notify_infos[zone_id].prepare_notify_out()
-                self.notify_num += 1 
+                self.notify_num += 1
                 self._notifying_zones.append(zone_id)
 
     def _dispatcher(self, started_event):
@@ -300,7 +304,7 @@ class NotifyOut:
         try:
             r_fds, w, e = select.select(valid_socks, [], [], block_timeout)
         except select.error as err:
-            if err.args[0] != EINTR:
+            if err.args[0] != errno.EINTR:
                 return {}, {}
 
         if self._read_sock in r_fds: # user has called shutdown()
diff --git a/src/lib/python/isc/notify/tests/Makefile.am b/src/lib/python/isc/notify/tests/Makefile.am
index c5f0165..a83ff86 100644
--- a/src/lib/python/isc/notify/tests/Makefile.am
+++ b/src/lib/python/isc/notify/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
 # required by loadable python modules.
 LIBRARY_PATH_PLACEHOLDER =
 if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
 # test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index c4c149c..44725d0 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -99,36 +99,51 @@ class TestNotifyOut(unittest.TestCase):
         self._notify._notify_infos[('example.org.', 'IN')] = MockZoneNotifyInfo('example.org.', 'IN')
         self._notify._notify_infos[('example.org.', 'CH')] = MockZoneNotifyInfo('example.org.', 'CH')
 
-        info = self._notify._notify_infos[('example.net.', 'IN')]
-        info.notify_slaves.append(('127.0.0.1', 53))
-        info.notify_slaves.append(('1.1.1.1', 5353))
+        net_info = self._notify._notify_infos[('example.net.', 'IN')]
+        net_info.notify_slaves.append(('127.0.0.1', 53))
+        net_info.notify_slaves.append(('1.1.1.1', 5353))
+        com_info = self._notify._notify_infos[('example.com.', 'IN')]
+        com_info.notify_slaves.append(('1.1.1.1', 5353))
+        com_ch_info = self._notify._notify_infos[('example.com.', 'CH')]
+        com_ch_info.notify_slaves.append(('1.1.1.1', 5353))
 
     def tearDown(self):
         self._db_file.close()
         os.unlink(self._db_file.name)
 
     def test_send_notify(self):
+        notify_out._MAX_NOTIFY_NUM = 2
+
         self._notify.send_notify('example.net')
         self.assertEqual(self._notify.notify_num, 1)
-        self.assertEqual(self._notify._notifying_zones[0], ('example.net.','IN'))
+        self.assertEqual(self._notify._notifying_zones[0], ('example.net.', 'IN'))
 
         self._notify.send_notify('example.com')
         self.assertEqual(self._notify.notify_num, 2)
-        self.assertEqual(self._notify._notifying_zones[1], ('example.com.','IN'))
+        self.assertEqual(self._notify._notifying_zones[1], ('example.com.', 'IN'))
 
-        notify_out._MAX_NOTIFY_NUM = 3
+        # notify_num is equal to MAX_NOTIFY_NUM, append it to waiting_zones list.
         self._notify.send_notify('example.com', 'CH')
-        self.assertEqual(self._notify.notify_num, 3)
-        self.assertEqual(self._notify._notifying_zones[2], ('example.com.','CH'))
-
-        self._notify.send_notify('example.org.')
-        self.assertEqual(self._notify._waiting_zones[0], ('example.org.', 'IN'))
-        self._notify.send_notify('example.org.')
+        self.assertEqual(self._notify.notify_num, 2)
         self.assertEqual(1, len(self._notify._waiting_zones))
 
+        # zone_id is already in notifying_zones list, append it to waiting_zones list.
+        self._notify.send_notify('example.net')
+        self.assertEqual(2, len(self._notify._waiting_zones))
+        self.assertEqual(self._notify._waiting_zones[1], ('example.net.', 'IN'))
+
+        # zone_id is already in waiting_zones list, skip it.
+        self._notify.send_notify('example.net')
+        self.assertEqual(2, len(self._notify._waiting_zones))
+
+        # has no slave masters, skip it.
         self._notify.send_notify('example.org.', 'CH')
+        self.assertEqual(self._notify.notify_num, 2)
+        self.assertEqual(2, len(self._notify._waiting_zones))
+
+        self._notify.send_notify('example.org.')
+        self.assertEqual(self._notify.notify_num, 2)
         self.assertEqual(2, len(self._notify._waiting_zones))
-        self.assertEqual(self._notify._waiting_zones[1], ('example.org.', 'CH'))
 
     def test_wait_for_notify_reply(self):
         self._notify.send_notify('example.net.')
@@ -171,6 +186,7 @@ class TestNotifyOut(unittest.TestCase):
         self._notify.send_notify('example.net.')
         self._notify.send_notify('example.com.')
         notify_out._MAX_NOTIFY_NUM = 2
+        # zone example.org. has no slave servers.
         self._notify.send_notify('example.org.')
         self._notify.send_notify('example.com.', 'CH')
 
@@ -179,17 +195,19 @@ class TestNotifyOut(unittest.TestCase):
         self.assertEqual(0, info.notify_try_num)
         self.assertEqual(info.get_current_notify_target(), ('1.1.1.1', 5353))
         self.assertEqual(2, self._notify.notify_num)
+        self.assertEqual(1, len(self._notify._waiting_zones))
 
         self._notify._notify_next_target(info)
         self.assertEqual(0, info.notify_try_num)
         self.assertIsNone(info.get_current_notify_target())
         self.assertEqual(2, self._notify.notify_num)
-        self.assertEqual(1, len(self._notify._waiting_zones))
+        self.assertEqual(0, len(self._notify._waiting_zones))
 
         example_com_info = self._notify._notify_infos[('example.com.', 'IN')]
         self._notify._notify_next_target(example_com_info)
-        self.assertEqual(2, self._notify.notify_num)
-        self.assertEqual(2, len(self._notify._notifying_zones))
+        self.assertEqual(1, self._notify.notify_num)
+        self.assertEqual(1, len(self._notify._notifying_zones))
+        self.assertEqual(0, len(self._notify._waiting_zones))
 
     def test_handle_notify_reply(self):
         self.assertEqual(notify_out._BAD_REPLY_PACKET, self._notify._handle_notify_reply(None, b'badmsg'))
diff --git a/src/lib/python/isc/testutils/Makefile.am b/src/lib/python/isc/testutils/Makefile.am
index 8f00a9b..dd032fb 100644
--- a/src/lib/python/isc/testutils/Makefile.am
+++ b/src/lib/python/isc/testutils/Makefile.am
@@ -1 +1 @@
-EXTRA_DIST = __init__.py parse_args.py
+EXTRA_DIST = __init__.py parse_args.py tsigctx_mock.py
diff --git a/src/lib/python/isc/testutils/tsigctx_mock.py b/src/lib/python/isc/testutils/tsigctx_mock.py
new file mode 100644
index 0000000..a9af9b9
--- /dev/null
+++ b/src/lib/python/isc/testutils/tsigctx_mock.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from pydnspp import *
+
+class MockTSIGContext(TSIGContext):
+    """Tthis is a mock of TSIGContext class for testing.
+    Via its "error" attribute, you can fake the result of verify(), thereby
+    you can test many of TSIG related tests without requiring actual crypto
+    setups.  "error" should be either a TSIGError type value or a callable
+    object (typically a function).  In the latter case, the callable object
+    will take the context as a parameter, and is expected to return a
+    TSIGError object.
+    """
+
+    def __init__(self, tsig_key):
+        super().__init__(tsig_key)
+        self.error = None
+        self.verify_called = 0  # number of verify() called
+
+    def sign(self, qid, data):
+        """Transparently delegate the processing to the super class.
+        It doesn't matter much anyway because normal applications that would
+        be implemented in Python normally won't call TSIGContext.sign()
+        directly.
+        """
+        return super().sign(qid, data)
+
+    def verify(self, tsig_record, data):
+        self.verify_called += 1
+        # call real "verify" so that we can notice any misue (which would
+        # result in exception.
+        super().verify(tsig_record, data)
+        return self.get_error()
+
+    def get_error(self):
+        if self.error is None:
+            return super().get_error()
+        if hasattr(self.error, '__call__'):
+            return self.error(self)
+        return self.error
diff --git a/src/lib/python/isc/util/Makefile.am b/src/lib/python/isc/util/Makefile.am
index 7ab8048..f6cbb78 100644
--- a/src/lib/python/isc/util/Makefile.am
+++ b/src/lib/python/isc/util/Makefile.am
@@ -1,5 +1,5 @@
 SUBDIRS = . tests
 
-python_PYTHON = __init__.py process.py socketserver_mixin.py
+python_PYTHON = __init__.py process.py socketserver_mixin.py file.py
 
 pythondir = $(pyexecdir)/isc/util
diff --git a/src/lib/python/isc/util/file.py b/src/lib/python/isc/util/file.py
new file mode 100644
index 0000000..faef9a8
--- /dev/null
+++ b/src/lib/python/isc/util/file.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""Various functions for working with files and directories."""
+
+from os.path import exists, join
+
+def path_search(filename, paths):
+    """
+    Searches list of paths to find filename in one of them. The found one will
+    be returned or IOError will be returned if it isn't found.
+    """
+    for p in paths:
+        f = join(p, filename)
+        if exists(f):
+            return f
+    raise IOError("'" + filename + "' not found in " + str(paths))
diff --git a/src/lib/python/isc/util/tests/Makefile.am b/src/lib/python/isc/util/tests/Makefile.am
index f32fda0..0ce96de 100644
--- a/src/lib/python/isc/util/tests/Makefile.am
+++ b/src/lib/python/isc/util/tests/Makefile.am
@@ -1,5 +1,5 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = process_test.py socketserver_mixin_test.py
+PYTESTS = process_test.py socketserver_mixin_test.py file_test.py
 EXTRA_DIST = $(PYTESTS)
 
 # test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/python/isc/util/tests/file_test.py b/src/lib/python/isc/util/tests/file_test.py
new file mode 100644
index 0000000..fb765d7
--- /dev/null
+++ b/src/lib/python/isc/util/tests/file_test.py
@@ -0,0 +1,32 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import isc.util.file
+import unittest
+
+class FileTest(unittest.TestCase):
+    def test_search_path_find(self):
+        """Test it returns the first occurence of the file"""
+        self.assertEqual('./Makefile',
+                         isc.util.file.path_search('Makefile',
+                                                  ['/no/such/directory/', '.',
+                                                  '../tests/']))
+
+    def test_search_path_notfound(self):
+        """Test it throws an exception when the file can't be found"""
+        self.assertRaises(IOError, isc.util.file.path_search, 'no file', ['/no/such/directory'])
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index 0ee5813..b753cc9 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -28,6 +28,7 @@
 #include <dns/message.h>
 #include <dns/opcode.h>
 #include <dns/exceptions.h>
+#include <dns/rdataclass.h>
 
 #include <resolve/resolve.h>
 #include <cache/resolver_cache.h>
@@ -35,15 +36,77 @@
 #include <nsas/nameserver_address.h>
 
 #include <asio.hpp>
-#include <asiolink/dns_service.h>
-#include <asiolink/io_fetch.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/io_fetch.h>
 #include <asiolink/io_service.h>
 #include <resolve/recursive_query.h>
 
 using isc::log::dlog;
 using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::asiolink;
 
-namespace asiolink {
+namespace isc {
+namespace asiodns {
+
+namespace {
+// Function to check if the given name/class has any address in the cache
+bool
+hasAddress(const Name& name, const RRClass& rrClass,
+      const isc::cache::ResolverCache& cache)
+{
+    // FIXME: If we are single-stack and we get only the other type of
+    // address, what should we do? In that case, it will be considered
+    // unreachable, which is most probably true, because A and AAAA will
+    // usually have the same RTT, so we should have both or none from the
+    // glue.
+    return (cache.lookup(name, RRType::A(), rrClass) != RRsetPtr() ||
+            cache.lookup(name, RRType::AAAA(), rrClass) != RRsetPtr());
+}
+
+}
+
+/// \brief Find deepest usable delegation in the cache
+///
+/// This finds the deepest delegation we have in cache and is safe to use.
+/// It is not public function, therefore it's not in header. But it's not
+/// in anonymous namespace, so we can call it from unittests.
+/// \param name The name we want to delegate to.
+/// \param cache The place too look for known delegations.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+                  isc::cache::ResolverCache& cache)
+{
+    RRsetPtr cachedNS;
+    // Look for delegation point from bottom, until we find one with
+    // IP address or get to root.
+    //
+    // We need delegation with IP address so we can ask it right away.
+    // If we don't have the IP address, we would need to ask above it
+    // anyway in the best case, and the NS could be inside the zone,
+    // and we could get all loopy with the NSAS in the worst case.
+    while (name.getLabelCount() > 1 &&
+           (cachedNS = cache.lookupDeepestNS(name, rrclass)) != RRsetPtr()) {
+        // Look if we have an IP address for the NS
+        for (RdataIteratorPtr ns(cachedNS->getRdataIterator());
+             !ns->isLast(); ns->next()) {
+            // Do we have IP for this specific NS?
+            if (hasAddress(dynamic_cast<const rdata::generic::NS&>(
+                               ns->getCurrent()).getNSName(), rrclass,
+                           cache)) {
+                // Found one, stop checking and use this zone
+                // (there may be more addresses, that's only better)
+                return (cachedNS->getName().toText());
+            }
+        }
+        // We don't have anything for this one, so try something higher
+        if (name.getLabelCount() > 1) {
+            name = name.split(1);
+        }
+    }
+    // Fallback, nothing found, start at root
+    return (".");
+}
 
 typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
 
@@ -57,19 +120,19 @@ RecursiveQuery::RecursiveQuery(DNSService& dns_service,
     const std::vector<std::pair<std::string, uint16_t> >& upstream,
     const std::vector<std::pair<std::string, uint16_t> >& upstream_root,
     int query_timeout, int client_timeout, int lookup_timeout,
-    unsigned retries) :
+    unsigned retries)
+    :
     dns_service_(dns_service),
     nsas_(nsas), cache_(cache),
     upstream_(new AddressVector(upstream)),
     upstream_root_(new AddressVector(upstream_root)),
     test_server_("", 0),
     query_timeout_(query_timeout), client_timeout_(client_timeout),
-    lookup_timeout_(lookup_timeout), retries_(retries)
+    lookup_timeout_(lookup_timeout), retries_(retries), rtt_recorder_()
 {
 }
 
 // Set the test server - only used for unit testing.
-
 void
 RecursiveQuery::setTestServer(const std::string& address, uint16_t port) {
     dlog("Setting test server to " + address + "(" +
@@ -78,6 +141,11 @@ RecursiveQuery::setTestServer(const std::string& address, uint16_t port) {
     test_server_.second = port;
 }
 
+// Set the RTT recorder - only used for testing
+void
+RecursiveQuery::setRttRecorder(boost::shared_ptr<RttRecorder>& recorder) {
+    rtt_recorder_ = recorder;
+}
 
 namespace {
 
@@ -123,13 +191,12 @@ private:
     // Info for (re)sending the query (the question and destination)
     Question question_;
 
+    // This is the query message got from client
+    ConstMessagePtr query_message_;
+
     // This is where we build and store our final answer
     MessagePtr answer_message_;
 
-    // currently we use upstream as the current list of NS records
-    // we should differentiate between forwarding and resolving
-    boost::shared_ptr<AddressVector> upstream_;
-
     // Test server - only used for testing.  This takes precedence over all
     // other servers if the port is non-zero.
     std::pair<std::string, uint16_t> test_server_;
@@ -223,11 +290,14 @@ private:
     // event; we can cancel the NSAS callback safely.
     size_t outstanding_events_;
 
+    // RTT Recorder.  Used for testing, the RTTs of queries are
+    // sent to this object as well as being used to update the NSAS.
+    boost::shared_ptr<RttRecorder> rtt_recorder_;
+
     // perform a single lookup; first we check the cache to see
     // if we have a response for our query stored already. if
     // so, call handlerecursiveresponse(), if not, we call send()
     void doLookup() {
-        cur_zone_ = ".";
         dlog("doLookup: try cache");
         Message cached_message(Message::RENDER);
         isc::resolve::initResponseMessage(question_, cached_message);
@@ -243,9 +313,12 @@ private:
                 stop();
             }
         } else {
+            dlog("doLookup: get lowest usable delegation from cache");
+            cur_zone_ = deepestDelegation(question_.getName(),
+                                          question_.getClass(), cache_);
             send();
         }
-        
+
     }
 
     // Send the current question to the given nameserver address
@@ -270,13 +343,8 @@ private:
         }
     }
     
-    // 'general' send; if we are in forwarder mode, send a query to
-    // a random nameserver in our forwarders list. If we are in
-    // recursive mode, ask the NSAS to give us an address.
+    // 'general' send, ask the NSAS to give us an address.
     void send(IOFetch::Protocol protocol = IOFetch::UDP) {
-        // If are in forwarder mode, send it to a random
-        // forwarder. If not, ask the NSAS for an address
-        const int uc = upstream_->size();
         protocol_ = protocol;   // Store protocol being used for this
         if (test_server_.second != 0) {
             dlog("Sending upstream query (" + question_.toText() +
@@ -288,18 +356,6 @@ private:
                 test_server_.second, buffer_, this,
                 query_timeout_);
             io_.get_io_service().post(query);
-        } else if (uc > 0) {
-            // TODO: use boost, or rand()-utility function we provide
-            int serverIndex = rand() % uc;
-            dlog("Sending upstream query (" + question_.toText() +
-                ") to " + upstream_->at(serverIndex).first);
-            ++outstanding_events_;
-            gettimeofday(&current_ns_qsent_time, NULL);
-            IOFetch query(protocol, io_, question_,
-                upstream_->at(serverIndex).first,
-                upstream_->at(serverIndex).second, buffer_, this,
-                query_timeout_);
-            io_.get_io_service().post(query);
         } else {
             // Ask the NSAS for an address for the current zone,
             // the callback will call the actual sendTo()
@@ -474,18 +530,19 @@ public:
     RunningQuery(IOService& io,
         const Question& question,
         MessagePtr answer_message,
-        boost::shared_ptr<AddressVector> upstream,
         std::pair<std::string, uint16_t>& test_server,
         OutputBufferPtr buffer,
         isc::resolve::ResolverInterface::CallbackPtr cb,
         int query_timeout, int client_timeout, int lookup_timeout,
         unsigned retries,
         isc::nsas::NameserverAddressStore& nsas,
-        isc::cache::ResolverCache& cache) :
+        isc::cache::ResolverCache& cache,
+        boost::shared_ptr<RttRecorder>& recorder)
+        :
         io_(io),
         question_(question),
+        query_message_(),
         answer_message_(answer_message),
-        upstream_(upstream),
         test_server_(test_server),
         buffer_(buffer),
         resolvercallback_(cb),
@@ -502,7 +559,8 @@ public:
         cur_zone_("."),
         nsas_callback_(new ResolverNSASCallback(this)),
         nsas_callback_out_(false),
-        outstanding_events_(0)
+        outstanding_events_(0),
+        rtt_recorder_(recorder)
     {
         // Setup the timer to stop trying (lookup_timeout)
         if (lookup_timeout >= 0) {
@@ -619,9 +677,11 @@ public:
                 rtt = 1000 * (cur_time.tv_sec - current_ns_qsent_time.tv_sec);
                 rtt += (cur_time.tv_usec - current_ns_qsent_time.tv_usec) / 1000;
             }
-
             dlog("RTT: " + boost::lexical_cast<std::string>(rtt));
             current_ns_address.updateRTT(rtt);
+            if (rtt_recorder_) {
+                rtt_recorder_->addRtt(rtt);
+            }
 
             try {
                 Message incoming(Message::PARSE);
@@ -630,8 +690,7 @@ public:
                 incoming.fromWire(ibuf);
 
                 buffer_->clear();
-                if (recursive_mode() &&
-                    incoming.getRcode() == Rcode::NOERROR()) {
+                if (incoming.getRcode() == Rcode::NOERROR()) {
                     done_ = handleRecursiveAnswer(incoming);
                 } else {
                     isc::resolve::copyResponseMessage(incoming, answer_message_);
@@ -665,13 +724,11 @@ public:
         } else if (!done_ && retries_--) {
             // Query timed out, but we have some retries, so send again
             dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", resending query");
-            if (recursive_mode()) {
-                current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
-            }
+            current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
             send();
         } else {
             // We are either already done, or out of retries
-            if (recursive_mode() && result == IOFetch::TIME_OUT) {
+            if (result == IOFetch::TIME_OUT) {
                 dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", giving up");
                 current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
             }
@@ -688,12 +745,179 @@ public:
     void makeSERVFAIL() {
         isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
     }
-    
-    // Returns true if we are in 'recursive' mode
-    // Returns false if we are in 'forwarding' mode
-    // (i.e. if we have anything in upstream_)
-    bool recursive_mode() const {
-        return upstream_->empty();
+};
+
+class ForwardQuery : public IOFetch::Callback {
+private:
+    // The io service to handle async calls
+    IOService& io_;
+
+    // This is the query message got from client
+    ConstMessagePtr query_message_;
+
+    // This is where we build and store our final answer
+    MessagePtr answer_message_;
+
+    // List of nameservers to forward to
+    boost::shared_ptr<AddressVector> upstream_;
+
+    // Buffer to store the result.
+    OutputBufferPtr buffer_;
+
+    // This will be notified when we succeed or fail
+    isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
+
+    /*
+     * TODO Do something more clever with timeouts. In the long term, some
+     *     computation of average RTT, increase with each retry, etc.
+     */
+    // Timeout information
+    int query_timeout_;
+
+    // TODO: replace by our wrapper
+    asio::deadline_timer client_timer;
+    asio::deadline_timer lookup_timer;
+
+    // Make FowardQuery deletes itself safely. for more information see
+    // the comments of outstanding_events in RunningQuery.
+    size_t outstanding_events_;
+
+    // If we have a client timeout, we call back with a failure message,
+    // but we do not stop yet. We use this variable to make sure we
+    // don't call back a second time later
+    bool callback_called_;
+
+    // send the query to the server.
+    void send(IOFetch::Protocol protocol = IOFetch::UDP) {
+        const int uc = upstream_->size();
+        buffer_->clear();
+        int serverIndex = rand() % uc;
+        ConstQuestionPtr question = *(query_message_->beginQuestion());
+        dlog("Sending upstream query (" + question->toText() +
+             ") to " + upstream_->at(serverIndex).first);
+        ++outstanding_events_;
+        // Forward the query, create the IOFetch with
+        // query message, so that query flags can be forwarded
+        // together.
+        IOFetch query(protocol, io_, query_message_,
+            upstream_->at(serverIndex).first,
+            upstream_->at(serverIndex).second,
+            buffer_, this, query_timeout_);
+
+        io_.get_io_service().post(query);
+    }
+
+public:
+    ForwardQuery(IOService& io,
+        ConstMessagePtr query_message,
+        MessagePtr answer_message,
+        boost::shared_ptr<AddressVector> upstream,
+        OutputBufferPtr buffer,
+        isc::resolve::ResolverInterface::CallbackPtr cb,
+        int query_timeout, int client_timeout, int lookup_timeout) :
+        io_(io),
+        query_message_(query_message),
+        answer_message_(answer_message),
+        upstream_(upstream),
+        buffer_(buffer),
+        resolvercallback_(cb),
+        query_timeout_(query_timeout),
+        client_timer(io.get_io_service()),
+        lookup_timer(io.get_io_service()),
+        outstanding_events_(0),
+        callback_called_(false)
+    {
+        // Setup the timer to stop trying (lookup_timeout)
+        if (lookup_timeout >= 0) {
+            lookup_timer.expires_from_now(
+                boost::posix_time::milliseconds(lookup_timeout));
+            ++outstanding_events_;
+            lookup_timer.async_wait(boost::bind(&ForwardQuery::lookupTimeout, this));
+        }
+
+        // Setup the timer to send an answer (client_timeout)
+        if (client_timeout >= 0) {
+            client_timer.expires_from_now(
+                boost::posix_time::milliseconds(client_timeout));
+            ++outstanding_events_;
+            client_timer.async_wait(boost::bind(&ForwardQuery::clientTimeout, this));
+        }
+
+        send();
+    }
+
+    virtual void lookupTimeout() {
+        if (!callback_called_) {
+            makeSERVFAIL();
+            callCallback(false);
+        }
+        assert(outstanding_events_ > 0);
+        --outstanding_events_;
+        stop();
+    }
+
+    virtual void clientTimeout() {
+        if (!callback_called_) {
+            makeSERVFAIL();
+            callCallback(false);
+        }
+        assert(outstanding_events_ > 0);
+        --outstanding_events_;
+        stop();
+    }
+
+    // If the callback has not been called yet, call it now
+    // If success is true, we call 'success' with our answer_message
+    // If it is false, we call failure()
+    void callCallback(bool success) {
+        if (!callback_called_) {
+            callback_called_ = true;
+            if (success) {
+                resolvercallback_->success(answer_message_);
+            } else {
+                resolvercallback_->failure();
+            }
+        }
+    }
+
+    virtual void stop() {
+        // if we cancel our timers, we will still get an event for
+        // that, so we cannot delete ourselves just yet (those events
+        // would be bound to a deleted object)
+        // cancel them one by one, both cancels should get us back
+        // here again.
+        // same goes if we have an outstanding query (can't delete
+        // until that one comes back to us)
+        lookup_timer.cancel();
+        client_timer.cancel();
+        if (outstanding_events_ > 0) {
+            return;
+        } else {
+            delete this;
+        }
+    }
+
+    // This function is used as callback from DNSQuery.
+    virtual void operator()(IOFetch::Result result) {
+        // XXX is this the place for TCP retry?
+        assert(outstanding_events_ > 0);
+        --outstanding_events_;
+        if (result != IOFetch::TIME_OUT) {
+            // we got an answer
+            Message incoming(Message::PARSE);
+            InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
+            incoming.fromWire(ibuf);
+            isc::resolve::copyResponseMessage(incoming, answer_message_);
+            callCallback(true);
+        }
+
+        stop();
+    }
+
+    // Clear the answer parts of answer_message, and set the rcode
+    // to servfail
+    void makeSERVFAIL() {
+        isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
     }
 };
 
@@ -736,10 +960,11 @@ RecursiveQuery::resolve(const QuestionPtr& question,
         } else {
             dlog("Message not found in cache, starting recursive query");
             // It will delete itself when it is done
-            new RunningQuery(io, *question, answer_message, upstream_,
+            new RunningQuery(io, *question, answer_message,
                              test_server_, buffer, callback,
                              query_timeout_, client_timeout_,
-                             lookup_timeout_, retries_, nsas_, cache_);
+                             lookup_timeout_, retries_, nsas_,
+                             cache_, rtt_recorder_);
         }
     }
 }
@@ -789,14 +1014,44 @@ RecursiveQuery::resolve(const Question& question,
         } else {
             dlog("Message not found in cache, starting recursive query");
             // It will delete itself when it is done
-            new RunningQuery(io, question, answer_message, upstream_,
+            new RunningQuery(io, question, answer_message, 
                              test_server_, buffer, crs, query_timeout_,
                              client_timeout_, lookup_timeout_, retries_,
-                             nsas_, cache_);
+                             nsas_, cache_, rtt_recorder_);
         }
     }
 }
 
+void
+RecursiveQuery::forward(ConstMessagePtr query_message,
+    MessagePtr answer_message,
+    OutputBufferPtr buffer,
+    DNSServer* server,
+    isc::resolve::ResolverInterface::CallbackPtr callback)
+{
+    // XXX: eventually we will need to be able to determine whether
+    // the message should be sent via TCP or UDP, or sent initially via
+    // UDP and then fall back to TCP on failure, but for the moment
+    // we're only going to handle UDP.
+    IOService& io = dns_service_.getIOService();
 
+    if (!callback) {
+        callback.reset(new isc::resolve::ResolverCallbackServer(server));
+    }
+
+    // TODO: general 'prepareinitialanswer'
+    answer_message->setOpcode(isc::dns::Opcode::QUERY());
+    ConstQuestionPtr question = *query_message->beginQuestion();
+    answer_message->addQuestion(*question);
+
+    // implement the simplest forwarder, which will pass
+    // everything throught without interpretation, except
+    // QID, port number. The response will not be cached.
+    // It will delete itself when it is done
+    new ForwardQuery(io, query_message, answer_message,
+                      upstream_, buffer, callback, query_timeout_,
+                      client_timeout_, lookup_timeout_);
+}
 
-} // namespace asiolink
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h
index 1180d55..b9fb80d 100644
--- a/src/lib/resolve/recursive_query.h
+++ b/src/lib/resolve/recursive_query.h
@@ -15,18 +15,49 @@
 #ifndef __RECURSIVE_QUERY_H
 #define __RECURSIVE_QUERY_H 1
 
-#include <asiolink/dns_service.h>
-#include <asiolink/dns_server.h>
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/dns_server.h>
 #include <nsas/nameserver_address_store.h>
 #include <cache/resolver_cache.h>
 
-namespace asiolink {
-/// \brief The \c RecursiveQuery class provides a layer of abstraction around
-/// the ASIO code that carries out an upstream query.
+namespace isc {
+namespace asiodns {
+
+/// \brief RTT Recorder
+///
+/// Used for testing, this class will hold the set of round-trip times to
+/// nameservers for the current recursive query.
+///
+/// A pointer to an object of this class is passed to RecursiveQuery which in
+/// turn passes it to the created RunningQuery class.  When a running query
+/// completes, its RTT is passed to the RTT Recorder object.
+class RttRecorder {
+public:
+    /// \brief Record Time
+    ///
+    /// Adds a round-trip time to the internal vector of times.
+    ///
+    /// \param RTT to record.
+    void addRtt(uint32_t rtt) {
+        rtt_.push_back(rtt);
+    }
+
+    /// \brief Return RTT Vector
+    std::vector<uint32_t> getRtt() const {
+        return rtt_;
+    }
+
+private:
+    std::vector<uint32_t>   rtt_;   ///< Stored round-trip times
+};
+
+
+/// \brief Recursive Query
 ///
-/// This design is very preliminary; currently it is only capable of
-/// handling simple forward requests to a single resolver.
+/// The \c RecursiveQuery class provides a layer of abstraction around
+/// the ASIO code that carries out an upstream query.
+
 class RecursiveQuery {
     ///
     /// \name Constructors
@@ -56,17 +87,25 @@ public:
                    isc::nsas::NameserverAddressStore& nsas,
                    isc::cache::ResolverCache& cache,
                    const std::vector<std::pair<std::string, uint16_t> >&
-                   upstream, 
+                   upstream,
                    const std::vector<std::pair<std::string, uint16_t> >&
-                   upstream_root, 
+                   upstream_root,
                    int query_timeout = 2000,
                    int client_timeout = 4000,
                    int lookup_timeout = 30000,
                    unsigned retries = 3);
     //@}
 
+    /// \brief Set Round-Trip Time Recorder
+    ///
+    /// Sets the RTT recorder object.  This is not accessed directly, instead
+    /// it is passed to created RunningQuery objects.
+    ///
+    /// \param recorder Pointer to the RTT recorder object used to hold RTTs.
+    void setRttRecorder(boost::shared_ptr<RttRecorder>& recorder);
+
     /// \brief Initiate resolving
-    /// 
+    ///
     /// When sendQuery() is called, a (set of) message(s) is sent
     /// asynchronously. If upstream servers are set, one is chosen
     /// and the response (if any) from that server will be returned.
@@ -99,9 +138,23 @@ public:
     /// \param server A pointer to the \c DNSServer object handling the client
     void resolve(const isc::dns::Question& question,
                  isc::dns::MessagePtr answer_message,
-                 isc::dns::OutputBufferPtr buffer,
+                 isc::util::OutputBufferPtr buffer,
                  DNSServer* server);
 
+    /// \brief Initiates forwarding for the given query.
+    ///
+    ///  Others parameters are same with the parameters of
+    ///  function resolve().
+    ///
+    /// \param query_message the full query got from client.
+    /// \param callback callback object
+    void forward(isc::dns::ConstMessagePtr query_message,
+                 isc::dns::MessagePtr answer_message,
+                 isc::util::OutputBufferPtr buffer,
+                 DNSServer* server,
+                 isc::resolve::ResolverInterface::CallbackPtr callback =
+                     isc::resolve::ResolverInterface::CallbackPtr());
+
     /// \brief Set Test Server
     ///
     /// This method is *only* for unit testing the class.  If set, it enables
@@ -113,7 +166,7 @@ public:
     /// \param address IP address of the test server.
     /// \param port Port number of the test server
     void setTestServer(const std::string& address, uint16_t port);
-    
+
 private:
     DNSService& dns_service_;
     isc::nsas::NameserverAddressStore& nsas_;
@@ -127,7 +180,9 @@ private:
     int client_timeout_;
     int lookup_timeout_;
     unsigned retries_;
+    boost::shared_ptr<RttRecorder>  rtt_recorder_;  ///< Round-trip time recorder
 };
 
-}      // namespace asiolink
+}      // namespace asiodns
+}      // namespace isc
 #endif // __RECURSIVE_QUERY_H
diff --git a/src/lib/resolve/resolver_callback.h b/src/lib/resolve/resolver_callback.h
index f69d8a7..79138e8 100644
--- a/src/lib/resolve/resolver_callback.h
+++ b/src/lib/resolve/resolver_callback.h
@@ -15,9 +15,11 @@
 #ifndef _ISC_RESOLVER_CALLBACK_H
 #define _ISC_RESOLVER_CALLBACK_H 1
 
-#include <asiolink/asiolink.h>
+#include <asiodns/dns_server.h>
 #include <dns/message.h>
 
+#include <resolve/resolver_interface.h>
+
 namespace isc {
 namespace resolve {
 
@@ -31,7 +33,7 @@ namespace resolve {
 /// as the server itself should also have a reference.
 class ResolverCallbackServer : public ResolverInterface::Callback {
 public:
-    ResolverCallbackServer(asiolink::DNSServer* server) :
+    ResolverCallbackServer(asiodns::DNSServer* server) :
         server_(server->clone()) {}
     ~ResolverCallbackServer() { delete server_; };
     
@@ -39,7 +41,7 @@ public:
     void failure();
 
 private:
-    asiolink::DNSServer* server_;
+    asiodns::DNSServer* server_;
 };
 
 } //namespace resolve
diff --git a/src/lib/resolve/tests/Makefile.am b/src/lib/resolve/tests/Makefile.am
index a403272..edea7cd 100644
--- a/src/lib/resolve/tests/Makefile.am
+++ b/src/lib/resolve/tests/Makefile.am
@@ -27,6 +27,7 @@ run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/nsas/libnsas.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/cache/libcache.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/asiodns/libasiodns.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/resolve/libresolve.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index ab1ffa3..4e939fa 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -30,11 +30,14 @@
 #include <dns/tests/unittest_util.h>
 #include <dns/rcode.h>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/unittests/resolver.h>
 #include <dns/message.h>
+#include <dns/rdataclass.h>
 
 #include <nsas/nameserver_address_store.h>
 #include <cache/resolver_cache.h>
+#include <resolve/resolve.h>
 
 // IMPORTANT: We shouldn't directly use ASIO definitions in this test.
 // In particular, we must not include asio.hpp in this file.
@@ -45,17 +48,31 @@
 // If we need to test something at the level of underlying ASIO and need
 // their definition, that test should go to asiolink/internal/tests.
 #include <resolve/recursive_query.h>
+#include <asiodns/dns_lookup.h>
 #include <asiolink/io_socket.h>
 #include <asiolink/io_service.h>
 #include <asiolink/io_message.h>
 #include <asiolink/io_error.h>
-#include <asiolink/dns_lookup.h>
 #include <asiolink/simple_callback.h>
 
 using isc::UnitTestUtil;
 using namespace std;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
 using namespace isc::dns;
+using namespace isc::util;
+
+namespace isc {
+namespace asiodns {
+
+// This is defined in recursive_query.cc, but not in header (it's not public
+// function). So bring it in to be tested.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+                  isc::cache::ResolverCache& cache);
+
+}
+}
 
 namespace {
 const char* const TEST_SERVER_PORT = "53535";
@@ -108,6 +125,9 @@ class RecursiveQueryTest : public ::testing::Test {
 protected:
     RecursiveQueryTest();
     ~RecursiveQueryTest() {
+        // It would delete itself, but after the io_service_, which could
+        // segfailt in case there were unhandled requests
+        resolver_.reset();
         if (res_ != NULL) {
             freeaddrinfo(res_);
         }
@@ -316,10 +336,10 @@ protected:
     private:
         // Currently unused; these will be used for testing
         // asynchronous lookup calls via the asyncLookup() method
-        boost::shared_ptr<asiolink::IOMessage> io_message_;
+        boost::shared_ptr<isc::asiolink::IOMessage> io_message_;
         isc::dns::MessagePtr message_;
         isc::dns::MessagePtr answer_message_;
-        isc::dns::OutputBufferPtr respbuf_;
+        isc::util::OutputBufferPtr respbuf_;
 
         // Callback functions provided by the caller
         const SimpleCallback* checkin_;
@@ -346,12 +366,6 @@ protected:
         private:
             bool* done_;
     };
-    
-    class MockResolver : public isc::resolve::ResolverInterface {
-        void resolve(const QuestionPtr& question,
-                     const ResolverInterface::CallbackPtr& callback) {
-        }
-    };
 
     // This version of mock server just stops the io_service when it is resumed
     // the second time. (Used in the clientTimeout test, where resume
@@ -421,16 +435,17 @@ protected:
     vector<uint8_t> callback_data_;
     int sock_;
     struct addrinfo* res_;
+    boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
 };
 
 RecursiveQueryTest::RecursiveQueryTest() :
     dns_service_(NULL), callback_(NULL), callback_protocol_(0),
-    callback_native_(-1), sock_(-1), res_(NULL)
+    callback_native_(-1), sock_(-1), res_(NULL),
+    resolver_(new isc::util::unittests::TestResolver())
 {
     io_service_ = new IOService();
     setDNSService(true, true);
-    boost::shared_ptr<MockResolver>mock_resolver(new MockResolver());
-    nsas_ = new isc::nsas::NameserverAddressStore(mock_resolver);
+    nsas_ = new isc::nsas::NameserverAddressStore(resolver_);
 }
 
 TEST_F(RecursiveQueryTest, v6UDPSend) {
@@ -565,9 +580,12 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
                       singleAddress(TEST_IPV4_ADDR, port));
 
     Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
+    Message query_message(Message::RENDER);
+    isc::resolve::initResponseMessage(q, query_message);
+
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.resolve(q, answer, buffer, &server);
+    rq.forward(ConstMessagePtr(&query_message), answer, buffer, &server);
 
     char data[4096];
     size_t size = sizeof(data);
@@ -632,8 +650,41 @@ bool tryRead(int sock_, int recv_options, size_t max, int* num) {
     return true;
 }
 
+// Mock resolver callback for testing forward query.
+class MockResolverCallback : public isc::resolve::ResolverInterface::Callback {
+public:
+    enum ResultValue {
+        DEFAULT = 0,
+        SUCCESS = 1,
+        FAILURE = 2
+    };
+
+    MockResolverCallback(DNSServer* server):
+        result(DEFAULT),
+        server_(server->clone())
+    {}
 
-// Test it tries the correct amount of times before giving up
+    ~MockResolverCallback() {
+        delete server_;
+    }
+
+    void success(const isc::dns::MessagePtr response) {
+        result = SUCCESS;
+        server_->resume(true);
+    }
+
+    void failure() {
+        result = FAILURE;
+        server_->resume(false);
+    }
+
+    uint32_t result;
+private:
+    DNSServer* server_;
+};
+
+// Test query timeout, set query timeout is lower than client timeout
+// and lookup timeout.
 TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
     // Prepare the service (we do not use the common setup, we do not answer
     setDNSService();
@@ -655,26 +706,20 @@ TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    query.resolve(question, answer, buffer, &server);
+    Message query_message(Message::RENDER);
+    isc::resolve::initResponseMessage(question, query_message);
 
+    boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
     // Run the test
     io_service_->run();
-
-    // Read up to 3 packets.  Use some ad hoc timeout to prevent an infinite
-    // block (see also recvUDP()).
-    int recv_options = setSocketTimeout(sock_, 10, 0);
-    int num = 0;
-    bool read_success = tryRead(sock_, recv_options, 3, &num);
-
-    // The query should 'succeed' with an error response
-    EXPECT_TRUE(done);
-    EXPECT_EQ(3, num);
-    EXPECT_TRUE(read_success);
+    EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
 }
 
 // If we set client timeout to lower than querytimeout, we should
-// get a failure answer, but still see retries
-// (no actual answer is given here yet)
+// get a failure answer
+// (no actual answer is given here yet. TODO the returned error message
+// should be tested)
 TEST_F(RecursiveQueryTest, forwardClientTimeout) {
     // Prepare the service (we do not use the common setup, we do not answer
     setDNSService();
@@ -689,36 +734,25 @@ TEST_F(RecursiveQueryTest, forwardClientTimeout) {
 
     // Do the answer
     const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    // Set it up to retry twice before client timeout fires
-    // Since the lookup timer has not fired, it should retry
-    // four times
     RecursiveQuery query(*dns_service_,
                          *nsas_, cache_,
                          singleAddress(TEST_IPV4_ADDR, port),
                          singleAddress(TEST_IPV4_ADDR, port),
-                         200, 480, 4000, 4);
-    Question question(Name("example.net"), RRClass::IN(), RRType::A());
+                         1000, 10, 4000, 4);
+    Question q(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    query.resolve(question, answer, buffer, &server);
+    Message query_message(Message::RENDER);
+    isc::resolve::initResponseMessage(q, query_message);
 
+    boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
     // Run the test
     io_service_->run();
-
-    // we know it'll fail, so make it a shorter timeout
-    int recv_options = setSocketTimeout(sock_, 1, 0);
-
-    // Try to read 4 times
-    int num = 0;
-    bool read_success = tryRead(sock_, recv_options, 4, &num);
-
-    // The query should fail
-    EXPECT_TRUE(done1);
-    EXPECT_EQ(3, num);
-    EXPECT_FALSE(read_success);
+    EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
 }
 
-// If we set lookup timeout to lower than querytimeout*retries, we should
-// fail before the full amount of retries
+// If we set lookup timeout to lower than querytimeout, the lookup
+// will fail.
 TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
     // Prepare the service (we do not use the common setup, we do not answer
     setDNSService();
@@ -734,30 +768,22 @@ TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
 
     // Do the answer
     const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    // Set up the test so that it will retry 5 times, but the lookup
-    // timeout will fire after only 3 normal timeouts
     RecursiveQuery query(*dns_service_,
                          *nsas_, cache_,
                          singleAddress(TEST_IPV4_ADDR, port),
                          singleAddress(TEST_IPV4_ADDR, port),
-                         200, 4000, 480, 5);
+                         1000, 4000, 10, 5);
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    query.resolve(question, answer, buffer, &server);
 
+    Message query_message(Message::RENDER);
+    isc::resolve::initResponseMessage(question, query_message);
+
+    boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
     // Run the test
     io_service_->run();
-
-    int recv_options = setSocketTimeout(sock_, 1, 0);
-
-    // Try to read 5 times, should stop after 3 reads
-    int num = 0;
-    bool read_success = tryRead(sock_, recv_options, 5, &num);
-
-    // The query should fail and respond with an error
-    EXPECT_TRUE(done);
-    EXPECT_EQ(3, num);
-    EXPECT_FALSE(read_success);
+    EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
 }
 
 // Set everything very low and see if this doesn't cause weird
@@ -777,8 +803,6 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
 
     // Do the answer
     const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    // Set up the test so that it will retry 5 times, but the lookup
-    // timeout will fire after only 3 normal timeouts
     RecursiveQuery query(*dns_service_,
                          *nsas_, cache_,
                          singleAddress(TEST_IPV4_ADDR, port),
@@ -786,21 +810,15 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
                          1, 1, 1, 1);
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    query.resolve(question, answer, buffer, &server);
 
+    Message query_message(Message::RENDER);
+    isc::resolve::initResponseMessage(question, query_message);
+
+    boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
     // Run the test
     io_service_->run();
-
-    int recv_options = setSocketTimeout(sock_, 1, 0);
-
-    // Try to read 5 times, should stop after 3 reads
-    int num = 0;
-    bool read_success = tryRead(sock_, recv_options, 5, &num);
-
-    // The query should fail and respond with an error
-    EXPECT_TRUE(done);
-    EXPECT_EQ(1, num);
-    EXPECT_FALSE(read_success);
+    EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
 }
 
 // as mentioned above, we need a more better framework for this,
@@ -855,7 +873,88 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
     EXPECT_EQ(0, answer->getRRCount(Message::SECTION_ANSWER));
 }
 
+// Test that we don't start at root when we have a lower NS cached.
+TEST_F(RecursiveQueryTest, CachedNS) {
+    setDNSService(true, true);
+
+    // Check we have a reasonable fallback - if there's nothing of interest
+    // in the cache, start at root.
+    EXPECT_EQ(".", deepestDelegation(Name("www.somewhere.deep.example.org"),
+                                     RRClass::IN(), cache_));
+
+    // Prefill the cache. There's a zone with a NS and IP address for one
+    // of them (to see that one is enough) and another deeper one, with NS,
+    // but without IP.
+    RRsetPtr nsUpper(new RRset(Name("example.org"), RRClass::IN(),
+                               RRType::NS(), RRTTL(300)));
+    nsUpper->addRdata(rdata::generic::NS(Name("ns.example.org")));
+    nsUpper->addRdata(rdata::generic::NS(Name("ns2.example.org")));
+
+    RRsetPtr nsLower(new RRset(Name("somewhere.deep.example.org"),
+                               RRClass::IN(), RRType::NS(), RRTTL(300)));
+    nsLower->addRdata(rdata::generic::NS(Name("ns.somewhere.deep.example.org"))
+                      );
+
+    RRsetPtr nsIp(new RRset(Name("ns2.example.org"), RRClass::IN(),
+                            RRType::A(), RRTTL(300)));
+    nsIp->addRdata(rdata::in::A("192.0.2.1"));
+
+    // Make sure the test runs in the correct environment (we don't test
+    // the cache, but we need it to unswer this way for the test, so we
+    // just make sure)
+    ASSERT_TRUE(cache_.update(nsUpper));
+    ASSERT_TRUE(cache_.update(nsLower));
+    ASSERT_TRUE(cache_.update(nsIp));
+    RRsetPtr deepest(cache_.lookupDeepestNS(Name(
+        "www.somewhere.deep.example.org"), RRClass::IN()));
+    ASSERT_NE(RRsetPtr(), deepest);
+    ASSERT_EQ(nsLower->getName(), deepest->getName());
+
+    // Direct check of the function that chooses the delegation point
+    // It should not use nsLower, because we don't have IP address for
+    // that one. But it can choose nsUpper.
+    EXPECT_EQ("example.org.",
+              deepestDelegation(Name("www.somewhere.deep.example.org"),
+              RRClass::IN(), cache_));
+
+    // Now more complex and indirect test:
+    // We ask it to resolve the name for us. It will pick up a delegation
+    // point and ask NSAS for it. NSAS will in turn ask resolver for NS record
+    // of the delegation point. We then pick it up from the fake resolver
+    // and check it is the correct one. This checks the delegation point
+    // travels safely trough the whole path there (it would be enough to check
+    // it up to NSAS, but replacing NSAS is more complicated, so we just
+    // include in the test as well for simplicity).
+
+    // Prepare the recursive query
+    vector<pair<string, uint16_t> > roots;
+    roots.push_back(pair<string, uint16_t>("192.0.2.2", 53));
+
+    RecursiveQuery rq(*dns_service_, *nsas_, cache_,
+                      vector<pair<string, uint16_t> >(), roots);
+    // Ask a question at the bottom. It should not use the lower NS, because
+    // it would lead to a loop in NS. But it can use the nsUpper one, it has
+    // an IP address and we can avoid asking root.
+    Question q(Name("www.somewhere.deep.example.org"), RRClass::IN(),
+               RRType::A());
+    OutputBufferPtr buffer(new OutputBuffer(0));
+    MessagePtr answer(new Message(Message::RENDER));
+    // The server is here so we have something to pass there
+    MockServer server(*io_service_);
+    rq.resolve(q, answer, buffer, &server);
+    // We don't need to run the service in this test. We are interested only
+    // in the place it starts resolving at
+
+    // Look what is asked by NSAS - it should be our delegation point.
+    EXPECT_NO_THROW(EXPECT_EQ(nsUpper->getName(),
+                              (*resolver_)[0]->getName()) <<
+                    "It starts resolving at the wrong place") <<
+        "It does not ask NSAS anything, how does it know where to send?";
+}
+
 // TODO: add tests that check whether the cache is updated on succesfull
 // responses, and not updated on failures.
 
+
+
 }
diff --git a/src/lib/resolve/tests/recursive_query_unittest_2.cc b/src/lib/resolve/tests/recursive_query_unittest_2.cc
index 643c5a3..3e62336 100644
--- a/src/lib/resolve/tests/recursive_query_unittest_2.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest_2.cc
@@ -17,13 +17,16 @@
 #include <iomanip>
 #include <iostream>
 #include <string>
+#include <vector>
 
 #include <gtest/gtest.h>
 #include <boost/bind.hpp>
 
 #include <asio.hpp>
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
+#include <util/io_utilities.h>
+
 #include <dns/question.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -35,19 +38,21 @@
 #include <dns/rrttl.h>
 #include <dns/rdata.h>
 
-#include <asiolink/asiolink_utilities.h>
-#include <asiolink/dns_service.h>
+#include <util/io_utilities.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/io_fetch.h>
 #include <asiolink/io_address.h>
 #include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
 #include <asiolink/io_service.h>
 #include <resolve/recursive_query.h>
 #include <resolve/resolver_interface.h>
 
 using namespace asio;
 using namespace asio::ip;
+using namespace isc::asiolink;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
+using namespace isc::util;
 using namespace isc::resolve;
 using namespace std;
 
@@ -71,7 +76,8 @@ using namespace std;
 /// directed to one or other of the "servers" in the RecursiveQueryTest2 class,
 /// regardless of the glue returned in referrals.
 
-namespace asiolink {
+namespace isc {
+namespace asiodns {
 
 const std::string TEST_ADDRESS = "127.0.0.1";   ///< Servers are on this address
 const uint16_t TEST_PORT = 5301;                ///< ... and this port
@@ -649,13 +655,17 @@ TEST_F(RecursiveQueryTest2, Resolve) {
                           boost::bind(&RecursiveQueryTest2::tcpAcceptHandler,
                                       this, _1, 0));
 
-    // Set up the RecursiveQuery object.
+    // Set up the RecursiveQuery object. We will also test that it correctly records
+    // RTT times by setting up a RTT recorder object as well.
     std::vector<std::pair<std::string, uint16_t> > upstream;         // Empty
     std::vector<std::pair<std::string, uint16_t> > upstream_root;    // Empty
     RecursiveQuery query(dns_service_, *nsas_, cache_,
                          upstream, upstream_root);
     query.setTestServer(TEST_ADDRESS, TEST_PORT);
 
+    boost::shared_ptr<RttRecorder> recorder(new RttRecorder());
+    query.setRttRecorder(recorder);
+
     // Set up callback to receive notification that the query has completed.
     isc::resolve::ResolverInterface::CallbackPtr
         resolver_callback(new ResolverCallback(service_));
@@ -672,6 +682,17 @@ TEST_F(RecursiveQueryTest2, Resolve) {
     ResolverCallback* rc = static_cast<ResolverCallback*>(resolver_callback.get());
     EXPECT_TRUE(rc->getRun());
     EXPECT_TRUE(rc->getStatus());
+
+    // Finally, check that all the RTTs were "reasonable" (defined here as
+    // being below 2 seconds).  This is an explicit check to test that the
+    // variables in the RTT calculation are at least being initialized; if they
+    // weren't, we would expect some absurdly high answers.
+    vector<uint32_t> rtt = recorder->getRtt();
+    EXPECT_GT(rtt.size(), 0);
+    for (int i = 0; i < rtt.size(); ++i) {
+        EXPECT_LT(rtt[i], 2000);
+    }
 }
 
-} // namespace asiolink
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/resolve/tests/resolver_callback_unittest.cc b/src/lib/resolve/tests/resolver_callback_unittest.cc
index 6370e22..e94f13d 100644
--- a/src/lib/resolve/tests/resolver_callback_unittest.cc
+++ b/src/lib/resolve/tests/resolver_callback_unittest.cc
@@ -13,8 +13,8 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <gtest/gtest.h>
+#include <asiodns/dns_server.h>
 #include <resolve/resolver_callback.h>
-#include <asiolink/asiolink.h>
 
 using namespace isc::resolve;
 
@@ -22,7 +22,7 @@ using namespace isc::resolve;
 // We want to check if resume is called
 // Since the server will get cloned(), we want the clones to share
 // our bools for whether resume got called and with what value
-class DummyServer : public asiolink::DNSServer {
+class DummyServer : public isc::asiodns::DNSServer {
 public:
     DummyServer(DummyServer* orig) {
         resume_called_ = orig->getResumeCalled();
@@ -31,10 +31,10 @@ public:
     DummyServer(bool* resume_called, bool* resume_value) :
         resume_called_(resume_called), resume_value_(resume_value)
     {}
-    
+
     bool* getResumeCalled() { return resume_called_; }
     bool* getResumeValue() { return resume_value_; }
-    
+
     DNSServer* clone() {
         DummyServer* n = new DummyServer(this);
         return n;
diff --git a/src/lib/server_common/Makefile.am b/src/lib/server_common/Makefile.am
index dfb3014..a3063ba 100644
--- a/src/lib/server_common/Makefile.am
+++ b/src/lib/server_common/Makefile.am
@@ -18,9 +18,12 @@ endif
 
 lib_LTLIBRARIES = libserver_common.la
 libserver_common_la_SOURCES = portconfig.h portconfig.cc
+libserver_common_la_SOURCES += keyring.h keyring.cc
 libserver_common_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 libserver_common_la_LIBADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 libserver_common_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/config/libcfgclient.la
 libserver_common_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
 
 CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/server_common/keyring.cc b/src/lib/server_common/keyring.cc
new file mode 100644
index 0000000..f68db70
--- /dev/null
+++ b/src/lib/server_common/keyring.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <server_common/keyring.h>
+
+using namespace isc::dns;
+using namespace isc::data;
+
+namespace isc {
+namespace server_common {
+
+typedef boost::shared_ptr<TSIGKeyRing> KeyringPtr;
+
+KeyringPtr keyring;
+
+namespace {
+
+void
+updateKeyring(const std::string&, ConstElementPtr data) {
+    ConstElementPtr list(data->get("keys"));
+    KeyringPtr load(new TSIGKeyRing);
+    for (size_t i(0); i < list->size(); ++ i) {
+        load->add(TSIGKey(list->get(i)->stringValue()));
+    }
+    keyring.swap(load);
+}
+
+}
+
+void
+initKeyring(config::ModuleCCSession& session) {
+    if (keyring) {
+        // We are already initialized
+        return;
+    }
+    session.addRemoteConfig("tsig_keys", updateKeyring, false);
+}
+
+void
+deinitKeyring(config::ModuleCCSession& session) {
+    if (!keyring) {
+        // Not initialized, ignore it
+        return;
+    }
+    keyring.reset();
+    session.removeRemoteConfig("tsig_keys");
+}
+
+}
+}
diff --git a/src/lib/server_common/keyring.h b/src/lib/server_common/keyring.h
new file mode 100644
index 0000000..8832095
--- /dev/null
+++ b/src/lib/server_common/keyring.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef ISC_SERVER_COMMON_KEYRING_H
+#define ISC_SERVER_COMMON_KEYRING_H
+
+#include <boost/shared_ptr.hpp>
+#include <dns/tsigkey.h>
+#include <config/ccsession.h>
+
+/**
+ * \file keyring.h
+ * \brief TSIG keyring loaded from configuration.
+ *
+ * This file contains routines for loading a TSIG key ring from
+ * the tsig_keys configuration section and keeping them up to date
+ * on updates.
+ *
+ * You simply initialize/load the keyring with isc::server_common::initKeyring
+ * and then just use the key ring in in isc::server_common::keyring. It is
+ * automatically reloaded, when the configuration updates, so you no longer
+ * needs to care about it.
+ *
+ * If you want to keep a key (or session) for longer time or your application
+ * is multithreaded, you might want to have a copy of the shared pointer.
+ * Otherwise an update might replace the keyring and delete the keys in the
+ * old one.
+ */
+
+namespace isc {
+
+namespace server_common {
+
+/**
+ * \brief The key ring itself
+ *
+ * This is where the key ring is stored. You can directly use it to your needs,
+ * but you need to call initKeyring first, otherwise you'll find a NULL pointer
+ * here only.
+ */
+extern boost::shared_ptr<dns::TSIGKeyRing> keyring;
+
+/**
+ * \brief Load the key ring for the first time
+ *
+ * This loads the key ring from configuration to keyring. It also registers for
+ * config updates, so from now on, it'll be kept up to date.
+ *
+ * You can unload the key ring with deinitKeyring.
+ *
+ * If it is already loaded, this function does nothing. So, if more than one
+ * part of an application needs to use the key ring, they all can just call
+ * this independently to ensure the keyring is loaded.
+ *
+ * \param session The configuration session used to talk to the config manager.
+ */
+void
+initKeyring(config::ModuleCCSession& session);
+
+/**
+ * \brief Unload the key ring
+ *
+ * This can be used to unload the key ring. It will reset the keyring to NULL
+ * and stop receiving updates of the configuration.
+ *
+ * The need for this function should be quite rare, as it isn't required to be
+ * called before application shutdown. And not calling it has only small
+ * performance penalty -- the keyring will be kept in memory and updated when
+ * the user changes configuration.
+ *
+ * This does nothing if the key ring is not loaded currently.
+ *
+ * \param session The configuration session used to talk to the config manager.
+ *
+ * \todo What do we do when the data that come are invalid? Should we ignore it,
+ *     as walidity should have been checked already in the config manager, or
+ *     throw? What about when we get an update and it's invalid?
+ */
+void
+deinitKeyring(config::ModuleCCSession& session);
+
+}
+}
+
+#endif
diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc
index 3765f52..7b2b3dd 100644
--- a/src/lib/server_common/portconfig.cc
+++ b/src/lib/server_common/portconfig.cc
@@ -15,7 +15,7 @@
 #include <server_common/portconfig.h>
 
 #include <asiolink/io_address.h>
-#include <asiolink/dns_service.h>
+#include <asiodns/dns_service.h>
 #include <log/dummylog.h>
 
 #include <boost/foreach.hpp>
@@ -23,7 +23,8 @@
 
 using namespace std;
 using namespace isc::data;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
 using isc::log::dlog;
 
 namespace isc {
@@ -82,7 +83,7 @@ setAddresses(DNSService& service, const AddressList& addresses) {
 void
 installListenAddresses(const AddressList& newAddresses,
                        AddressList& addressStore,
-                       asiolink::DNSService& service)
+                       isc::asiodns::DNSService& service)
 {
     try {
         dlog("Setting listen addresses:");
@@ -95,11 +96,17 @@ installListenAddresses(const AddressList& newAddresses,
     }
     catch (const exception& e) {
         /*
-         * We couldn't set it. So return it back. If that fails as well,
-         * we have a problem.
+         * If one of the addresses isn't set successfully, we will restore
+         * the old addresses, the behavior is that either all address are
+         * set successuflly or none of them will be used. whether this
+         * behavior is user desired, maybe we need revisited it later. And
+         * if address setting is more smarter, it should check whether some
+         * part of the new address already in used to avoid interuption the
+         * service.
          *
-         * If that fails, bad luck, but we are useless anyway, so just die
-         * and let boss start us again.
+         * If the address setting still failed, we can live with it, since
+         * user will get error info, command control can be used to set new
+         * address. So we just catch the exception without propagating outside
          */
         dlog(string("Unable to set new address: ") + e.what(), true);
         try {
@@ -108,9 +115,10 @@ installListenAddresses(const AddressList& newAddresses,
         catch (const exception& e2) {
             dlog("Unable to recover from error;", true);
             dlog(string("Rollback failed with: ") + e2.what(), true);
-            abort();
         }
-        throw; // Let it fly a little bit further
+        //Anyway the new configure has problem, we need to notify configure
+        //manager the new configure doesn't work
+        throw;
     }
 }
 
diff --git a/src/lib/server_common/portconfig.h b/src/lib/server_common/portconfig.h
index bcb8528..e4e7bf6 100644
--- a/src/lib/server_common/portconfig.h
+++ b/src/lib/server_common/portconfig.h
@@ -25,9 +25,11 @@
 /*
  * Some forward declarations.
  */
-namespace asiolink {
+namespace isc {
+namespace asiodns {
 class DNSService;
 }
+}
 
 namespace isc {
 namespace server_common {
@@ -112,7 +114,7 @@ parseAddresses(isc::data::ConstElementPtr addresses,
 void
 installListenAddresses(const AddressList& newAddresses,
                        AddressList& addressStore,
-                       asiolink::DNSService& dnsService);
+                       asiodns::DNSService& dnsService);
 
 }
 }
diff --git a/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am
index 55ccc85..cecb98b 100644
--- a/src/lib/server_common/tests/Makefile.am
+++ b/src/lib/server_common/tests/Makefile.am
@@ -12,7 +12,7 @@ endif
 # Some versions of GCC warn about some versions of Boost regarding
 # missing initializer for members in its posix_time.
 # https://svn.boost.org/trac/boost/ticket/3477
-# But older GCC compilers don't have the flag.     
+# But older GCC compilers don't have the flag.
 AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 
 if USE_CLANGPP
@@ -27,6 +27,8 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += portconfig_unittest.cc
+run_unittests_SOURCES += keyring_test.cc
+nodist_run_unittests_SOURCES = data_path.h
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -35,8 +37,13 @@ run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 endif
 
 noinst_PROGRAMS = $(TESTS)
+
+EXTRA_DIST = testdata/spec.spec
diff --git a/src/lib/server_common/tests/data_path.h.in b/src/lib/server_common/tests/data_path.h.in
new file mode 100644
index 0000000..8ac0380
--- /dev/null
+++ b/src/lib/server_common/tests/data_path.h.in
@@ -0,0 +1,16 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")   
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#define TEST_DATA_PATH "@abs_srcdir@/testdata"
+#define PLUGIN_DATA_PATH "@top_srcdir@/src/bin/cfgmgr/plugins"
diff --git a/src/lib/server_common/tests/keyring_test.cc b/src/lib/server_common/tests/keyring_test.cc
new file mode 100644
index 0000000..6d2f226
--- /dev/null
+++ b/src/lib/server_common/tests/keyring_test.cc
@@ -0,0 +1,132 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <server_common/keyring.h>
+#include <server_common/tests/data_path.h>
+
+#include <config/tests/fake_session.h>
+#include <config/ccsession.h>
+#include <dns/name.h>
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+
+using namespace isc::data;
+using namespace isc::config;
+using namespace isc::server_common;
+using namespace isc::dns;
+
+namespace {
+
+class KeyringTest : public ::testing::Test {
+public:
+    KeyringTest() :
+        session(ElementPtr(new ListElement), ElementPtr(new ListElement),
+                ElementPtr(new ListElement)),
+        specfile(std::string(TEST_DATA_PATH) + "/spec.spec")
+    {
+        session.getMessages()->add(createAnswer());
+        mccs.reset(new ModuleCCSession(specfile, session, NULL, NULL));
+    }
+    isc::cc::FakeSession session;
+    std::auto_ptr<ModuleCCSession> mccs;
+    std::string specfile;
+    void doInit() {
+        // Prepare the module specification for it and the config
+        session.getMessages()->
+            add(createAnswer(0,
+                             moduleSpecFromFile(std::string(PLUGIN_DATA_PATH) +
+                                                "/tsig_keys.spec").
+                             getFullSpec()));
+        session.getMessages()->add(createAnswer(0, Element::fromJSON(
+            "{\"keys\": [\"key:MTIzNAo=:hmac-sha1\"]}")));
+        // Now load it
+        EXPECT_NO_THROW(initKeyring(*mccs));
+        EXPECT_NE(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+            "No keyring even after init";
+    }
+};
+
+// Test usual use - init, using the keyring, update, deinit
+TEST_F(KeyringTest, keyring) {
+    // First, initialize it
+    {
+        SCOPED_TRACE("Init");
+        doInit();
+
+        // Make sure it contains the correct key
+        TSIGKeyRing::FindResult result(keyring->find(Name("key"),
+                                                     TSIGKey::HMACSHA1_NAME()));
+        EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
+    }
+
+    {
+        SCOPED_TRACE("Update");
+        session.addMessage(createCommand("config_update", Element::fromJSON(
+            "{\"keys\": [\"another:MTIzNAo=:hmac-sha256\"]}")),
+                           "tsig_keys", "*");
+        mccs->checkCommand();
+
+        // Make sure it no longer contains the original key
+        TSIGKeyRing::FindResult result(keyring->find(Name("key"),
+                                                     TSIGKey::HMACSHA1_NAME()));
+        EXPECT_EQ(TSIGKeyRing::NOTFOUND, result.code);
+        // but it does contain the new one
+        TSIGKeyRing::FindResult result2 = keyring->find(Name("another"),
+            TSIGKey::HMACSHA256_NAME());
+        EXPECT_EQ(TSIGKeyRing::SUCCESS, result2.code);
+    }
+
+    {
+        SCOPED_TRACE("Deinit");
+        deinitKeyring(*mccs);
+        EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+            "The keyring didn't disappear";
+    }
+}
+
+// Init twice
+TEST_F(KeyringTest, initTwice) {
+    // It is NULL before
+    EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+        "Someone forgot to deinit it before";
+    {
+        SCOPED_TRACE("First init");
+        doInit();
+    }
+    boost::shared_ptr<TSIGKeyRing> backup(keyring);
+    {
+        SCOPED_TRACE("Second init");
+        EXPECT_NO_THROW(initKeyring(*mccs)) <<
+            "It not only does something when it is already initialized, "
+            "it even throws at it";
+    }
+    EXPECT_EQ(backup, keyring) << "The second init replaced the data";
+    deinitKeyring(*mccs);
+}
+
+// deinit when not initialized
+TEST_F(KeyringTest, extraDeinit) {
+    // It is NULL before
+    EXPECT_EQ(boost::shared_ptr<TSIGKeyRing>(), keyring) <<
+        "Someone forgot to deinit it before";
+    // Check that it doesn't get confused when we do not have it initialized
+    EXPECT_NO_THROW(deinitKeyring(*mccs));
+    // It is still NULL
+    EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+        "Where did it get something after deinit?";
+}
+
+}
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
index fabdfa2..65963eb 100644
--- a/src/lib/server_common/tests/portconfig_unittest.cc
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -17,6 +17,7 @@
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
 #include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
 
 #include <gtest/gtest.h>
 #include <string>
@@ -25,7 +26,8 @@ using namespace isc::server_common::portconfig;
 using namespace isc::data;
 using namespace isc;
 using namespace std;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
 
 namespace {
 
@@ -175,7 +177,7 @@ TEST_F(InstallListenAddresses, rollback) {
     EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
     checkAddresses(valid_, "Before rollback");
     // This should not bind them, but should leave the original addresses
-    EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), IOError);
+    EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), exception);
     checkAddresses(valid_, "After rollback");
 }
 
diff --git a/src/lib/server_common/tests/testdata/spec.spec b/src/lib/server_common/tests/testdata/spec.spec
new file mode 100644
index 0000000..3e0a822
--- /dev/null
+++ b/src/lib/server_common/tests/testdata/spec.spec
@@ -0,0 +1,6 @@
+{
+    "module_spec": {
+        "module_name": "test"
+    }
+}
+
diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h
index 4bec83d..2441ad7 100644
--- a/src/lib/testutils/mockups.h
+++ b/src/lib/testutils/mockups.h
@@ -19,7 +19,7 @@
 
 #include <xfr/xfrout_client.h>
 
-#include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
 
 // A minimal mock configuration session.  Most the methods are
 // stubbed out, except for a very basic group_sendmsg() and
@@ -94,7 +94,7 @@ private:
 };
 
 // A nonoperative DNSServer object to be used in calls to processMessage().
-class MockServer : public asiolink::DNSServer {
+class MockServer : public isc::asiodns::DNSServer {
 public:
     MockServer() : done_(false) {}
     void operator()(asio::error_code, size_t) {}
diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc
index 4fec4ca..1d79d71 100644
--- a/src/lib/testutils/srv_test.cc
+++ b/src/lib/testutils/srv_test.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <netinet/in.h>
 
 #include <dns/message.h>
@@ -25,7 +27,8 @@
 #include <testutils/srv_test.h>
 
 using namespace isc::dns;
-using namespace asiolink;
+using namespace isc::util;
+using namespace isc::asiolink;
 
 namespace isc {
 namespace testutils {
@@ -203,7 +206,7 @@ SrvTestBase::ednsBadVers() {
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 1);
     EXPECT_FALSE(parse_message->getEDNS()); // EDNS isn't added at this point
 
-    isc::dns::InputBuffer ib(response_obuffer->getData(),
+    InputBuffer ib(response_obuffer->getData(),
                              response_obuffer->getLength());
     isc::dns::Message parsed(isc::dns::Message::PARSE);
     parsed.fromWire(ib);
diff --git a/src/lib/testutils/srv_test.h b/src/lib/testutils/srv_test.h
index 7361a76..a848ffc 100644
--- a/src/lib/testutils/srv_test.h
+++ b/src/lib/testutils/srv_test.h
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/buffer.h>
+#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -99,9 +99,9 @@ protected:
     asiolink::IOSocket* io_sock;
     asiolink::IOMessage* io_message;
     const asiolink::IOEndpoint* endpoint;
-    isc::dns::OutputBuffer request_obuffer;
+    isc::util::OutputBuffer request_obuffer;
     isc::dns::MessageRenderer request_renderer;
-    isc::dns::OutputBufferPtr response_obuffer;
+    isc::util::OutputBufferPtr response_obuffer;
     std::vector<uint8_t> data;
 };
 } // end of namespace testutils
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
new file mode 100644
index 0000000..3cb1229
--- /dev/null
+++ b/src/lib/util/Makefile.am
@@ -0,0 +1,30 @@
+SUBDIRS = . tests unittests io pyunittests
+# The io/tests is hack, because otherwise we can not order these directories
+# properly. Unittests use io and io/tests use unittest.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+lib_LTLIBRARIES = libutil.la
+libutil_la_SOURCES  = filename.h filename.cc
+libutil_la_SOURCES += locks.h lru_list.h
+libutil_la_SOURCES += strutil.h strutil.cc
+libutil_la_SOURCES += buffer.h io_utilities.h
+libutil_la_SOURCES += time_utilities.h time_utilities.cc
+libutil_la_SOURCES += hash/sha1.h hash/sha1.cc
+libutil_la_SOURCES += encode/base16_from_binary.h
+libutil_la_SOURCES += encode/base32hex.h encode/base64.h
+libutil_la_SOURCES += encode/base32hex_from_binary.h
+libutil_la_SOURCES += encode/base_n.cc encode/hex.h
+libutil_la_SOURCES += encode/binary_from_base32hex.h
+libutil_la_SOURCES += encode/binary_from_base16.h
+libutil_la_SOURCES += random/qid_gen.h random/qid_gen.cc
+libutil_la_SOURCES += random/random_number_generator.h
+
+EXTRA_DIST = python/pycppwrapper_util.h
+
+libutil_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/util/buffer.h b/src/lib/util/buffer.h
new file mode 100644
index 0000000..b7a8e28
--- /dev/null
+++ b/src/lib/util/buffer.h
@@ -0,0 +1,524 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __BUFFER_H
+#define __BUFFER_H 1
+
+#include <stdlib.h>
+#include <cstring>
+#include <vector>
+
+#include <string.h>
+
+#include <stdint.h>
+
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace util {
+
+///
+/// \brief A standard DNS module exception that is thrown if an out-of-range
+/// buffer operation is being performed.
+///
+class InvalidBufferPosition : public Exception {
+public:
+    InvalidBufferPosition(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+///\brief The \c InputBuffer class is a buffer abstraction for manipulating
+/// read-only data.
+///
+/// The main purpose of this class is to provide a safe placeholder for
+/// examining wire-format data received from a network.
+///
+/// Applications normally use this class only in a limited situation: as an
+/// interface between legacy I/O operation (such as receiving data from a BSD
+/// socket) and the rest of the BIND10 DNS library.  One common usage of this
+/// class for an application would therefore be something like this:
+///
+/// \code unsigned char buf[1024];
+/// struct sockaddr addr;
+/// socklen_t addrlen = sizeof(addr);
+/// int cc = recvfrom(s, buf, sizeof(buf), 0, &addr, &addrlen);
+/// InputBuffer buffer(buf, cc);
+/// // pass the buffer to a DNS message object to parse the message \endcode
+///
+/// Other BIND10 DNS classes will then use methods of this class to get access
+/// to the data, but the application normally doesn't have to care about the
+/// details.
+///
+/// An \c InputBuffer object internally holds a reference to the given data,
+/// rather than make a local copy of the data.  Also, it does not have an
+/// ownership of the given data.  It is application's responsibility to ensure
+/// the data remains valid throughout the lifetime of the \c InputBuffer
+/// object.  Likewise, this object generally assumes the data isn't modified
+/// throughout its lifetime; if the application modifies the data while this
+/// object retains a reference to it, the result is undefined.  The application
+/// will also be responsible for releasing the data when it's not needed if it
+/// was dynamically acquired.
+///
+/// This is a deliberate design choice: although it's safer to make a local
+/// copy of the given data on construction, it would cause unacceptable
+/// performance overhead, especially considering that a DNS message can be
+/// as large as a few KB.  Alternatively, we could allow the object to allocate
+/// memory internally and expose it to the application to store network data
+/// in it.  This is also a bad design, however, in that we would effectively
+/// break the abstraction employed in the class, and do so by publishing
+/// "read-only" stuff as a writable memory region.  Since there doesn't seem to
+/// be a perfect solution, we have adopted what we thought a "least bad" one.
+///
+/// Methods for reading data from the buffer generally work like an input
+/// stream: it begins with the head of the data, and once some length of data
+/// is read from the buffer, the next read operation will take place from the
+/// head of the unread data.  An object of this class internally holds (a
+/// notion of) where the next read operation should start.  We call it the
+/// <em>read position</em> in this document.
+class InputBuffer {
+public:
+    ///
+    /// \name Constructors and Destructor
+    //@{
+    /// \brief Constructor from variable length of data.
+    ///
+    /// It is caller's responsibility to ensure that the data is valid as long
+    /// as the buffer exists.
+    /// \param data A pointer to the data stored in the buffer.
+    /// \param len The length of the data in bytes.
+    InputBuffer(const void* data, size_t len) :
+        position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
+    //@}
+
+    ///
+    /// \name Getter Methods
+    //@{
+    /// \brief Return the length of the data stored in the buffer.
+    size_t getLength() const { return (len_); }
+    /// \brief Return the current read position.
+    size_t getPosition() const { return (position_); }
+    //@}
+
+    ///
+    /// \name Setter Methods
+    ///
+    //@{
+    /// \brief Set the read position of the buffer to the given value.
+    ///
+    /// The new position must be in the valid range of the buffer; otherwise
+    /// an exception of class \c isc::dns::InvalidBufferPosition will be thrown.
+    /// \param position The new position (offset from the beginning of the
+    /// buffer).
+    void setPosition(size_t position)
+    {
+        if (position > len_)
+            isc_throw(InvalidBufferPosition, "position is too large");
+        position_ = position;
+    }
+    //@}
+
+    ///
+    /// \name Methods for reading data from the buffer.
+    //@{
+    /// \brief Read an unsigned 8-bit integer from the buffer and return it.
+    ///
+    /// If the remaining length of the buffer is smaller than 8-bit, an
+    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
+    uint8_t readUint8()
+    {
+        if (position_ + sizeof(uint8_t) > len_) {
+            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+        }
+
+        return (data_[position_++]);
+    }
+    /// \brief Read an unsigned 16-bit integer in network byte order from the
+    /// buffer, convert it to host byte order, and return it.
+    ///
+    /// If the remaining length of the buffer is smaller than 16-bit, an
+    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
+    uint16_t readUint16()
+    {
+        uint16_t data;
+        const uint8_t* cp;
+
+        if (position_ + sizeof(data) > len_) {
+            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+        }
+
+        cp = &data_[position_];
+        data = ((unsigned int)(cp[0])) << 8;
+        data |= ((unsigned int)(cp[1]));
+        position_ += sizeof(data);
+
+        return (data);
+    }
+    /// \brief Read an unsigned 32-bit integer in network byte order from the
+    /// buffer, convert it to host byte order, and return it.
+    ///
+    /// If the remaining length of the buffer is smaller than 32-bit, an
+    /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
+    uint32_t readUint32()
+    {
+        uint32_t data;
+        const uint8_t* cp;
+
+        if (position_ + sizeof(data) > len_) {
+            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+        }
+
+        cp = &data_[position_];
+        data = ((unsigned int)(cp[0])) << 24;
+        data |= ((unsigned int)(cp[1])) << 16;
+        data |= ((unsigned int)(cp[2])) << 8;
+        data |= ((unsigned int)(cp[3]));
+        position_ += sizeof(data);
+
+        return (data);
+    }
+    /// \brief Read data of the specified length from the buffer and copy it to
+    /// the caller supplied buffer.
+    ///
+    /// The data is copied as stored in the buffer; no conversion is performed.
+    /// If the remaining length of the buffer is smaller than the specified
+    /// length, an exception of class \c isc::dns::InvalidBufferPosition will
+    /// be thrown.
+    void readData(void* data, size_t len)
+    {
+        if (position_ + len > len_) {
+            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+        }
+
+        memcpy(data, &data_[position_], len);
+        position_ += len;
+    }
+    //@}
+
+private:
+    size_t position_;
+
+    // XXX: The following must be private, but for a short term workaround with
+    // Boost.Python binding, we changed it to protected.  We should soon
+    // revisit it.
+protected:
+    const uint8_t* data_;
+    size_t len_;
+};
+
+///
+///\brief The \c OutputBuffer class is a buffer abstraction for manipulating
+/// mutable data.
+///
+/// The main purpose of this class is to provide a safe workplace for
+/// constructing wire-format data to be sent out to a network.  Here,
+/// <em>safe</em> means that it automatically allocates necessary memory and
+/// avoid buffer overrun.
+///
+/// Like for the \c InputBuffer class, applications normally use this class only
+/// in a limited situation.  One common usage of this class for an application
+/// would be something like this:
+///
+/// \code OutputBuffer buffer(4096); // give a sufficiently large initial size
+/// // pass the buffer to a DNS message object to construct a wire-format
+/// // DNS message.
+/// struct sockaddr to;
+/// sendto(s, buffer.getData(), buffer.getLength(), 0, &to, sizeof(to));
+/// \endcode
+///
+/// where the \c getData() method gives a reference to the internal memory
+/// region stored in the \c buffer object.  This is a suboptimal design in that
+/// it exposes an encapsulated "handle" of an object to its user.
+/// Unfortunately, there is no easy way to avoid this without involving
+/// expensive data copy if we want to use this object with a legacy API such as
+/// a BSD socket interface.  And, indeed, this is one major purpose for this
+/// object.  Applications should use this method only under such a special
+/// circumstance.  It should also be noted that the memory region returned by
+/// \c getData() may be invalidated after a subsequent write operation.
+///
+/// An \c OutputBuffer class object automatically extends its memory region when
+/// data is written beyond the end of the current buffer.  However, it will
+/// involve performance overhead such as reallocating more memory and copying
+/// data.  It is therefore recommended to construct the buffer object with a
+/// sufficiently large initial size.
+/// The \c getCapacity() method provides the current maximum size of data
+/// (including the portion already written) that can be written into the buffer
+/// without causing memory reallocation.
+///
+/// Methods for writing data into the buffer generally work like an output
+/// stream: it begins with the head of the buffer, and once some length of data
+/// is written into the buffer, the next write operation will take place from
+/// the end of the buffer.  Other methods to emulate "random access" are also
+/// provided (e.g., \c writeUint16At()).  The normal write operations are
+/// normally exception-free as this class automatically extends the buffer
+/// when necessary.  However, in extreme cases such as an attempt of writing
+/// multi-GB data, a separate exception (e.g., \c std::bad_alloc) may be thrown
+/// by the system.  This also applies to the constructor with a very large
+/// initial size.
+///
+/// Note to developers: it may make more sense to introduce an abstract base
+/// class for the \c OutputBuffer and define the simple implementation as a
+/// a concrete derived class.  That way we can provide flexibility for future
+/// extension such as more efficient buffer implementation or allowing users
+/// to have their own customized version without modifying the source code.
+/// We in fact considered that option, but at the moment chose the simpler
+/// approach with a single concrete class because it may make the
+/// implementation unnecessarily complicated while we were still not certain
+/// if we really want that flexibility.  We may revisit the class design as
+/// we see more applications of the class.  The same considerations apply to
+/// the \c InputBuffer and \c MessageRenderer classes.
+class OutputBuffer {
+public:
+    ///
+    /// \name Constructors and Destructor
+    ///
+    //@{
+    /// \brief Constructor from the initial size of the buffer.
+    ///
+    /// \param len The initial length of the buffer in bytes.
+    OutputBuffer(size_t len) :
+        buffer_(NULL),
+        size_(0),
+        allocated_(len)
+    {
+        // We use malloc and free instead of C++ new[] and delete[].
+        // This way we can use realloc, which may in fact do it without a copy.
+        buffer_ = static_cast<uint8_t*>(malloc(allocated_));
+        if (buffer_ == NULL && len != 0) {
+            throw std::bad_alloc();
+        }
+    }
+
+    /// \brief Copy constructor
+    OutputBuffer(const OutputBuffer& other) :
+        buffer_(NULL),
+        size_(other.size_),
+        allocated_(other.allocated_)
+    {
+        buffer_ = static_cast<uint8_t*>(malloc(allocated_));
+        if (buffer_ == NULL && allocated_ != 0) {
+            throw std::bad_alloc();
+        }
+        memcpy(buffer_, other.buffer_, size_);
+    }
+
+    /// \brief Destructor
+    ~ OutputBuffer() {
+        free(buffer_);
+    }
+    //@}
+
+    /// \brief Assignment operator
+    OutputBuffer& operator =(const OutputBuffer& other) {
+        uint8_t* newbuff(static_cast<uint8_t*>(malloc(other.allocated_)));
+        if (newbuff == NULL && other.allocated_ != 0) {
+            throw std::bad_alloc();
+        }
+        free(buffer_);
+        buffer_ = newbuff;
+        size_ = other.size_;
+        allocated_ = other.allocated_;
+        memcpy(buffer_, other.buffer_, size_);
+        return (*this);
+    }
+
+    ///
+    /// \name Getter Methods
+    ///
+    //@{
+    /// \brief Return the current capacity of the buffer.
+    size_t getCapacity() const { return (allocated_); }
+    /// \brief Return a pointer to the head of the data stored in the buffer.
+    ///
+    /// The caller can assume that the subsequent \c getLength() bytes are
+    /// identical to the stored data of the buffer.
+    ///
+    /// Note: The pointer returned by this method may be invalidated after a
+    /// subsequent write operation.
+    const void* getData() const { return (buffer_); }
+    /// \brief Return the length of data written in the buffer.
+    size_t getLength() const { return (size_); }
+    /// \brief Return the value of the buffer at the specified position.
+    ///
+    /// \c pos must specify the valid position of the buffer; otherwise an
+    /// exception class of \c InvalidBufferPosition will be thrown.
+    ///
+    /// \param pos The position in the buffer to be returned.
+    uint8_t operator[](size_t pos) const
+    {
+        if (pos >= size_) {
+            isc_throw(InvalidBufferPosition, "read at invalid position");
+        }
+        return (buffer_[pos]);
+    }
+    //@}
+
+    ///
+    /// \name Methods for writing data into the buffer.
+    ///
+    //@{
+    /// \brief Insert a specified length of gap at the end of the buffer.
+    ///
+    /// The caller should not assume any particular value to be inserted.
+    /// This method is provided as a shortcut to make a hole in the buffer
+    /// that is to be filled in later, e.g, by \ref writeUint16At().
+    /// \param len The length of the gap to be inserted in bytes.
+    void skip(size_t len) {
+        ensureAllocated(size_ + len);
+        size_ += len;
+    }
+
+    /// \brief Trim the specified length of data from the end of the buffer.
+    ///
+    /// The specified length must not exceed the current data size of the
+    /// buffer; otherwise an exception of class \c isc::OutOfRange will
+    /// be thrown.
+    ///
+    /// \param len The length of data that should be trimmed.
+    void trim(size_t len)
+    {
+        if (len > size_) {
+            isc_throw(OutOfRange, "trimming too large from output buffer");
+        }
+        size_ -= len;
+    }
+    /// \brief Clear buffer content.
+    ///
+    /// This method can be used to re-initialize and reuse the buffer without
+    /// constructing a new one.
+    void clear() { size_ = 0; }
+    /// \brief Write an unsigned 8-bit integer into the buffer.
+    ///
+    /// \param data The 8-bit integer to be written into the buffer.
+    void writeUint8(uint8_t data) {
+        ensureAllocated(size_ + 1);
+        buffer_[size_ ++] = data;
+    }
+
+    /// \brief Write an unsigned 8-bit integer into the buffer.
+    ///
+    /// The position must be lower than the size of the buffer,
+    /// otherwise an exception of class \c isc::dns::InvalidBufferPosition
+    /// will be thrown.
+    ///
+    /// \param data The 8-bit integer to be written into the buffer.
+    /// \param pos The position in the buffer to write the data.
+    void writeUint8At(uint8_t data, size_t pos) {
+        if (pos + sizeof(data) > size_) {
+            isc_throw(InvalidBufferPosition, "write at invalid position");
+        }
+        buffer_[pos] = data;
+    }
+
+    /// \brief Write an unsigned 16-bit integer in host byte order into the
+    /// buffer in network byte order.
+    ///
+    /// \param data The 16-bit integer to be written into the buffer.
+    void writeUint16(uint16_t data)
+    {
+        ensureAllocated(size_ + sizeof(data));
+        buffer_[size_ ++] = static_cast<uint8_t>((data & 0xff00U) >> 8);
+        buffer_[size_ ++] = static_cast<uint8_t>(data & 0x00ffU);
+    }
+    /// \brief Write an unsigned 16-bit integer in host byte order at the
+    /// specified position of the buffer in network byte order.
+    ///
+    /// The buffer must have a sufficient room to store the given data at the
+    /// given position, that is, <code>pos + 2 < getLength()</code>;
+    /// otherwise an exception of class \c isc::dns::InvalidBufferPosition will
+    /// be thrown.
+    /// Note also that this method never extends the buffer.
+    ///
+    /// \param data The 16-bit integer to be written into the buffer.
+    /// \param pos The beginning position in the buffer to write the data.
+    void writeUint16At(uint16_t data, size_t pos)
+    {
+        if (pos + sizeof(data) > size_) {
+            isc_throw(InvalidBufferPosition, "write at invalid position");
+        }
+
+        buffer_[pos] = static_cast<uint8_t>((data & 0xff00U) >> 8);
+        buffer_[pos + 1] = static_cast<uint8_t>(data & 0x00ffU);
+    }
+    /// \brief Write an unsigned 32-bit integer in host byte order
+    /// into the buffer in network byte order.
+    ///
+    /// \param data The 32-bit integer to be written into the buffer.
+    void writeUint32(uint32_t data)
+    {
+        ensureAllocated(size_ + sizeof(data));
+        buffer_[size_ ++] = static_cast<uint8_t>((data & 0xff000000) >> 24);
+        buffer_[size_ ++] = static_cast<uint8_t>((data & 0x00ff0000) >> 16);
+        buffer_[size_ ++] = static_cast<uint8_t>((data & 0x0000ff00) >> 8);
+        buffer_[size_ ++] = static_cast<uint8_t>(data & 0x000000ff);
+    }
+    /// \brief Copy an arbitrary length of data into the buffer.
+    ///
+    /// No conversion on the copied data is performed.
+    ///
+    /// \param data A pointer to the data to be copied into the buffer.
+    /// \param len The length of the data in bytes.
+    void writeData(const void *data, size_t len)
+    {
+        ensureAllocated(size_ + len);
+        memcpy(buffer_ + size_, data, len);
+        size_ += len;
+    }
+    //@}
+
+private:
+    // The actual data
+    uint8_t* buffer_;
+    // How many bytes are used
+    size_t size_;
+    // How many bytes do we have preallocated (eg. the capacity)
+    size_t allocated_;
+    // Make sure at last needed_size bytes are allocated in the buffer
+    void ensureAllocated(size_t needed_size) {
+        if (allocated_ < needed_size) {
+            // Guess some bigger size
+            size_t new_size = (allocated_ == 0) ? 1024 : allocated_;
+            while (new_size < needed_size) {
+                new_size *= 2;
+            }
+            // Allocate bigger space
+            uint8_t* new_buffer_(static_cast<uint8_t*>(realloc(buffer_,
+                new_size)));
+            if (new_buffer_ == NULL) {
+                // If it fails, the original block is left intact by it
+                throw std::bad_alloc();
+            }
+            buffer_ = new_buffer_;
+            allocated_ = new_size;
+        }
+    }
+};
+
+/// \brief Pointer-like types pointing to \c InputBuffer or \c OutputBuffer
+///
+/// These types are expected to be used as an argument in asynchronous
+/// callback functions.  The internal reference-counting will ensure that
+/// that ongoing state information will not be lost if the object
+/// that originated the asynchronous call falls out of scope.
+typedef boost::shared_ptr<InputBuffer> InputBufferPtr;
+typedef boost::shared_ptr<OutputBuffer> OutputBufferPtr;
+
+} // namespace util
+} // namespace isc
+#endif  // __BUFFER_H
+
+// Local Variables: 
+// mode: c++
+// End: 
diff --git a/src/lib/util/encode/base16_from_binary.h b/src/lib/util/encode/base16_from_binary.h
new file mode 100644
index 0000000..8606c61
--- /dev/null
+++ b/src/lib/util/encode/base16_from_binary.h
@@ -0,0 +1,108 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
+#define BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// base16_from_binary.h (derived from boost base64_from_binary.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <cstddef> // size_t
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#if defined(BOOST_NO_STDC_NAMESPACE)
+namespace std{ 
+    using ::size_t; 
+} // namespace std
+#endif
+
+// See base32hex_from_binary.h for why we need base64_from...hpp here.
+#include <boost/archive/iterators/base64_from_binary.hpp>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert binary integers to base16 characters
+
+namespace detail {
+
+template<class CharType>
+struct from_4_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char * lookup_table = 
+            "0123456789"
+            "ABCDEF";
+        assert(t < 16);
+        return (lookup_table[static_cast<size_t>(t)]);
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_4_bit<CharType>,
+//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
+//  > base16_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class base16_from_binary : 
+    public transform_iterator<
+        detail::from_4_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        BOOST_DEDUCED_TYPENAME detail::from_4_bit<CharType>,
+        Base
+    > super_t;
+
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    base16_from_binary(BOOST_PFTO_WRAPPER(T) start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
+            detail::from_4_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    base16_from_binary(const base16_from_binary & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::from_4_bit<CharType>()
+        )
+    {}
+//    base16_from_binary(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
diff --git a/src/lib/util/encode/base32hex.h b/src/lib/util/encode/base32hex.h
new file mode 100644
index 0000000..d7129d7
--- /dev/null
+++ b/src/lib/util/encode/base32hex.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __BASE32HEX_H
+#define __BASE32HEX_H 1
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace util {
+namespace encode {
+
+/// \brief Encode binary data in the base32hex format.
+///
+/// The underlying implementation is shared with \c encodeBase64, and all
+/// description except the format (base32hex) equally applies.
+///
+/// Note: the encoding format is base32hex, not base32.
+///
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base32hex encoded value for
+/// binary.
+std::string encodeBase32Hex(const std::vector<uint8_t>& binary);
+
+/// \brief Decode a text encoded in the base32hex format into the
+/// original %data.
+///
+/// The underlying implementation is shared with \c decodeBase64, and all
+/// description except the format (base32hex) equally applies.
+///
+/// Note: the encoding format is base32hex, not base32.
+///
+/// \param input A text encoded in the base32hex format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeBase32Hex(const std::string& input, std::vector<uint8_t>& result);
+
+} // namespace encode 
+} // namespace util
+} // namespace isc
+
+#endif  // __BASE32HEX_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/encode/base32hex_from_binary.h b/src/lib/util/encode/base32hex_from_binary.h
new file mode 100644
index 0000000..5d16d04
--- /dev/null
+++ b/src/lib/util/encode/base32hex_from_binary.h
@@ -0,0 +1,110 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
+#define BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// base32hex_from_binary.h (derived from boost base64_from_binary.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <cstddef> // size_t
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#if defined(BOOST_NO_STDC_NAMESPACE)
+namespace std{ 
+    using ::size_t; 
+} // namespace std
+#endif
+
+// We use the same boost header files used in "base64_from_".  Since the
+// precise path to these headers may vary depending on the boost version we
+// simply include the base64 header here.
+#include <boost/archive/iterators/base64_from_binary.hpp>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert binary integers to base32hex characters
+
+namespace detail {
+
+template<class CharType>
+struct from_5_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char * lookup_table = 
+            "0123456789"
+            "ABCDEFGHIJKLMNOPQRSTUV";
+        assert(t < 32);
+        return (lookup_table[static_cast<size_t>(t)]);
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_5_bit<CharType>,
+//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
+//  > base32hex_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class base32hex_from_binary : 
+    public transform_iterator<
+        detail::from_5_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        BOOST_DEDUCED_TYPENAME detail::from_5_bit<CharType>,
+        Base
+    > super_t;
+
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    base32hex_from_binary(BOOST_PFTO_WRAPPER(T) start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
+            detail::from_5_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    base32hex_from_binary(const base32hex_from_binary & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::from_5_bit<CharType>()
+        )
+    {}
+//    base32hex_from_binary(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
diff --git a/src/lib/util/encode/base64.h b/src/lib/util/encode/base64.h
new file mode 100644
index 0000000..6b1b346
--- /dev/null
+++ b/src/lib/util/encode/base64.h
@@ -0,0 +1,79 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __BASE64_H
+#define __BASE64_H 1
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace util {
+namespace encode {
+
+/// \brief Encode binary data in the base64 format.
+///
+/// This function returns a new \c std::string object that stores a text
+/// encoded in the base64 format for the given \c binary %data.
+/// The resulting string will be a valid, canonical form of base64
+/// representation as specified in RFC4648.
+///
+/// If memory allocation for the returned string fails, a corresponding
+/// standard exception will be thrown.  This function never throws exceptions
+/// otherwise.
+///
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base64 encoded value for binary.
+std::string encodeBase64(const std::vector<uint8_t>& binary);
+
+/// \brief Decode a text encoded in the base64 format into the original %data.
+///
+/// The \c input argument must be a valid string represented in the base64
+/// format as specified in RFC4648.  Space characters (spaces, tabs, newlines)
+/// can be included in \c input and will be ignored.  Without spaces, the
+/// length of string must be a multiple of 4 bytes with necessary paddings.
+/// Also it must be encoded using the canonical encoding (see RFC4648).
+/// If any of these conditions is not met, an exception of class
+/// \c isc::BadValue will be thrown.
+///
+/// If \c result doesn't have sufficient capacity to store all decoded %data
+/// and memory allocation fails, a corresponding standard exception will be
+/// thrown.  If the caller knows the necessary length (which can in theory
+/// be calculated from the input string), this situation can be avoided by
+/// reserving sufficient space for \c result beforehand.
+///
+/// Any existing %data in \c result will be removed.  This is the case in some
+/// of the cases where an exception is thrown; that is, this function only
+/// provides the basic exception guarantee.
+///
+/// \param input A text encoded in the base64 format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeBase64(const std::string& input, std::vector<uint8_t>& result);
+
+} // namespace encode
+} // namespace util
+} // namespace isc
+
+#endif  // __BASE64_H
+
+// Local Variables: 
+// mode: c++
+// End: 
diff --git a/src/lib/util/encode/base_n.cc b/src/lib/util/encode/base_n.cc
new file mode 100644
index 0000000..406dc77
--- /dev/null
+++ b/src/lib/util/encode/base_n.cc
@@ -0,0 +1,398 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+#include <cassert>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/math/common_factor.hpp>
+
+#include <util/encode/base32hex_from_binary.h>
+#include <util/encode/binary_from_base32hex.h>
+#include <util/encode/base16_from_binary.h>
+#include <util/encode/binary_from_base16.h>
+#include <util/encode/base32hex.h>
+#include <util/encode/base64.h>
+
+#include <exceptions/exceptions.h>
+
+using namespace std;
+using namespace boost::archive::iterators;
+
+namespace isc {
+namespace util {
+namespace encode {
+
+// In the following anonymous namespace, we provide a generic framework
+// to encode/decode baseN format.  We use the following tools:
+// - boost base64_from_binary/binary_from_base64: provide mapping table for
+//   base64.
+//   These classes take another iterator (Base) as a template argument, and
+//   their dereference operator (operator*()) first retrieves an input value
+//   from Base via Base::operator* and converts the value using their mapping
+//   table.  The converted value is returned as their own operator*.
+// - base{32hex,16}_from_binary/binary_from_base{32hex,16}: provide mapping
+//   table for base32hex and base16.  A straightforward variation of their
+//   base64 counterparts.
+// - EncodeNormalizer/DecodeNormalizer: supplemental filter handling baseN
+//   padding characters (=)
+// - boost transform_width: an iterator framework for handling data stream
+//   per bit-group.  It takes another iterator (Base) and output/input bit
+//   numbers (BitsOut/BitsIn) template arguments.  A transform_width object
+//   internally maintains a bit stream, which can be retrieved per BitsOut
+//   bits via its dereference operator (operator*()).  It builds the stream
+//   by internally iterating over the Base object via Base::operator++ and
+//   Base::operator*, using the least BitsIn bits of the result of
+//   Base::operator*.  In our usage BitsIn for encoding and BitsOut for
+//   decoding are always 8 (# of bits for one byte).
+//
+// Its dereference operator
+//   retrieves BitsIn bits from the result of "*Base" (if necessary it
+//   internally calls ++Base) 
+//
+// A conceptual description of how the encoding and decoding work is as
+// follows:
+// Encoding:
+//   input binary data => Normalizer (append sufficient number of 0 bits)
+//                     => transform_width (extract bit groups from the original
+//                                         stream)
+//                     => baseXX_from_binary (convert each bit group to an
+//                                            encoded byte using the mapping)
+// Decoding:
+//   input baseXX text => Normalizer (convert '='s to the encoded characters
+//                                    corresponding to 0, e.g. 'A's in base64)
+//                     => binary_from_baseXX (convert each encoded byte into
+//                                            the original group bit)
+//                     => transform_width (build original byte stream by
+//                                         concatenating the decoded bit
+//                                         stream)
+//
+// Below, we define a set of templated classes to handle different parameters
+// for different encoding algorithms.
+namespace {
+// Common constants used for all baseN encoding.
+const char BASE_PADDING_CHAR = '=';
+const uint8_t BINARY_ZERO_CODE = 0;
+  
+// EncodeNormalizer is an input iterator intended to be used as a filter
+// between the binary stream and baseXX_from_binary translator (via
+// transform_width).  An EncodeNormalizer object is configured with two
+// iterators (base and base_end), specifying the head and end of the input
+// stream.  It internally iterators over the original stream, and return
+// each byte of the stream intact via its dereference operator until it
+// reaches the end of the stream.  After that the EncodeNormalizer object
+// will return 0 no matter how many times it is subsequently incremented.
+// This is necessary because the input binary stream may not contain
+// sufficient bits for a full encoded text while baseXX_from_binary expects
+// a sufficient length of input.
+// Note: this class is intended to be used within this implementation file,
+// and assumes "base < base_end" on construction without validating the
+// arguments.  The behavior is undefined if this assumption doesn't hold.
+class EncodeNormalizer : public iterator<input_iterator_tag, uint8_t> {
+public:
+    EncodeNormalizer(const vector<uint8_t>::const_iterator& base,
+                     const vector<uint8_t>::const_iterator& base_end) :
+        base_(base), base_end_(base_end), in_pad_(false)
+    {}
+    EncodeNormalizer& operator++() {
+        if (!in_pad_) {
+            ++base_;
+        }
+        if (base_ == base_end_) {
+            in_pad_ = true;
+        }
+        return (*this);
+    }
+    const uint8_t& operator*() const {
+        if (in_pad_) {
+            return (BINARY_ZERO_CODE);
+        } else {
+            return (*base_);
+        }
+    }
+    bool operator==(const EncodeNormalizer& other) const {
+        return (base_ == other.base_);
+    }
+private:
+    vector<uint8_t>::const_iterator base_;
+    const vector<uint8_t>::const_iterator base_end_;
+    bool in_pad_;
+};
+
+// DecodeNormalizer is an input iterator intended to be used as a filter
+// between the encoded baseX stream and binary_from_baseXX.
+// A DecodeNormalizer object is configured with three string iterators
+// (base, base_beginpad, and base_end), specifying the head of the string,
+// the beginning position of baseX padding (when there's padding), and
+// end of the string, respectively.  It internally iterators over the original
+// stream, and return each character of the encoded string via its dereference
+// operator until it reaches base_beginpad.  After that the DecodeNormalizer
+// will return the encoding character corresponding to the all-0 value
+// (which is specified on construction via base_zero_code.  see also
+// BaseZeroCode below).  This translation is necessary because
+// binary_from_baseXX doesn't accept the padding character (i.e. '=').
+// Note: this class is intended to be used within this implementation file,
+// and for simplicity assumes "base < base_beginpad <= base_end" on
+// construction without validating the arguments.  The behavior is undefined
+// if this assumption doesn't hold.
+class DecodeNormalizer : public iterator<input_iterator_tag, char> {
+public:
+    DecodeNormalizer(const char base_zero_code,
+                     const string::const_iterator& base,
+                     const string::const_iterator& base_beginpad,
+                     const string::const_iterator& base_end) :
+        base_zero_code_(base_zero_code),
+        base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
+        in_pad_(false)
+    {}
+    DecodeNormalizer& operator++() {
+        ++base_;
+        while (base_ != base_end_ && isspace(*base_)) {
+            ++base_;
+        }
+        if (base_ == base_beginpad_) {
+            in_pad_ = true;
+        }
+        return (*this);
+    }
+    const char& operator*() const {
+        if (in_pad_ && *base_ == BASE_PADDING_CHAR) {
+            return (base_zero_code_);
+        } else {
+            return (*base_);
+        }
+    }
+    bool operator==(const DecodeNormalizer& other) const {
+        return (base_ == other.base_);
+    }
+private:
+    const char base_zero_code_;
+    string::const_iterator base_;
+    const string::const_iterator base_beginpad_;
+    const string::const_iterator base_end_;
+    bool in_pad_;
+};
+
+// BitsPerChunk: number of bits to be converted using the baseN mapping table.
+//               e.g. 6 for base64.
+// BaseZeroCode: the byte character that represents a value of 0 in
+//               the corresponding encoding.  e.g. 'A' for base64.
+// Encoder: baseX_from_binary<transform_width<EncodeNormalizer,
+//                                            BitsPerChunk, 8> >
+// Decoder: transform_width<binary_from_baseX<DecodeNormalizer>,
+//                          8, BitsPerChunk>
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+struct BaseNTransformer {
+    static string encode(const vector<uint8_t>& binary);
+    static void decode(const char* algorithm,
+                       const string& base64, vector<uint8_t>& result);
+
+    // BITS_PER_GROUP is the number of bits for the smallest possible (non
+    // empty) bit string that can be converted to a valid baseN encoded text
+    // without padding.  It's the least common multiple of 8 and BitsPerChunk,
+    // e.g. 24 for base64.
+    static const int BITS_PER_GROUP =
+        boost::math::static_lcm<BitsPerChunk, 8>::value;
+
+    // MAX_PADDING_CHARS is the maximum number of padding characters
+    // that can appear in a valid baseN encoded text.
+    // It's group_len - chars_for_byte, where group_len is the number of
+    // encoded characters to represent BITS_PER_GROUP bits, and
+    // chars_for_byte is the number of encoded character that is needed to
+    // represent a single byte, which is ceil(8 / BitsPerChunk).
+    // For example, for base64 we need two encoded characters to represent a
+    // byte, and each group consists of 4 encoded characters, so
+    // MAX_PADDING_CHARS is 4 - 2 = 2.
+    static const int MAX_PADDING_CHARS =
+        BITS_PER_GROUP / BitsPerChunk -
+        (8 / BitsPerChunk + ((8 % BitsPerChunk) == 0 ? 0 : 1));
+}; 
+
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+string
+BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::encode(
+    const vector<uint8_t>& binary)
+{
+    // calculate the resulting length.
+    size_t bits = binary.size() * 8;
+    if (bits % BITS_PER_GROUP > 0) {
+        bits += (BITS_PER_GROUP - (bits % BITS_PER_GROUP));
+    }
+    const size_t len = bits / BitsPerChunk;
+
+    string result;
+    result.reserve(len);
+    result.assign(Encoder(EncodeNormalizer(binary.begin(), binary.end())),
+                  Encoder(EncodeNormalizer(binary.end(), binary.end())));
+    assert(len >= result.length());
+    result.append(len - result.length(), BASE_PADDING_CHAR);
+    return (result);
+}
+
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+void
+BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::decode(
+    const char* const algorithm,
+    const string& input,
+    vector<uint8_t>& result)
+{
+    // enumerate the number of trailing padding characters (=), ignoring
+    // white spaces.  since baseN_from_binary doesn't accept padding,
+    // we handle it explicitly.
+    size_t padchars = 0;
+    string::const_reverse_iterator srit = input.rbegin();
+    string::const_reverse_iterator srit_end = input.rend();
+    while (srit != srit_end) {
+        char ch = *srit;
+        if (ch == BASE_PADDING_CHAR) {
+            if (++padchars > MAX_PADDING_CHARS) {
+                isc_throw(BadValue, "Too many " << algorithm
+                          << " padding characters: " << input);
+            }
+        } else if (!isspace(ch)) {
+            break;
+        }
+        ++srit;
+    }
+    // then calculate the number of padding bits corresponding to the padding
+    // characters.  In general, the padding bits consist of all-zero
+    // trailing bits of the last encoded character followed by zero bits
+    // represented by the padding characters:
+    // 1st pad  2nd pad  3rd pad...
+    // +++===== =======  ===...    (+: from encoded chars, =: from pad chars)
+    // 0000...0 0......0 000...
+    // 0      7 8     15 16.... (bits)
+    // The number of bits for the '==...' part is padchars * BitsPerChunk.
+    // So the total number of padding bits is the smallest multiple of 8 
+    // that is >= padchars * BitsPerChunk.
+    // (Below, note the common idiom of the bitwise AND with ~7.  It clears the
+    // lowest three bits, so has the effect of rounding the result down to the
+    // nearest multiple of 8)
+    const size_t padbits = (padchars * BitsPerChunk + 7) & ~7;
+
+    // In some encoding algorithm, it could happen that a padding byte would
+    // contain a full set of encoded bits, which is not allowed by definition
+    // of padding.  For example, if BitsPerChunk is 5, the following
+    // representation could happen:
+    // ++00000= (+: from encoded chars, 0: encoded char for '0', =: pad chars)
+    // 0      7 (bits)
+    // This must actually be encoded as follows:
+    // ++======
+    // 0      7 (bits)
+    // The following check rejects this type of invalid encoding.
+    if (padbits > BitsPerChunk * (padchars + 1)) {
+        isc_throw(BadValue, "Invalid " << algorithm << "padding: " << input);
+    }
+
+    // convert the number of bits in bytes for convenience.
+    const size_t padbytes = padbits / 8;
+
+    try {
+        result.assign(Decoder(DecodeNormalizer(BaseZeroCode, input.begin(),
+                                               srit.base(), input.end())),
+                      Decoder(DecodeNormalizer(BaseZeroCode, input.end(),
+                                               input.end(), input.end())));
+    } catch (const dataflow_exception& ex) {
+        // convert any boost exceptions into our local one.
+        isc_throw(BadValue, ex.what());
+    }
+
+    // Confirm the original BaseX text is the canonical encoding of the
+    // data, that is, that the first byte of padding is indeed 0.
+    // (DecodeNormalizer and binary_from_baseXX ensure that the rest of the
+    // padding is all zero).
+    assert(result.size() >= padbytes);
+    if (padbytes > 0 && *(result.end() - padbytes) != 0) {
+            isc_throw(BadValue, "Non 0 bits included in " << algorithm
+                      << " padding: " << input);
+    }
+
+    // strip the padded zero-bit fields
+    result.resize(result.size() - padbytes);
+}
+
+//
+// Instantiation for BASE-64
+//
+typedef
+base64_from_binary<transform_width<EncodeNormalizer, 6, 8> > base64_encoder;
+typedef
+transform_width<binary_from_base64<DecodeNormalizer>, 8, 6> base64_decoder;
+typedef BaseNTransformer<6, 'A', base64_encoder, base64_decoder>
+Base64Transformer;
+
+//
+// Instantiation for BASE-32HEX
+//
+typedef
+base32hex_from_binary<transform_width<EncodeNormalizer, 5, 8> >
+base32hex_encoder;
+typedef
+transform_width<binary_from_base32hex<DecodeNormalizer>, 8, 5>
+base32hex_decoder;
+typedef BaseNTransformer<5, '0', base32hex_encoder, base32hex_decoder>
+Base32HexTransformer;
+
+//
+// Instantiation for BASE-16 (HEX)
+//
+typedef
+base16_from_binary<transform_width<EncodeNormalizer, 4, 8> > base16_encoder;
+typedef
+transform_width<binary_from_base16<DecodeNormalizer>, 8, 4> base16_decoder;
+typedef BaseNTransformer<4, '0', base16_encoder, base16_decoder>
+Base16Transformer;
+}
+
+string
+encodeBase64(const vector<uint8_t>& binary) {
+    return (Base64Transformer::encode(binary));
+}
+
+void
+decodeBase64(const string& input, vector<uint8_t>& result) {
+    Base64Transformer::decode("base64", input, result);
+}
+
+string
+encodeBase32Hex(const vector<uint8_t>& binary) {
+    return (Base32HexTransformer::encode(binary));
+}
+
+void
+decodeBase32Hex(const string& input, vector<uint8_t>& result) {
+    Base32HexTransformer::decode("base32hex", input, result);
+}
+
+string
+encodeHex(const vector<uint8_t>& binary) {
+    return (Base16Transformer::encode(binary));
+}
+
+void
+decodeHex(const string& input, vector<uint8_t>& result) {
+    Base16Transformer::decode("base16", input, result);
+}
+
+} // namespace encode
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/encode/binary_from_base16.h b/src/lib/util/encode/binary_from_base16.h
new file mode 100644
index 0000000..50342f1
--- /dev/null
+++ b/src/lib/util/encode/binary_from_base16.h
@@ -0,0 +1,120 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// binary_from_base16.h (derived from boost binary_from_base64.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+// See binary_from_base32hex.h for why we need _from_base64.hpp here.
+#include <boost/archive/iterators/binary_from_base64.hpp>
+
+#include <exceptions/exceptions.h>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert base16 characters to binary data
+
+namespace detail {
+
+template<class CharType>
+struct to_4_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char lookup_table[] = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
+             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
+            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 40-4f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
+            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 60-6f
+        };
+        // metrowerks trips this assertion - how come?
+        #if ! defined(__MWERKS__)
+        BOOST_STATIC_ASSERT(0x70 == sizeof(lookup_table));
+        #endif
+        signed char value = -1;
+        if((unsigned)t < sizeof(lookup_table))
+            value = lookup_table[(unsigned)t];
+        if(-1 == value) { 
+            isc_throw(isc::BadValue,
+                      "attempt to decode a value not in base16 char set");
+        }
+        return (value);
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_4_bit<CharType>,
+//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
+//  > base16_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class binary_from_base16 : public
+    transform_iterator<
+        detail::to_4_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        detail::to_4_bit<CharType>,
+        Base
+    > super_t;
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    binary_from_base16(BOOST_PFTO_WRAPPER(T)  start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
+            detail::to_4_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    binary_from_base16(const binary_from_base16 & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::to_4_bit<CharType>()
+        )
+    {}
+//    binary_from_base16(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+
+// Local Variables: 
+// mode: c++
+// End: 
diff --git a/src/lib/util/encode/binary_from_base32hex.h b/src/lib/util/encode/binary_from_base32hex.h
new file mode 100644
index 0000000..1d83f54
--- /dev/null
+++ b/src/lib/util/encode/binary_from_base32hex.h
@@ -0,0 +1,123 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// binary_from_base32hex.h (derived from boost binary_from_base64.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+// We use the same boost header files used in "_from_base64".  Since the
+// precise path to these headers may vary depending on the boost version we
+// simply include the base64 header here.
+#include <boost/archive/iterators/binary_from_base64.hpp>
+
+#include <exceptions/exceptions.h>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert base32hex characters to binary data
+
+namespace detail {
+
+template<class CharType>
+struct to_5_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char lookup_table[] = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
+             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
+            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 40-4f
+            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
+            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 60-6f
+            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 70-7f
+        };
+        // metrowerks trips this assertion - how come?
+        #if ! defined(__MWERKS__)
+        BOOST_STATIC_ASSERT(0x80 == sizeof(lookup_table));
+        #endif
+        signed char value = -1;
+        if((unsigned)t < sizeof(lookup_table))
+            value = lookup_table[(unsigned)t];
+        if(-1 == value) { 
+            isc_throw(isc::BadValue,
+                      "attempt to decode a value not in base32hex char set");
+        }
+        return (value);
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_5_bit<CharType>,
+//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
+//  > base32hex_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class binary_from_base32hex : public
+    transform_iterator<
+        detail::to_5_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        detail::to_5_bit<CharType>,
+        Base
+    > super_t;
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    binary_from_base32hex(BOOST_PFTO_WRAPPER(T)  start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
+            detail::to_5_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    binary_from_base32hex(const binary_from_base32hex & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::to_5_bit<CharType>()
+        )
+    {}
+//    binary_from_base32hex(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+
+// Local Variables: 
+// mode: c++
+// End: 
diff --git a/src/lib/util/encode/hex.h b/src/lib/util/encode/hex.h
new file mode 100644
index 0000000..5c806fc
--- /dev/null
+++ b/src/lib/util/encode/hex.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __HEX_H
+#define __HEX_H 1
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace util {
+namespace encode {
+/// \brief Encode binary data in the base16 ('hex') format.
+///
+/// The underlying implementation is shared with \c encodeBase64, and most of
+/// the description except the format (base16) equally applies.
+/// Another notable exception is that the base16 encoding doesn't require
+/// padding, so padding related considerations and the notion of canonical
+/// encoding don't apply.
+///
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base16 encoded value for
+/// binary.
+std::string encodeHex(const std::vector<uint8_t>& binary);
+
+/// \brief Decode a text encoded in the base16 ('hex') format into the
+/// original %data.
+///
+/// The underlying implementation is shared with \c decodeBase64, and most
+/// of the description except the format (base16) equally applies.
+/// Another notable exception is that the base16 encoding doesn't require
+/// padding, so padding related considerations and the notion of canonical
+/// encoding don't apply.
+///
+/// \param input A text encoded in the base16 format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeHex(const std::string& input, std::vector<uint8_t>& result);
+
+} // namespace encode
+} // namespace util
+} // namespace isc
+
+#endif  // __HEX_H
+
+// Local Variables: 
+// mode: c++
+// End: 
diff --git a/src/lib/util/filename.cc b/src/lib/util/filename.cc
new file mode 100644
index 0000000..1f2e5db
--- /dev/null
+++ b/src/lib/util/filename.cc
@@ -0,0 +1,137 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <iostream>
+#include <algorithm>
+#include <string>
+
+#include <ctype.h>
+
+#include <util/filename.h>
+
+using namespace std;
+
+
+namespace isc {
+namespace util {
+
+// Split string into components.  Any backslashes are assumed to have
+// been replaced by forward slashes.
+
+void
+Filename::split(const string& full_name, string& directory,
+    string& name, string& extension) const
+{
+    directory = name = extension = "";
+    bool dir_present = false;
+    if (!full_name.empty()) {
+
+        // Find the directory.
+        size_t last_slash = full_name.find_last_of('/');
+        if (last_slash != string::npos) {
+
+            // Found the last slash, so extract directory component and
+            // set where the scan for the last_dot should terminate.
+            directory = full_name.substr(0, last_slash + 1);
+            if (last_slash == full_name.size()) {
+
+                // The entire string was a directory, so exit not and don't
+                // do any more searching.
+                return;
+            }
+
+            // Found a directory so note the fact.
+            dir_present = true;
+        }
+
+        // Now search backwards for the last ".".
+        size_t last_dot = full_name.find_last_of('.');
+        if ((last_dot == string::npos) ||
+            (dir_present && (last_dot < last_slash))) {
+
+            // Last "." either not found or it occurs to the left of the last
+            // slash if a directory was present (so it is part of a directory
+            // name).  In this case, the remainder of the string after the slash
+            // is the name part.
+            name = full_name.substr(last_slash + 1);
+            return;
+        }
+
+        // Did find a valid dot, so it and everything to the right is the
+        // extension...
+        extension = full_name.substr(last_dot);
+
+        // ... and the name of the file is everything in between.
+        if ((last_dot - last_slash) > 1) {
+            name = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
+        }
+    }
+
+}
+
+// Expand the stored filename with the default.
+
+string
+Filename::expandWithDefault(const string& defname) const {
+
+    string def_directory("");
+    string def_name("");
+    string def_extension("");
+
+    // Normalize the input string.
+    string copy_defname = isc::util::str::trim(defname);
+#ifdef WIN32
+    isc::util::str::normalizeSlash(copy_defname);
+#endif
+
+    // Split into the components
+    split(copy_defname, def_directory, def_name, def_extension);
+
+    // Now construct the result.
+    string retstring =
+        (directory_.empty() ? def_directory : directory_) +
+        (name_.empty() ? def_name : name_) +
+        (extension_.empty() ? def_extension : extension_);
+    return (retstring);
+}
+
+// Use the stored name as default for a given name
+
+string
+Filename::useAsDefault(const string& name) const {
+
+    string name_directory("");
+    string name_name("");
+    string name_extension("");
+
+    // Normalize the input string.
+    string copy_name = isc::util::str::trim(name);
+#ifdef WIN32
+    isc::util::str::normalizeSlash(copy_name);
+#endif
+
+    // Split into the components
+    split(copy_name, name_directory, name_name, name_extension);
+
+    // Now construct the result.
+    string retstring =
+        (name_directory.empty() ? directory_ : name_directory) +
+        (name_name.empty() ? name_ : name_name) +
+        (name_extension.empty() ? extension_ : name_extension);
+    return (retstring);
+}
+
+
+} // namespace log
+} // namespace isc
diff --git a/src/lib/util/filename.h b/src/lib/util/filename.h
new file mode 100644
index 0000000..984ecb0
--- /dev/null
+++ b/src/lib/util/filename.h
@@ -0,0 +1,161 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __FILENAME_H
+#define __FILENAME_H
+
+#include <string>
+
+#include <util/strutil.h>
+
+namespace isc {
+namespace util {
+
+/// \brief Class to Manipulate Filenames
+///
+/// This is a utility class to manipulate filenames.  It repeats some of the
+/// features found in the Boost filename class, but is self-contained so avoids
+/// the need to link in the Boost library.
+///
+/// A Unix-style filename comprises three parts:
+///
+/// Directory - everything up to and including the last "/".  If there is no
+/// "/" in the string, there is no directory component.  Note that the
+/// requirement of a trailing slash eliminates the ambiguity of whether a
+/// component is a directory or not, e.g. in /alpha/beta", "beta" could be the
+/// name of a directory or is could be a file.  The interpretation here is that
+/// "beta" is the name of a file (although that file could be a directory).
+///
+/// Note: Under Windows, the drive letter is considered to be part of the
+/// directory specification.  Unless this class becomes more widely-used on
+/// Windows, there is no point in adding redundant code.
+///
+/// Name - everthing from the character after the last "/" up to but not
+/// including the last ".".
+///
+/// Extension - everthing from the right-most "." (after the right-most "/") to
+/// the end of the string.  If there is no "." after the last "/", there is
+/// no file extension.
+///
+/// (Note that on Windows, this function will replace all "\" characters
+/// with "/" characters on input strings.)
+///
+/// This class provides functions for extracting the components and for
+/// substituting components.
+
+
+class Filename {
+public:
+
+    /// \brief Constructor
+    Filename(const std::string& name) :
+        full_name_(""), directory_(""), name_(""), extension_("")
+    {
+        setName(name);
+    }
+
+    /// \brief Sets Stored Filename
+    ///
+    /// \param name New name to replaced currently stored name
+    void setName(const std::string& name) {
+        full_name_ = isc::util::str::trim(name);
+#ifdef WIN32
+        isc::util::str::normalizeSlash(full_name_);
+#endif
+        split(full_name_, directory_, name_, extension_);
+    }
+
+    /// \return Stored Filename
+    std::string fullName() const {
+        return (full_name_);
+    }
+
+    /// \return Directory of Given File Name
+    std::string directory() const {
+        return (directory_);
+    }
+
+    /// \return Name of Given File Name
+    std::string name() const {
+        return (name_);
+    }
+
+    /// \return Extension of Given File Name
+    std::string extension() const {
+        return (extension_);
+    }
+
+    /// \brief Expand Name with Default
+    ///
+    /// A default file specified is supplied and used to fill in any missing
+    /// fields.  For example, if the name stored is "/a/b" and the supplied
+    /// name is "c.d", the result is "/a/b.d": the only field missing from the
+    /// stored name is the extension, which is supplied by the default.
+    /// Another example would be to store "a.b" and to supply a default of
+    /// "/c/d/" - the result is "/c/d/a.b".  (Note that if the supplied default
+    /// was "/c/d", the result would be "/c/a.b", even if "/c/d" were actually
+    /// a directory.)
+    ///
+    /// \param defname Default name
+    ///
+    /// \return Name expanded with defname.
+    std::string expandWithDefault(const std::string& defname) const;
+
+    /// \brief Use as Default and Substitute into String
+    ///
+    /// Does essentially the inverse of expand(); that filled in the stored
+    /// name with a default and returned the result.  This treats the stored
+    /// name as the default and uses it to fill in a given name.  In essence,
+    /// the code:
+    /// \code
+    ///       Filename f("/a/b");
+    ///       result = f.expandWithdefault("c.d");
+    /// \endcode
+    /// gives as a result "/a/b.d".  This is the same as:
+    /// \code
+    ///       Filename f("c.d");
+    ///       result = f.useAsDefault("/a/b");
+    /// \endcode
+    ///
+    /// \param name Name to expand
+    ///
+    /// \return Name expanded with stored name
+    std::string useAsDefault(const std::string& name) const;
+
+private:
+    /// \brief Split Name into Components
+    ///
+    /// Splits the file name into the directory, name and extension parts.
+    /// The name is assumed to have had back slashes replaced by forward
+    /// slashes (if appropriate).
+    ///
+    /// \param full_name Name to split
+    /// \param directory Returned directory part
+    /// \param name Returned name part
+    /// \param extension Returned extension part
+    void split(const std::string& full_name, std::string& directory,
+       std::string& name, std::string& extension) const;
+
+    // Members
+
+    std::string full_name_;     ///< Given name
+    std::string directory_;     ///< Directory part
+    std::string name_;          ///< Name part
+    std::string extension_;     ///< Extension part
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // __FILENAME_H
diff --git a/src/lib/util/hash/sha1.cc b/src/lib/util/hash/sha1.cc
new file mode 100644
index 0000000..091e293
--- /dev/null
+++ b/src/lib/util/hash/sha1.cc
@@ -0,0 +1,492 @@
+/*
+ *  Description:
+ *      This file implements the Secure Hash Signature Standard
+ *      algorithms as defined in the National Institute of Standards
+ *      and Technology Federal Information Processing Standards
+ *      Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2
+ *      published on August 1, 2002, and the FIPS PUB 180-2 Change
+ *      Notice published on February 28, 2004.
+ *
+ *      A combined document showing all algorithms is available at
+ *              http://csrc.nist.gov/publications/fips/
+ *              fips180-2/fips180-2withchangenotice.pdf
+ *
+ *      The SHA-1 algorithm produces a 160-bit message digest for a
+ *      given data stream.  It should take about 2**n steps to find a
+ *      message with the same digest as a given message and
+ *      2**(n/2) to find any two messages with the same digest,
+ *      when n is the digest size in bits.  Therefore, this
+ *      algorithm can serve as a means of providing a
+ *      "fingerprint" for a message.
+ *
+ *  Portability Issues:
+ *      SHA-1 is defined in terms of 32-bit "words".  This code
+ *      uses <stdint.h> (included via "sha.h") to define 32 and 8
+ *      bit unsigned integer types.  If your C compiler does not
+ *      support 32 bit unsigned integers, this code is not
+ *      appropriate.
+ *
+ *  Caveats:
+ *      SHA-1 is designed to work with messages less than 2^64 bits
+ *      long. This implementation uses SHA1Input() to hash the bits
+ *      that are a multiple of the size of an 8-bit character, and then
+ *      uses SHA1FinalBits() to hash the final few bits of the input.
+ *
+ *  Authorship:
+ *      This file is adapted from RFC 4634, by D. Eastlake et al.
+ *      Copyright (C) The Internet Society (2006).
+ *
+ *      Permission is granted for all uses, commercial and non-commercial,
+ *      of the sample code found in Section 8.  Royalty free license to
+ *      use, copy, modify and distribute the software found in Section 8 is
+ *      granted, provided that this document is identified in all material
+ *      mentioning or referencing this software, and provided that
+ *      redistributed derivative works do not contain misleading author or
+ *      version information.
+ *
+ *      The authors make no representations concerning either the
+ *      merchantability of this software or the suitability of this
+ *      software for any particular purpose.  It is provided "as is"
+ *      without express or implied warranty of any kind.
+ *      
+ */
+#include <util/hash/sha1.h>
+
+namespace isc {
+namespace util {
+namespace hash {
+
+/* Local Function Prototyptes */
+static void SHA1Finalize(SHA1Context *, uint8_t Pad_Byte);
+static void SHA1PadMessage(SHA1Context *, uint8_t Pad_Byte);
+static void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ * Define functions used by SHA1 hash
+ */
+static inline uint32_t
+SHA_Ch(const uint32_t x, const uint32_t y, const uint32_t z) {
+    return (((x) & ((y) ^ (z))) ^ (z));
+}
+
+static inline uint32_t
+SHA_Maj(const uint32_t x, const uint32_t y, const uint32_t z) {
+    return (((x) & ((y) | (z))) | ((y) & (z)));
+}
+
+static inline uint32_t
+SHA_Parity(const uint32_t x, const uint32_t y, const uint32_t z) {
+    return ((x) ^ (y) ^ (z));
+}
+
+static inline int 
+SHA1CircularShift(uint8_t bits, uint32_t word) {
+    return ((word << bits) | (word >> (32 - bits)));
+}
+
+static inline bool
+SHA1AddLength(SHA1Context *context, uint32_t length) {
+    uint32_t addTemp = context->Length_Low;
+    context->Length_Low += length;
+    if (context->Length_Low < addTemp && ++context->Length_High == 0) {
+        return (true);
+    } else {
+        return (false);
+    }
+}
+
+/*
+ *  SHA1Reset
+ *
+ *  Description:
+ *      This function will initialize the SHA1Context in preparation
+ *      for computing a new SHA1 message digest.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to reset.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Reset(SHA1Context *context) {
+    if (!context) {
+        return (SHA_NULL);
+    }
+
+    context->Length_Low             = 0;
+    context->Length_High            = 0;
+    context->Message_Block_Index    = 0;
+
+    context->Intermediate_Hash[0]   = 0x67452301;
+    context->Intermediate_Hash[1]   = 0xEFCDAB89;
+    context->Intermediate_Hash[2]   = 0x98BADCFE;
+    context->Intermediate_Hash[3]   = 0x10325476;
+    context->Intermediate_Hash[4]   = 0xC3D2E1F0;
+
+    context->Computed   = 0;
+    context->Corrupted  = 0;
+    return (SHA_SUCCESS);
+}
+
+
+/*
+ *  SHA1Input
+ *
+ *  Description:
+ *      This function accepts an array of octets as the next portion
+ *      of the message.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The SHA context to update
+ *      message_array: [in]
+ *          An array of characters representing the next portion of
+ *          the message.
+ *      length: [in]
+ *          The length of the message in message_array
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned length) {
+    if (!length) {
+        return (SHA_SUCCESS);
+    }
+
+    if (!context || !message_array) {
+        return (SHA_NULL);
+    }
+
+    if (context->Computed) {
+        context->Corrupted = SHA_STATEERROR;
+        return (SHA_STATEERROR);
+    }
+
+    if (context->Corrupted) {
+         return (context->Corrupted);
+    }
+
+    while(length-- && !context->Corrupted) {
+        context->Message_Block[context->Message_Block_Index++] =
+                                                    (*message_array & 0xFF);
+
+        if (!SHA1AddLength(context, 8) &&
+            (context->Message_Block_Index == SHA1_BLOCKSIZE))
+        {
+            SHA1ProcessMessageBlock(context);
+        }
+
+        message_array++;
+    }
+
+    return (SHA_SUCCESS);
+}
+
+/*
+ * SHA1FinalBits
+ *
+ * Description:
+ *   This function will add in any final bits of the message.
+ *
+ * Parameters:
+ *   context: [in/out]
+ *     The SHA context to update
+ *   message_bits: [in]
+ *     The final bits of the message, in the upper portion of the
+ *     byte. (Use 0b###00000 instead of 0b00000### to input the
+ *     three bits ###.)
+ *   length: [in]
+ *     The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ *   sha Error Code.
+ */
+int SHA1FinalBits(SHA1Context *context, const uint8_t message_bits,
+                  unsigned int length)
+{
+    uint8_t masks[8] = {
+        /* 0 0b00000000 */ 0x00,
+        /* 1 0b10000000 */ 0x80,
+        /* 2 0b11000000 */ 0xC0,
+        /* 3 0b11100000 */ 0xE0,
+        /* 4 0b11110000 */ 0xF0,
+        /* 5 0b11111000 */ 0xF8,
+        /* 6 0b11111100 */ 0xFC,
+        /* 7 0b11111110 */ 0xFE
+    };
+    uint8_t markbit[8] = {
+        /* 0 0b10000000 */ 0x80,
+        /* 1 0b01000000 */ 0x40,
+        /* 2 0b00100000 */ 0x20,
+        /* 3 0b00010000 */ 0x10,
+        /* 4 0b00001000 */ 0x08,
+        /* 5 0b00000100 */ 0x04,
+        /* 6 0b00000010 */ 0x02,
+        /* 7 0b00000001 */ 0x01
+    };
+
+    if (!length) {
+        return (SHA_SUCCESS);
+    }
+
+    if (!context) {
+        return (SHA_NULL);
+    }
+
+    if (context->Computed || (length >= 8) || (length == 0)) {
+        context->Corrupted = SHA_STATEERROR;
+        return (SHA_STATEERROR);
+    }
+
+    if (context->Corrupted) {
+        return (context->Corrupted);
+    }
+
+    SHA1AddLength(context, length);
+    SHA1Finalize(context,
+                 (uint8_t) ((message_bits & masks[length]) | markbit[length]));
+
+    return (SHA_SUCCESS);
+}
+
+/*
+ *  SHA1Result
+ *
+ *  Description:
+ *      This function will return the 160-bit message digest into the
+ *      Message_Digest array  provided by the caller.
+ *      NOTE: The first octet of hash is stored in the 0th element,
+ *            the last octet of hash in the 19th element.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to use to calculate the SHA-1 hash.
+ *      Message_Digest: [out]
+ *          Where the digest is returned.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1_HASHSIZE]) {
+    int i;
+
+    if (!context || !Message_Digest) {
+        return (SHA_NULL);
+    }
+
+    if (context->Corrupted) {
+        return (context->Corrupted);
+    }
+
+    if (!context->Computed) {
+        SHA1Finalize(context, 0x80);
+    }
+
+    for(i = 0; i < SHA1_HASHSIZE; ++i) {
+        Message_Digest[i] = context->Intermediate_Hash[i>>2]
+                            >> 8 * (3 - (i & 0x03));
+    }
+
+    return (SHA_SUCCESS);
+}
+
+/*
+ * SHA1Finalize
+ *
+ * Description:
+ *   This helper function finishes off the digest calculations.
+ *
+ * Parameters:
+ *   context: [in/out]
+ *     The SHA context to update
+ *   Pad_Byte: [in]
+ *     The last byte to add to the digest before the 0-padding
+ *     and length. This will contain the last bits of the message
+ *     followed by another single bit. If the message was an
+ *     exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ *   sha Error Code.
+ *
+ */
+static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) {
+    int i;
+    SHA1PadMessage(context, Pad_Byte);
+    /* message may be sensitive, clear it out */
+    for (i = 0; i < SHA1_BLOCKSIZE; ++i)
+        context->Message_Block[i] = 0;
+    context->Length_Low = 0;  /* and clear length */
+    context->Length_High = 0;
+    context->Computed = 1;
+}
+
+/*
+ *  SHA1PadMessage
+ *
+ *  Description:
+ *      According to the standard, the message must be padded to an even
+ *      512 bits.  The first padding bit must be a '1'.  The last 64
+ *      bits represent the length of the original message.  All bits in
+ *      between should be 0.  This function will pad the message
+ *      according to those rules by filling the Message_Block array
+ *      accordingly.  It will also call the ProcessMessageBlock function
+ *      provided appropriately.  When it returns, it can be assumed that
+ *      the message digest has been computed.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to pad
+ *      Pad_Byte: [in]
+ *          The last byte to add to the digest before the 0-padding
+ *          and length. This will contain the last bits of the message
+ *          followed by another single bit. If the message was an
+ *          exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ */
+static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) {
+    /*
+     * Check to see if the current message block is too small to hold
+     * the initial padding bits and length. If so, we will pad the
+     * block, process it, and then continue padding into a second
+     * block.
+     */
+    if (context->Message_Block_Index >= (SHA1_BLOCKSIZE - 8)) {
+        context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+        while (context->Message_Block_Index < SHA1_BLOCKSIZE) {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+
+        SHA1ProcessMessageBlock(context);
+    } else
+        context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+
+    while (context->Message_Block_Index < (SHA1_BLOCKSIZE - 8))
+        context->Message_Block[context->Message_Block_Index++] = 0;
+
+    /*
+     * Store the message length as the last 8 octets
+     */
+    context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
+    context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
+    context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
+    context->Message_Block[59] = (uint8_t) (context->Length_High);
+    context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
+    context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
+    context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
+    context->Message_Block[63] = (uint8_t) (context->Length_Low);
+
+    SHA1ProcessMessageBlock(context);
+}
+
+/*
+ *  SHA1ProcessMessageBlock
+ *
+ *  Description:
+ *      This helper function will process the next 512 bits of the
+ *      message stored in the Message_Block array.
+ *
+ *  Parameters:
+ *      None.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the
+ *      names used in the publication.
+ *
+ *
+ */
+static void
+SHA1ProcessMessageBlock(SHA1Context *context) {
+    /* Constants defined in FIPS-180-2, section 4.2.1 */
+    const uint32_t K[] = {
+        0x5A827999,
+        0x6ED9EBA1,
+        0x8F1BBCDC,
+        0xCA62C1D6
+    };
+    int           t;                 /* Loop counter                */
+    uint32_t      temp;              /* Temporary word value        */
+    uint32_t      W[80];             /* Word sequence               */
+    uint32_t      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     * Initialize the first 16 words in the array W
+     */
+    for (t = 0; t < 16; t++) {
+        W[t]  = ((uint32_t)context->Message_Block[t * 4]) << 24;
+        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16;
+        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8;
+        W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]);
+    }
+
+    for (t = 16; t < 80; t++) {
+        W[t] = SHA1CircularShift(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = context->Intermediate_Hash[0];
+    B = context->Intermediate_Hash[1];
+    C = context->Intermediate_Hash[2];
+    D = context->Intermediate_Hash[3];
+    E = context->Intermediate_Hash[4];
+
+    for (t = 0; t < 20; t++) {
+        temp = SHA1CircularShift(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 20; t < 40; t++) {
+        temp = SHA1CircularShift(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 40; t < 60; t++) {
+        temp = SHA1CircularShift(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 60; t < 80; t++) {
+        temp = SHA1CircularShift(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    context->Intermediate_Hash[0] += A;
+    context->Intermediate_Hash[1] += B;
+    context->Intermediate_Hash[2] += C;
+    context->Intermediate_Hash[3] += D;
+    context->Intermediate_Hash[4] += E;
+
+    context->Message_Block_Index = 0;
+}
+
+} // namespace hash
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/hash/sha1.h b/src/lib/util/hash/sha1.h
new file mode 100644
index 0000000..6089ca8
--- /dev/null
+++ b/src/lib/util/hash/sha1.h
@@ -0,0 +1,91 @@
+/*
+ *  sha1.h
+ *
+ *  Description:
+ *      This is the header file for code which implements the Secure
+ *      Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ *      April 17, 1995.
+ *
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the names
+ *      used in the publication.
+ *
+ *      Please read the file sha1.cc for more information.
+ *
+ *  Authorship:
+ *      This file is adapted from RFC 4634, by D. Eastlake et al.
+ *      Copyright (C) The Internet Society (2006).
+ *
+ *      Permission is granted for all uses, commercial and non-commercial,
+ *      of the sample code found in Section 8.  Royalty free license to
+ *      use, copy, modify and distribute the software found in Section 8 is
+ *      granted, provided that this document is identified in all material
+ *      mentioning or referencing this software, and provided that
+ *      redistributed derivative works do not contain misleading author or
+ *      version information.
+ *
+ *      The authors make no representations concerning either the
+ *      merchantability of this software or the suitability of this
+ *      software for any particular purpose.  It is provided "as is"
+ *      without express or implied warranty of any kind.
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#include <stdint.h>
+
+namespace isc {
+namespace util {
+namespace hash {
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ *    name              meaning
+ *  uint32_t         unsigned 32 bit integer
+ *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)
+ *  int_least16_t    integer of >= 16 bits
+ *
+ */
+
+enum {
+    SHA_SUCCESS = 0,
+    SHA_NULL,            /* Null pointer parameter */
+    SHA_STATEERROR       /* called Input after Result */
+};
+
+enum {
+    SHA1_HASHSIZE = 20,
+    SHA1_HASHBITS = 20,
+    SHA1_BLOCKSIZE = 64
+};
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct SHA1Context
+{
+    uint32_t Intermediate_Hash[SHA1_HASHSIZE/4]; /* Message Digest */
+    uint32_t Length_Low;                /* Message length in bits */
+    uint32_t Length_High;               /* Message length in bits */
+    int_least16_t Message_Block_Index;  /* Index into message block array */
+    uint8_t Message_Block[64];          /* 512-bit message blocks */
+    int Computed;                       /* Is the digest computed? */
+    int Corrupted;                      /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ *  Function Prototypes
+ */
+extern int SHA1Reset(SHA1Context *);
+extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
+                     unsigned int bytecount);
+extern int SHA1FinalBits(SHA1Context *, const uint8_t bits,
+                         unsigned int bitcount);
+extern int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1_HASHSIZE]);
+
+} // namespace hash
+} // namespace util
+} // namespace isc
+#endif
diff --git a/src/lib/util/io/Makefile.am b/src/lib/util/io/Makefile.am
new file mode 100644
index 0000000..9f06ef9
--- /dev/null
+++ b/src/lib/util/io/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = . tests
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+lib_LTLIBRARIES = libutil_io.la
+libutil_io_la_SOURCES = fd.h fd.cc fd_share.h fd_share.cc
+libutil_io_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing
+
+CLEANFILES = *.gcno *.gcda
+
+pyexec_LTLIBRARIES = libutil_io_python.la
+# Python prefers .so, while some OSes (specifically MacOS) use a different
+# suffix for dynamic objects.  -module is necessary to work this around.
+libutil_io_python_la_LDFLAGS = -module
+libutil_io_python_la_SOURCES = fdshare_python.cc
+libutil_io_python_la_LIBADD = libutil_io.la
+libutil_io_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
+libutil_io_python_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/util/io/fd.cc b/src/lib/util/io/fd.cc
new file mode 100644
index 0000000..04e64dc
--- /dev/null
+++ b/src/lib/util/io/fd.cc
@@ -0,0 +1,70 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "fd.h"
+
+#include <unistd.h>
+#include <cerrno>
+
+namespace isc {
+namespace util {
+namespace io {
+
+bool
+write_data(const int fd, const void *buffer_v, const size_t length) {
+    const unsigned char *buffer(static_cast<const unsigned char *>(buffer_v));
+    size_t rest(length);
+    // Just keep writing until all is written
+    while (rest) {
+        ssize_t written(write(fd, buffer, rest));
+        if (rest == -1) {
+            if (errno == EINTR) { // Just keep going
+                continue;
+            } else {
+                return false;
+            }
+        } else { // Wrote something
+            rest -= written;
+            buffer += written;
+        }
+    }
+    return true;
+}
+
+ssize_t
+read_data(const int fd, void *buffer_v, const size_t length) {
+    unsigned char *buffer(static_cast<unsigned char *>(buffer_v));
+    size_t rest(length), already(0);
+    while (rest) { // Stil something to read
+        ssize_t amount(read(fd, buffer, rest));
+        if (rest == -1) {
+            if (errno == EINTR) { // Continue on interrupted call
+                continue;
+            } else {
+                return -1;
+            }
+        } else if (amount) {
+            already += amount;
+            rest -= amount;
+            buffer += amount;
+        } else { // EOF
+            return already;
+        }
+    }
+    return already;
+}
+
+}
+}
+}
diff --git a/src/lib/util/io/fd.h b/src/lib/util/io/fd.h
new file mode 100644
index 0000000..bdd2d41
--- /dev/null
+++ b/src/lib/util/io/fd.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_IO_FD_H
+#define __UTIL_IO_FD_H 1
+
+#include <unistd.h>
+
+/**
+ * @file fd.h
+ * @short Wrappers around common unix fd manipulation functions.
+ */
+
+namespace isc {
+namespace util {
+namespace io {
+
+/*
+ * \short write() that writes everything.
+ * Wrapper around write(). The difference is, it never writes less data
+ * and looks successfull (eg. it blocks until all data are written).
+ * Retries on signals.
+ *
+ * \return True if sucessfull, false otherwise. The errno variable is left
+ *     intact.
+ * \param fd Where to write.
+ * \param data The buffer to write.
+ * \param length How much data is there to write.
+ */
+bool
+write_data(const int fd, const void *data, const size_t length);
+
+/*
+ * \short read() that reads everything.
+ * Wrapper around read(). It does not do short reads, if it returns less,
+ * it means there was EOF. It retries on signals.
+ *
+ * \return Number of bytes read or -1 on error.
+ * \param fd Where to read data from.
+ * \param data Where to put the data.
+ * \param length How many of them.
+ */
+ssize_t
+read_data(const int fd, void *buffer, const size_t length);
+
+}
+}
+}
+
+#endif // __UTIL_IO_FD_H
diff --git a/src/lib/util/io/fd_share.cc b/src/lib/util/io/fd_share.cc
new file mode 100644
index 0000000..92576e0
--- /dev/null
+++ b/src/lib/util/io/fd_share.cc
@@ -0,0 +1,139 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstring>
+#include <cstdlib>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <stdlib.h>             // for malloc and free
+#include "fd_share.h"
+
+namespace isc {
+namespace util {
+namespace io {
+
+namespace {
+// Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
+// In order to ensure as much portability as possible, we provide wrapper
+// functions of these macros.
+// Note that cmsg_space() could run slow on OSes that do not have
+// CMSG_SPACE.
+inline socklen_t
+cmsg_len(const socklen_t len) {
+#ifdef CMSG_LEN
+    return (CMSG_LEN(len));
+#else
+    // Cast NULL so that any pointer arithmetic performed by CMSG_DATA
+    // is correct.
+    const uintptr_t hdrlen = (uintptr_t)CMSG_DATA(((struct cmsghdr*)NULL));
+    return (hdrlen + len);
+#endif
+}
+
+inline socklen_t
+cmsg_space(const socklen_t len) {
+#ifdef CMSG_SPACE
+    return (CMSG_SPACE(len));
+#else
+    struct msghdr msg;
+    struct cmsghdr* cmsgp;
+    // XXX: The buffer length is an ad hoc value, but should be enough
+    // in a practical sense.
+    char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_control = dummybuf;
+    msg.msg_controllen = sizeof(dummybuf);
+
+    cmsgp = (struct cmsghdr*)dummybuf;
+    cmsgp->cmsg_len = cmsg_len(len);
+
+    cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+    if (cmsgp != NULL) {
+        return ((char*)cmsgp - (char*)msg.msg_control);
+    } else {
+        return (0);
+    }
+#endif  // CMSG_SPACE
+}
+}
+
+int
+recv_fd(const int sock) {
+    struct msghdr msghdr;
+    struct iovec iov_dummy;
+    unsigned char dummy_data;
+
+    iov_dummy.iov_base = &dummy_data;
+    iov_dummy.iov_len = sizeof(dummy_data);
+    msghdr.msg_name = NULL;
+    msghdr.msg_namelen = 0;
+    msghdr.msg_iov = &iov_dummy;
+    msghdr.msg_iovlen = 1;
+    msghdr.msg_flags = 0;
+    msghdr.msg_controllen = cmsg_space(sizeof(int));
+    msghdr.msg_control = malloc(msghdr.msg_controllen);
+    if (msghdr.msg_control == NULL) {
+        return (FD_OTHER_ERROR);
+    }
+
+    if (recvmsg(sock, &msghdr, 0) < 0) {
+        free(msghdr.msg_control);
+        return (FD_COMM_ERROR);
+    }
+    const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
+    int fd = FD_OTHER_ERROR;
+    if (cmsg != NULL && cmsg->cmsg_len == cmsg_len(sizeof(int)) &&
+        cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+        fd = *(const int*)CMSG_DATA(cmsg);
+    }
+    free(msghdr.msg_control);
+    return (fd);
+}
+
+int
+send_fd(const int sock, const int fd) {
+    struct msghdr msghdr;
+    struct iovec iov_dummy;
+    unsigned char dummy_data = 0;
+
+    iov_dummy.iov_base = &dummy_data;
+    iov_dummy.iov_len = sizeof(dummy_data);
+    msghdr.msg_name = NULL;
+    msghdr.msg_namelen = 0;
+    msghdr.msg_iov = &iov_dummy;
+    msghdr.msg_iovlen = 1;
+    msghdr.msg_flags = 0;
+    msghdr.msg_controllen = cmsg_space(sizeof(int));
+    msghdr.msg_control = malloc(msghdr.msg_controllen);
+    if (msghdr.msg_control == NULL) {
+        return (FD_OTHER_ERROR);
+    }
+
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
+    cmsg->cmsg_len = cmsg_len(sizeof(int));
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    *(int*)CMSG_DATA(cmsg) = fd;
+
+    const int ret = sendmsg(sock, &msghdr, 0);
+    free(msghdr.msg_control);
+    return (ret >= 0 ? 0 : FD_COMM_ERROR);
+}
+
+} // End for namespace io
+} // End for namespace util
+} // End for namespace isc
diff --git a/src/lib/util/io/fd_share.h b/src/lib/util/io/fd_share.h
new file mode 100644
index 0000000..b74d4ef
--- /dev/null
+++ b/src/lib/util/io/fd_share.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef FD_SHARE_H_
+#define FD_SHARE_H_
+
+/**
+ * \file fd_share.h
+ * \short Support to transfer file descriptors between processes.
+ * \todo This interface is very C-ish. Should we have some kind of exceptions?
+ */
+
+namespace isc {
+namespace util {
+namespace io {
+
+const int FD_COMM_ERROR = -2;
+const int FD_OTHER_ERROR = -1;
+
+/**
+ * \short Receives a file descriptor.
+ * This receives a file descriptor sent over an unix domain socket. This
+ * is the counterpart of send_fd().
+ *
+ * \return FD_COMM_ERROR when there's error receiving the socket, FD_OTHER_ERROR
+ *     when there's a different error.
+ * \param sock The unix domain socket to read from. Tested and it does
+ *     not work with a pipe.
+ */
+int recv_fd(const int sock);
+
+/**
+ * \short Sends a file descriptor.
+ * This sends a file descriptor over an unix domain socket. This is the
+ * counterpart of recv_fd().
+ *
+ * \return FD_COMM_ERROR when there's error sending the socket, FD_OTHER_ERROR
+ *     for all other possible errors.
+ * \param sock The unix domain socket to send to. Tested and it does not
+ *     work with a pipe.
+ * \param fd The file descriptor to send. It should work with any valid
+ *     file descriptor.
+ */
+int send_fd(const int sock, const int fd);
+
+} // End for namespace io
+} // End for namespace util
+} // End for namespace isc
+
+#endif
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/io/fdshare_python.cc b/src/lib/util/io/fdshare_python.cc
new file mode 100644
index 0000000..0a41107
--- /dev/null
+++ b/src/lib/util/io/fdshare_python.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include <config.h>
+
+#include "fd_share.h"
+
+
+static PyObject*
+fdshare_recv_fd(PyObject*, PyObject* args) {
+    int sock, fd;
+    if (!PyArg_ParseTuple(args, "i", &sock)) {
+        return (NULL);
+    }
+    fd = isc::util::io::recv_fd(sock);
+    return (Py_BuildValue("i", fd));
+}
+
+static PyObject*
+fdshare_send_fd(PyObject*, PyObject* args) {
+    int sock, fd, result;
+    if (!PyArg_ParseTuple(args, "ii", &sock, &fd)) {
+        return (NULL);
+    }
+    result = isc::util::io::send_fd(sock, fd);
+    return (Py_BuildValue("i", result));
+}
+
+static PyMethodDef fdshare_Methods[] = {
+    {"send_fd",  fdshare_send_fd, METH_VARARGS, ""},
+    {"recv_fd",  fdshare_recv_fd, METH_VARARGS, ""},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+static PyModuleDef bind10_fdshare_python = {
+    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
+    "bind10_fdshare",
+    "Python bindings for fdshare",
+    -1,
+    fdshare_Methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+PyMODINIT_FUNC
+PyInit_libutil_io_python(void) {
+    PyObject *mod = PyModule_Create(&bind10_fdshare_python);
+    if (mod == NULL) {
+        return (NULL);
+    }
+
+    PyObject* FD_COMM_ERROR = Py_BuildValue("i", isc::util::io::FD_COMM_ERROR);
+    if (FD_COMM_ERROR == NULL) {
+        Py_XDECREF(mod);
+        return (NULL);
+    }
+    int ret = PyModule_AddObject(mod, "FD_COMM_ERROR", FD_COMM_ERROR);
+    if (-1 == ret) {
+        Py_XDECREF(FD_COMM_ERROR);
+        Py_XDECREF(mod);
+        return (NULL);
+    }
+
+    PyObject* FD_OTHER_ERROR = Py_BuildValue("i",
+                                             isc::util::io::FD_OTHER_ERROR);
+    if (FD_OTHER_ERROR == NULL) {
+        Py_XDECREF(mod);
+        return (NULL);
+    }
+    ret = PyModule_AddObject(mod, "FD_OTHER_ERROR", FD_OTHER_ERROR);
+    if (-1 == ret) {
+        Py_XDECREF(FD_OTHER_ERROR);
+        Py_XDECREF(mod);
+        return (NULL);
+    }
+
+    return (mod);
+}
+
diff --git a/src/lib/util/io/tests/Makefile.am b/src/lib/util/io/tests/Makefile.am
new file mode 100644
index 0000000..56d50cf
--- /dev/null
+++ b/src/lib/util/io/tests/Makefile.am
@@ -0,0 +1,25 @@
+CLEANFILES = *.gcno *.gcda
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += fd_tests.cc
+run_unittests_SOURCES += fd_share_tests.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
+run_unittests_LDADD += \
+	$(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/util/io/tests/fd_share_tests.cc b/src/lib/util/io/tests/fd_share_tests.cc
new file mode 100644
index 0000000..0902ce0
--- /dev/null
+++ b/src/lib/util/io/tests/fd_share_tests.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "../fd.h"
+#include "../fd_share.h"
+
+#include <util/unittests/fork.h>
+
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <cstdio>
+
+using namespace isc::util::io;
+using namespace isc::util::unittests;
+
+namespace {
+
+// We test that we can transfer a pipe over other pipe
+TEST(FDShare, transfer) {
+    // Get a pipe and fork
+    int pipes[2];
+    ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 0, pipes));
+    pid_t sender(fork());
+    ASSERT_NE(-1, sender);
+    if(sender) { // We are in parent
+        // Close the other side of pipe, we want only writible one
+        EXPECT_NE(-1, close(pipes[0]));
+        // Get a process to check data
+        int fd(0);
+        pid_t checker(check_output(&fd, "data", 4));
+        ASSERT_NE(-1, checker);
+        // Now, send the file descriptor, close it and close the pipe
+        EXPECT_NE(-1, send_fd(pipes[1], fd));
+        EXPECT_NE(-1, close(pipes[1]));
+        EXPECT_NE(-1, close(fd));
+        // Check both subprocesses ended well
+        EXPECT_TRUE(process_ok(sender));
+        EXPECT_TRUE(process_ok(checker));
+    } else { // We are in child. We do not use ASSERT here
+        // Close the write end, we only read
+        if(close(pipes[1])) {
+            exit(1);
+        }
+        // Get the file descriptor
+        int fd(recv_fd(pipes[0]));
+        if(fd == -1) {
+            exit(1);
+        }
+        // This pipe is not needed
+        if(close(pipes[0])) {
+            exit(1);
+        }
+        // Send "data" trough the received fd, close it and be done
+        if(!write_data(fd, "data", 4) || close(fd) == -1) {
+            exit(1);
+        }
+        exit(0);
+    }
+}
+
+}
diff --git a/src/lib/util/io/tests/fd_tests.cc b/src/lib/util/io/tests/fd_tests.cc
new file mode 100644
index 0000000..12b70d8
--- /dev/null
+++ b/src/lib/util/io/tests/fd_tests.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "../fd.h"
+
+#include <util/unittests/fork.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util::io;
+using namespace isc::util::unittests;
+
+namespace {
+
+// Make sure the test is large enough and does not fit into one
+// read or write request
+const size_t TEST_DATA_SIZE = 8 * 1024 * 1024;
+
+class FDTest : public ::testing::Test {
+    public:
+        unsigned char *data, *buffer;
+        FDTest() :
+            // We do not care what is inside, we just need it to be the same
+            data(new unsigned char[TEST_DATA_SIZE]),
+            buffer(NULL)
+        { }
+        ~ FDTest() {
+            delete[] data;
+            delete[] buffer;
+        }
+};
+
+// Test we read what was sent
+TEST_F(FDTest, read) {
+    int read_pipe(0);
+    buffer = new unsigned char[TEST_DATA_SIZE];
+    pid_t feeder(provide_input(&read_pipe, data, TEST_DATA_SIZE));
+    ASSERT_GE(feeder, 0);
+    ssize_t received(read_data(read_pipe, buffer, TEST_DATA_SIZE));
+    EXPECT_TRUE(process_ok(feeder));
+    EXPECT_EQ(TEST_DATA_SIZE, received);
+    EXPECT_EQ(0, memcmp(data, buffer, received));
+}
+
+// Test we write the correct thing
+TEST_F(FDTest, write) {
+    int write_pipe(0);
+    pid_t checker(check_output(&write_pipe, data, TEST_DATA_SIZE));
+    ASSERT_GE(checker, 0);
+    EXPECT_TRUE(write_data(write_pipe, data, TEST_DATA_SIZE));
+    EXPECT_EQ(0, close(write_pipe));
+    EXPECT_TRUE(process_ok(checker));
+}
+
+}
diff --git a/src/lib/util/io/tests/run_unittests.cc b/src/lib/util/io/tests/run_unittests.cc
new file mode 100644
index 0000000..e787ab1
--- /dev/null
+++ b/src/lib/util/io/tests/run_unittests.cc
@@ -0,0 +1,22 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char *argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/src/lib/util/io_utilities.h b/src/lib/util/io_utilities.h
new file mode 100644
index 0000000..ecab3ce
--- /dev/null
+++ b/src/lib/util/io_utilities.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __IO_UTILITIES_H
+#define __IO_UTILITIES_H
+
+#include <cstddef>
+
+namespace isc {
+namespace util {
+
+/// \brief Read Unsigned 16-Bit Integer from Buffer
+///
+/// This is essentially a copy of the isc::util::InputBuffer::readUint16.  It
+/// should really be moved into a separate library.
+///
+/// \param buffer Data buffer at least two bytes long of which the first two
+///        bytes are assumed to represent a 16-bit integer in network-byte
+///        order.
+///
+/// \return Value of 16-bit integer
+inline uint16_t
+readUint16(const void* buffer) {
+    const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
+
+    uint16_t result = (static_cast<uint16_t>(byte_buffer[0])) << 8;
+    result |= static_cast<uint16_t>(byte_buffer[1]);
+
+    return (result);
+}
+
+/// \brief Write Unisgned 16-Bit Integer to Buffer
+///
+/// This is essentially a copy of isc::util::OutputBuffer::writeUint16.  It
+/// should really be moved into a separate library.
+///
+/// \param value 16-bit value to convert
+/// \param buffer Data buffer at least two bytes long into which the 16-bit
+///        value is written in network-byte order.
+
+inline void
+writeUint16(uint16_t value, void* buffer) {
+    uint8_t* byte_buffer = static_cast<uint8_t*>(buffer);
+
+    byte_buffer[0] = static_cast<uint8_t>((value & 0xff00U) >> 8);
+    byte_buffer[1] = static_cast<uint8_t>(value & 0x00ffU);
+}
+
+} // namespace util
+} // namespace isc
+
+#endif // __ASIOLINK_UTILITIES_H
diff --git a/src/lib/util/locks.h b/src/lib/util/locks.h
new file mode 100644
index 0000000..971c413
--- /dev/null
+++ b/src/lib/util/locks.h
@@ -0,0 +1,115 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// This file (right now) provides dummy locks
+/// It also contains code to use boost/threads locks:
+///
+/// if USE_BOOST_THREADS is defined, we typedef the relevant classes
+/// and derive from the relevant templates so our dummy locks are
+/// replaced by the boost locks (--enable-boost-threads)
+///
+/// If USE_BOOST_THREADS is NOT defined, all locks are dummy classes
+/// that don't actually do anything. At this moment, only the very
+/// minimal set of methods that we actually use is defined.
+///
+/// Note that we need to include <config.h> in our .cc files for that
+/// to be set. we might want to enfore this at compile time with a check
+/// (TODO)
+
+#ifndef __LOCKS_
+#define __LOCKS_
+
+#ifndef USE_BOOST_THREADS
+
+namespace isc {
+namespace util {
+namespace locks {
+
+class mutex {
+};
+
+class recursive_mutex {
+};
+
+class upgradable_mutex {
+};
+
+template <typename T>
+class sharable_lock {
+public:
+    sharable_lock(T) { }
+};
+
+template <typename T>
+class scoped_lock {
+public:
+    scoped_lock(T) { }
+
+    void lock() {}
+    void unlock() {}
+};
+
+} // namespace locks
+} // namespace util
+} // namespace isc
+
+#else // USE_BOOST_THREADS
+
+// Workaround for a problem with boost and sunstudio 5.10
+// There is a version check in there that appears wrong,
+// which makes including boost/thread.hpp fail
+// This will probably be fixed in a future version of boost,
+// in which case this part can be removed then
+#ifdef NEED_SUNPRO_WORKAROUND
+#if defined(__SUNPRO_CC) && __SUNPRO_CC == 0x5100
+#undef __SUNPRO_CC
+#define __SUNPRO_CC 0x5090
+#endif
+#endif // NEED_SUNPRO_WORKAROUND
+
+#include <boost/thread.hpp>
+#include <boost/interprocess/sync/sharable_lock.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
+#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+
+namespace isc {
+namespace util {
+namespace locks {
+
+typedef boost::mutex mutex;
+typedef boost::interprocess::interprocess_upgradable_mutex upgradable_mutex;
+typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex;
+
+template <typename T>
+struct sharable_lock : public boost::interprocess::sharable_lock<T> {
+public:
+    sharable_lock(T&  mtype) : boost::interprocess::sharable_lock<T>(mtype) {}
+};
+
+
+template <class T>
+struct scoped_lock : public boost::interprocess::scoped_lock<T> {
+public:
+    scoped_lock(T& mtype) : boost::interprocess::scoped_lock<T>(mtype) { }
+};
+
+} // namespace locks
+} // namespace util
+} // namespace isc
+
+
+#endif // USE_BOOST_THREADS
+
+#endif // __LOCKS_
diff --git a/src/lib/util/lru_list.h b/src/lib/util/lru_list.h
new file mode 100644
index 0000000..797c3c9
--- /dev/null
+++ b/src/lib/util/lru_list.h
@@ -0,0 +1,260 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LRU_LIST_H
+#define __LRU_LIST_H
+
+#include <list>
+#include <string>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <util/locks.h>
+
+namespace isc {
+namespace util {
+
+/// \brief LRU List
+///
+/// Provides the LRU list for the zone and nameserver objects.  The list is
+/// created with a specific size.  Entries are added to the back of the list
+/// and removed from the front.  It is also possible to pull an element out
+/// of the middle of the list and add it to the end of the list, an action that
+/// should be done when the element is referenced.
+///
+/// It is not intended that the class be copied, and the derivation from
+/// boost::noncopyable enforces this.
+template <typename T>
+class LruList : boost::noncopyable {
+public:
+    typedef typename std::list<boost::shared_ptr<T> > lru_list;
+    typedef typename lru_list::iterator               iterator;
+
+    /// \brief Dropped Operation
+    ///
+    /// When an object is dropped from the LRU list because it has not been
+    /// accessed for some time, it is possible that the action should trigger
+    /// some other functions.  For this reason, it is possible to register
+    /// a list-wide functor object to execute in this casee.
+    ///
+    /// Note that the function does not execute as the result of a call to
+    /// remove() - that is an explicit call and it is assumed that the caller
+    /// will handle any additional operations needed.
+    class Dropped {
+    public:
+        /// \brief Constructor
+        Dropped(){}
+
+        /// \brief Virtual Destructor
+        virtual ~Dropped(){}
+
+        /// \brief Dropped Object Handler
+        ///
+        /// Function object called when the object drops off the end of the
+        /// LRU list.
+        ///
+        /// \param drop Object being dropped.
+        virtual void operator()(T* drop) const = 0;
+    };
+
+    /// \brief Constructor
+    ///
+    /// \param max_size Maximum size of the list before elements are dropped.
+    /// \param dropped Pointer to a function object that will get called as
+    /// elements are dropped.  This object will be stored using a shared_ptr,
+    /// so should be allocated with new().
+    LruList(uint32_t max_size = 1000, Dropped* dropped = NULL) :
+        max_size_(max_size), count_(0), dropped_(dropped)
+    {}
+
+    /// \brief Virtual Destructor
+    virtual ~LruList()
+    {}
+
+    /// \brief Add Element
+    ///
+    /// Add a new element to the end of the list.
+    ///
+    /// \param element Reference to the element to add.
+    ///
+    /// \return Handle describing the element in the LRU list.
+    virtual void add(boost::shared_ptr<T>& element);
+
+    /// \brief Remove Element
+    ///
+    /// Removes an element from the list.  If the element is not present (i.e.
+    /// its internal list pointer is invalid), this is a no-op.
+    ///
+    /// \param element Reference to the element to remove.
+    virtual void remove(boost::shared_ptr<T>& element);
+
+    /// \brief Touch Element
+    ///
+    /// The name comes from the Unix "touch" command.  All this does is to
+    /// move the specified entry from the middle of the list to the end of
+    /// the list.
+    ///
+    /// \param element Reference to the element to touch.
+    virtual void touch(boost::shared_ptr<T>& element);
+
+    /// \brief Drop All the Elements in the List .
+    ///
+    /// All the elements will be dropped from the list container, and their
+    /// drop handler(if there is one) will be called, when done, the size of
+    /// of list will be 0.
+    virtual void clear();
+
+    /// \brief Return Size of the List
+    ///
+    /// An independent count is kept of the list size, as list.size() may take
+    /// some time if the list is big.
+    ///
+    /// \return Number of elements in the list
+    virtual uint32_t size() const {
+
+        // Don't bother to lock the mutex.  If an update is in progress, we
+        // receive either the value just before the update or just after it.
+        // Either way, this call could have come just before or just after
+        // that operation, so the value would have been just as uncertain.
+        return count_;
+    }
+
+    /// \brief Return Maximum Size
+    ///
+    /// \return Maximum size of the list
+    virtual uint32_t getMaxSize() const {
+        return max_size_;
+    }
+
+    /// \brief Set Maximum Size
+    ///
+    /// \param max_size New maximum list size
+    virtual void setMaxSize(uint32_t max_size) {
+        max_size_ = max_size;
+    }
+
+private:
+    locks::mutex                   mutex_;     ///< List protection
+    std::list<boost::shared_ptr<T> >    lru_;       ///< The LRU list itself
+    uint32_t                            max_size_;  ///< Max size of the list
+    uint32_t                            count_;     ///< Count of elements
+    boost::shared_ptr<Dropped>          dropped_;   ///< Dropped object
+};
+
+// Add entry to the list
+template <typename T>
+void LruList<T>::add(boost::shared_ptr<T>& element) {
+
+    // Protect list against concurrent access
+    locks::scoped_lock<locks::mutex> lock(mutex_);
+
+    // Add the entry and set its pointer field to point into the list.
+    // insert() is used to get the pointer.
+    element->setLruIterator(lru_.insert(lru_.end(), element));
+
+    // ... and update the count while we have the mutex.
+    ++count_;
+
+    // If the count takes us above the maximum size of the list, remove elements
+    // from the front.  The current list size could be more than one above the
+    // maximum size of the list if the maximum size was changed after
+    // construction.
+    while (count_ > max_size_) {
+        if (!lru_.empty()) {
+
+            // Run the drop handler (if there is one) on the
+
+            // to-be-dropped object.
+            if (dropped_) {
+                (*dropped_)(lru_.begin()->get());
+            }
+
+            // ... and get rid of it from the list
+            lru_.pop_front();
+            --count_;
+        }
+        else {
+
+            // TODO: Log this condition (count_ > 0 when list empty) -
+            // it should not happen
+            count_ = 0;
+            break;
+        }
+    }
+}
+
+// Remove an element from the list
+template <typename T>
+void LruList<T>::remove(boost::shared_ptr<T>& element) {
+
+    // An element can only be removed it its internal pointer is valid.
+    // If it is, the pointer can be used to access the list because no matter
+    // what other elements are added or removed, the pointer remains valid.
+    //
+    // If the pointer is not valid, this is a no-op.
+    if (element->iteratorValid()) {
+
+        // Is valid, so protect list against concurrent access
+        locks::scoped_lock<locks::mutex> lock(mutex_);
+
+        lru_.erase(element->getLruIterator());  // Remove element from list
+        element->invalidateIterator();          // Invalidate pointer
+        --count_;                               // One less element
+    }
+}
+
+// Touch an element - remove it from the list and add to the end
+template <typename T>
+void LruList<T>::touch(boost::shared_ptr<T>& element) {
+
+    // As before, if the pointer is not valid, this is a no-op.
+    if (element->iteratorValid()) {
+
+        // Protect list against concurrent access
+        locks::scoped_lock<locks::mutex> lock(mutex_);
+
+        // Move the element to the end of the list.
+        lru_.splice(lru_.end(), lru_, element->getLruIterator());
+
+        // Update the iterator in the element to point to it.  We can
+        // offset from end() as a list has a bidirectional iterator.
+        iterator i = lru_.end();
+        element->setLruIterator(--i);
+    }
+}
+
+// Clear the list-  when done, the size of list will be 0.
+template <typename T>
+void LruList<T>::clear() {
+    // Protect list against concurrent access
+    locks::scoped_lock<locks::mutex> lock(mutex_);
+
+    // ... and update the count while we have the mutex.
+    count_ = 0;
+    typename std::list<boost::shared_ptr<T> >::iterator iter;
+    if (dropped_) {
+        for (iter = lru_.begin(); iter != lru_.end(); ++iter) {
+            // Call the drop handler.
+            (*dropped_)(iter->get());
+        }
+    }
+
+    lru_.clear();
+}
+
+}   // namespace util
+}   // namespace isc
+
+#endif // __LRU_LIST_H
diff --git a/src/lib/util/python/mkpywrapper.py.in b/src/lib/util/python/mkpywrapper.py.in
new file mode 100755
index 0000000..4bf7752
--- /dev/null
+++ b/src/lib/util/python/mkpywrapper.py.in
@@ -0,0 +1,100 @@
+#!@PYTHON@
+
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""This utility program generates a C++ header and implementation files
+that can be used as a template of C++ python binding for a C++ class.
+
+Usage: ./mkpywrapper.py ClassName
+(the script should be run on this directory)
+
+It will generate two files: classname_python.h and classname_python.cc,
+many of whose definitions are in the namespace isc::MODULE_NAME::python.
+By default MODULE_NAME will be 'dns' (because this tool is originally
+intended to be used for the C++ python binding of the DNS library), but
+can be changed via the -m command line option.
+
+The generated files contain code fragments that are commonly used in
+C++ python binding implementations.  It will define a class named
+s_ClassName which is a derived class of PyModule and can meet the
+requirement of the CPPPyObjectContainer template class (see
+pycppwrapper_util.h).  It also defines (and declares in the header file)
+"classname_type", which is of PyTypeObject and is intended to be used
+to define details of the python bindings for the ClassName class.
+
+In many cases the header file can be used as a startpoint of the
+binding development without modification.  But you may want to make
+ClassName::cppobj a constant variable (and you should if you can).
+Many definitions of classname_python.cc should also be able to be used
+just as defined, but some will need to be changed or removed.  In
+particular, you should at least adjust ClassName_init().  You'll
+probably also need to add more definitions to that file to provide
+complete features of the C++ class.
+"""
+
+import datetime, string, sys
+from optparse import OptionParser
+
+# Remember the current year to produce the copyright boilerplate
+YEAR = datetime.date.today().timetuple()[0]
+
+def dump_file(out_file, temp_file, class_name, module):
+    for line in temp_file.readlines():
+        line = line.replace("@YEAR@", str(YEAR))
+        line = line.replace("@CPPCLASS at _H", class_name.upper() + "_H")
+        line = line.replace("@CPPCLASS@", class_name)
+        line = line.replace("@cppclass@", class_name.lower())
+        line = line.replace("@MODULE@", module)
+        out_file.write(line)
+
+def dump_wrappers(class_name, output, module):
+    try:
+        if output == "-":
+            header_file = sys.stdout
+        else:
+            header_file = open(output + "_python.h", "w")
+        header_template_file = open("wrapper_template.h", "r")
+        if output == "-":
+            impl_file = sys.stdout
+        else:
+            impl_file = open(output + "_python.cc", "w")
+        impl_template_file = open("wrapper_template.cc", "r")
+    except:
+        sys.stderr.write('Failed to open C++ file(s)\n')
+        sys.exit(1)
+    dump_file(header_file, header_template_file, class_name, module)
+    dump_file(impl_file, impl_template_file, class_name, module)
+
+usage = '''usage: %prog [options] class_name'''
+
+if __name__ == "__main__":
+    parser = OptionParser(usage=usage)
+    parser.add_option('-o', '--output', action='store', dest='output',
+                      default=None, metavar='FILE',
+                      help='prefix of output file names [default: derived from the class name]')
+    parser.add_option('-m', '--module', action='store', dest='module',
+                      default='dns',
+                      help='C++ module name of the wrapper (for namespaces) [default: dns]')
+    (options, args) = parser.parse_args()
+
+    if len(args) == 0:
+        parser.error('input file is missing')
+
+    class_name = args[0]
+    if not options.output:
+        options.output = class_name.lower()
+
+    dump_wrappers(class_name, options.output, options.module)
diff --git a/src/lib/util/python/pycppwrapper_util.h b/src/lib/util/python/pycppwrapper_util.h
new file mode 100644
index 0000000..fd55c19
--- /dev/null
+++ b/src/lib/util/python/pycppwrapper_util.h
@@ -0,0 +1,308 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYCPPWRAPPER_UTIL_H
+#define __PYCPPWRAPPER_UTIL_H 1
+
+#include <Python.h>
+
+#include <exceptions/exceptions.h>
+
+/**
+ * @file pycppwrapper_util.h
+ * @short Shared definitions for python/C(++) API
+ *
+ * This utility defines a set of convenient wrappers for the python C API
+ * to use it safely from our C++ bindings.  The python C API has many pitfalls
+ * such as not-so-consistent reference count policies.  Also, many existing
+ * examples are careless about error handling.  It's easy to find on the net
+ * example (even of "production use") python extensions like this:
+ *
+ * \code
+ *     new_exception = PyErr_NewException("mymodule.Exception", NULL, NULL);
+ *     // new_exception can be NULL, in which case the call to
+ *     // PyModule_AddObject will cause a surprising disruption.
+ *     PyModule_AddObject(mymodule, "Exception", new_exception); \endcode
+ *
+ * When using the python C API with C++, we should also be careful about
+ * exception safety.  The underlying C++ code (including standard C++ libraries
+ * and memory allocation) can throw exceptions, in which case we need to
+ * make sure any intermediate python objects are cleaned up (we also need to
+ * catch the C++ exceptions inside the binding and convert them to python
+ * errors, but that's a different subject).  This is not a trivial task
+ * because the python objects are represented as bare C pointers (so there's
+ * no destructor) and we need to address the exception safety along with python
+ * reference counters (so we cannot naively apply standard smart pointers).
+ *
+ * This utility tries to help address these issues.
+ *
+ * Also, it's intentional that this is a header-only utility.  This way the
+ * C++ loadable module won't depend on another C++ library (which is not
+ * necessarily wrong, but would increase management cost such as link-time
+ * troubles only for a small utility feature).
+ */
+
+namespace isc {
+namespace util {
+namespace python {
+
+/// This is thrown inside this utility when it finds a NULL pointer is passed
+/// when it should not be NULL.
+class PyCPPWrapperException : public isc::Exception {
+public:
+    PyCPPWrapperException(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// This helper class is similar to the standard autoptr and manages PyObject
+/// using some kind of RAII techniques.  It is, however, customized for the
+/// python C API.
+///
+/// A PyObjectContainer object is constructed with a pointer to PyObject,
+/// which is often just created dynamically.  The caller will eventually
+/// attach the object to a different python object (often a module or class)
+/// via specific methods or directly return it to the python interpreter.
+///
+/// There are two cases in destructing the object: with or without decreasing
+/// a reference to the PyObject.  If the object is intended to be an argument
+/// to another python C library that increases the reference to the object for
+/// itself, we should normally release our own reference; otherwise the
+/// reference will leak and the object won't be garbage collected.  Also, when
+/// an unexpected error happens in the form of C++ exception, we should
+/// release the reference to prevent resource leak.
+///
+/// In some other cases, we should simply give our reference to the caller.
+/// That is the case when the created object itself is a return value of
+/// an extended python method written in the C++ binding.  Likewise, some
+/// python C library functions "steal" the reference.  In these cases we
+/// should not decrease the reference; otherwise it would cause duplicate free.
+///
+/// By default, the destructor of this class releases the reference to the
+/// PyObject.  If this behavior is desirable, you can extract the original
+/// bare pointer to the PyObject by the \c get() method.  If you don't want
+/// the reference to be decreased, the original bare pointer should be
+/// extracted using the \c release() method.
+///
+/// There are two convenience methods for commonly used operations:
+/// \c installAsClassVariable() to add the PyObject as a class variable
+/// and \c installToModule to add the PyObject to a specified python module.
+/// These methods (at least to some extent) take care of the reference to
+/// the object (either release or keep) depending on the usage context so
+/// that the user don't have to worry about it.
+///
+/// On construction, this class expects the pointer can be NULL.
+/// If it happens it immediately throws a \c PyCPPWrapperException exception.
+/// This behavior is to convert failures in the python C API (such as
+/// PyObject_New() returning NULL) to C++ exception so that we can unify
+/// error handling in the style of C++ exceptions.
+///
+/// Examples 1: To create a tuple of two python objects, do this:
+///
+/// \code
+///     try {
+///         PyObjectContainer container0(Py_BuildValue("I", 0));
+///         PyObjectContainer container1(Py_BuildValue("s", cppobj.toText().c_str()));
+///         return (Py_BuildValue("OO", container0.get(), container1.get()));
+///     } catch { ... set python exception, etc ... } \endcode
+///
+/// Commonly deployed buggy implementation to achieve this would be like this:
+/// \code
+///    return (Py_BuildValue("OO", Py_BuildValue("I", 0),
+///                          Py_BuildValue("s", cppobj.toText().c_str())));
+/// \endcode
+/// One clear bug of this code is that references to the element objects of
+/// the tuple will leak.
+/// (Assuming \c cppobj.toText() can throw) this code is also not exception
+/// safe; if \c cppobj.toText() throws the reference to the first object
+/// will leak, even if the code tried to do the necessary cleanup in the
+/// successful case.
+/// Further, this code naively passes the result of the first two calls to
+/// \c Py_BuildValue() to the third one even if they can be NULL.
+/// In this specific case, it happens to be okay because \c Py_BuildValue()
+/// accepts NULL and treats it as an indication of error.  But not all
+/// python C library works that way (remember, the API is so inconsistent)
+/// and we need to refer to the API manual every time we have to worry about
+/// passing a NULL object to a library function.  We'd certainly like to
+/// avoid such development overhead.  The code using \c PyObjectContainer
+/// addresses all these problems.
+///
+/// Examples 2: Install a (constant) variable to a class.
+///
+/// \code
+///    try {
+///        // installClassVariable is a wrapper of
+///        // PyObjectContainer::installAsClassVariable.  See below.
+///        installClassVariable(myclass_type, "SOME_CONSTANT",
+///                             Py_BuildValue("I", 0));
+///    } catch { ... }
+/// \endcode
+///
+/// Examples 3: Install a custom exception to a module.
+///
+/// \code
+///    PyObject* new_exception; // publicly visible
+///    ...
+///    try {
+///        new_exception = PyErr_NewException("mymodule.NewException",
+///                                           NULL, NULL);
+///        PyObjectContainer(new_exception).installToModule(mymodule,
+///                                                         "NewException");
+///    } catch { ... }
+/// \endcode
+///
+/// Note that \c installToModule() keeps the reference to \c new_exception
+/// by default.  This is a common practice when we introduce a custom
+/// exception in a python biding written in C/C++.  See the code comment
+/// of the method for more details.
+struct PyObjectContainer {
+    PyObjectContainer(PyObject* obj) : obj_(obj) {
+        if (obj_ == NULL) {
+            isc_throw(PyCPPWrapperException, "Unexpected NULL PyObject, "
+                      "probably due to short memory");
+        }
+    }
+    virtual ~PyObjectContainer() {
+        if (obj_ != NULL) {
+            Py_DECREF(obj_);
+        }
+    }
+    PyObject* get() {
+        return (obj_);
+    }
+    PyObject* release() {
+        PyObject* ret = obj_;
+        obj_ = NULL;
+        return (ret);
+    }
+
+    // Install the enclosed PyObject to the specified python class 'pyclass'
+    // as a variable named 'name'.
+    void installAsClassVariable(PyTypeObject& pyclass, const char* name) {
+        if (PyDict_SetItemString(pyclass.tp_dict, name, obj_) < 0) {
+            isc_throw(PyCPPWrapperException, "Failed to set a class variable, "
+                      "probably due to short memory");
+        }
+        // Ownership successfully transferred to the class object.  We'll let
+        // it be released in the destructor.
+    }
+
+    // Install the enclosed PyObject to the specified module 'mod' as an
+    // object named 'name'.
+    // By default, this method explicitly keeps the reference to the object
+    // even after the module "steals" it.  To cancel this behavior and give
+    // the reference to the module completely, the third parameter 'keep_ref'
+    // should be set to false.
+    void installToModule(PyObject* mod, const char* name,
+                         bool keep_ref = true)
+    {
+        if (PyModule_AddObject(mod, name, obj_) < 0) {
+            isc_throw(PyCPPWrapperException, "Failed to add an object to "
+                      "module, probably due to short memory");
+        }
+        // PyModule_AddObject has "stolen" the reference, so unless we
+        // have to retain it ourselves we don't (shouldn't) decrease it.
+        // However, we actually often need to keep our own reference because
+        // objects added to a module are often referenced via non local
+        // C/C++ variables in various places of the C/C++ code.  In order
+        // for the code to run safely even if some buggy/evil python program
+        // performs 'del mod.obj', we need the extra reference.  See, e.g.:
+        // http://docs.python.org/py3k/c-api/init.html#Py_Initialize
+        // http://mail.python.org/pipermail/python-dev/2005-June/054238.html
+        if (keep_ref) {
+            Py_INCREF(obj_);
+        }
+        obj_ = NULL;
+    }
+
+protected:
+    PyObject* obj_;
+};
+
+/// This templated class is a derived class of \c PyObjectContainer and
+/// manages C++-class based python objects.
+///
+/// The template parameter \c PYSTRUCT must be a derived class (structure) of
+/// \c PyObject that has a member variable named \c cppobj, which must be a
+/// a pointer to \c CPPCLASS (the second template parameter).
+///
+/// For example, to define a custom python class based on a C++ class, MyClass,
+/// we'd define a class (struct) named \c s_MyClass like this:
+/// \code
+///    class s_MyClass : public PyObject {
+///    public:
+///       s_MyClass() : cppobj(NULL) {}
+///       MyClass* cppobj;
+///    };
+/// \endcode
+///
+/// And, to build and return a python version of MyClass object, write the
+/// following C++ code:
+/// \code
+///    typedef CPPPyObjectContainer<s_MyClass, MyClass> MyContainer;
+///    try {
+///        // below, myclass_type is of \c PyTypeObject that defines
+///        // a python class (type) for MyClass
+///        MyContainer container(PyObject_New(s_MyClass, myclass_type));
+///        container.set(new MyClass());
+///        return (container.release()); // give the reference to the caller
+///    } catch { ... }
+/// \endcode
+///
+/// This code prevents bugs like NULL pointer dereference when \c PyObject_New
+/// fails or resource leaks when new'ing \c MyClass results in an exception.
+/// Note that we use \c release() (derived from the base class) instead of
+/// \c get(); in this case we should simply pass the reference generated in
+/// \c PyObject_New() to the caller.
+template <typename PYSTRUCT, typename CPPCLASS>
+struct CPPPyObjectContainer : public PyObjectContainer {
+    CPPPyObjectContainer(PYSTRUCT* obj) : PyObjectContainer(obj) {}
+
+    // This method associates a C++ object with the corresponding python
+    // object enclosed in this class.
+    void set(CPPCLASS* value) {
+        if (value == NULL) {
+            isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                      "probably due to short memory");
+        }
+        static_cast<PYSTRUCT*>(obj_)->cppobj = value;
+    }
+
+    // This is a convenience short cut to associate a C++ object with the
+    // python object and install it to the specified python class \c pyclass
+    // as a variable named \c name.
+    void installAsClassVariable(PyTypeObject& pyclass, const char* name,
+                                CPPCLASS* value)
+    {
+        set(value);
+        PyObjectContainer::installAsClassVariable(pyclass, name);
+    }
+};
+
+/// A shortcut function to install a python class variable.
+///
+/// It installs a python object \c obj to a specified class \c pyclass
+/// as a variable named \c name.
+inline void
+installClassVariable(PyTypeObject& pyclass, const char* name, PyObject* obj) {
+    PyObjectContainer(obj).installAsClassVariable(pyclass, name);
+}
+
+} // namespace python
+} // namespace util
+} // namespace isc
+#endif // __PYCPPWRAPPER_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/python/wrapper_template.cc b/src/lib/util/python/wrapper_template.cc
new file mode 100644
index 0000000..691e4bf
--- /dev/null
+++ b/src/lib/util/python/wrapper_template.cc
@@ -0,0 +1,309 @@
+// Copyright (C) @YEAR@  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Enable this if you use s# variants with PyArg_ParseTuple(), see
+// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
+//#define PY_SSIZE_T_CLEAN
+
+// Python.h needs to be placed at the head of the program file, see:
+// http://docs.python.org/py3k/extending/extending.html#a-simple-example
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include "@cppclass at _python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::@MODULE@;
+using namespace isc::@MODULE@::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// @CPPCLASS@
+//
+
+// Trivial constructor.
+s_ at CPPCLASS@::s_ at CPPCLASS@() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_ at CPPCLASS@, @CPPCLASS@> @CPPCLASS at Container;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int @CPPCLASS at _init(s_ at CPPCLASS@* self, PyObject* args);
+void @CPPCLASS at _destroy(s_ at CPPCLASS@* self);
+
+// These are the functions we export
+// ADD/REMOVE/MODIFY THE FOLLOWING AS APPROPRIATE FOR THE ACTUAL CLASS.
+//
+PyObject* @CPPCLASS at _toText(const s_ at CPPCLASS@* const self);
+PyObject* @CPPCLASS at _str(PyObject* self);
+PyObject* @CPPCLASS at _richcmp(const s_ at CPPCLASS@* const self,
+                            const s_ at CPPCLASS@* const other, int op);
+
+// This is quite specific pydnspp.  For other wrappers this should probably
+// be removed.
+PyObject* @CPPCLASS at _toWire(const s_ at CPPCLASS@* self, PyObject* args);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef @CPPCLASS at _methods[] = {
+    { "to_text", reinterpret_cast<PyCFunction>(@CPPCLASS at _toText), METH_NOARGS,
+      "Returns the text representation" },
+    // This is quite specific pydnspp.  For other wrappers this should probably
+    // be removed:
+    { "to_wire", reinterpret_cast<PyCFunction>(@CPPCLASS at _toWire), METH_VARARGS,
+      "Converts the @CPPCLASS@ object to wire format.\n"
+      "The argument can be either a MessageRenderer or an object that "
+      "implements the sequence interface. If the object is mutable "
+      "(for instance a bytearray()), the wire data is added in-place.\n"
+      "If it is not (for instance a bytes() object), a new object is "
+      "returned" },
+    { NULL, NULL, 0, NULL }
+};
+
+// This is a template of typical code logic of python class initialization
+// with C++ backend.  You'll need to adjust it according to details of the
+// actual C++ class.
+int
+ at CPPCLASS@_init(s_ at CPPCLASS@* self, PyObject* args) {
+    try {
+        if (PyArg_ParseTuple(args, "REPLACE ME")) {
+            // YOU'LL NEED SOME VALIDATION, PREPARATION, ETC, HERE.
+            self->cppobj = new @CPPCLASS@(/*NECESSARY PARAMS*/);
+            return (0);
+        }
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct @CPPCLASS@ object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in constructing @CPPCLASS@");
+        return (-1);
+    }
+
+    PyErr_SetString(PyExc_TypeError,
+                    "Invalid arguments to @CPPCLASS@ constructor");
+
+    return (-1);
+}
+
+// This is a template of typical code logic of python object destructor.
+// In many cases you can use it without modification, but check that carefully.
+void
+ at CPPCLASS@_destroy(s_ at CPPCLASS@* const self) {
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+// This should be able to be used without modification as long as the
+// underlying C++ class has toText().
+PyObject*
+ at CPPCLASS@_toText(const s_ at CPPCLASS@* const self) {
+    try {
+        // toText() could throw, so we need to catch any exceptions below.
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Failed to convert @CPPCLASS@ object to text: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "converting @CPPCLASS@ object to text");
+    }
+    return (NULL);
+}
+
+PyObject*
+ at CPPCLASS@_str(PyObject* self) {
+    // Simply call the to_text method we already defined
+    return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+                                const_cast<char*>("")));
+}
+
+PyObject* 
+ at CPPCLASS@_richcmp(const s_ at CPPCLASS@* const self,
+                   const s_ at CPPCLASS@* const other,
+                   const int op)
+{
+    bool c = false;
+
+    // Check for null and if the types match. If different type,
+    // simply return False
+    if (other == NULL || (self->ob_type != other->ob_type)) {
+        Py_RETURN_FALSE;
+    }
+
+    // Only equals and not equals here, unorderable type
+    switch (op) {
+    case Py_LT:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+        return (NULL);
+    case Py_LE:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+        return (NULL);
+    case Py_EQ:
+        c = (*self->cppobj == *other->cppobj);
+        break;
+    case Py_NE:
+        c = (*self->cppobj != *other->cppobj);
+        break;
+    case Py_GT:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+        return (NULL);
+    case Py_GE:
+        PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+        return (NULL);
+    }
+    if (c) {
+        Py_RETURN_TRUE;
+    } else {
+        Py_RETURN_FALSE;
+    }
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace @MODULE@ {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_ at CPPCLASS@
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject @cppclass at _type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "pydnspp. at CPPCLASS@",
+    sizeof(s_ at CPPCLASS@),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(@CPPCLASS at _destroy),       // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash 
+    NULL,                               // tp_call
+    // THIS MAY HAVE TO BE CHANGED TO NULL:
+    @CPPCLASS at _str,                       // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    "The @CPPCLASS@ class objects is...(COMPLETE THIS)",
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    // THIS MAY HAVE TO BE CHANGED TO NULL:
+    reinterpret_cast<richcmpfunc>(@CPPCLASS at _richcmp), // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    @CPPCLASS at _methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(@CPPCLASS at _init),            // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_ at CPPCLASS@(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&@cppclass at _type) < 0) {
+        return (false);
+    }
+    void* p = &@cppclass at _type;
+    if (PyModule_AddObject(mod, "@CPPCLASS@", static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&@cppclass at _type);
+
+    // The following template is the typical procedure for installing class
+    // variables.  If the class doesn't have a class variable, remove the
+    // entire try-catch clauses.
+    try {
+        // Constant class variables
+        installClassVariable(@cppclass at _type, "REPLACE_ME",
+                             Py_BuildValue("REPLACE ME"));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in @CPPCLASS@ initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in @CPPCLASS@ initialization");
+        return (false);
+    }
+
+    return (true);
+}
+
+PyObject*
+create at CPPCLASS@Object(const @CPPCLASS@& source) {
+    @CPPCLASS at Container container =
+        PyObject_New(s_ at CPPCLASS@, &@cppclass at _type);
+    container.set(new @CPPCLASS@(source));
+    return (container.release());
+}
+} // namespace python
+} // namespace @MODULE@
+} // namespace isc
diff --git a/src/lib/util/python/wrapper_template.h b/src/lib/util/python/wrapper_template.h
new file mode 100644
index 0000000..d68a658
--- /dev/null
+++ b/src/lib/util/python/wrapper_template.h
@@ -0,0 +1,59 @@
+// Copyright (C) @YEAR@  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_ at CPPCLASS@_H
+#define __PYTHON_ at CPPCLASS@_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace @MODULE@ {
+class @CPPCLASS@;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_ at CPPCLASS@ : public PyObject {
+public:
+    s_ at CPPCLASS@();
+    @CPPCLASS@* cppobj;
+};
+
+extern PyTypeObject @cppclass at _type;
+
+bool initModulePart_ at CPPCLASS@(PyObject* mod);
+
+// Note: this utility function works only when @CPPCLASS@ is a copy
+// constructable.
+// And, it would only be useful when python binding needs to create this
+// object frequently.  Otherwise, it would (or should) probably better to
+// remove the declaration and definition of this function.
+//
+/// This is A simple shortcut to create a python @CPPCLASS@ object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called with in a try block
+/// followed by necessary setup for python exception.
+PyObject* create at CPPCLASS@Object(const @CPPCLASS@& source);
+
+} // namespace python
+} // namespace @MODULE@
+} // namespace isc
+#endif // __PYTHON_ at CPPCLASS@_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/pyunittests/Makefile.am b/src/lib/util/pyunittests/Makefile.am
new file mode 100644
index 0000000..e8fefbd
--- /dev/null
+++ b/src/lib/util/pyunittests/Makefile.am
@@ -0,0 +1,14 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+pyexec_LTLIBRARIES = pyunittests_util.la
+pyunittests_util_la_SOURCES = pyunittests_util.cc
+pyunittests_util_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
+pyunittests_util_la_LDFLAGS = $(PYTHON_LDFLAGS)
+
+# Python prefers .so, while some OSes (specifically MacOS) use a different
+# suffix for dynamic objects.  -module is necessary to work this around.
+pyunittests_util_la_LDFLAGS += -module
+pyunittests_util_la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
+pyunittests_util_la_LIBADD += $(PYTHON_LIB)
diff --git a/src/lib/util/pyunittests/pyunittests_util.cc b/src/lib/util/pyunittests/pyunittests_util.cc
new file mode 100644
index 0000000..d266c84
--- /dev/null
+++ b/src/lib/util/pyunittests/pyunittests_util.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <Python.h>
+
+#include <stdint.h>
+
+// see util/time_utilities.h
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+int64_t fake_current_time;
+
+int64_t
+getFakeTime() {
+    return (fake_current_time);
+}
+
+PyObject*
+fixCurrentTime(PyObject*, PyObject* args) {
+    PyObject* maybe_none;
+    if (PyArg_ParseTuple(args, "L", &fake_current_time)) {
+        isc::util::detail::gettimeFunction = getFakeTime;
+    } else if (PyArg_ParseTuple(args, "O", &maybe_none) &&
+               maybe_none == Py_None) {
+        isc::util::detail::gettimeFunction = NULL;
+    } else {
+         PyErr_SetString(PyExc_TypeError, "Invalid arguments to "
+                         "pyunittests_util.fix_current_time");
+         return (NULL);
+    }
+
+    PyErr_Clear();
+    Py_RETURN_NONE;
+}
+
+PyMethodDef PyUnittestsUtilMethods[] = {
+    { "fix_current_time", fixCurrentTime, METH_VARARGS,
+      "Fix the current system time at the specified (fake) value.\n\n"
+      "This is useful for testing modules that depend on the current time.\n"
+      "Note that it only affects C++ modules that use gettimeWrapper() "
+      "defined in libutil, which allows a hook for testing.\n"
+      "If an integer (signed 64bit) is given, the current time will be fixed "
+      "to that value; if None is specified (which is the default) the use of "
+      "faked time will be canceled."
+    },
+    { NULL, NULL, 0, NULL}
+};
+
+PyModuleDef pyunittests_util = {
+    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
+    "pyunittests_util",
+    "This module is a collection of utilities useful for testing "
+    "the BIND 10 C++ binding modules.",
+    -1,
+    PyUnittestsUtilMethods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+} // end of unnamed namespace
+
+PyMODINIT_FUNC
+PyInit_pyunittests_util(void) {
+    return (PyModule_Create(&pyunittests_util));
+}
diff --git a/src/lib/util/random/qid_gen.cc b/src/lib/util/random/qid_gen.cc
new file mode 100644
index 0000000..43041ad
--- /dev/null
+++ b/src/lib/util/random/qid_gen.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#include <util/random/qid_gen.h>
+
+#include <sys/time.h>
+
+namespace isc {
+namespace util {
+namespace random {
+
+QidGenerator qid_generator_instance;
+
+QidGenerator&
+QidGenerator::getInstance() {
+    return (qid_generator_instance);
+}
+
+QidGenerator::QidGenerator() : dist_(0, 65535),
+                               vgen_(generator_, dist_)
+{
+    seed();
+}
+
+void
+QidGenerator::seed() {
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec);
+}
+
+uint16_t
+QidGenerator::generateQid() {
+    return (vgen_());
+}
+
+
+} // namespace random
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/random/qid_gen.h b/src/lib/util/random/qid_gen.h
new file mode 100644
index 0000000..1af43c1
--- /dev/null
+++ b/src/lib/util/random/qid_gen.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#ifndef __QID_GEN_H
+#define __QID_GEN_H
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/variate_generator.hpp>
+
+namespace isc {
+namespace util {
+namespace random {
+
+/// This class generates Qids for outgoing queries
+///
+/// It is implemented as a singleton; the public way to access it
+/// is to call getInstance()->generateQid().
+///
+/// It automatically seeds it with the current time when it is first
+/// used.
+class QidGenerator {
+public:
+    /// \brief Returns the singleton instance of the QidGenerator
+    ///
+    /// Returns a reference to the singleton instance of the generator
+    static QidGenerator& getInstance();
+
+    /// \brief Default constructor
+    ///
+    /// It is recommended that getInstance is used rather than creating
+    /// separate instances of this class.
+    ///
+    /// The constructor automatically seeds the generator with the
+    /// current time.
+    QidGenerator();
+
+    /// Generate a Qid
+    ///
+    /// \return A random Qid
+    uint16_t generateQid();
+
+    /// \brief Seeds the QidGenerator (based on the current time)
+    ///
+    /// This is automatically called by the constructor
+    void seed();
+
+private:
+    // "Mersenne Twister: A 623-dimensionally equidistributed
+    // uniform pseudo-random number generator", Makoto Matsumoto and
+    // Takuji Nishimura, ACM Transactions on Modeling and Computer
+    // Simulation: Special Issue on Uniform Random Number Generation,
+    // Vol. 8, No. 1, January 1998, pp. 3-30.
+    //
+    // mt19937 is an implementation of one of the pseudo random
+    // generators described in this paper.
+    boost::mt19937 generator_;
+
+    // For qid's we want a uniform distribution
+    boost::uniform_int<> dist_;
+
+    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
+};
+
+
+} // namespace random
+} // namespace util
+} // namespace isc
+
+#endif // __QID_GEN_H
diff --git a/src/lib/util/random/random_number_generator.h b/src/lib/util/random/random_number_generator.h
new file mode 100644
index 0000000..485ea7a
--- /dev/null
+++ b/src/lib/util/random/random_number_generator.h
@@ -0,0 +1,208 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __NSAS_RANDOM_NUMBER_GENERATOR_H
+#define __NSAS_RANDOM_NUMBER_GENERATOR_H
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include <exceptions/exceptions.h>
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+
+namespace isc {
+namespace util {
+namespace random {
+
+class InvalidLimits : public isc::BadValue {
+public:
+    InvalidLimits(const char* file, size_t line, const char* what) :
+        isc::BadValue(file, line, what) {}
+};
+
+class SumNotOne : public isc::BadValue {
+public:
+    SumNotOne(const char* file, size_t line, const char* what) :
+        isc::BadValue(file, line, what) {}
+};
+
+class InvalidProbValue : public isc::BadValue {
+public:
+    InvalidProbValue(const char* file, size_t line, const char* what) :
+        isc::BadValue(file, line, what) {}
+};
+
+
+
+/// \brief Uniform random integer generator
+///
+/// Generate uniformly distributed integers in range of [min, max]
+class UniformRandomIntegerGenerator{
+public:
+    /// \brief Constructor
+    ///
+    /// \param min The minimum number in the range
+    /// \param max The maximum number in the range
+    UniformRandomIntegerGenerator(int min, int max):
+        min_(std::min(min, max)), max_(std::max(min, max)),
+        dist_(min_, max_), generator_(rng_, dist_)
+    {
+        // To preserve the restriction of the underlying uniform_int class (and
+        // to retain compatibility with earlier versions of the class), we will
+        // abort if the minimum and maximum given are the wrong way round.
+        if (min > max) {
+            isc_throw(InvalidLimits, "minimum limit is greater than maximum "
+                      "when initializing UniformRandomIntegerGenerator");
+        }
+
+        // Init with the current time
+        rng_.seed(time(NULL));
+    }
+
+    /// \brief Generate uniformly distributed integer
+    int operator()() { return generator_(); }
+private:
+    /// Hide default and copy constructor
+    UniformRandomIntegerGenerator();///< Default constructor
+    UniformRandomIntegerGenerator(const UniformRandomIntegerGenerator&); ///< Copy constructor
+
+    int min_;                       ///< The minimum integer that can generate
+    int max_;                       ///< The maximum integer that can generate
+    boost::uniform_int<> dist_;     ///< Distribute uniformly.
+    boost::mt19937 rng_;            ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator
+    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_; ///< Uniform generator
+};
+
+/// \brief Weighted random integer generator
+///
+/// Generate random integers according different probabilities
+class WeightedRandomIntegerGenerator {
+public:
+    /// \brief Constructor
+    ///
+    /// \param probabilities The probabies for all the integers, the probability must be 
+    /// between 0 and 1.0, the sum of probabilities must be equal to 1.
+    /// For example, if the probabilities contains the following values:
+    /// 0.5 0.3 0.2, the 1st integer will be generated more frequently than the
+    /// other integers and the probability is proportional to its value.
+    /// \param min The minimum integer that generated, other integers will be 
+    /// min, min + 1, ..., min + probabilities.size() - 1
+    WeightedRandomIntegerGenerator(const std::vector<double>& probabilities,
+        size_t min = 0):
+        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min)
+    {
+        // The probabilities must be valid.  Checking is quite an expensive
+        // operation, so is only done in a debug build.
+        assert(areProbabilitiesValid(probabilities));
+
+        // Calculate the partial sum of probabilities
+        std::partial_sum(probabilities.begin(), probabilities.end(),
+                                     std::back_inserter(cumulative_));
+        // Init with the current time
+        rng_.seed(time(NULL));
+    }
+
+    /// \brief Default constructor
+    ///
+    WeightedRandomIntegerGenerator():
+        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0)
+    {
+    }
+
+    /// \brief Reset the probabilities
+    ///
+    /// Change the weights of each integers
+    /// \param probabilities The probabies for all the integers
+    /// \param min The minimum integer that generated
+    void reset(const std::vector<double>& probabilities, size_t min = 0)
+    {
+        // The probabilities must be valid.
+        assert(areProbabilitiesValid(probabilities));
+
+        // Reset the cumulative sum
+        cumulative_.clear();
+
+        // Calculate the partial sum of probabilities
+        std::partial_sum(probabilities.begin(), probabilities.end(),
+                                     std::back_inserter(cumulative_));
+
+        // Reset the minimum integer
+        min_ = min;
+    }
+
+    /// \brief Generate weighted random integer
+    size_t operator()()
+    {
+        return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_()) 
+            - cumulative_.begin() + min_;
+    }
+
+private:
+    /// \brief Check the validation of probabilities vector
+    ///
+    /// The probability must be in range of [0, 1.0] and the sum must be equal
+    /// to 1.0.  Empty probabilities are also valid.
+    ///
+    /// Checking the probabilities is quite an expensive operation, so it is
+    /// only done during a debug build (via a call through assert()).  However,
+    /// instead of letting assert() call abort(), if this method encounters an
+    /// error, an exception is thrown.  This makes unit testing somewhat easier.
+    ///
+    /// \param probabilities Vector of probabilities.
+    bool areProbabilitiesValid(const std::vector<double>& probabilities) const
+    {
+        typedef std::vector<double>::const_iterator Iterator;
+        double sum = probabilities.empty() ? 1.0 : 0.0;
+        for(Iterator it = probabilities.begin(); it != probabilities.end(); ++it){
+            //The probability must be in [0, 1.0]
+            if(*it < 0.0 || *it > 1.0) {
+                isc_throw(InvalidProbValue,
+                          "probability must be in the range 0..1");
+            }
+
+            sum += *it;
+        }
+
+        double epsilon = 0.0001;
+        // The sum must be equal to 1
+       if (std::fabs(sum - 1.0) >= epsilon) {
+           isc_throw(SumNotOne, "Sum of probabilities is not equal to 1");
+       }
+
+       return true;
+    }
+
+    std::vector<double> cumulative_;    ///< Partial sum of the probabilities
+    boost::mt19937 rng_;                ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator 
+    boost::uniform_real<> dist_;        ///< Uniformly distributed real numbers
+
+    // Shortcut typedef
+    // This typedef is placed directly before its use, as the sunstudio
+    // compiler could not handle it being anywhere else (don't know why)
+    typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator;
+    UniformRealGenerator uniform_real_gen_;     ///< Uniformly distributed random real numbers generator
+
+    size_t min_;                                ///< The minimum integer that will be generated
+};
+
+}   // namespace random
+}   // namespace util
+}   // namespace isc
+
+#endif//__NSAS_RANDOM_NUMBER_GENERATOR_H
diff --git a/src/lib/util/strutil.cc b/src/lib/util/strutil.cc
new file mode 100644
index 0000000..161f9ac
--- /dev/null
+++ b/src/lib/util/strutil.cc
@@ -0,0 +1,137 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <numeric>
+
+#include <string.h>
+#include <util/strutil.h>
+
+using namespace std;
+
+namespace isc {
+namespace util {
+namespace str {
+
+// Normalize slashes
+
+void
+normalizeSlash(std::string& name) {
+    if (!name.empty()) {
+        size_t pos = 0;
+        while ((pos = name.find('\\', pos)) != std::string::npos) {
+            name[pos] = '/';
+        }
+    }
+}
+
+// Trim String
+
+string
+trim(const string& instring) {
+    static const char* blanks = " \t\n";
+
+    string retstring = "";
+    if (!instring.empty()) {
+
+        // Search for first non-blank character in the string
+        size_t first = instring.find_first_not_of(blanks);
+        if (first != string::npos) {
+
+            // String not all blanks, so look for last character
+            size_t last = instring.find_last_not_of(blanks);
+
+            // Extract the trimmed substring
+            retstring = instring.substr(first, (last - first + 1));
+        }
+    }
+
+    return (retstring);
+}
+
+// Tokenise string.  As noted in the header, this is locally written to avoid
+// another dependency on a Boost library.
+
+vector<string>
+tokens(const std::string& text, const std::string& delim) {
+    vector<string> result;
+
+    // Search for the first non-delimiter character
+    size_t start = text.find_first_not_of(delim);
+    while (start != string::npos) {
+
+        // Non-delimiter found, look for next delimiter
+        size_t end = text.find_first_of(delim, start);
+        if (end != string::npos) {
+
+            // Delimiter found, so extract string & search for start of next
+            // non-delimiter segment.
+            result.push_back(text.substr(start, (end - start)));
+            start = text.find_first_not_of(delim, end);
+
+        } else {
+
+            // End of string found, extract rest of string and flag to exit
+            result.push_back(text.substr(start));
+            start = string::npos;
+        }
+    }
+
+    return (result);
+}
+
+// Local function to pass to accumulate() for summing up string lengths.
+
+namespace {
+
+size_t
+lengthSum(string::size_type curlen, const string& cur_string) {
+    return (curlen + cur_string.size());
+}
+
+}
+
+// Provide printf-style formatting.
+
+std::string
+format(const std::string& format, const std::vector<std::string>& args) {
+
+    static const string flag = "%s";
+
+    // Initialize return string.  To speed things up, we'll reserve an
+    // appropriate amount of space - current string size, plus length of all
+    // the argument strings, less two characters for each argument (the %s in
+    // the format string is being replaced).
+    string result;
+    size_t length = accumulate(args.begin(), args.end(), format.size(),
+        lengthSum) - (args.size() * flag.size());
+    result.reserve(length);
+
+    // Iterate through replacing all tokens
+    result = format;
+    size_t tokenpos = 0;    // Position of last token replaced
+    int i = 0;              // Index into argument array
+
+    while ((i < args.size()) && (tokenpos != string::npos)) {
+        tokenpos = result.find(flag, tokenpos);
+        if (tokenpos != string::npos) {
+            result.replace(tokenpos, flag.size(), args[i++]);
+        }
+    }
+
+    return (result);
+}
+
+} // namespace str
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/strutil.h b/src/lib/util/strutil.h
new file mode 100644
index 0000000..e044c15
--- /dev/null
+++ b/src/lib/util/strutil.h
@@ -0,0 +1,147 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __STRUTIL_H
+#define __STRUTIL_H
+
+#include <algorithm>
+#include <cctype>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace util {
+namespace str {
+
+/// \brief A Set of C++ Utilities for Manipulating Strings
+
+/// \brief Normalize Backslash
+///
+/// Only relevant to Windows, this replaces all "\" in a string with "/" and
+/// returns the result.  On other systems it is a no-op.  Note that Windows does
+/// recognise file names with the "\" replaced by "/" (at least in system calls,
+/// if not the command line).
+///
+/// \param name Name to be substituted
+void normalizeSlash(std::string& name);
+
+
+/// \brief Trim Leading and Trailing Spaces
+///
+/// Returns a copy of the input string but with any leading or trailing spaces
+/// or tabs removed.
+///
+/// \param instring Input string to modify
+///
+/// \return String with leading and trailing spaces removed
+std::string trim(const std::string& instring);
+
+
+/// \brief Split String into Tokens
+///
+/// Splits a string into tokens (the tokens being delimited by one or more of
+/// the delimiter characters) and returns the tokens in a vector array. Note
+/// that adjacent delimiters are considered to be a single delimiter.
+///
+/// Special cases are:
+/// -# The empty string is considered to be zero tokens.
+/// -# A string comprising nothing but delimiters is considered to be zero
+///    tokens.
+///
+/// The reasoning behind this is that the string can be thought of as having
+/// invisible leading and trailing delimiter characters.  Therefore both cases
+/// reduce to a set of contiguous delimiters, which are considered a single
+/// delimiter (so getting rid of the string).
+///
+/// We could use Boost for this, but this (simple) function eliminates one
+/// dependency in the code.
+///
+/// \param text String to be split.  Passed by value as the internal copy is
+/// altered during the processing.
+/// \param delim Delimiter characters
+///
+/// \return Vector of tokens.
+std::vector<std::string> tokens(const std::string& text,
+        const std::string& delim = std::string(" \t\n"));
+
+
+/// \brief Uppercase Character
+///
+/// Used in uppercase() to pass as an argument to std::transform().  The
+/// function std::toupper() can't be used as it takes an "int" as its argument;
+/// this confuses the template expansion mechanism because dereferencing a
+/// string::iterator returns a char.
+///
+/// \param chr Character to be upper-cased.
+///
+/// \return Uppercase version of the argument
+inline char toUpper(char chr) {
+    return (static_cast<char>(std::toupper(static_cast<int>(chr))));
+}
+
+
+/// \brief Uppercase String
+///
+/// A convenience function to uppercase a string.
+///
+/// \param text String to be upper-cased.
+inline void uppercase(std::string& text) {
+    std::transform(text.begin(), text.end(), text.begin(),
+        isc::util::str::toUpper);
+}
+
+/// \brief Lowercase Character
+///
+/// Used in lowercase() to pass as an argument to std::transform().  The
+/// function std::tolower() can't be used as it takes an "int" as its argument;
+/// this confuses the template expansion mechanism because dereferencing a
+/// string::iterator returns a char.
+///
+/// \param chr Character to be lower-cased.
+///
+/// \return Lowercase version of the argument
+inline char toLower(char chr) {
+    return (static_cast<char>(std::tolower(static_cast<int>(chr))));
+}
+
+/// \brief Lowercase String
+///
+/// A convenience function to lowercase a string
+///
+/// \param text String to be lower-cased.
+inline void lowercase(std::string& text) {
+    std::transform(text.begin(), text.end(), text.begin(),
+        isc::util::str::toLower);
+}
+
+
+/// \brief Apply Formatting
+///
+/// Given a printf-style format string containing only "%s" place holders
+/// (others are ignored) and a vector of strings, this produces a single string
+/// with the placeholders replaced.
+///
+/// \param format Format string
+/// \param args Vector of argument strings
+///
+/// \return Resultant string
+std::string format(const std::string& format,
+    const std::vector<std::string>& args);
+
+
+} // namespace str
+} // namespace util
+} // namespace isc
+
+#endif // __STRUTIL_H
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
new file mode 100644
index 0000000..7b97202
--- /dev/null
+++ b/src/lib/util/tests/Makefile.am
@@ -0,0 +1,41 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  =
+run_unittests_SOURCES += filename_unittest.cc
+run_unittests_SOURCES += strutil_unittest.cc
+run_unittests_SOURCES += run_unittests.cc
+run_unittests_SOURCES += base32hex_unittest.cc
+run_unittests_SOURCES += base64_unittest.cc
+run_unittests_SOURCES += hex_unittest.cc
+run_unittests_SOURCES += sha1_unittest.cc
+run_unittests_SOURCES += buffer_unittest.cc
+run_unittests_SOURCES += time_utilities_unittest.cc
+run_unittests_SOURCES += random_number_generator_unittest.cc
+run_unittests_SOURCES += lru_list_unittest.cc
+run_unittests_SOURCES += io_utilities_unittest.cc
+run_unittests_SOURCES += qid_gen_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+run_unittests_LDADD  = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/util/tests/base32hex_unittest.cc b/src/lib/util/tests/base32hex_unittest.cc
new file mode 100644
index 0000000..bf79627
--- /dev/null
+++ b/src/lib/util/tests/base32hex_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+
+#include <cctype>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/base32hex.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base32HexTest : public ::testing::Test {
+protected:
+    Base32HexTest() : encoding_chars("0123456789ABCDEFGHIJKLMNOPQRSTUV=") {
+        // test vectors from RFC4648
+        test_sequence.push_back(StringPair("", ""));
+        test_sequence.push_back(StringPair("f", "CO======"));
+        test_sequence.push_back(StringPair("fo", "CPNG===="));
+        test_sequence.push_back(StringPair("foo", "CPNMU==="));
+        test_sequence.push_back(StringPair("foob", "CPNMUOG="));
+        test_sequence.push_back(StringPair("fooba", "CPNMUOJ1"));
+        test_sequence.push_back(StringPair("foobar", "CPNMUOJ1E8======"));
+
+        // the same data, encoded using lower case chars (testable only
+        // for the decode side)
+        test_sequence_lower.push_back(StringPair("f", "co======"));
+        test_sequence_lower.push_back(StringPair("fo", "cpng===="));
+        test_sequence_lower.push_back(StringPair("foo", "cpnmu==="));
+        test_sequence_lower.push_back(StringPair("foob", "cpnmuog="));
+        test_sequence_lower.push_back(StringPair("fooba", "cpnmuoj1"));
+        test_sequence_lower.push_back(StringPair("foobar",
+                                                 "cpnmuoj1e8======"));
+    }
+    vector<StringPair> test_sequence;
+    vector<StringPair> test_sequence_lower;
+    vector<uint8_t> decoded_data;
+    const string encoding_chars;
+};
+
+void
+decodeCheck(const string& input_string, vector<uint8_t>& output,
+            const string& expected)
+{
+    decodeBase32Hex(input_string, output);
+    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
+}
+
+TEST_F(Base32HexTest, decode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decodeCheck((*it).second, decoded_data, (*it).first);
+    }
+
+    // whitespace should be allowed
+    decodeCheck("CP NM\tUOG=", decoded_data, "foob");
+    decodeCheck("CPNMU===\n", decoded_data, "foo");
+
+    // invalid number of padding characters
+    EXPECT_THROW(decodeBase32Hex("CPNMU0==", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase32Hex("CO0=====", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase32Hex("CO=======", decoded_data), // too many ='s
+                 BadValue);
+
+    // intermediate padding isn't allowed
+    EXPECT_THROW(decodeBase32Hex("CPNMUOG=CPNMUOG=", decoded_data), BadValue);
+
+    // Non canonical form isn't allowed.
+    // P => 25(11001), so the padding byte would be 01000000
+    EXPECT_THROW(decodeBase32Hex("0P======", decoded_data), BadValue);
+}
+
+TEST_F(Base32HexTest, decodeLower) {
+    for (vector<StringPair>::const_iterator it = test_sequence_lower.begin();
+         it != test_sequence_lower.end();
+         ++it) {
+        decodeCheck((*it).second, decoded_data, (*it).first);
+    }
+}
+
+TEST_F(Base32HexTest, encode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decoded_data.assign((*it).first.begin(), (*it).first.end());
+        EXPECT_EQ((*it).second, encodeBase32Hex(decoded_data));
+    }
+}
+
+// For Base32Hex we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(Base32HexTest, decodeMap) {
+    string input(8, '0');       // input placeholder
+
+    // We're going to populate an input string with only the last character
+    // not equal to the zero character ('0') for each valid base32hex encoding
+    // character.  Decoding that input should result in a data stream with
+    // the last byte equal to the numeric value represented by the that
+    // character.  For example, we'll generate and confirm the following:
+    // "00000000" => should be 0 (as a 40bit integer)
+    // "00000001" => should be 1 (as a 40bit integer)
+    // ...
+    // "0000000V" => should be 31 (as a 40bit integer)
+    // We also check the use of an invalid character for the last character
+    // surely fails. '=' should be accepted as a valid padding in this
+    // context; space characters shouldn't be allowed in this context.
+
+    for (int i = 0; i < 256; ++i) {
+        input[7] = i;
+
+        const char ch = toupper(i);
+        const size_t pos = encoding_chars.find(ch);
+        if (pos == string::npos) {
+            EXPECT_THROW(decodeBase32Hex(input, decoded_data), BadValue);
+        } else {
+            decodeBase32Hex(input, decoded_data);
+            if (ch == '=') {
+                EXPECT_EQ(4, decoded_data.size());
+            } else {
+                EXPECT_EQ(5, decoded_data.size());
+                EXPECT_EQ(pos, decoded_data[4]);
+            }
+        }
+    }
+}
+
+TEST_F(Base32HexTest, encodeMap) {
+    for (int i = 0; i < 32; ++i) {
+        decoded_data.assign(4, 0);
+        decoded_data.push_back(i);
+        EXPECT_EQ(encoding_chars[i], encodeBase32Hex(decoded_data)[7]);
+    }
+}
+
+}
diff --git a/src/lib/util/tests/base64_unittest.cc b/src/lib/util/tests/base64_unittest.cc
new file mode 100644
index 0000000..c2b2785
--- /dev/null
+++ b/src/lib/util/tests/base64_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/base64.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base64Test : public ::testing::Test {
+protected:
+    Base64Test()
+    {
+        // test vectors from RFC4648
+        test_sequence.push_back(StringPair("", ""));
+        test_sequence.push_back(StringPair("f", "Zg=="));
+        test_sequence.push_back(StringPair("fo", "Zm8="));
+        test_sequence.push_back(StringPair("foo", "Zm9v"));
+        test_sequence.push_back(StringPair("foob", "Zm9vYg=="));
+        test_sequence.push_back(StringPair("fooba", "Zm9vYmE="));
+        test_sequence.push_back(StringPair("foobar", "Zm9vYmFy"));
+    }
+    vector<StringPair> test_sequence;
+    vector<uint8_t> decoded_data;
+};
+
+void
+decodeCheck(const string& input_string, vector<uint8_t>& output,
+            const string& expected)
+{
+    decodeBase64(input_string, output);
+    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
+}
+
+TEST_F(Base64Test, decode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decodeCheck((*it).second, decoded_data, (*it).first);
+    }
+
+    // whitespace should be allowed
+    decodeCheck("Zm 9v\tYmF\ny", decoded_data, "foobar");
+    decodeCheck("Zm9vYg==", decoded_data, "foob");
+    decodeCheck("Zm9vYmE=\n", decoded_data, "fooba");
+
+    // only up to 2 padding characters are allowed
+    EXPECT_THROW(decodeBase64("A===", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase64("A= ==", decoded_data), BadValue);
+
+    // intermediate padding isn't allowed
+    EXPECT_THROW(decodeBase64("YmE=YmE=", decoded_data), BadValue);
+
+    // Non canonical form isn't allowed.
+    // Z => 25(011001), m => 38(100110), 9 => 60(111101), so the padding
+    // byte would be 0100 0000.
+    EXPECT_THROW(decodeBase64("Zm9=", decoded_data), BadValue);
+    // Same for the 1st padding byte.  This would make it 01100000.
+    EXPECT_THROW(decodeBase64("Zm==", decoded_data), BadValue);
+}
+
+TEST_F(Base64Test, encode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decoded_data.assign((*it).first.begin(), (*it).first.end());
+        EXPECT_EQ((*it).second, encodeBase64(decoded_data));
+    }
+}
+}
diff --git a/src/lib/util/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc
new file mode 100644
index 0000000..0cd1823
--- /dev/null
+++ b/src/lib/util/tests/buffer_unittest.cc
@@ -0,0 +1,242 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+
+namespace {
+
+using isc::util::InputBuffer;
+using isc::util::OutputBuffer;
+
+class BufferTest : public ::testing::Test {
+protected:
+    BufferTest() : ibuffer(testdata, sizeof(testdata)), obuffer(0),
+                   expected_size(0)
+    {
+        data16 = (2 << 8) | 3;
+        data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
+        memset(vdata, 0, sizeof(testdata));
+    }
+
+    InputBuffer ibuffer;
+    OutputBuffer obuffer;
+    static const uint8_t testdata[5];
+    uint8_t vdata[sizeof(testdata)];
+    size_t expected_size;
+    uint16_t data16;
+    uint32_t data32;
+};
+
+const uint8_t BufferTest::testdata[5] = {1, 2, 3, 4, 5};
+
+TEST_F(BufferTest, inputBufferRead) {
+    EXPECT_EQ(5, ibuffer.getLength());
+    EXPECT_EQ(1, ibuffer.readUint8());
+    EXPECT_EQ(1, ibuffer.getPosition());
+    data16 = ibuffer.readUint16();
+    EXPECT_EQ((2 << 8) | 3, data16);
+    EXPECT_EQ(3, ibuffer.getPosition());
+    ibuffer.setPosition(1);
+    EXPECT_EQ(1, ibuffer.getPosition());
+    data32 = ibuffer.readUint32();
+    EXPECT_EQ((2 << 24) | (3 << 16) | (4 << 8) | 5, data32);
+    ibuffer.setPosition(0);
+    memset(vdata, 0, sizeof(vdata));
+    ibuffer.readData(vdata, sizeof(vdata));
+    EXPECT_EQ(0, memcmp(vdata, testdata, sizeof(testdata)));
+}
+
+TEST_F(BufferTest, inputBufferException) {
+    EXPECT_THROW(ibuffer.setPosition(6), isc::util::InvalidBufferPosition);
+
+    ibuffer.setPosition(sizeof(testdata));
+    EXPECT_THROW(ibuffer.readUint8(), isc::util::InvalidBufferPosition);
+
+    ibuffer.setPosition(sizeof(testdata) - 1);
+    EXPECT_THROW(ibuffer.readUint16(), isc::util::InvalidBufferPosition);
+
+    ibuffer.setPosition(sizeof(testdata) - 3);
+    EXPECT_THROW(ibuffer.readUint32(), isc::util::InvalidBufferPosition);
+
+    ibuffer.setPosition(sizeof(testdata) - 4);
+    EXPECT_THROW(ibuffer.readData(vdata, sizeof(vdata)),
+                 isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferExtend) {
+    EXPECT_EQ(0, obuffer.getCapacity());
+    EXPECT_EQ(0, obuffer.getLength());
+    obuffer.writeUint8(10);
+    EXPECT_LT(0, obuffer.getCapacity());
+    EXPECT_EQ(1, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferWrite) {
+    const uint8_t* cp;
+
+    obuffer.writeUint8(1);
+    expected_size += sizeof(uint8_t);
+    EXPECT_EQ(expected_size, obuffer.getLength());
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(1, *cp);
+
+    obuffer.writeUint16(data16);
+    expected_size += sizeof(data16);
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(expected_size, obuffer.getLength());
+    EXPECT_EQ(2, *(cp + 1));
+    EXPECT_EQ(3, *(cp + 2));
+
+    obuffer.writeUint32(data32);
+    expected_size += sizeof(data32);
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(expected_size, obuffer.getLength());
+    EXPECT_EQ(4, *(cp + 3));
+    EXPECT_EQ(5, *(cp + 4));
+    EXPECT_EQ(6, *(cp + 5));
+    EXPECT_EQ(7, *(cp + 6));
+
+    obuffer.writeData(testdata, sizeof(testdata));
+    expected_size += sizeof(testdata);
+    EXPECT_EQ(expected_size, obuffer.getLength());
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(0, memcmp(cp + 7, testdata, sizeof(testdata)));
+}
+
+TEST_F(BufferTest, outputBufferWriteat) {
+    obuffer.writeUint32(data32);
+    expected_size += sizeof(data32);
+
+    // overwrite 2nd byte
+    obuffer.writeUint8At(4, 1);
+    EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
+    const uint8_t* cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(4, *(cp + 1));
+
+    // overwrite 2nd and 3rd bytes
+    obuffer.writeUint16At(data16, 1);
+    EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(2, *(cp + 1));
+    EXPECT_EQ(3, *(cp + 2));
+
+    // overwrite 3rd and 4th bytes
+    obuffer.writeUint16At(data16, 2);
+    EXPECT_EQ(expected_size, obuffer.getLength());
+    cp = static_cast<const uint8_t*>(obuffer.getData());
+    EXPECT_EQ(2, *(cp + 2));
+    EXPECT_EQ(3, *(cp + 3));
+
+    EXPECT_THROW(obuffer.writeUint8At(data16, 5),
+                 isc::util::InvalidBufferPosition);
+    EXPECT_THROW(obuffer.writeUint8At(data16, 4),
+                 isc::util::InvalidBufferPosition);
+    EXPECT_THROW(obuffer.writeUint16At(data16, 3),
+                 isc::util::InvalidBufferPosition);
+    EXPECT_THROW(obuffer.writeUint16At(data16, 4),
+                 isc::util::InvalidBufferPosition);
+    EXPECT_THROW(obuffer.writeUint16At(data16, 5),
+                 isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferSkip) {
+    obuffer.skip(4);
+    EXPECT_EQ(4, obuffer.getLength());
+
+    obuffer.skip(2);
+    EXPECT_EQ(6, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferTrim) {
+    obuffer.writeData(testdata, sizeof(testdata));
+    EXPECT_EQ(5, obuffer.getLength());
+
+    obuffer.trim(1);
+    EXPECT_EQ(4, obuffer.getLength());
+
+    obuffer.trim(2);
+    EXPECT_EQ(2, obuffer.getLength());
+
+    EXPECT_THROW(obuffer.trim(3), OutOfRange);
+}
+
+TEST_F(BufferTest, outputBufferReadat) {
+    obuffer.writeData(testdata, sizeof(testdata));
+    for (int i = 0; i < sizeof(testdata); i ++) {
+        EXPECT_EQ(testdata[i], obuffer[i]);
+    }
+    EXPECT_THROW(obuffer[sizeof(testdata)], isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferClear) {
+    obuffer.writeData(testdata, sizeof(testdata));
+    obuffer.clear();
+    EXPECT_EQ(0, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferCopy) {
+    obuffer.writeData(testdata, sizeof(testdata));
+
+    EXPECT_NO_THROW({
+        OutputBuffer copy(obuffer);
+        ASSERT_EQ(sizeof(testdata), copy.getLength());
+        for (int i = 0; i < sizeof(testdata); i ++) {
+            EXPECT_EQ(testdata[i], copy[i]);
+            if (i + 1 < sizeof(testdata)) {
+                obuffer.writeUint16At(0, i);
+            }
+            EXPECT_EQ(testdata[i], copy[i]);
+        }
+        obuffer.clear();
+        ASSERT_EQ(sizeof(testdata), copy.getLength());
+    });
+}
+
+TEST_F(BufferTest, outputBufferAssign) {
+    OutputBuffer another(0);
+    another.clear();
+    obuffer.writeData(testdata, sizeof(testdata));
+
+    EXPECT_NO_THROW({
+        another = obuffer;
+        ASSERT_EQ(sizeof(testdata), another.getLength());
+        for (int i = 0; i < sizeof(testdata); i ++) {
+            EXPECT_EQ(testdata[i], another[i]);
+            if (i + 1 < sizeof(testdata)) {
+                obuffer.writeUint16At(0, i);
+            }
+            EXPECT_EQ(testdata[i], another[i]);
+        }
+        obuffer.clear();
+        ASSERT_EQ(sizeof(testdata), another.getLength());
+    });
+}
+
+TEST_F(BufferTest, outputBufferZeroSize) {
+    // Some OSes might return NULL on malloc for 0 size, so check it works
+    EXPECT_NO_THROW({
+        OutputBuffer first(0);
+        OutputBuffer copy(first);
+        OutputBuffer second(0);
+        second = first;
+    });
+}
+
+}
diff --git a/src/lib/util/tests/filename_unittest.cc b/src/lib/util/tests/filename_unittest.cc
new file mode 100644
index 0000000..33e6456
--- /dev/null
+++ b/src/lib/util/tests/filename_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <util/filename.h>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+class FilenameTest : public ::testing::Test {
+protected:
+    FilenameTest()
+    {
+    }
+};
+
+
+// Check that the name can be changed
+
+TEST_F(FilenameTest, SetName) {
+    Filename fname("/a/b/c.d");
+    EXPECT_EQ("/a/b/c.d", fname.fullName());
+
+    fname.setName("test.txt");
+    EXPECT_EQ("test.txt", fname.fullName());
+}
+
+
+// Check that the components are split correctly.  This is a check of the
+// private member split() method.
+
+TEST_F(FilenameTest, Components) {
+
+    // Complete name
+    Filename fname("/alpha/beta/gamma.delta");
+    EXPECT_EQ("/alpha/beta/", fname.directory());
+    EXPECT_EQ("gamma", fname.name());
+    EXPECT_EQ(".delta", fname.extension());
+
+    // Directory only
+    fname.setName("/gamma/delta/");
+    EXPECT_EQ("/gamma/delta/", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // Filename only
+    fname.setName("epsilon");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("epsilon", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // Extension only
+    fname.setName(".zeta");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ(".zeta", fname.extension());
+
+    // Missing directory
+    fname.setName("eta.theta");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("eta", fname.name());
+    EXPECT_EQ(".theta", fname.extension());
+
+    // Missing filename
+    fname.setName("/iota/.kappa");
+    EXPECT_EQ("/iota/", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ(".kappa", fname.extension());
+
+    // Missing extension
+    fname.setName("lambda/mu/nu");
+    EXPECT_EQ("lambda/mu/", fname.directory());
+    EXPECT_EQ("nu", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // Check that the decomposition can occur in the presence of leading and
+    // trailing spaces
+    fname.setName("  lambda/mu/nu\t  ");
+    EXPECT_EQ("lambda/mu/", fname.directory());
+    EXPECT_EQ("nu", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // Empty string
+    fname.setName("");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // ... and just spaces
+    fname.setName("  ");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    // Check corner cases - where separators are present, but strings are
+    // absent.
+    fname.setName("/");
+    EXPECT_EQ("/", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ("", fname.extension());
+
+    fname.setName(".");
+    EXPECT_EQ("", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ(".", fname.extension());
+
+    fname.setName("/.");
+    EXPECT_EQ("/", fname.directory());
+    EXPECT_EQ("", fname.name());
+    EXPECT_EQ(".", fname.extension());
+
+    // Note that the space is a valid filename here; only leading and trailing
+    // spaces should be trimmed.
+    fname.setName("/ .");
+    EXPECT_EQ("/", fname.directory());
+    EXPECT_EQ(" ", fname.name());
+    EXPECT_EQ(".", fname.extension());
+
+    fname.setName(" / . ");
+    EXPECT_EQ("/", fname.directory());
+    EXPECT_EQ(" ", fname.name());
+    EXPECT_EQ(".", fname.extension());
+}
+
+// Check that the expansion with a default works.
+
+TEST_F(FilenameTest, ExpandWithDefault) {
+    Filename fname("a.b");
+
+    // These tests also check that the trimming of the default component is
+    // done properly.
+    EXPECT_EQ("/c/d/a.b", fname.expandWithDefault(" /c/d/  "));
+    EXPECT_EQ("/c/d/a.b", fname.expandWithDefault("/c/d/e.f"));
+    EXPECT_EQ("a.b", fname.expandWithDefault("e.f"));
+
+    fname.setName("/a/b/c");
+    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault(".d"));
+    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("x.d"));
+    EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("/s/t/u.d"));
+    EXPECT_EQ("/a/b/c", fname.expandWithDefault("/s/t/u"));
+
+    fname.setName(".h");
+    EXPECT_EQ("/a/b/c.h", fname.expandWithDefault("/a/b/c.msg"));
+}
+
+// Check that we can use this as a default in expanding a filename
+
+TEST_F(FilenameTest, UseAsDefault) {
+
+    Filename fname("a.b");
+
+    // These tests also check that the trimming of the default component is
+    // done properly.
+    EXPECT_EQ("/c/d/a.b", fname.useAsDefault(" /c/d/  "));
+    EXPECT_EQ("/c/d/e.f", fname.useAsDefault("/c/d/e.f"));
+    EXPECT_EQ("e.f", fname.useAsDefault("e.f"));
+
+    fname.setName("/a/b/c");
+    EXPECT_EQ("/a/b/c.d", fname.useAsDefault(".d"));
+    EXPECT_EQ("/a/b/x.d", fname.useAsDefault("x.d"));
+    EXPECT_EQ("/s/t/u.d", fname.useAsDefault("/s/t/u.d"));
+    EXPECT_EQ("/s/t/u", fname.useAsDefault("/s/t/u"));
+    EXPECT_EQ("/a/b/c", fname.useAsDefault(""));
+}
diff --git a/src/lib/util/tests/hex_unittest.cc b/src/lib/util/tests/hex_unittest.cc
new file mode 100644
index 0000000..52bccea
--- /dev/null
+++ b/src/lib/util/tests/hex_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+
+#include <vector>
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/hex.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+const string hex_txt("DEADBEEFDECADE");
+const string hex_txt_space("DEAD BEEF DECADE");
+const string hex_txt_lower("deadbeefdecade");
+
+class HexTest : public ::testing::Test {
+protected:
+    HexTest() : encoding_chars("0123456789ABCDEF") {}
+    vector<uint8_t> decoded_data;
+    const string encoding_chars;
+};
+
+TEST_F(HexTest, encodeHex) {
+    std::vector<uint8_t> data;
+
+    data.push_back(0xde);
+    data.push_back(0xad);
+    data.push_back(0xbe);
+    data.push_back(0xef);
+    data.push_back(0xde);
+    data.push_back(0xca);
+    data.push_back(0xde);
+    EXPECT_EQ(hex_txt, encodeHex(data));
+}
+
+void
+compareData(const std::vector<uint8_t>& data) {
+    EXPECT_EQ(0xde, data[0]);
+    EXPECT_EQ(0xad, data[1]);
+    EXPECT_EQ(0xbe, data[2]);
+    EXPECT_EQ(0xef, data[3]);
+    EXPECT_EQ(0xde, data[4]);
+    EXPECT_EQ(0xca, data[5]);
+    EXPECT_EQ(0xde, data[6]);
+}
+
+TEST_F(HexTest, decodeHex) {
+    std::vector<uint8_t> result;
+
+    decodeHex(hex_txt, result);
+    compareData(result);
+
+    // lower case hex digits should be accepted
+    result.clear();
+    decodeHex(hex_txt_lower, result);
+    compareData(result);
+
+    // white space should be ignored
+    result.clear();
+    decodeHex(hex_txt_space, result);
+    compareData(result);
+
+    // Bogus input: should fail
+    result.clear();
+    EXPECT_THROW(decodeHex("1x", result), BadValue);
+
+    // Bogus input: encoded string must have an even number of characters.
+    result.clear();
+    EXPECT_THROW(decodeHex("dea", result), BadValue);
+}
+
+// For Hex encode/decode we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(HexTest, decodeMap) {
+    string input("00");       // input placeholder
+
+    // See Base32HexTest.decodeMap for details of the following tests.
+    for (int i = 0; i < 256; ++i) {
+        input[1] = i;
+
+        const char ch = toupper(i);
+        const size_t pos = encoding_chars.find(ch);
+        if (pos == string::npos) {
+            EXPECT_THROW(decodeHex(input, decoded_data), BadValue);
+        } else {
+            decodeHex(input, decoded_data);
+            EXPECT_EQ(1, decoded_data.size());
+            EXPECT_EQ(pos, decoded_data[0]);
+        }
+    }
+}
+
+TEST_F(HexTest, encodeMap) {
+    for (int i = 0; i < 16; ++i) {
+        decoded_data.clear();
+        decoded_data.push_back(i);
+        EXPECT_EQ(encoding_chars[i], encodeHex(decoded_data)[1]);
+    }
+}
+
+}
diff --git a/src/lib/util/tests/io_utilities_unittest.cc b/src/lib/util/tests/io_utilities_unittest.cc
new file mode 100644
index 0000000..4aad560
--- /dev/null
+++ b/src/lib/util/tests/io_utilities_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// \brief Test of asiolink utilties
+///
+/// Tests the fuctionality of the asiolink utilities code by comparing them
+/// with the equivalent methods in isc::dns::[Input/Output]Buffer.
+
+#include <cstddef>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+#include <util/io_utilities.h>
+
+using namespace isc::util;
+
+TEST(asioutil, readUint16) {
+
+    // Reference buffer
+    uint8_t data[2];
+    InputBuffer buffer(data, sizeof(data));
+
+    // Avoid possible compiler warnings by only setting uint8_t variables to
+    // uint8_t values.
+    uint8_t i8 = 0;
+    uint8_t j8 = 0;
+    for (int i = 0; i < (2 << 8); ++i, ++i8) {
+        for (int j = 0; j < (2 << 8); ++j, ++j8) {
+            data[0] = i8;
+            data[1] = j8;
+            buffer.setPosition(0);
+            EXPECT_EQ(buffer.readUint16(), readUint16(data));
+        }
+    }
+}
+
+
+TEST(asioutil, writeUint16) {
+
+    // Reference buffer
+    OutputBuffer buffer(2);
+    uint8_t test[2];
+
+    // Avoid possible compiler warnings by only setting uint16_t variables to
+    // uint16_t values.
+    uint16_t i16 = 0;
+    for (uint32_t i = 0; i < (2 << 16); ++i, ++i16) {
+
+        // Write the reference data
+        buffer.clear();
+        buffer.writeUint16(i16);
+
+        // ... and the test data
+        writeUint16(i16, test);
+
+        // ... and compare
+        const uint8_t* ref = static_cast<const uint8_t*>(buffer.getData());
+        EXPECT_EQ(ref[0], test[0]);
+        EXPECT_EQ(ref[1], test[1]);
+    }
+}
diff --git a/src/lib/util/tests/lru_list_unittest.cc b/src/lib/util/tests/lru_list_unittest.cc
new file mode 100644
index 0000000..bfb3b4d
--- /dev/null
+++ b/src/lib/util/tests/lru_list_unittest.cc
@@ -0,0 +1,428 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <stdint.h>
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+#include <gtest/gtest.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <util/lru_list.h>
+
+using namespace std;
+
+namespace isc {
+namespace util {
+
+/// \brief Invalid Iterator
+///
+/// Thrown if an attempt was made to access the iterator - the pointer into
+/// the LRU list where this element is located - when it is marked as invalid.
+class InvalidLruIterator : public isc::Exception {
+public:
+    InvalidLruIterator(const char* file, size_t line, const char* what) :
+        Exception(file, line, what)
+    {}
+};
+
+template <typename T>
+class TestEntryT : public boost::enable_shared_from_this <T> {
+public:
+
+    /// \brief Constructor
+    ///
+    /// \param name Name that will be used for the object.  This will form
+    /// part of the key.
+    /// \param class_code Class associated with the object.
+    TestEntryT() : valid_(false)
+    {}
+
+    /// \brief Virtual Destructor
+    virtual ~TestEntryT()
+        {}
+
+    /// \brief Sets the iterator of the object
+    ///
+    /// Sets the iterator of an object and, as a side effect, marks it as valid.
+    ///
+    /// \param iterator Iterator of this element in the list
+    virtual void setLruIterator(typename LruList<T>::iterator iterator) {
+        iterator_ = iterator;
+        valid_ = true;
+    }
+
+    /// \brief Return Iterator
+    ///
+    /// \return iterator Iterator of this element in the list.
+    ///
+    /// \exception InvalidLruIterator Thrown if the iterator is not valid.
+    virtual typename LruList<T>::iterator getLruIterator() const {
+        /*if (! valid_) {
+            isc_throw(InvalidLruIterator,
+                "pointer of element into LRU list was not valid");
+        }*/
+        return iterator_;
+    }
+
+    /// \brief Iterator Valid
+    ///
+    /// \return true if the stored iterator is valid.
+    virtual bool iteratorValid() const {
+        return valid_;
+    }
+
+    /// \brief Invalidate Iterator
+    ///
+    /// Marks the iterator as invalid; it can oly be set valid again by a call
+    /// to setLruIterator.
+    virtual void invalidateIterator() {
+        valid_ = false;
+    }
+
+private:
+    typename LruList<T>::iterator  iterator_;  ///< Handle into the LRU List
+    bool                           valid_;     ///< true if handle is valid
+};
+
+class TestEntry : public TestEntryT<TestEntry> {
+public:
+    TestEntry(std::string name, const int & code) :
+        name_(name), code_(code)
+    {}
+
+    /// \brief Get the Name
+    ///
+    /// \return Name given to this object
+    virtual std::string getName() const {
+        return name_;
+    }
+
+    /// \brief Set the Name
+    ///
+    /// \param name New name of the object
+    virtual void setName(const std::string& name) {
+        name_ = name;
+    }
+
+    /// \brief Get the Class
+    ///
+    /// \return Class code assigned to this object
+    virtual const int& getCode() const {
+        return code_;
+    }
+
+    /// \brief Set the Class
+    ///
+    /// \param code New code of the object
+    virtual void setCode(const int& code) {
+        code_ = code;
+    }
+
+private:
+    std::string name_;          ///< Name of the object
+    int code_;    ///< Class of the object
+
+};
+
+/// \brief Dropped Functor Class
+///
+/// Functor object is called when an object is dropped from the LRU list.
+/// To prove that it has run, this function does nothing more than set the
+/// MS bit on the 16-bit code value.
+class Dropped : public LruList<TestEntry>::Dropped {
+public:
+    virtual void operator()(TestEntry* entry) const {
+        entry->setCode(entry->getCode() | 0x8000);
+    }
+};
+
+
+/// \brief Text Fixture Class
+class LruListTest : public ::testing::Test {
+protected:
+    LruListTest() :
+        entry1_(new TestEntry("alpha", 1)),
+        entry2_(new TestEntry("beta", 3)),
+        entry3_(new TestEntry("gamma", 4)),
+        entry4_(new TestEntry("delta", 1)),
+        entry5_(new TestEntry("epsilon", 4)),
+        entry6_(new TestEntry("zeta", 3)),
+        entry7_(new TestEntry("eta", 1))
+    {}
+
+    virtual ~LruListTest() 
+    {}
+
+    boost::shared_ptr<TestEntry>    entry1_;
+    boost::shared_ptr<TestEntry>    entry2_;
+    boost::shared_ptr<TestEntry>    entry3_;
+    boost::shared_ptr<TestEntry>    entry4_;
+    boost::shared_ptr<TestEntry>    entry5_;
+    boost::shared_ptr<TestEntry>    entry6_;
+    boost::shared_ptr<TestEntry>    entry7_;
+};
+
+
+// Test of the constructor
+TEST_F(LruListTest, Constructor) {
+    LruList<TestEntry>  lru(100);
+    EXPECT_EQ(100, lru.getMaxSize());
+    EXPECT_EQ(0, lru.size());
+}
+
+// Test of Get/Set the maximum number of entrys
+TEST_F(LruListTest, GetSet) {
+    LruList<TestEntry>  lru(100);
+    EXPECT_EQ(100, lru.getMaxSize());
+    lru.setMaxSize(42);
+    EXPECT_EQ(42, lru.getMaxSize());
+}
+
+// Test that adding an entry really does add an entry
+TEST_F(LruListTest, Add) {
+    LruList<TestEntry>  lru(100);
+    EXPECT_EQ(0, lru.size());
+
+    lru.add(entry1_);
+    EXPECT_EQ(1, lru.size());
+
+    lru.add(entry2_);
+    EXPECT_EQ(2, lru.size());
+}
+
+// Test that removing an entry really does remove it.
+TEST_F(LruListTest, Remove) {
+    LruList<TestEntry>  lru(100);
+    EXPECT_EQ(0, lru.size());
+
+    EXPECT_FALSE(entry1_->iteratorValid());
+    lru.add(entry1_);
+    EXPECT_TRUE(entry1_->iteratorValid());
+    EXPECT_EQ(1, lru.size());
+
+    EXPECT_FALSE(entry2_->iteratorValid());
+    lru.add(entry2_);
+    EXPECT_TRUE(entry2_->iteratorValid());
+    EXPECT_EQ(2, lru.size());
+
+    lru.remove(entry1_);
+    EXPECT_FALSE(entry1_->iteratorValid());
+    EXPECT_EQ(1, lru.size());
+}
+
+// Check that adding a new entry to a limited size list does delete the
+// oldest entry from the list.
+TEST_F(LruListTest, SizeLimit) {
+    LruList<TestEntry>  lru(3);
+    EXPECT_EQ(0, lru.size());
+
+    // Add first entry and check that the shared pointer's reference count
+    // has increased.  There will be two references: one from the "entry1_"
+    // member in the test fixture class, and one from the list.
+    EXPECT_EQ(1, entry1_.use_count());
+    lru.add(entry1_);
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, lru.size());
+
+    // Same for entry 2.
+    EXPECT_EQ(1, entry2_.use_count());
+    lru.add(entry2_);
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, lru.size());
+
+    // Same for entry 3.
+    EXPECT_EQ(1, entry3_.use_count());
+    lru.add(entry3_);
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(3, lru.size());
+
+    // Adding entry 4 should remove entry 1 from the list.  This will
+    // delete the list's shared pointer to the entry and will therefore
+    // drop the reference count back to one (from the "entry1_" member in
+    // the text fixture class).
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    lru.add(entry4_);
+    EXPECT_EQ(1, entry1_.use_count());
+    EXPECT_EQ(2, entry4_.use_count());
+    EXPECT_EQ(3, lru.size());
+
+    // Adding entry 5 should remove entry 2 from the list.
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    lru.add(entry5_);
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(2, entry5_.use_count());
+    EXPECT_EQ(3, lru.size());
+}
+
+// Check that "touching" an entry adds it to the back of the list.
+TEST_F(LruListTest, Touch) {
+
+    // Create the list
+    LruList<TestEntry>  lru(3);
+    EXPECT_EQ(0, lru.size());
+    lru.add(entry1_);
+    lru.add(entry2_);
+    lru.add(entry3_);
+
+    // Check the reference counts of the entrys and the list size
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(1, entry6_.use_count());
+    EXPECT_EQ(1, entry7_.use_count());
+    EXPECT_EQ(3, lru.size());
+
+    // "Touch" the first entry
+    lru.touch(entry1_);
+
+    // Adding two more entries should not remove the touched entry.
+    lru.add(entry4_);
+    lru.add(entry5_);
+
+    // Check the status of the entrys and the list.
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(1, entry3_.use_count());
+    EXPECT_EQ(2, entry4_.use_count());
+    EXPECT_EQ(2, entry5_.use_count());
+    EXPECT_EQ(1, entry6_.use_count());
+    EXPECT_EQ(1, entry7_.use_count());
+    EXPECT_EQ(3, lru.size());
+
+    // Now touch the entry agin to move it to the back of the list.
+    // This checks that the iterator stored in the entry as a result of the
+    // last touch operation is valid.
+    lru.touch(entry1_);
+
+    // Check this by adding two more entrys and checking reference counts
+    // to see what is stored.
+    lru.add(entry6_);
+    lru.add(entry7_);
+
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(1, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(2, entry6_.use_count());
+    EXPECT_EQ(2, entry7_.use_count());
+    EXPECT_EQ(3, lru.size());
+}
+
+// Dropped functor tests: tests that the function object is called when an
+// object expires from the list.
+TEST_F(LruListTest, Dropped) {
+
+    // Create an object with an expiration handler.
+    LruList<TestEntry> lru(3, new Dropped());
+
+    // Fill the list
+    lru.add(entry1_);
+    lru.add(entry2_);
+    lru.add(entry3_);
+
+    EXPECT_EQ(1, entry1_->getCode());
+    EXPECT_EQ(3, entry2_->getCode());
+
+    // Add another entry and check that the handler runs.
+    EXPECT_EQ(0, (entry1_->getCode() & 0x8000));
+    lru.add(entry4_);
+    EXPECT_NE(0, (entry1_->getCode() & 0x8000));
+
+    EXPECT_EQ(0, (entry2_->getCode() & 0x8000));
+    lru.add(entry5_);
+    EXPECT_NE(0, (entry2_->getCode() & 0x8000));
+
+    // Delete an entry and check that the handler does not run. 
+    EXPECT_EQ(0, (entry3_->getCode() & 0x8000));
+    lru.remove(entry3_);
+    EXPECT_EQ(0, (entry3_->getCode() & 0x8000));
+}
+
+// Clear functor tests: tests whether all the elements in
+// the list are dropped properly and the size of list is
+// set to 0.
+TEST_F(LruListTest, Clear) {
+    // Create an object with an expiration handler.
+    LruList<TestEntry> lru(3, new Dropped());
+
+    // Fill the list
+    lru.add(entry1_);
+    lru.add(entry2_);
+    lru.add(entry3_);
+
+    EXPECT_EQ(1, entry1_->getCode());
+    EXPECT_EQ(3, entry2_->getCode());
+    EXPECT_EQ(4, entry3_->getCode());
+
+    EXPECT_EQ(0, (entry1_->getCode() & 0x8000));
+    EXPECT_EQ(0, (entry2_->getCode() & 0x8000));
+    EXPECT_EQ(0, (entry3_->getCode() & 0x8000));
+
+    // Clear the lru list, and check the drop handler run
+    lru.clear();
+    EXPECT_NE(0, (entry1_->getCode() & 0x8000));
+    EXPECT_NE(0, (entry2_->getCode() & 0x8000));
+    EXPECT_NE(0, (entry3_->getCode() & 0x8000));
+ 
+    EXPECT_EQ(0, lru.size());
+}
+
+// Miscellaneous tests - pathological conditions
+TEST_F(LruListTest, Miscellaneous) {
+
+    // Zero size list should not allow entrys to be added
+    LruList<TestEntry> lru_1(0);
+    lru_1.add(entry1_);
+    EXPECT_EQ(0, lru_1.size());
+    EXPECT_EQ(1, entry1_.use_count());
+
+    // Removing an uninserted entry should not affect the list.
+    LruList<TestEntry> lru_2(100);
+    lru_2.add(entry1_);
+    lru_2.add(entry2_);
+    lru_2.add(entry3_);
+    EXPECT_EQ(3, lru_2.size());
+
+    lru_2.remove(entry4_);
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(3, lru_2.size());
+
+    // Touching an uninserted entry should not affect the list.
+    lru_2.touch(entry5_);
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(3, lru_2.size());
+}
+
+}   // namespace nsas
+}   // namespace isc
diff --git a/src/lib/util/tests/qid_gen_unittest.cc b/src/lib/util/tests/qid_gen_unittest.cc
new file mode 100644
index 0000000..60c81ae
--- /dev/null
+++ b/src/lib/util/tests/qid_gen_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+/// \brief Test of QidGenerator
+///
+
+#include <gtest/gtest.h>
+
+#include <util/random/qid_gen.h>
+
+using namespace isc::util::random;
+
+// Tests the operation of the Qid generator
+
+// Check that getInstance returns a singleton
+TEST(QidGenerator, singleton) {
+    QidGenerator& g1 = QidGenerator::getInstance();
+    QidGenerator& g2 = QidGenerator::getInstance();
+
+    EXPECT_TRUE(&g1 == &g2);
+}
+
+TEST(QidGenerator, generate) {
+    // We'll assume that boost's generator is 'good enough', and won't
+    // do full statistical checking here. Let's just call it the xkcd
+    // test (http://xkcd.com/221/), and check if three consecutive
+    // generates are not all the same.
+    uint16_t one, two, three;
+    QidGenerator& gen = QidGenerator::getInstance();
+    one = gen.generateQid();
+    two = gen.generateQid();
+    three = gen.generateQid();
+    ASSERT_FALSE((one == two) && (one == three));
+}
diff --git a/src/lib/util/tests/random_number_generator_unittest.cc b/src/lib/util/tests/random_number_generator_unittest.cc
new file mode 100644
index 0000000..23d5b88
--- /dev/null
+++ b/src/lib/util/tests/random_number_generator_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <util/random/random_number_generator.h>
+
+namespace isc {
+namespace util {
+namespace random {
+
+using namespace std;
+
+/// \brief Test Fixture Class for uniform random number generator
+///
+/// The hard part for this test is how to test that the number is random?
+/// and how to test that the number is uniformly distributed? 
+/// Or maybe we can trust the boost implementation
+class UniformRandomIntegerGeneratorTest : public ::testing::Test {
+public:
+    UniformRandomIntegerGeneratorTest():
+        gen_(min_, max_)
+    {
+    }
+    virtual ~UniformRandomIntegerGeneratorTest(){}
+
+    int gen() { return gen_(); }
+    int max() const { return max_; }
+    int min() const { return min_; }
+
+private:
+    UniformRandomIntegerGenerator gen_;
+
+    const static int min_ = 1;
+    const static int max_ = 10;
+};
+
+// Some validation tests will incur performance penalty, so the tests are
+// made only in "debug" version with assert(). But if NDEBUG is defined
+// the tests will be failed since assert() is non-op in non-debug version.
+// The "#ifndef NDEBUG" is added to make the tests be performed only in
+// non-debug environment.
+// Note: the death test is not supported by all platforms.  We need to
+// compile tests using it selectively.
+#if !defined(NDEBUG)
+// Test of the constructor
+TEST_F(UniformRandomIntegerGeneratorTest, Constructor) {
+    // The range must be min<=max
+    ASSERT_THROW(UniformRandomIntegerGenerator(3, 2), InvalidLimits);
+}
+#endif
+
+// Test of the generated integers are in the range [min, max]
+TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) {
+    vector<int> numbers;
+
+    // Generate a lot of random integers
+    for (int i = 0; i < max()*10; ++i) {
+        numbers.push_back(gen());
+    }
+
+    // Remove the duplicated values
+    sort(numbers.begin(), numbers.end());
+    vector<int>::iterator it = unique(numbers.begin(), numbers.end());
+
+    // make sure the numbers are in range [min, max]
+    ASSERT_EQ(it - numbers.begin(), max() - min() + 1); 
+}
+
+/// \brief Test Fixture Class for weighted random number generator
+class WeightedRandomIntegerGeneratorTest : public ::testing::Test {
+public:
+    WeightedRandomIntegerGeneratorTest()
+    { }
+
+    virtual ~WeightedRandomIntegerGeneratorTest()
+    { }
+};
+
+// Test of the weighted random number generator constructor
+TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) {
+    vector<double> probabilities;
+
+    // If no probabilities is provided, the smallest integer will always be generated
+    WeightedRandomIntegerGenerator gen(probabilities, 123);
+    for (int i = 0; i < 100; ++i) {
+        ASSERT_EQ(gen(), 123);
+    }
+
+/// Some validation tests will incur performance penalty, so the tests are
+/// made only in "debug" version with assert(). But if NDEBUG is defined
+/// the tests will be failed since assert() is non-op in non-debug version.
+/// The "#ifndef NDEBUG" is added to make the tests be performed only in
+/// non-debug environment.
+#if !defined(NDEBUG)
+    //The probability must be >= 0
+    probabilities.push_back(-0.1);
+    probabilities.push_back(1.1);
+    ASSERT_THROW(WeightedRandomIntegerGenerator gen2(probabilities),
+                 InvalidProbValue);
+
+    //The probability must be <= 1.0
+    probabilities.clear();
+    probabilities.push_back(0.1);
+    probabilities.push_back(1.1);
+    ASSERT_THROW(WeightedRandomIntegerGenerator gen3(probabilities),
+                 InvalidProbValue);
+
+    //The sum must be equal to 1.0
+    probabilities.clear();
+    probabilities.push_back(0.2);
+    probabilities.push_back(0.9);
+    ASSERT_THROW(WeightedRandomIntegerGenerator gen4(probabilities), SumNotOne);
+
+    //The sum must be equal to 1.0
+    probabilities.clear();
+    probabilities.push_back(0.3);
+    probabilities.push_back(0.2);
+    probabilities.push_back(0.1);
+    ASSERT_THROW(WeightedRandomIntegerGenerator gen5(probabilities), SumNotOne);
+#endif
+}
+
+// Test the randomization of the generator
+TEST_F(WeightedRandomIntegerGeneratorTest, WeightedRandomization) {
+    const int repeats = 100000;
+    // We repeat the simulation for N=repeats times
+    // for each probability p, its average is mu = N*p
+    // variance sigma^2 = N * p * (1-p)
+    // sigma = sqrt(N*2/9)
+    // we should make sure that mu - 4sigma < count < mu + 4sigma
+    // which means for 99.99366% of the time this should be true
+    {
+        double p = 0.5;
+        vector<double> probabilities;
+        probabilities.push_back(p);
+        probabilities.push_back(p);
+
+        // Uniformly generated integers
+        WeightedRandomIntegerGenerator gen(probabilities);
+        int c1 = 0;
+        int c2 = 0;
+        for (int i = 0; i < repeats; ++i){
+            int n = gen();
+            if (n == 0) {
+                ++c1;
+            } else if (n == 1) {
+                ++c2;
+            }
+        }
+        double mu = repeats * p;
+        double sigma = sqrt(repeats * p * (1 - p));
+        ASSERT_TRUE(fabs(c1 - mu) < 4*sigma);
+        ASSERT_TRUE(fabs(c2 - mu) < 4*sigma);
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        double p1 = 0.2;
+        double p2 = 0.8;
+        probabilities.push_back(p1);
+        probabilities.push_back(p2);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for (int i = 0; i < repeats; ++i) {
+            int n = gen();
+            if (n == 0) {
+                ++c1;
+            } else if (n == 1) {
+                ++c2;
+            }
+        }
+        double mu1 = repeats * p1;
+        double mu2 = repeats * p2;
+        double sigma1 = sqrt(repeats * p1 * (1 - p1));
+        double sigma2 = sqrt(repeats * p2 * (1 - p2));
+        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
+        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        double p1 = 0.8;
+        double p2 = 0.2;
+        probabilities.push_back(p1);
+        probabilities.push_back(p2);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for (int i = 0; i < repeats; ++i) {
+            int n = gen();
+            if (n == 0) {
+                ++c1;
+            } else if (n == 1) {
+                ++c2;
+            }
+        }
+        double mu1 = repeats * p1;
+        double mu2 = repeats * p2;
+        double sigma1 = sqrt(repeats * p1 * (1 - p1));
+        double sigma2 = sqrt(repeats * p2 * (1 - p2));
+        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
+        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        int c3 = 0;
+        double p1 = 0.5;
+        double p2 = 0.25;
+        double p3 = 0.25;
+        probabilities.push_back(p1);
+        probabilities.push_back(p2);
+        probabilities.push_back(p3);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for (int i = 0; i < repeats; ++i){
+            int n = gen();
+            if (n == 0) {
+                ++c1;
+            } else if (n == 1) {
+                ++c2;
+            } else if (n == 2) {
+                ++c3;
+            }
+        }
+        double mu1 = repeats * p1;
+        double mu2 = repeats * p2;
+        double mu3 = repeats * p3;
+        double sigma1 = sqrt(repeats * p1 * (1 - p1));
+        double sigma2 = sqrt(repeats * p2 * (1 - p2));
+        double sigma3 = sqrt(repeats * p3 * (1 - p3));
+        ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
+        ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
+        ASSERT_TRUE(fabs(c3 - mu3) < 4*sigma3);
+    }
+}
+
+// Test the reset function of generator
+TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) {
+    const int repeats = 100000;
+    vector<double> probabilities;
+    int c1 = 0;
+    int c2 = 0;
+    double p1 = 0.8;
+    double p2 = 0.2;
+    probabilities.push_back(p1);
+    probabilities.push_back(p2);
+    WeightedRandomIntegerGenerator gen(probabilities);
+    for (int i = 0; i < repeats; ++i) {
+        int n = gen();
+        if (n == 0) {
+            ++c1;
+        } else if (n == 1) {
+            ++c2;
+        }
+    }
+    double mu1 = repeats * p1;
+    double mu2 = repeats * p2;
+    double sigma1 = sqrt(repeats * p1 * (1 - p1));
+    double sigma2 = sqrt(repeats * p2 * (1 - p2));
+    ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
+    ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
+
+    // Reset the probabilities
+    probabilities.clear();
+    c1 = c2 = 0;
+    p1 = 0.2;
+    p2 = 0.8;
+    probabilities.push_back(p1);
+    probabilities.push_back(p2);
+    gen.reset(probabilities);
+    for (int i = 0; i < repeats; ++i) {
+        int n = gen();
+        if (n == 0) {
+            ++c1;
+        } else if (n == 1) {
+            ++c2;
+        }
+    }
+    mu1 = repeats * p1;
+    mu2 = repeats * p2;
+    sigma1 = sqrt(repeats * p1 * (1 - p1));
+    sigma2 = sqrt(repeats * p2 * (1 - p2));
+    ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1);
+    ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2);
+}
+
+} // namespace random
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/tests/run_unittests.cc b/src/lib/util/tests/run_unittests.cc
new file mode 100644
index 0000000..bd3c4c9
--- /dev/null
+++ b/src/lib/util/tests/run_unittests.cc
@@ -0,0 +1,21 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/util/tests/sha1_unittest.cc b/src/lib/util/tests/sha1_unittest.cc
new file mode 100644
index 0000000..6d62349
--- /dev/null
+++ b/src/lib/util/tests/sha1_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+#include <string>
+
+#include <util/hash/sha1.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+
+namespace isc {
+namespace util {
+namespace hash {
+class Sha1Test : public ::testing::Test {
+protected:
+    Sha1Test() {}
+};
+
+// Tests copied from RFC 3174
+TEST_F(Sha1Test, Test1) {
+    SHA1Context sha;
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
+        0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "abc", 3));
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test2) {
+    SHA1Context sha;
+    string test("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
+        0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
+                           test.length()));
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test3) {
+    SHA1Context sha;
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e,
+        0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    for (int i = 0; i < 1000000; i++) {
+        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "a", 1));
+    }
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test4) {
+    SHA1Context sha;
+    string test("01234567012345670123456701234567"
+                "01234567012345670123456701234567");
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0xde, 0xa3, 0x56, 0xa2, 0xcd, 0xdd, 0x90, 0xc7, 0xa7, 0xec,
+        0xed, 0xc5, 0xeb, 0xb5, 0x63, 0x93, 0x4f, 0x46, 0x04, 0x52
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    for (int i = 0; i < 10; i++) {
+        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
+                               test.length()));
+    }
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+} // namespace hash
+} // namespace util
+} // namespace isc
+
diff --git a/src/lib/util/tests/strutil_unittest.cc b/src/lib/util/tests/strutil_unittest.cc
new file mode 100644
index 0000000..cd3a9ca
--- /dev/null
+++ b/src/lib/util/tests/strutil_unittest.cc
@@ -0,0 +1,215 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <util/strutil.h>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+class StringUtilTest : public ::testing::Test {
+protected:
+    StringUtilTest()
+    {
+    }
+};
+
+
+// Check for slash replacement
+
+TEST_F(StringUtilTest, Slash) {
+
+    string instring = "";
+    isc::util::str::normalizeSlash(instring);
+    EXPECT_EQ("", instring);
+
+    instring = "C:\\A\\B\\C.D";
+    isc::util::str::normalizeSlash(instring);
+    EXPECT_EQ("C:/A/B/C.D", instring);
+
+    instring = "// \\ //";
+    isc::util::str::normalizeSlash(instring);
+    EXPECT_EQ("// / //", instring);
+}
+
+// Check that leading and trailing space trimming works
+
+TEST_F(StringUtilTest, Trim) {
+
+    // Empty and full string.
+    EXPECT_EQ("", isc::util::str::trim(""));
+    EXPECT_EQ("abcxyz", isc::util::str::trim("abcxyz"));
+
+    // Trim right-most blanks
+    EXPECT_EQ("ABC", isc::util::str::trim("ABC   "));
+    EXPECT_EQ("ABC", isc::util::str::trim("ABC\t\t  \n\t"));
+
+    // Left-most blank trimming
+    EXPECT_EQ("XYZ", isc::util::str::trim("  XYZ"));
+    EXPECT_EQ("XYZ", isc::util::str::trim("\t\t  \tXYZ"));
+
+    // Right and left, with embedded spaces
+    EXPECT_EQ("MN \t OP", isc::util::str::trim("\t\tMN \t OP \t"));
+}
+
+// Check tokenization.  Note that ASSERT_EQ is used to check the size of the
+// returned vector; if not as expected, the following references may be invalid
+// so should not be used.
+
+TEST_F(StringUtilTest, Tokens) {
+    vector<string>  result;
+
+    // Default delimiters
+
+    // Degenerate cases
+    result = isc::util::str::tokens("");          // Empty string
+    EXPECT_EQ(0, result.size());
+
+    result = isc::util::str::tokens(" \n ");      // String is all delimiters
+    EXPECT_EQ(0, result.size());
+
+    result = isc::util::str::tokens("abc");       // String has no delimiters
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("abc"), result[0]);
+
+    // String containing leading and/or trailing delimiters, no embedded ones.
+    result = isc::util::str::tokens("\txyz");     // One leading delimiter
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("xyz"), result[0]);
+
+    result = isc::util::str::tokens("\t \nxyz");  // Multiple leading delimiters
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("xyz"), result[0]);
+
+    result = isc::util::str::tokens("xyz\n");     // One trailing delimiter
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("xyz"), result[0]);
+
+    result = isc::util::str::tokens("xyz  \t");   // Multiple trailing
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("xyz"), result[0]);
+
+    result = isc::util::str::tokens("\t xyz \n"); // Leading and trailing
+    ASSERT_EQ(1, result.size());
+    EXPECT_EQ(string("xyz"), result[0]);
+
+    // Embedded delimiters
+    result = isc::util::str::tokens("abc\ndef");  // 2 tokens, one separator
+    ASSERT_EQ(2, result.size());
+    EXPECT_EQ(string("abc"), result[0]);
+    EXPECT_EQ(string("def"), result[1]);
+
+    result = isc::util::str::tokens("abc\t\t\ndef");  // 2 tokens, 3 separators
+    ASSERT_EQ(2, result.size());
+    EXPECT_EQ(string("abc"), result[0]);
+    EXPECT_EQ(string("def"), result[1]);
+
+    result = isc::util::str::tokens("abc\n  \tdef\t\tghi");
+    ASSERT_EQ(3, result.size());                // Multiple tokens, many delims
+    EXPECT_EQ(string("abc"), result[0]);
+    EXPECT_EQ(string("def"), result[1]);
+    EXPECT_EQ(string("ghi"), result[2]);
+
+    // Embedded and non-embedded delimiters
+
+    result = isc::util::str::tokens("\t\t  \nabc\n  \tdef\t\tghi   \n\n");
+    ASSERT_EQ(3, result.size());                // Multiple tokens, many delims
+    EXPECT_EQ(string("abc"), result[0]);
+    EXPECT_EQ(string("def"), result[1]);
+    EXPECT_EQ(string("ghi"), result[2]);
+
+    // Non-default delimiter
+    result = isc::util::str::tokens("alpha/beta/ /gamma//delta/epsilon/", "/");
+    ASSERT_EQ(6, result.size());
+    EXPECT_EQ(string("alpha"), result[0]);
+    EXPECT_EQ(string("beta"), result[1]);
+    EXPECT_EQ(string(" "), result[2]);
+    EXPECT_EQ(string("gamma"), result[3]);
+    EXPECT_EQ(string("delta"), result[4]);
+    EXPECT_EQ(string("epsilon"), result[5]);
+
+    // Non-default delimiters (plural)
+    result = isc::util::str::tokens("+*--alpha*beta+ -gamma**delta+epsilon-+**",
+        "*+-");
+    ASSERT_EQ(6, result.size());
+    EXPECT_EQ(string("alpha"), result[0]);
+    EXPECT_EQ(string("beta"), result[1]);
+    EXPECT_EQ(string(" "), result[2]);
+    EXPECT_EQ(string("gamma"), result[3]);
+    EXPECT_EQ(string("delta"), result[4]);
+    EXPECT_EQ(string("epsilon"), result[5]);
+}
+
+// Changing case
+
+TEST_F(StringUtilTest, ChangeCase) {
+    string mixed("abcDEFghiJKLmno123[]{=+--+]}");
+    string upper("ABCDEFGHIJKLMNO123[]{=+--+]}");
+    string lower("abcdefghijklmno123[]{=+--+]}");
+
+    string test = mixed;
+    isc::util::str::lowercase(test);
+    EXPECT_EQ(lower, test);
+
+    test = mixed;
+    isc::util::str::uppercase(test);
+    EXPECT_EQ(upper, test);
+}
+
+// Formatting
+
+TEST_F(StringUtilTest, Formatting) {
+
+    vector<string> args;
+    args.push_back("arg1");
+    args.push_back("arg2");
+    args.push_back("arg3");
+
+    string format1 = "This is a string with no tokens";
+    EXPECT_EQ(format1, isc::util::str::format(format1, args));
+
+    string format2 = "";    // Empty string
+    EXPECT_EQ(format2, isc::util::str::format(format2, args));
+
+    string format3 = "   ";    // Empty string
+    EXPECT_EQ(format3, isc::util::str::format(format3, args));
+
+    string format4 = "String with %d non-string tokens %lf";
+    EXPECT_EQ(format4, isc::util::str::format(format4, args));
+
+    string format5 = "String with %s correct %s number of tokens %s";
+    string result5 = "String with arg1 correct arg2 number of tokens arg3";
+    EXPECT_EQ(result5, isc::util::str::format(format5, args));
+
+    string format6 = "String with %s too %s few tokens";
+    string result6 = "String with arg1 too arg2 few tokens";
+    EXPECT_EQ(result6, isc::util::str::format(format6, args));
+
+    string format7 = "String with %s too %s many %s tokens %s !";
+    string result7 = "String with arg1 too arg2 many arg3 tokens %s !";
+    EXPECT_EQ(result7, isc::util::str::format(format7, args));
+
+    string format8 = "String with embedded%s%s%stokens";
+    string result8 = "String with embeddedarg1arg2arg3tokens";
+    EXPECT_EQ(result8, isc::util::str::format(format8, args));
+
+    // Handle an empty vector
+    args.clear();
+    string format9 = "%s %s";
+    EXPECT_EQ(format9, isc::util::str::format(format9, args));
+}
diff --git a/src/lib/util/tests/time_utilities_unittest.cc b/src/lib/util/tests/time_utilities_unittest.cc
new file mode 100644
index 0000000..9261ea0
--- /dev/null
+++ b/src/lib/util/tests/time_utilities_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+
+#include <time.h>
+
+#include <util/time_utilities.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::util;
+
+// See time_utilities.cc
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+
+class DNSSECTimeTest : public ::testing::Test {
+protected:
+    ~DNSSECTimeTest() {
+        detail::gettimeFunction = NULL;
+    }
+};
+
+TEST_F(DNSSECTimeTest, fromText) {
+    // In most cases (in practice) the 32-bit and 64-bit versions should
+    // behave identically, so we'll mainly test the 32-bit version, which
+    // will be more commonly used in actual code (because many of the wire
+    // format time field are 32-bit).  The subtle cases where these two
+    // return different values will be tested at the end of this test case.
+
+    // These are bogus and should be rejected
+    EXPECT_THROW(timeFromText32("2011 101120000"), InvalidTime);
+    EXPECT_THROW(timeFromText32("201101011200-0"), InvalidTime);
+
+    // Short length (or "decimal integer" version of representation;
+    // it's valid per RFC4034, but is not supported in this implementation)
+    EXPECT_THROW(timeFromText32("20100223"), InvalidTime);
+
+    // Leap year checks
+    EXPECT_THROW(timeFromText32("20110229120000"), InvalidTime);
+    EXPECT_THROW(timeFromText32("21000229120000"), InvalidTime);
+    EXPECT_NO_THROW(timeFromText32("20000229120000"));
+    EXPECT_NO_THROW(timeFromText32("20120229120000"));
+
+    // unusual case: this implementation allows SS=60 for "leap seconds"
+    EXPECT_NO_THROW(timeFromText32("20110101120060"));
+
+    // Out of range parameters
+    EXPECT_THROW(timeFromText32("19100223214617"), InvalidTime); // YY<1970
+    EXPECT_THROW(timeFromText32("20110001120000"), InvalidTime); // MM=00
+    EXPECT_THROW(timeFromText32("20111301120000"), InvalidTime); // MM=13
+    EXPECT_THROW(timeFromText32("20110100120000"), InvalidTime); // DD=00
+    EXPECT_THROW(timeFromText32("20110132120000"), InvalidTime); // DD=32
+    EXPECT_THROW(timeFromText32("20110431120000"), InvalidTime); // 'Apr31'
+    EXPECT_THROW(timeFromText32("20110101250000"), InvalidTime); // HH=25
+    EXPECT_THROW(timeFromText32("20110101126000"), InvalidTime); // mm=60
+    EXPECT_THROW(timeFromText32("20110101120061"), InvalidTime); // SS=61
+
+    // Feb 7, 06:28:15 UTC 2106 is the possible maximum time that can be
+    // represented as an unsigned 32bit integer without overflow.
+    EXPECT_EQ(4294967295LU, timeFromText32("21060207062815"));
+
+    // After that, timeFromText32() should start returning the second count
+    // modulo 2^32.
+    EXPECT_EQ(0, timeFromText32("21060207062816"));
+    EXPECT_EQ(10, timeFromText32("21060207062826"));
+
+    // On the other hand, the 64-bit version should return monotonically
+    // increasing counters.
+    EXPECT_EQ(4294967296LL, timeFromText64("21060207062816"));
+    EXPECT_EQ(4294967306LL, timeFromText64("21060207062826"));
+}
+
+// This helper templated function tells timeToText32 a faked current time.
+// The template parameter is that faked time in the form of int64_t seconds
+// since epoch.
+template <int64_t NOW>
+int64_t
+testGetTime() {
+    return (NOW);
+}
+
+// Seconds since epoch for the year 10K eve.  Commonly used in some tests
+// below.
+const uint64_t YEAR10K_EVE = 253402300799LL;
+
+TEST_F(DNSSECTimeTest, toText) {
+    // Check a basic case with the default (normal) gettimeFunction
+    // based on the "real current time".
+    // Note: this will fail after year 2078, but at that point we won't use
+    // this program anyway:-)
+    EXPECT_EQ("20100311233000", timeToText32(1268350200));
+
+    // Set the current time to: Feb 18 09:04:14 UTC 2012 (an arbitrary choice
+    // in the range of the first half of uint32 since epoch).
+    detail::gettimeFunction = testGetTime<1329555854LL>;
+
+    // Test the "year 2038" problem.
+    // Check the result of toText() for "INT_MIN" in int32_t.  It's in the
+    // 68-year range from the faked current time, so the result should be
+    // in year 2038, instead of 1901.
+    EXPECT_EQ("20380119031408", timeToText64(0x80000000L));
+    EXPECT_EQ("20380119031408", timeToText32(0x80000000L));
+
+    // A controversial case: what should we do with "-1"?  It's out of range
+    // in future, but according to RFC time before epoch doesn't seem to be
+    // considered "in-range" either.  Our toText() implementation handles
+    // this range as a special case and always treats them as future time
+    // until year 2038.  This won't be a real issue in practice, though,
+    // since such too large values won't be used in actual deployment by then.
+    EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
+
+    // After the singular point of year 2038, the first half of uint32 can
+    // point to a future time.
+    // Set the current time to: Apr 1 00:00:00 UTC 2038:
+    detail::gettimeFunction = testGetTime<2153692800LL>;
+    // then time "10" is Feb 7 06:28:26 UTC 2106
+    EXPECT_EQ("21060207062826", timeToText32(10));
+    // in 64-bit, it's 2^32 + 10
+    EXPECT_EQ("21060207062826", timeToText64(0x10000000aLL));
+
+    // After year 2106, the upper half of uint32 can point to past time
+    // (as it should).
+    detail::gettimeFunction = testGetTime<0x10000000aLL>;
+    EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
+
+    // Try very large time value.  Actually it's the possible farthest time
+    // that can be represented in the form of YYYYMMDDHHmmSS.
+    EXPECT_EQ("99991231235959", timeToText64(YEAR10K_EVE));
+    detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
+    EXPECT_EQ("99991231235959", timeToText32(4294197631LU));
+}
+
+TEST_F(DNSSECTimeTest, overflow) {
+    // Jan 1, Year 10,000.
+    EXPECT_THROW(timeToText64(253402300800LL), InvalidTime);
+    detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
+    EXPECT_THROW(timeToText32(4294197632LU), InvalidTime);
+}
+
+}
diff --git a/src/lib/util/time_utilities.cc b/src/lib/util/time_utilities.cc
new file mode 100644
index 0000000..9303ab5
--- /dev/null
+++ b/src/lib/util/time_utilities.cc
@@ -0,0 +1,207 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+
+#include <sys/time.h>
+
+#include <string>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <stdio.h>
+#include <time.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/time_utilities.h>
+
+using namespace std;
+
+namespace {
+int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+inline bool
+isLeap(const int y) {
+    return ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0);
+}
+
+unsigned int
+yearSecs(const int year) {
+    return ((isLeap(year) ? 366 : 365 ) * 86400);
+}
+
+unsigned int
+monthSecs(const int month, const int year) {
+    return ((days[month] + ((month == 1 && isLeap(year)) ? 1 : 0 )) * 86400);
+}
+}
+
+namespace isc {
+namespace util {
+
+string
+timeToText64(uint64_t value) {
+    struct tm tm;
+    unsigned int secs;
+
+    // We cannot rely on gmtime() because time_t may not be of 64 bit
+    // integer.  The following conversion logic is borrowed from BIND 9.
+    tm.tm_year = 70;
+    while ((secs = yearSecs(tm.tm_year + 1900)) <= value) {
+        value -= secs;
+        ++tm.tm_year;
+        if (tm.tm_year + 1900 > 9999) {
+            isc_throw(InvalidTime,
+                      "Time value out of range (year > 9999): " <<
+                      tm.tm_year + 1900);
+        }
+    }
+    tm.tm_mon = 0;
+    while ((secs = monthSecs(tm.tm_mon, tm.tm_year + 1900)) <= value) {
+        value -= secs;
+        tm.tm_mon++;
+    }
+    tm.tm_mday = 1;
+    while (86400 <= value) {
+        value -= 86400;
+        ++tm.tm_mday;
+    }
+    tm.tm_hour = 0;
+    while (3600 <= value) {
+        value -= 3600;
+        ++tm.tm_hour;
+    }
+    tm.tm_min = 0;
+    while (60 <= value) {
+        value -= 60;
+        ++tm.tm_min;
+    }
+    tm.tm_sec = value;    // now t < 60, so this substitution is safe.
+
+    ostringstream oss;
+    oss << setfill('0')
+        << setw(4) << tm.tm_year + 1900
+        << setw(2) << tm.tm_mon + 1
+        << setw(2) << tm.tm_mday
+        << setw(2) << tm.tm_hour
+        << setw(2) << tm.tm_min
+        << setw(2) << tm.tm_sec;
+    return (oss.str());
+}
+
+// timeToText32() below uses the current system time.  To test it with
+// unusual current time values we introduce the following function pointer;
+// when it's non NULL, we call it to get the (normally faked) current time.
+// Otherwise we use the standard gettimeofday(2).  This hook is specifically
+// intended for testing purposes, so, even if it's visible outside of this
+// library, it's not even declared in a header file.
+namespace detail {
+int64_t (*gettimeFunction)() = NULL;
+
+int64_t
+gettimeWrapper() {
+    if (gettimeFunction != NULL) {
+        return (gettimeFunction());
+    }
+
+    struct timeval now;
+    gettimeofday(&now, NULL);
+
+    return (static_cast<int64_t>(now.tv_sec));
+}
+}
+
+string
+timeToText32(const uint32_t value) {
+    // We first adjust the time to the closest epoch based on the current time.
+    // Note that the following variables must be signed in order to handle
+    // time until year 2038 correctly.
+    const int64_t start = detail::gettimeWrapper() - 0x7fffffff;
+    int64_t base = 0;
+    int64_t t;
+    while ((t = (base + value)) < start) {
+        base += 0x100000000LL;
+    }
+
+    // Then convert it to text.
+    return (timeToText64(t));
+}
+
+namespace {
+const size_t DATE_LEN = 14;      // YYYYMMDDHHmmSS
+
+inline void
+checkRange(const int min, const int max, const int value,
+           const string& valname)
+{
+    if ((value >= min) && (value <= max)) {
+        return;
+    }
+    isc_throw(InvalidTime, "Invalid " << valname << "value: " << value);
+}
+}
+
+uint64_t
+timeFromText64(const string& time_txt) {
+    // Confirm the source only consists digits.  sscanf() allows some
+    // minor exceptions.
+    for (int i = 0; i < time_txt.length(); ++i) {
+        if (!isdigit(time_txt.at(i))) {
+            isc_throw(InvalidTime, "Couldn't convert non-numeric time value: "
+                      << time_txt);
+        }
+    }
+
+    int year, month, day, hour, minute, second;
+    if (time_txt.length() != DATE_LEN ||
+        sscanf(time_txt.c_str(), "%4d%2d%2d%2d%2d%2d",
+               &year, &month, &day, &hour, &minute, &second) != 6)
+    {
+        isc_throw(InvalidTime, "Couldn't convert time value: " << time_txt);
+    }
+
+    checkRange(1970, 9999, year, "year");
+    checkRange(1, 12, month, "month");
+    checkRange(1, days[month - 1] + ((month == 2 && isLeap(year)) ? 1 : 0),
+            day, "day");
+    checkRange(0, 23, hour, "hour");
+    checkRange(0, 59, minute, "minute");
+    checkRange(0, 60, second, "second"); // 60 == leap second.
+
+    uint64_t timeval = second + (60 * minute) + (3600 * hour) +
+        ((day - 1) * 86400);
+    for (int m = 0; m < (month - 1); ++m) {
+            timeval += days[m] * 86400;
+    }
+    if (isLeap(year) && month > 2) {
+            timeval += 86400;
+    }
+    for (int y = 1970; y < year; ++y) {
+        timeval += ((isLeap(y) ? 366 : 365 ) * 86400);
+    }
+
+    return (timeval);
+}
+
+uint32_t
+timeFromText32(const string& time_txt) {
+    // The implicit conversion from uint64_t to uint32_t should just work here,
+    // because we only need to drop higher 32 bits.
+    return (timeFromText64(time_txt));
+}
+
+}
+}
diff --git a/src/lib/util/time_utilities.h b/src/lib/util/time_utilities.h
new file mode 100644
index 0000000..a53089d
--- /dev/null
+++ b/src/lib/util/time_utilities.h
@@ -0,0 +1,173 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TIME_UTILITIES_H
+#define __TIME_UTILITIES_H 1
+
+#include <string>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <exceptions/exceptions.h>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace util {
+
+///
+/// \brief A standard DNS (or ISC) module exception that is thrown if 
+/// a time conversion function encounters bad input
+///
+class InvalidTime : public Exception {
+public:
+    InvalidTime(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+namespace detail {
+/// Return the current time in seconds
+///
+/// This function returns the "current" time in seconds from epoch
+/// (00:00:00 January 1, 1970) as a 64-bit signed integer.  The return
+/// value can represent a point of time before epoch as a negative number.
+///
+/// This function is provided to help test time conscious implementations
+/// such as DNSSEC and TSIG signatures.  It is difficult to test them with
+/// an unusual or a specifically chosen "current" via system-provided
+/// library functions to get time.  This function acts as a straightforward
+/// wrapper of such a library function, but provides test code with a hook
+/// to return an arbitrary time value: if \c isc::util::detail::gettimeFunction
+/// is set to a pointer of function that returns 64-bit signed integer,
+/// \c gettimeWrapper() calls that function instead of the system library.
+///
+/// This hook variable is specifically intended for testing purposes, so,
+/// even if it's visible outside of this library, it's not even declared in a
+/// header file.
+///
+/// If the implementation doesn't need to be tested with faked current time,
+/// it should simply use the system supplied library function instead of
+/// this one.
+int64_t gettimeWrapper();
+}
+
+///
+/// \name DNSSEC time conversion functions.
+///
+/// These functions convert between times represented in seconds (in integer)
+/// since epoch and those in the textual form used in the RRSIG records.
+/// For integers we provide both 32-bit and 64-bit versions.
+/// The RRSIG expiration and inception fields are both 32-bit unsigned
+/// integers, so 32-bit versions would be more useful for protocol operations.
+/// However, with 32-bit integers we need to take into account wrap-around
+/// points and compare values using the serial number arithmetic as specified
+/// in RFC4034, which would be more error prone.  We therefore provide 64-bit
+/// versions, too.
+///
+/// The timezone is always UTC for these functions.
+//@{
+/// Convert textual DNSSEC time to integer, 64-bit version.
+///
+/// The textual form must only consist of digits and be in the form of
+/// YYYYMMDDHHmmSS, where:
+/// - YYYY must be between 1970 and 9999
+/// - MM must be between 01 and 12
+/// - DD must be between 01 and 31 and must be a valid day for the month
+///   represented in 'MM'.  For example, if MM is 04, DD cannot be 31.
+///   DD can be 29 when MM is 02 only when YYYY is a leap year.
+/// - HH must be between 00 and 23
+/// - mm must be between 00 and 59
+/// - SS must be between 00 and 60
+///
+/// For all fields the range includes the begin and end values.  Note that
+/// 60 is allowed for 'SS', intending a leap second, although in real operation
+/// it's unlikely to be specified.
+///
+/// If the given text is valid, this function converts it to an unsigned
+/// 64-bit number of seconds since epoch (1 January 1970 00:00:00) and returns
+/// the converted value.  64 bits are sufficient to represent all possible
+/// values for the valid format uniquely, so there is no overflow.
+///
+/// \note RFC4034 also defines the textual form of an unsigned decimal integer
+/// for the corresponding time in seconds.  This function doesn't support
+/// this form, and if given it throws an exception of class \c InvalidTime.
+///
+/// \exception InvalidTime The given textual representation is invalid.
+///
+/// \param time_txt Textual time in the form of YYYYMMDDHHmmSS
+/// \return Seconds since epoch corresponding to \c time_txt
+uint64_t
+timeFromText64(const std::string& time_txt);
+
+/// Convert textual DNSSEC time to integer, 32-bit version.
+///
+/// This version is the same as \c timeFromText64() except that the return
+/// value is wrapped around to an unsigned 32-bit integer, simply dropping
+/// the upper 32 bits.
+uint32_t
+timeFromText32(const std::string& time_txt);
+
+/// Convert integral DNSSEC time to textual form, 64-bit version.
+///
+/// This function takes an integer that would be seconds since epoch and
+/// converts it in the form of YYYYMMDDHHmmSS.  For example, if \c value is
+/// 0, it returns "19700101000000".  If the value corresponds to a point
+/// of time on and after year 10,000, which cannot be represented in the
+/// YYYY... form, an exception of class \c InvalidTime will be thrown.
+///
+/// \exception InvalidTime The given time specifies on or after year 10,000.
+/// \exception Other A standard exception, if resource allocation for the
+/// returned text fails.
+///
+/// \param value Seconds since epoch to be converted.
+/// \return Textual representation of \c value in the form of YYYYMMDDHHmmSS.
+std::string
+timeToText64(uint64_t value);
+
+/// Convert integral DNSSEC time to textual form, 32-bit version.
+///
+/// This version is the same as \c timeToText64(), but the time value
+/// is expected to be the lower 32 bits of the full 64-bit value.
+/// These two will be different on and after a certain point of time
+/// in year 2106, so this function internally resolves the ambiguity
+/// using the current system time at the time of function call;
+/// it first identifies the range of [N*2^32 - 2^31, N*2^32 + 2^31)
+/// that contains the current time, and interprets \c value in the context
+/// of that range.  It then applies the same process as \c timeToText64().
+///
+/// There is one important exception in this processing, however.
+/// Until 19 Jan 2038 03:14:08 (2^31 seconds since epoch), this range
+/// would contain time before epoch.  In order to ensure the returned
+/// value is also a valid input to \c timeFromText, this function uses
+/// a special range [0, 2^32) until that time.  As a result, all upper
+/// half of the 32-bit values are treated as a future time.  For example,
+/// 2^32-1 (the highest value in 32-bit unsigned integers) will be converted
+/// to "21060207062815", instead of "19691231235959".
+std::string
+timeToText32(const uint32_t value);
+
+//@}
+}
+}
+
+#endif  // __DNSSECTIME_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am
new file mode 100644
index 0000000..340cd1f
--- /dev/null
+++ b/src/lib/util/unittests/Makefile.am
@@ -0,0 +1,10 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+lib_LTLIBRARIES = libutil_unittests.la
+libutil_unittests_la_SOURCES = fork.h fork.cc resolver.h
+libutil_unittests_la_SOURCES += newhook.h newhook.cc
+libutil_unittests_la_SOURCES += testdata.h testdata.cc
+libutil_unittests_la_SOURCES += textdata.h
+
+CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/util/unittests/README b/src/lib/util/unittests/README
new file mode 100644
index 0000000..0ed888f
--- /dev/null
+++ b/src/lib/util/unittests/README
@@ -0,0 +1,5 @@
+This directory contains some code that is useful while writing various
+unittest code. It doesn't contain any code that would actually run in
+bind10.
+
+Because this is a test code, we do not test it explicitly.
diff --git a/src/lib/util/unittests/fork.cc b/src/lib/util/unittests/fork.cc
new file mode 100644
index 0000000..3414a3c
--- /dev/null
+++ b/src/lib/util/unittests/fork.cc
@@ -0,0 +1,145 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "fork.h"
+
+#include <util/io/fd.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <cerrno>
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace isc::util::io;
+
+namespace {
+
+// Just a NOP function to ignore a signal but let it interrupt function.
+void no_handler(int) { }
+
+};
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+bool
+process_ok(pid_t process) {
+    // Create a timeout
+    struct sigaction ignored, original;
+    memset(&ignored, 0, sizeof ignored);
+    ignored.sa_handler = no_handler;
+    if (sigaction(SIGALRM, &ignored, &original)) {
+        return false;
+    }
+    // It is long, but if everything is OK, it'll not happen
+    alarm(10);
+    int status;
+    int result(waitpid(process, &status, 0) == -1);
+    // Cancel the alarm and return the original handler
+    alarm(0);
+    if (sigaction(SIGALRM, &original, NULL)) {
+        return false;
+    }
+    // Check what we found out
+    if (result) {
+        if (errno == EINTR)
+            kill(process, SIGTERM);
+        return false;
+    }
+    return WIFEXITED(status) && WEXITSTATUS(status) == 0;
+}
+
+/*
+ * This creates a pipe, forks and feeds the pipe with given data.
+ * Used to provide the input in non-blocking/asynchronous way.
+ */
+pid_t
+provide_input(int *read_pipe, const void *input, const size_t length)
+{
+    int pipes[2];
+    if (pipe(pipes)) {
+        return -1;
+    }
+    *read_pipe = pipes[0];
+    pid_t pid(fork());
+    if (pid) { // We are in the parent
+        return pid;
+    } else { // This is in the child, just puth the data there
+        close(pipes[0]);
+        if (!write_data(pipes[1], input, length)) {
+            exit(1);
+        } else {
+            close(pipes[1]);
+            exit(0);
+        }
+    }
+}
+
+/*
+ * This creates a pipe, forks and reads the pipe and compares it
+ * with given data. Used to check output of run in asynchronous way.
+ */
+pid_t
+check_output(int *write_pipe, const void *output, const size_t length)
+{
+    int pipes[2];
+    if (pipe(pipes)) {
+        return -1;
+    }
+    *write_pipe = pipes[1];
+    pid_t pid(fork());
+    if (pid) { // We are in parent
+        close(pipes[0]);
+        return pid;
+    } else {
+        close(pipes[1]);
+        // We don't return the memory, but we're in tests and end this process
+        // right away.
+        unsigned char *buffer = new unsigned char[length + 1];
+        // Try to read one byte more to see if the output ends here
+        size_t got_length(read_data(pipes[0], buffer, length + 1));
+        bool ok(true);
+        if (got_length != length) {
+            fprintf(stderr, "Different length (expected %u, got %u)\n",
+                static_cast<unsigned>(length),
+                static_cast<unsigned>(got_length));
+            ok = false;
+        }
+        if(!ok || memcmp(buffer, output, length)) {
+            const unsigned char *output_c(static_cast<const unsigned char *>(
+                output));
+            // If they differ, print what we have
+            for(size_t i(0); i != got_length; ++ i) {
+                fprintf(stderr, "%02hhx", buffer[i]);
+            }
+            fprintf(stderr, "\n");
+            for(size_t i(0); i != length; ++ i) {
+                fprintf(stderr, "%02hhx", output_c[i]);
+            }
+            fprintf(stderr, "\n");
+            exit(1);
+        } else {
+            exit(0);
+        }
+    }
+}
+
+}
+}
+}
diff --git a/src/lib/util/unittests/fork.h b/src/lib/util/unittests/fork.h
new file mode 100644
index 0000000..3331cfa
--- /dev/null
+++ b/src/lib/util/unittests/fork.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_UNITTESTS_FORK_H
+#define __UTIL_UNITTESTS_FORK_H 1
+
+#include <unistd.h>
+
+/**
+ * @file fork.h
+ * @short Help functions to fork the test case process.
+ * Various functions to fork a process and feed some data to pipe, check
+ * its output and such lives here.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/**
+ * @short Checks that a process terminates correctly.
+ * Waits for a process to terminate (with a short timeout, this should be
+ * used whan the process is about tu terminate) and checks its exit code.
+ *
+ * @return True if the process terminates with 0, false otherwise.
+ * @param process The ID of process to wait for.
+ */
+bool
+process_ok(pid_t process);
+
+pid_t
+provide_input(int *read_pipe, const void *input, const size_t length);
+
+pid_t
+check_output(int *write_pipe, const void *output, const size_t length);
+
+} // End of the namespace
+}
+}
+
+#endif // __UTIL_UNITTESTS_FORK_H
diff --git a/src/lib/util/unittests/newhook.cc b/src/lib/util/unittests/newhook.cc
new file mode 100644
index 0000000..9e545a5
--- /dev/null
+++ b/src/lib/util/unittests/newhook.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdlib.h>
+
+#include <new>
+#include <stdexcept>
+
+#include "newhook.h"
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+void*
+operator new(size_t size) throw(std::bad_alloc) {
+    if (isc::util::unittests::force_throw_on_new &&
+        size == isc::util::unittests::throw_size_on_new) {
+        throw std::bad_alloc();
+    }
+    void* p = malloc(size);
+    if (p == NULL) {
+        throw std::bad_alloc();
+    }
+    return (p);
+}
+
+void
+operator delete(void* p) throw() {
+    if (p != NULL) {
+        free(p);
+    }
+}
+#endif
+
+namespace isc {
+namespace util {
+namespace unittests {
+bool force_throw_on_new = false;
+size_t throw_size_on_new = 0;
+}
+}
+}
diff --git a/src/lib/util/unittests/newhook.h b/src/lib/util/unittests/newhook.h
new file mode 100644
index 0000000..7eb8ade
--- /dev/null
+++ b/src/lib/util/unittests/newhook.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_UNITTESTS_NEWHOOK_H
+#define __UTIL_UNITTESTS_NEWHOOK_H 1
+
+/**
+ * @file newhook.h
+ * @short Enable the use of special operator new that throws for testing.
+ *
+ * This small utility allows a test case to force the global operator new
+ * to throw for a given size to test a case where memory allocation fails
+ * (which normally doesn't happen).  To enable the feature, everything must
+ * be built with defining ENABLE_CUSTOM_OPERATOR_NEW beforehand, and set
+ * \c force_throw_on_new to \c true and \c throw_size_on_new to the size
+ * of data that should trigger the exception, immediately before starting
+ * the specific test that needs the exception.
+ *
+ * Example:
+ * \code #include <util/unittests/newhook.h>
+ * ...
+ * TEST(SomeTest, newException) {
+ *        isc::util::unittests::force_throw_on_new = true;
+ *        isc::util::unittests::throw_size_on_new = sizeof(Foo);
+ *        try {
+ *            // this will do 'new Foo()' internally and should throw
+ *            createFoo();
+ *            isc::util::unittests::force_throw_on_new = false;
+ *            ASSERT_FALSE(true) << "Expected throw on new";
+ *        } catch (const std::bad_alloc&) {
+ *            isc::util::unittests::force_throw_on_new = false;
+ *            // do some integrity check, etc, if necessary
+ *        }
+ * } \endcode
+ *
+ * Replacing the global operator new (and delete) is a dangerous technique,
+ * and triggering an exception solely based on the allocation size is not
+ * reliable, so this feature is disabled by default two-fold: The
+ * ENABLE_CUSTOM_OPERATOR_NEW build time variable, and run-time
+ * \c force_throw_on_new.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+/// Switch to enable the use of special operator new
+///
+/// This is set to \c false by default.
+extern bool force_throw_on_new;
+
+/// The allocation size that triggers an exception in the special operator new
+///
+/// This is the exact size that causes an exception to be thrown;
+/// for example, if it is set to 100, an attempt of allocating 100 bytes
+/// will result in an exception, but allocation attempt for 101 bytes won't
+/// (unless, of course, memory is really exhausted and allocation really
+/// fails).
+///
+/// The default value is 0.  The value of this variable has no meaning
+/// unless the use of the special operator is enabled at build time and
+/// via \c force_throw_on_new.
+extern size_t throw_size_on_new;
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_NEWHOOK_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/resolver.h b/src/lib/util/unittests/resolver.h
new file mode 100644
index 0000000..560a892
--- /dev/null
+++ b/src/lib/util/unittests/resolver.h
@@ -0,0 +1,193 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef UTIL_UNITTEST_RESOLVER_H
+#define UTIL_UNITTEST_RESOLVER_H
+
+/// \file resolver.h
+/// \brief Fake resolver
+
+#include <map>
+#include <dns/rrset.h>
+#include <dns/question.h>
+#include <dns/message.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrttl.h>
+#include <resolve/resolver_interface.h>
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// \brief Put rrset into a message as an answer
+inline static isc::dns::MessagePtr
+createResponseMessage(isc::dns::RRsetPtr answer_rrset)
+{
+    isc::dns::MessagePtr response(new isc::dns::Message(
+        isc::dns::Message::RENDER));
+    response->setOpcode(isc::dns::Opcode::QUERY());
+    response->setRcode(isc::dns::Rcode::NOERROR());
+    response->addRRset(isc::dns::Message::SECTION_ANSWER, answer_rrset);
+    return response;
+}
+
+/// \brief Mock resolver
+///
+/// This class pretends to be a resolver. However, it only stores the
+/// requests and can answer them right away by prepared answers. It doesn't
+/// do any real work and is intended for testing purposes.
+class TestResolver : public isc::resolve::ResolverInterface {
+    private:
+        bool checkIndex(size_t index) {
+            return (requests.size() > index);
+        }
+
+        typedef std::map<isc::dns::Question, isc::dns::RRsetPtr>
+            PresetAnswers;
+        PresetAnswers answers_;
+    public:
+        typedef std::pair<isc::dns::QuestionPtr, CallbackPtr> Request;
+        /// \brief List of requests the tested class sent trough resolve
+        std::vector<Request> requests;
+
+        /// \brief Destructor
+        ///
+        /// This is important.  All callbacks in the requests vector must be
+        /// called to remove them from internal loops.  Without this, destroying
+        /// the NSAS object will leave memory assigned.
+        ~TestResolver() {
+            for (size_t i = 0; i < requests.size(); ++i) {
+                requests[i].second->failure();
+            }
+        }
+
+        /// \brief Testing version of resolve
+        ///
+        /// If there's a prepared answer (provided by addPresetAnswer), it
+        /// answers it right away. Otherwise it just stores the request in
+        /// the requests member so it can be examined later.
+        virtual void resolve(const isc::dns::QuestionPtr& q,
+                             const CallbackPtr& c)
+        {
+            PresetAnswers::iterator it(answers_.find(*q));
+            if (it == answers_.end()) {
+                requests.push_back(Request(q, c));
+            } else {
+                if (it->second) {
+                    c->success(createResponseMessage(it->second));
+                } else {
+                    c->failure();
+                }
+            }
+        }
+
+        /// \brief Add a preset answer.
+        ///
+        /// Add a preset answer. If shared_ptr() is passed (eg. NULL),
+        /// it will generate failure. If the question is not preset,
+        /// it goes to requests and you can answer later.
+        void addPresetAnswer(const isc::dns::Question& question,
+            isc::dns::RRsetPtr answer)
+        {
+            answers_[question] = answer;
+        }
+
+        /// \brief Thrown if the query at the given index does not exist.
+        class NoSuchRequest : public std::exception { };
+
+        /// \brief Thrown if the answer does not match the query
+        class DifferentRequest : public std::exception { };
+
+        /// \brief Provides the question of request on given answer
+        isc::dns::QuestionPtr operator[](size_t index) {
+            if (index >= requests.size()) {
+                throw NoSuchRequest();
+            }
+            return (requests[index].first);
+        }
+        /// \brief Test it asks for IP addresses
+        /// Looks if the two provided requests in resolver are A and AAAA.
+        /// Sorts them so index1 is A.
+        ///
+        /// Returns false if there aren't enough elements
+        bool asksIPs(const isc::dns::Name& name, size_t index1,
+                     size_t index2)
+        {
+            size_t max = (index1 < index2) ? index2 : index1;
+            if (!checkIndex(max)) {
+                return false;
+            }
+            EXPECT_EQ(name, (*this)[index1]->getName());
+            EXPECT_EQ(name, (*this)[index2]->getName());
+            EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index1]->getClass());
+            EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index2]->getClass());
+            // If they are the other way around, swap
+            if ((*this)[index1]->getType() == isc::dns::RRType::AAAA() &&
+                (*this)[index2]->getType() == isc::dns::RRType::A())
+            {
+                TestResolver::Request tmp((*this).requests[index1]);
+                (*this).requests[index1] =
+                    (*this).requests[index2];
+                (*this).requests[index2] = tmp;
+            }
+            // Check the correct addresses
+            EXPECT_EQ(isc::dns::RRType::A(), (*this)[index1]->getType());
+            EXPECT_EQ(isc::dns::RRType::AAAA(), (*this)[index2]->getType());
+            return (true);
+        }
+
+        /// \brief Answer a request
+        /// Sends a simple answer to a query.
+        /// 1) Provide index of a query and the address(es) to pass.
+        /// 2) Provide index of query and components of address to pass.
+        void answer(size_t index, isc::dns::RRsetPtr& set) {
+            if (index >= requests.size()) {
+                throw NoSuchRequest();
+            }
+            requests[index].second->success(createResponseMessage(set));
+        }
+
+        void answer(size_t index, const isc::dns::Name& name,
+                    const isc::dns::RRType& type,
+                    const isc::dns::rdata::Rdata& rdata, size_t TTL = 100)
+        {
+            isc::dns::RRsetPtr set(new isc::dns::RRset(name,
+                                                       isc::dns::RRClass::IN(),
+                                                       type,
+                                                       isc::dns::RRTTL(TTL)));
+            set->addRdata(rdata);
+            answer(index, set);
+        }
+        /// \Answer the query at index by list of nameservers
+        void provideNS(size_t index, isc::dns::RRsetPtr nameservers)
+        {
+            if (index >= requests.size()) {
+                throw NoSuchRequest();
+            }
+            if (requests[index].first->getName() != nameservers->getName() ||
+                requests[index].first->getType() != isc::dns::RRType::NS())
+            {
+                throw DifferentRequest();
+            }
+            requests[index].second->success(createResponseMessage(nameservers));
+        }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/util/unittests/testdata.cc b/src/lib/util/unittests/testdata.cc
new file mode 100644
index 0000000..2148d31
--- /dev/null
+++ b/src/lib/util/unittests/testdata.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <stdexcept>
+#include <fstream>
+#include <vector>
+
+#include "testdata.h"
+
+using namespace std;
+
+namespace {
+vector<string>&
+getDataPaths() {
+    static vector<string> data_path;
+    return (data_path);
+}
+}
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+void
+addTestDataPath(const string& path) {
+    getDataPaths().push_back(path);
+}
+
+void
+openTestData(const char* const datafile, ifstream& ifs) {
+    vector<string>::const_iterator it = getDataPaths().begin();
+    for (; it != getDataPaths().end(); ++it) {
+        string data_path = *it;
+        if (data_path.empty() || *data_path.rbegin() != '/') {
+            data_path.push_back('/');
+        }
+        ifs.open((data_path + datafile).c_str(), ios_base::in);
+        if (!ifs.fail()) {
+            return;
+        }
+    }
+
+    throw runtime_error("failed to open data file in data paths: " +
+                        string(datafile));
+}
+
+}
+}
+}
diff --git a/src/lib/util/unittests/testdata.h b/src/lib/util/unittests/testdata.h
new file mode 100644
index 0000000..03bd83a
--- /dev/null
+++ b/src/lib/util/unittests/testdata.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_UNITTESTS_TESTDATA_H
+#define __UTIL_UNITTESTS_TESTDATA_H 1
+
+/**
+ * @file testdata.h
+ * @short Manipulating test data files.
+ *
+ * This utility defines functions that help test case handle test data
+ * stored in a file.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+/// Add a path (directory) that \c openTestData() will search for test data
+/// files.
+void addTestDataPath(const std::string& path);
+
+/// Open a file specified by 'datafile' using the data paths registered via
+/// addTestDataPath().  On success, ifs will be ready for reading the data
+/// stored in 'datafile'.  If the data file cannot be open with any of the
+/// registered paths, a runtime_error exception will be thrown.
+///
+/// \note Care should be taken if you want to reuse the same single \c ifs
+/// for multiple input data.  Some standard C++ library implementations retain
+/// the failure bit if the first stream reaches the end of the first file,
+/// and make the second call to \c ifstream::open() fail.  The safest way
+/// is to use a different \c ifstream object for a new call to this function;
+/// alternatively make sure you explicitly clear the error bit by calling
+/// \c ifstream::clear() on \c ifs.
+void openTestData(const char* const datafile, std::ifstream& ifs);
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_TESTDATA_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/textdata.h b/src/lib/util/unittests/textdata.h
new file mode 100644
index 0000000..3e9b1aa
--- /dev/null
+++ b/src/lib/util/unittests/textdata.h
@@ -0,0 +1,103 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <istream>
+#include <string>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#ifndef __UTIL_UNITTESTS_TEXTDATA_H
+#define __UTIL_UNITTESTS_TEXTDATA_H 1
+
+/**
+ * @file textdata.h
+ * @short Utilities for tests with text data.
+ *
+ * This utility provides convenient helper functions for unit tests using
+ * textual data.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// Line-by-line text comparison.
+///
+/// This templated function takes two standard input streams, extracts
+/// strings from them, and compares the two sets of strings line by line.
+template <typename EXPECTED_STREAM, typename ACTUAL_STREAM>
+void
+matchTextData(EXPECTED_STREAM& expected, ACTUAL_STREAM& actual) {
+    std::string actual_line;
+    std::string expected_line;
+    while (std::getline(actual, actual_line), !actual.eof()) {
+        std::getline(expected, expected_line);
+        if (expected.eof()) {
+            FAIL() << "Redundant line in actual output: " << actual_line;
+            break;
+        }
+        if (actual.bad() || actual.fail() ||
+            expected.bad() || expected.fail()) {
+            throw std::runtime_error("Unexpected error in data streams");
+        }
+        EXPECT_EQ(expected_line, actual_line);
+    }
+    while (std::getline(expected, expected_line), !expected.eof()) {
+        ADD_FAILURE() << "Missing line in actual output: " << expected_line;
+    }
+}
+
+/// Similar to the fully templated version, but takes string for the second
+/// (actual) data.
+///
+/// Due to the nature of textual data, it will often be the case that test
+/// data is given as a string object.  This shortcut version helps such cases
+/// so that the test code doesn't have to create a string stream with the
+/// string data just for testing.
+template <typename EXPECTED_STREAM>
+void
+matchTextData(EXPECTED_STREAM& expected, const std::string& actual_text) {
+    std::istringstream iss(actual_text);
+    matchTextData(expected, iss);
+}
+
+/// Same for the previous version, but the first argument is string.
+template <typename ACTUAL_STREAM>
+void
+matchTextData(const std::string& expected_text, ACTUAL_STREAM& actual) {
+    std::istringstream iss(expected_text);
+    matchTextData(iss, actual);
+}
+
+/// Same for the previous two, but takes strings for both expected and
+/// actual data.
+void
+matchTextData(const std::string& expected_text,
+              const std::string& actual_text)
+{
+    std::istringstream expected_is(expected_text);
+    std::istringstream actual_is(actual_text);
+    matchTextData(expected_is, actual_is);
+}
+
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_TEXTDATA_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/xfr/Makefile.am b/src/lib/xfr/Makefile.am
index 79cee73..d714990 100644
--- a/src/lib/xfr/Makefile.am
+++ b/src/lib/xfr/Makefile.am
@@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 
-AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS += -Wno-unused-parameter # see src/lib/cc/Makefile.am
 if USE_CLANGPP
 AM_CXXFLAGS += -Wno-error
@@ -11,13 +11,5 @@ endif
 CLEANFILES = *.gcno *.gcda
 
 lib_LTLIBRARIES = libxfr.la
-libxfr_la_SOURCES = xfrout_client.h xfrout_client.cc 
-libxfr_la_SOURCES += fd_share.h fd_share.cc
-
-pyexec_LTLIBRARIES = libxfr_python.la
-# Python prefers .so, while some OSes (specifically MacOS) use a different
-# suffix for dynamic objects.  -module is necessary to work this around.
-libxfr_python_la_LDFLAGS = -module
-libxfr_python_la_SOURCES = fdshare_python.cc fd_share.cc fd_share.h
-libxfr_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-libxfr_python_la_CXXFLAGS = $(AM_CXXFLAGS)
+libxfr_la_SOURCES = xfrout_client.h xfrout_client.cc
+libxfr_la_LIBADD = $(top_builddir)/src/lib/util/io/libutil_io.la
diff --git a/src/lib/xfr/fd_share.cc b/src/lib/xfr/fd_share.cc
deleted file mode 100644
index 4e1f093..0000000
--- a/src/lib/xfr/fd_share.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <cstring>
-#include <cstdlib>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <stdlib.h>             // for malloc and free
-#include <xfr/fd_share.h>
-
-namespace isc {
-namespace xfr {
-
-namespace {
-// Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
-// In order to ensure as much portability as possible, we provide wrapper
-// functions of these macros.
-// Note that cmsg_space() could run slow on OSes that do not have
-// CMSG_SPACE.
-inline socklen_t
-cmsg_len(const socklen_t len) {
-#ifdef CMSG_LEN
-    return (CMSG_LEN(len));
-#else
-    // Cast NULL so that any pointer arithmetic performed by CMSG_DATA
-    // is correct.
-    const uintptr_t hdrlen = (uintptr_t)CMSG_DATA(((struct cmsghdr*)NULL));
-    return (hdrlen + len);
-#endif
-}
-
-inline socklen_t
-cmsg_space(const socklen_t len) {
-#ifdef CMSG_SPACE
-    return (CMSG_SPACE(len));
-#else
-    struct msghdr msg;
-    struct cmsghdr* cmsgp;
-    // XXX: The buffer length is an ad hoc value, but should be enough
-    // in a practical sense.
-    char dummybuf[sizeof(struct cmsghdr) + 1024];
-
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_control = dummybuf;
-    msg.msg_controllen = sizeof(dummybuf);
-
-    cmsgp = (struct cmsghdr*)dummybuf;
-    cmsgp->cmsg_len = cmsg_len(len);
-
-    cmsgp = CMSG_NXTHDR(&msg, cmsgp);
-    if (cmsgp != NULL) {
-        return ((char*)cmsgp - (char*)msg.msg_control);
-    } else {
-        return (0);
-    }
-#endif  // CMSG_SPACE
-}
-}
-
-int
-recv_fd(const int sock) {
-    struct msghdr msghdr;
-    struct iovec iov_dummy;
-    unsigned char dummy_data;
-
-    iov_dummy.iov_base = &dummy_data;
-    iov_dummy.iov_len = sizeof(dummy_data);
-    msghdr.msg_name = NULL;
-    msghdr.msg_namelen = 0;
-    msghdr.msg_iov = &iov_dummy;
-    msghdr.msg_iovlen = 1;
-    msghdr.msg_flags = 0;
-    msghdr.msg_controllen = cmsg_space(sizeof(int));
-    msghdr.msg_control = malloc(msghdr.msg_controllen);
-    if (msghdr.msg_control == NULL) {
-        return (-1);
-    }
-
-    if (recvmsg(sock, &msghdr, 0) < 0) {
-        free(msghdr.msg_control);
-        return (XFR_FD_RECEIVE_FAIL);
-    }
-    const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
-    int fd = -1;
-    if (cmsg != NULL && cmsg->cmsg_len == cmsg_len(sizeof(int)) &&
-        cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
-        fd = *(const int*)CMSG_DATA(cmsg);
-    }
-    free(msghdr.msg_control);
-    return (fd);
-}
-
-int
-send_fd(const int sock, const int fd) {
-    struct msghdr msghdr;
-    struct iovec iov_dummy;
-    unsigned char dummy_data = 0;
-
-    iov_dummy.iov_base = &dummy_data;
-    iov_dummy.iov_len = sizeof(dummy_data);
-    msghdr.msg_name = NULL;
-    msghdr.msg_namelen = 0;
-    msghdr.msg_iov = &iov_dummy;
-    msghdr.msg_iovlen = 1;
-    msghdr.msg_flags = 0;
-    msghdr.msg_controllen = cmsg_space(sizeof(int));
-    msghdr.msg_control = malloc(msghdr.msg_controllen);
-    if (msghdr.msg_control == NULL) {
-        return (-1);
-    }
-
-    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
-    cmsg->cmsg_len = cmsg_len(sizeof(int));
-    cmsg->cmsg_level = SOL_SOCKET;
-    cmsg->cmsg_type = SCM_RIGHTS;
-    *(int*)CMSG_DATA(cmsg) = fd;
-
-    const int ret = sendmsg(sock, &msghdr, 0);
-    free(msghdr.msg_control);
-    return (ret >= 0 ? 0 : -1);
-}
-
-} // End for namespace xfr
-} // End for namespace isc
diff --git a/src/lib/xfr/fd_share.h b/src/lib/xfr/fd_share.h
deleted file mode 100644
index 4ee5fd5..0000000
--- a/src/lib/xfr/fd_share.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef FD_SHARE_H_
-#define FD_SHARE_H_
-
-namespace isc {
-namespace xfr {
-
-/// Failed to receive xfr socket descriptor "fd" on unix domain socket 'sock'
-const int XFR_FD_RECEIVE_FAIL = -2;
-
-// Receive socket descriptor on unix domain socket 'sock'.
-// Returned value is the socket descriptor received.
-// Returned XFR_FD_RECEIVE_FAIL if failed to receive xfr socket descriptor
-// Errors are indicated by a return value of -1.
-int recv_fd(const int sock);
-
-// Send socket descriptor "fd" to server over unix domain socket 'sock',
-// the connection from socket 'sock' to unix domain server should be established first.
-// Errors are indicated by a return value of -1.
-int send_fd(const int sock, const int fd);
-
-} // End for namespace xfr
-} // End for namespace isc
-
-#endif
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/xfr/fdshare_python.cc b/src/lib/xfr/fdshare_python.cc
deleted file mode 100644
index 82b1b6e..0000000
--- a/src/lib/xfr/fdshare_python.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <structmember.h>
-
-#include <config.h>
-
-#include <xfr/fd_share.h>
-
-
-static PyObject*
-fdshare_recv_fd(PyObject*, PyObject* args) {
-    int sock, fd;
-    if (!PyArg_ParseTuple(args, "i", &sock)) {
-        return (NULL);
-    }
-    fd = isc::xfr::recv_fd(sock);
-    return (Py_BuildValue("i", fd));
-}
-
-static PyObject*
-fdshare_send_fd(PyObject*, PyObject* args) {
-    int sock, fd, result;
-    if (!PyArg_ParseTuple(args, "ii", &sock, &fd)) {
-        return (NULL);
-    }
-    result = isc::xfr::send_fd(sock, fd);
-    return (Py_BuildValue("i", result));
-}
-
-static PyMethodDef fdshare_Methods[] = {
-    {"send_fd",  fdshare_send_fd, METH_VARARGS, ""},
-    {"recv_fd",  fdshare_recv_fd, METH_VARARGS, ""},
-    {NULL, NULL, 0, NULL}        /* Sentinel */
-};
-
-
-static PyModuleDef bind10_fdshare_python = {
-    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
-    "bind10_fdshare",
-    "Python bindings for fdshare",
-    -1,
-    fdshare_Methods,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
-PyMODINIT_FUNC
-PyInit_libxfr_python(void) {
-    PyObject* mod = PyModule_Create(&bind10_fdshare_python);
-    if (mod == NULL) {
-        return (NULL);
-    }
-
-    PyObject* XFR_FD_RECEIVE_FAIL = Py_BuildValue("i", isc::xfr::XFR_FD_RECEIVE_FAIL);
-    if (XFR_FD_RECEIVE_FAIL == NULL) {
-        Py_XDECREF(mod);
-        return (NULL);
-    }
-    int ret = PyModule_AddObject(mod, "XFR_FD_RECEIVE_FAIL", XFR_FD_RECEIVE_FAIL);
-    if (-1 == ret) {
-        Py_XDECREF(XFR_FD_RECEIVE_FAIL);
-        Py_XDECREF(mod);
-        return (NULL);
-    }
-
-    return (mod);
-}
-
diff --git a/src/lib/xfr/python_xfr.cc b/src/lib/xfr/python_xfr.cc
deleted file mode 100644
index 52848ad..0000000
--- a/src/lib/xfr/python_xfr.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <boost/python.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/exception_translator.hpp>
-#include <boost/python/return_internal_reference.hpp>
-#include <boost/python/copy_const_reference.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <xfr/fd_share.h>
-
-using namespace isc::xfr;
-using namespace boost::python;
-
-BOOST_PYTHON_MODULE(bind10_xfr) {
-    def("recv_fd", &recv_fd);
-    def("send_fd", &send_fd);
-}
diff --git a/src/lib/xfr/xfrout_client.cc b/src/lib/xfr/xfrout_client.cc
index e9e736b..6ab905b 100644
--- a/src/lib/xfr/xfrout_client.cc
+++ b/src/lib/xfr/xfrout_client.cc
@@ -20,10 +20,11 @@
 #include <unistd.h>
 #include <asio.hpp>
 
-#include <xfr/fd_share.h>
+#include <util/io/fd_share.h>
 #include <xfr/xfrout_client.h>
 
 using namespace std;
+using namespace isc::util::io;
 using asio::local::stream_protocol;
 
 namespace isc {
@@ -72,7 +73,7 @@ XfroutClient::sendXfroutRequestInfo(const int tcp_sock,
                                     const void* const msg_data,
                                     const uint16_t msg_len)
 {
-    if (-1 == send_fd(impl_->socket_.native(), tcp_sock)) {
+    if (send_fd(impl_->socket_.native(), tcp_sock) < 0) {
         isc_throw(XfroutError,
                   "Failed to send the socket file descriptor "
                   "to xfrout module");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d4008c0..570c0e2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1 +1 @@
-SUBDIRS = system
+SUBDIRS = system tools
diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am
new file mode 100644
index 0000000..2f07494
--- /dev/null
+++ b/tests/tools/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = badpacket
diff --git a/tests/tools/badpacket/Makefile.am b/tests/tools/badpacket/Makefile.am
new file mode 100644
index 0000000..7df7077
--- /dev/null
+++ b/tests/tools/badpacket/Makefile.am
@@ -0,0 +1,33 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS  = badpacket
+badpacket_SOURCES  = badpacket.cc
+badpacket_SOURCES += command_options.cc command_options.h
+badpacket_SOURCES += header_flags.h
+badpacket_SOURCES += option_info.cc option_info.h
+badpacket_SOURCES += scan.cc scan.h
+badpacket_SOURCES += version.h
+
+badpacket_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_CLANGPP
+badpacket_CXXFLAGS += -Wno-error
+endif
+
+badpacket_LDADD  = $(top_builddir)/src/lib/asiodns/libasiodns.la
+badpacket_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+badpacket_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+badpacket_LDADD += $(top_builddir)/src/lib/log/liblog.la
+badpacket_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
diff --git a/tests/tools/badpacket/README b/tests/tools/badpacket/README
new file mode 100644
index 0000000..3f5e801
--- /dev/null
+++ b/tests/tools/badpacket/README
@@ -0,0 +1,53 @@
+"badpacket" is a tool intended to test that a nameserver can cope with
+incorrectly-formatted DNS messages.
+
+This particular incarnation of the tool allows various fields in the DNS
+message to be set to any value (including to values that invalidate the query).
+As well as setting individual values, it is possible to specify ranges; when
+this is done, the tool will send a set of packets so that each combination
+of values is checked.
+
+To illustrate this, consider the following command:
+
+badpacket --address 192.0.2.21 --port 5301 --aa 0-1 --cd 1
+          --rc 0-2 ftp.example.com
+
+(The command has been split across two lines for clarity.)
+
+The address and port flags are self-evident.  The other flags specify
+settings for the AA bit (0 and 1), CD bit (always 1) and the RCODE field
+(0, 1, 2). (The remaining fields in the flags word are not specified, so
+will always be zero.)  There are six combinations of these values, so six
+packets will sent to the remote server with the following settings:
+
+AA RCODE  CD Rest
+0    0    1   0
+0    1    1   0
+0    2    1   0
+1    0    1   0
+1    1    1   0
+1    2    1   0
+
+Each packet will cause a line to be output to stdout, which will have the
+following form:
+
+SUCCESS: (QR:0 OP:0 AA:0 TC:0 RD:0 RA:0 ...
+         (qr:1 op:0 aa:0 tc:0 rd:0 ra:1 ...
+
+(Again the text has been split across two lines for clarity. Also, the full
+list of fields has been truncated.)
+
+Each lines contains a status (SUCCESS indicates that a response was received,
+regardless of the contents of the response), the state of the fields in the
+flags word of the packet sent (in upper-case letters) and the state of the
+fields in the flags word of the response (in lower-case letters).
+
+TODO: At the moment the tool is limited to:
+* Setting values in the flags field.
+* Setting section counts to arbitrary values.
+* Extending or truncating the DNS message size.
+
+Additional options needed are:
+* Add data to sections that should be empty.
+* Deliberately mangle the names placed in the message sections (e.g. by altering
+  the label count fields).
diff --git a/tests/tools/badpacket/badpacket.cc b/tests/tools/badpacket/badpacket.cc
new file mode 100644
index 0000000..86bbc47
--- /dev/null
+++ b/tests/tools/badpacket/badpacket.cc
@@ -0,0 +1,62 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <unistd.h>
+#include <iostream>
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include "command_options.h"
+#include "scan.h"
+
+/// \brief Perform Bad Packet Scan
+///
+/// Scans the server by sending a sequence of (potentially) bad packets and
+/// printing the packet settings and the response received.  The principle
+/// raison d'etre for this is to check if a bad packet will cause a crash.
+///
+/// This particular version of the code allows a set of ranges to be set for:
+/// - The flags fields in the message.
+/// - The section count fields, regardless of what is in the section.
+/// - The message size: the message can be truncated or extended.
+///
+/// The program then sends a set of packets corresponding to all combinations
+/// of values in the ranges selected.
+
+// TODO: Extend to cover:
+// - Mangling the QNAME
+// - Adding names to the message sections
+// - Adding EDNS0 RR and magling the fields there
+
+using namespace isc::badpacket;
+
+/// \brief Main Program
+int main(int argc, char* argv[]) {
+
+    try {
+        // Parse command
+        CommandOptions options;
+        options.parse(argc, argv);
+
+        // Send the sequence of messages
+        Scan scanner;
+        scanner.scan(options);
+    } catch (isc::Exception& e) {
+        std::cout << "ERROR: " << e.what() << "\n";
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/tools/badpacket/command_options.cc b/tests/tools/badpacket/command_options.cc
new file mode 100644
index 0000000..eea5ff0
--- /dev/null
+++ b/tests/tools/badpacket/command_options.cc
@@ -0,0 +1,333 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <boost/lexical_cast.hpp>
+#include <getopt.h>
+
+#include "exceptions/exceptions.h"
+#include "util/strutil.h"
+
+#include "command_options.h"
+#include "option_info.h"
+#include "version.h"
+
+using namespace std;
+using namespace isc;
+
+namespace isc {
+namespace badpacket {
+
+// Reset stored values to the defaults.
+void
+CommandOptions::reset() {
+    address_ = "127.0.0.1";
+    port_ = 53;
+    timeout_ = 500;
+    qname_ = "www.example.com";
+
+    for (int i = 0; i < OptionInfo::SIZE; ++i) {
+        options_[i].minimum = OptionInfo::defval(i);
+        options_[i].maximum = OptionInfo::defval(i);
+        options_[i].present = false;
+    }
+}
+
+/// Parses the command-line options and records the results.
+void
+CommandOptions::parse(int argc, char* const argv[]) {
+
+    // Set up options for processing.  The declaration of the string constants
+    // as mutable arrays and putting the string variable into the "longopts"
+    // structure (as opposed to just putting a string literal there) is
+    // occasioned by a version of solaris which declares the first field as
+    // "char*" (instead of the correct "const char*").
+
+    // General options.
+    char HELP[] = {"help"};
+    char VERSION[] = {"version"};
+    char ADDRESS[] = {"address"};
+    char PORT[] = {"port"};
+    char TIMEOUT[] = {"timeout"};
+
+    // Settings for options in the flags field.
+    char QR[] = {"qr"};
+    char OP[] = {"op"};
+    char AA[] = {"aa"};
+    char TC[] = {"tc"};
+    char RD[] = {"rd"};
+    char RA[] = {"ra"};
+    char Z[]  = {"z"};
+    char AD[] = {"ad"};
+    char CD[] = {"cd"};
+    char RC[] = {"rc"};
+
+    // Settings for the count fields
+    char QC[] = {"qc"};
+    char AC[] = {"ac"};
+    char UC[] = {"uc"};
+    char DC[] = {"dc"};
+
+    // Message size
+    char MS[] = {"ms"};
+
+    const struct option longopts[] = {
+        {HELP,    0, NULL, 'h'},  // Print usage message and exit
+        {VERSION, 0, NULL, 'v'},  // Print program version and exit
+        {ADDRESS, 1, NULL, 'a'},  // Specify target server address
+        {PORT,    1, NULL, 'p'},  // Specify target port
+        {TIMEOUT, 1, NULL, 't'},  // Time to wait before timing out (ms)
+        {QR,      1, NULL, 'Q'},  // Query/response flag
+        {OP,      1, NULL, 'O'},  // Opcode
+        {AA,      1, NULL, 'A'},  // Authoritative answer
+        {TC,      1, NULL, 'T'},  // Truncated
+        {RD,      1, NULL, 'D'},  // recursion Desired
+        {RA,      1, NULL, 'R'},  // Recursion available
+        {Z,       1, NULL, 'Z'},  // must be Zero (reserved bit)
+        {AD,      1, NULL, 'U'},  // aUthenticated data
+        {CD,      1, NULL, 'C'},  // Checking disabled
+        {RC,      1, NULL, 'E'},  // rEsult code
+        {QC,      1, NULL, 'Y'},  // querY section count
+        {AC,      1, NULL, 'W'},  // ansWer section count
+        {UC,      1, NULL, 'H'},  // autHority section count
+        {DC,      1, NULL, 'I'},  // addItional section count
+        {MS,      1, NULL, 'M'},  // Message size
+        {NULL,    0, NULL, 0  }
+    };
+    const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:Y:W:H:I:M:";
+
+
+    // Set record of options to defaults before parsing
+    reset();
+
+    // Process command line
+    int    c;                       // Option being processed
+    optind = 0;                     // Reset parsing
+    while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+        switch (c) {
+            case 'h':   // --help
+                usage();
+                exit(0);
+
+            case 'v':   // --version
+                version();
+                exit(0);
+
+            case 'a':   // --address
+                address_ = optarg;
+                break;
+
+            case 'p':   // --port
+                port_ = boost::lexical_cast<uint16_t>(string(optarg));
+                break;
+
+            case 't':   // --timeout
+                timeout_ = boost::lexical_cast<int>(string(optarg));
+                break;
+
+            case 'Q':   // --qr (query/response)
+            case 'O':   // --op (operation code)
+            case 'A':   // --aa (authoritative answer)
+            case 'T':   // --tc (truncated)
+            case 'D':   // --rd (recursion desired)
+            case 'R':   // --ra (recursion available)
+            case 'Z':   // --z (zero: reserved bit)
+            case 'U':   // --ad (authenticated data)
+            case 'C':   // --cd (checking disabled)
+            case 'E':   // --rc (result code)
+            case 'Y':   // --qc (query count)
+            case 'W':   // --ac (answer count)
+            case 'H':   // --uc (authority count)
+            case 'I':   // --dc (additional count)
+            case 'M':   // --ms (message size)
+                processOptionValue(c, optarg);
+                break;
+
+            default:
+                isc_throw(isc::InvalidParameter,
+                          "unknown option given on the command line");
+        }
+    }
+
+    // Pick up a parameter if there is one (and report excess).
+    if (optind < argc) {
+        qname_ = argv[optind++];
+    }
+
+    if (optind < argc) {
+        isc_throw(isc::InvalidParameter,
+                  "only a single (optional) parameter may be specified on the command line");
+    }
+}
+
+// Print usage information.
+void
+CommandOptions::usage() {
+    cout << "Usage: badpacket [options] query\n"
+             "\n"
+            "Sends a sequence of DNS messages to the specified nameserver and prints the\n"
+            " results.  The packets are valid query packets but certain aspects of the\n"
+            " packets (such as the flags fields, section count fields and message size) can\n"
+            "be set to arbitrary values using the command-line switches.\n"
+            "\n"
+            "In the following list of command-line switches, '<range>' indicates a range of\n"
+            "values specified as either <integer> or <integer1>-<integer2> (e.g. both '42'\n"
+            "and '0-1' would be valid values for range).  The program sends a sequence of\n"
+            "messages that contain all combinations of the flag values.  For example,\n"
+            "specifying:\n"
+            "\n"
+            "--tc 0-1 --op 1-4 --aa 1 --rd 0-1\n"
+            "\n"
+            "... would send a total of 16 packets which would have all combinations of the\n"
+            "the tc bit set to 0 and 1, the rd bit set to 0 and 1, and the opcode set to all\n"
+            "values between 1 and 4.  All other flags fields would be zero except for the aa\n"
+            "bit which would always be 1.\n"
+            "\n"
+            "The long form of the option is given.  It can also be specified as a single-\n"
+            "character short-form, which is listed in sqare brackets in the description.\n"
+            "\n"
+            "General options are:\n"
+            "\n"
+            "--help              [-h] Prints this message and exits.\n"
+            "--version           [-v] Prints the program version number.\n"
+            "--address <address> [-a] Address of nameserver, which defaults to 127.0.0.1\n"
+            "--port <port>       [-p] Port to which to send query.  Defaults to 53.\n"
+            "--timeout <value>   [-t] Timeout value for the query.  Specified in ms, it\n"
+            "                         defaults to 500ms.\n"
+            "\n"
+            "The following options set fields in the outgoing DNS message flags word:\n"
+            "\n"
+            "--qr <range>        [-Q] Set query/response bit.  Valid <range> is 0-1.\n"
+            "--op <range>        [-O] Set opcode.  Valid <range> is 0-15.\n"
+            "--aa <range>        [-A] Set authoritative answer bit.  Valid <range> is 0-1.\n"
+            "--tc <range>        [-T] Set truncated bit.  Valid <range> is 0-1.\n"
+            "--rd <range>        [-D] Set recursion desired bit.  Valid <range> is 0-1.\n"
+            "--ra <range>        [-D] Set recursion available bit.  Valid <range> is 0-1.\n"
+            "--z <range>         [-Z] Set zero (reserved) bit.  Valid <range> is 0-1.\n"
+            "--ad <range>        [-U] Set authenticated data bit.  Valid <range> is 0-1.\n"
+            "--cd <range>        [-C] Set checking disabled bit.  Valid <range> is 0-1.\n"
+            "--rc <range>        [-E] Set rcode value.  Valid <range> is 0-15\n"
+            "\n"
+            "The following options set the various section counts (independent of what is\n"
+            "actually in the section):\n"
+            "\n"
+            "--qc <range>        [-Y] Set the query count.  Valid range is 0-65535.\n"
+            "--ac <range>        [-W] Set the answer count.  Valid range is 0-65535.\n"
+            "--uc <range>        [-H] Set the authority count.  Valid range is 0-65535.\n"
+            "--dc <range>        [-I] Set the additional count.  Valid range is 0-65535.\n"
+            "\n"
+            "Other options are:\n"
+            "\n"
+            "--ms <range>        [-M] Set the size of the message.  If the specified size\n"
+            "                         smaller than the natural message size, it is truncated.\n"
+            "                         If longer, the packet is extended with random values.\n"
+            "                         Valid range is 2 to 65536\n"
+            "\n"
+            "query               Name to query for.  The query is for an 'IN' A record.  If\n"
+            "                    not given, the name 'www.example.com' is used.\n"
+            "\n"
+            "The output is a single (very long) line containing the settings of the various\n"
+            "fields.  The settings for the outgoing packet are reported in uppercase letters\n"
+            "and that of the returned packet in lowercase.\n"
+            ;
+}
+
+// Print version information,
+void
+CommandOptions::version() {
+    cout << BADPACKET_VERSION << "\n";
+}
+
+// Process single flag that can be stored in the options_ member.
+void
+CommandOptions::processOptionValue(int c, const char* value) {
+
+    // Get values for this option.
+    int index = OptionInfo::getIndex(c);
+    const char* name = OptionInfo::name(index);
+    uint32_t minval = OptionInfo::minval(index);
+    uint32_t maxval = OptionInfo::maxval(index);
+
+    // Split the string up into one or two tokens.
+    vector<string> tokens = isc::util::str::tokens(string(value), "-");
+    if ((tokens.size() < 1) || (tokens.size() > 2)) {
+        isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
+                  "': it must be in the form 'int' or 'int1-int2'");
+    }
+
+    // Convert to uint32.
+    try {
+        options_[index].minimum = boost::lexical_cast<uint32_t>(tokens[0]);
+        if (tokens.size() == 2) {
+            options_[index].maximum = boost::lexical_cast<uint32_t>(tokens[1]);
+        } else {
+            options_[index].maximum = options_[index].minimum;
+        }
+    } catch (boost::bad_lexical_cast) {
+        isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
+                  "': it must be in the form 'int' or 'int1-int2'");
+    }
+
+    // Set the limits in the correct order.
+    if (options_[index].minimum > options_[index].maximum) {
+        swap(options_[index].minimum, options_[index].maximum);
+    }
+
+    // Check that tokens lie inside the allowed ranges.
+    if ((tokens.size() == 1) &&
+        ((options_[index].minimum < OptionInfo::minval(index)) || (options_[index].maximum > maxval))) {
+        isc_throw(isc::BadValue, "the value of " << options_[index].minimum <<
+                  " given for " << name << " is outside the range of " <<
+                  minval << " to " << maxval);
+    } else if (options_[index].minimum < minval) {
+        isc_throw(isc::BadValue, "the lower limit of " << options_[index].minimum <<
+                  " given for " << name << " is below the minimum permitted"
+                  " value of " << minval);
+    } else if (options_[index].maximum > maxval) {
+        isc_throw(isc::BadValue, "the upper limit of " << options_[index].maximum <<
+                  " given for " << name << " is above the maximum permitted"
+                  " value of " << maxval);
+    }
+
+    // And finally note that the option was specified on the command line
+    options_[index].present = true;
+}
+
+// Return information about the option - minimum and maximum values and whether
+// it was actually specified. (Note that if it wasn't, the maximum and minimum
+// values will have been set to the default recorded in the OptionInfo class.)
+uint32_t
+CommandOptions::minimum(int index) const {
+    OptionInfo::checkIndex(index);
+    return (options_[index].minimum);
+}
+
+uint32_t
+CommandOptions::maximum(int index) const {
+    OptionInfo::checkIndex(index);
+    return (options_[index].maximum);
+}
+
+bool
+CommandOptions::present(int index) const {
+    OptionInfo::checkIndex(index);
+    return (options_[index].present);
+}
+
+} // namespace badpacket
+} // namespace isc
diff --git a/tests/tools/badpacket/command_options.h b/tests/tools/badpacket/command_options.h
new file mode 100644
index 0000000..fc819e9
--- /dev/null
+++ b/tests/tools/badpacket/command_options.h
@@ -0,0 +1,162 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __COMMAND_OPTIONS_H
+#define __COMMAND_OPTIONS_H
+
+#include <cstdlib>
+#include <stdint.h>
+#include <utility>
+
+#include "option_info.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Command Options
+///
+/// This class is responsible for parsing the command-line and storing the
+/// specified options.
+///
+/// Some of the options perform general control (like setting the address of the
+/// nameserver under test, while the rest set values in the DNS message being
+/// sent.  Each of the latter options can be specified as either:
+///
+/// - \c --option value
+/// - \c --option value1-value2
+///
+/// Either way, two values are extracted the low value and the high value (in
+/// the former case, both are the same).  The values are stored and can be
+/// returned on request.
+///
+/// For simplicity, the class takes care of the --help and --version flags,
+/// each of which will cause a message to be printed to stdout and the program
+/// to terminate.
+
+class CommandOptions {
+public:
+
+    /// \brief Default Constructor
+    ///
+    /// Set values to defaults.
+    CommandOptions() {
+        reset();
+    }
+
+    /// \brief Return minimum value for option
+    ///
+    /// Applicable only to an option affecting a field in the message, this
+    /// method returns the minimum value that was given on the command line.
+    /// (If only a single value was given, it will be that value returned.)
+    /// If the option was not specified on the command line, the default value
+    /// set in the OptionsInfo class will be returned.
+    ///
+    /// \param index Index of the command-line option.
+    ///
+    /// \return uint32_t holding the minimum value given (or the default if
+    ///         the option was not specified on the command line).
+    uint32_t minimum(int index) const;
+
+    /// \brief Return maximum value for option
+    ///
+    /// Applicable only to an option affecting a field in the message, this
+    /// method returns the maximum value that was given on the command line.
+    /// (If only a single value was given, it will be that value returned.)
+    /// If the option was not specified on the command line, the default value
+    /// set in the OptionsInfo class will be returned.
+    ///
+    /// \param index Index of the command-line option.
+    ///
+    /// \return uint32_t holding the maximum value given (or the default if
+    ///         the option was not specified on the command line).
+    uint32_t maximum(int index) const;
+
+    /// \brief Reports if option was given on command line
+    ///
+    /// \param index Index of the command-line option.
+    ///
+    /// \return true if the option was present, false if not.
+    bool present(int index) const;
+
+
+    /// \brief Return target address
+    std::string getAddress() const {
+        return address_;
+    }
+
+    /// \brief Return target port
+    uint16_t getPort() const {
+        return port_;
+    }
+
+    /// \brief Return timeout
+    int getTimeout() const {
+        return timeout_;
+    }
+
+    /// \brief Return qname
+    std::string getQname() const {
+        return qname_;
+    }
+
+    /// \brief Reset to defaults
+    ///
+    /// Resets the CommandOptions object to default values.
+    void reset();
+
+    /// \brief Parse command line
+    ///
+    /// Parses the command line and stores the selected options.  The parsing
+    /// also handles the --help and --version commands: both of these will cause
+    /// some text to be printed to stdout, after which exit() is called to
+    /// terminate the program.
+    ///
+    /// \param argc Argument count passed to main().
+    /// \param argv Argument value array passed to main().
+    void parse(int argc, char* const argv[]);
+
+    /// \brief Print usage information and exit program
+    void usage();
+
+    /// \brief Print version information and exit program
+    void version();
+
+private:
+    /// \brief Process Option Value
+    ///
+    /// Processes a specific command-line option, interpreting the value and
+    /// placing it in the appropriate location.  On error a BadValue exception
+    /// is thrown.
+    ///
+    /// \param c Short form option character from the command line
+    /// \param value Value of the option read from the command line
+    void processOptionValue(int c, const char* value);
+
+    // Member variables
+
+    struct {
+        uint32_t    minimum;        ///< Minimum value specified
+        uint32_t    maximum;        ///< Maximum value specified
+        bool        present;        ///< true if specified on command line
+    } options_[OptionInfo::SIZE];   ///< Information about command options
+    std::string     address_;       ///< Address to where query is sent
+    uint16_t        port_;          ///< Target port
+    int             timeout_;       ///< Timeout for query
+    std::string     qname_;         ///< Query to make
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __COMMAND_OPTIONS_H
diff --git a/tests/tools/badpacket/header_flags.h b/tests/tools/badpacket/header_flags.h
new file mode 100644
index 0000000..5d74e75
--- /dev/null
+++ b/tests/tools/badpacket/header_flags.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __HEADER_FLAGS_H
+#define __HEADER_FLAGS_H
+
+#include <exceptions/exceptions.h>
+#include "option_info.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Header Flags
+///
+/// Simple class providing easy conversion between the header flags in a DNS
+/// message and a 16-bit value.
+
+class HeaderFlags {
+public:
+
+    /// \brief Constructor
+    HeaderFlags() {
+        reset();
+    }
+
+    /// \brief Reset values to zero
+    ///
+    /// Clears all flags.
+    void reset() {
+        setValue(0);
+    }
+
+    /// \brief Get header flags as 16-bit value
+    uint16_t getValue() const {
+        return (flags_);
+    }
+
+    /// \brief Set header flags as 16-bit value
+    ///
+    /// \param value 16-bit value to put into object as representing the
+    ///        header flags.
+    void setValue(uint16_t value) {
+        flags_ = value;
+    }
+
+    /// \brief Get field
+    ///
+    /// Return the value of a bit field in the flags word.
+    ///
+    /// \param int Index of the bit field in the OptionInfo data structure
+    ///
+    /// \return Value of the field.
+    uint16_t get(int index) const {
+        OptionInfo::checkIndex(index);
+        return ((flags_ & OptionInfo::mask(index)) >> OptionInfo::offset(index));
+    }
+
+    /// \brief Set field
+    ///
+    /// Sets the value of a bit field.
+    ///
+    /// \param int Index of the bit field in the OptionInfo data structure
+    /// \param value Value to set.  If the value is more than the field can
+    ///        hold, a BadValue exception is thrown.
+    void set(int index, uint16_t value) {
+
+        // Declare an OptionInfo object for brevity and check the index is
+        // valid.
+        OptionInfo o;
+        o.checkIndex(index);
+
+        // Ensure the value is within limits and throw an exception if not. (This
+        // should not really be needed, as the command line parsing should have
+        // checked the limits.  But be safe.)
+        if ((value < o.minval(index)) || (value > o.maxval(index))) {
+            isc_throw(isc::BadValue, "value of index " << index << " is out of range");
+        }
+
+        // Clear the field then set it with the value.
+        flags_ &= ~o.mask(index);
+        flags_ |= (value << o.offset(index));
+    }
+
+private:
+    uint16_t        flags_;     ///< Variable holding field values
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __HEADER_FLAGS_H
diff --git a/tests/tools/badpacket/option_info.cc b/tests/tools/badpacket/option_info.cc
new file mode 100644
index 0000000..e1c1f78
--- /dev/null
+++ b/tests/tools/badpacket/option_info.cc
@@ -0,0 +1,114 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "option_info.h"
+
+namespace {
+
+// Define the various options for the command switches.  This includes both the
+// long form and short form of the switch.  Unfortunately this means that the
+// information is duplicated here and where the long options are specified for
+// getopt_long, but this inconvenience is outweighed by the simplified command
+// processing.
+//
+// Fields are:
+// * Short option name
+// * Long option name
+// * Offset of 16-bit word holding datum in DNS message (if applicable)
+// * Bit mask for the data (if applicable)
+// * Offset of the bit field in the word (if applicable)
+// * Default value (this can be ignored if applicable)
+// * Minimum value specified on command line
+// * Maximum value specified on command line
+
+isc::badpacket::OptionInfo::Parameter option_information[] = {
+    {'Q', "qr",  2, 0x8000,  15,  0, 0,      1},
+    {'O', "op",  2, 0x7800,  11,  0, 0,     15},
+    {'A', "aa",  2, 0x0400,  10,  0, 0,      1},
+    {'T', "tc",  2, 0x0200,   9,  0, 0,      1},
+    {'D', "rd",  2, 0x0100,   8,  0, 0,      1},
+    {'R', "ra",  2, 0x0080,   7,  0, 0,      1},
+    {'Z', "z",   2, 0x0040,   6,  0, 0,      1},
+    {'U', "ad",  2, 0x0020,   5,  0, 0,      1},
+    {'C', "cd",  2, 0x0010,   4,  0, 0,      1},
+    {'E', "rc",  2, 0x000F,   0,  0, 0,     15},
+    {'Y', "qc",  4,      0,   0,  1, 0, 0xFFFF},
+    {'W', "ac",  6,      0,   0,  0, 0, 0xFFFF},
+    {'H', "uc",  8,      0,   0,  0, 0, 0xFFFF},
+    {'I', "dc", 10,      0,   0,  0, 0, 0xFFFF},
+    {'M', "ms",  0,      0,   0,  0, 1,  65536}
+};
+
+}   // Anonymous namespace
+
+namespace isc {
+namespace badpacket {
+
+// Locate the index of the information in the array from the short switch.
+int
+OptionInfo::getIndex(int c) {
+    for (int i = 0; i < SIZE; ++i) {
+        if (option_information[i].short_form == c) {
+            return (i);
+        }
+    }
+    isc_throw(isc::BadValue, "unknown option: " << c);
+}
+
+// Methods to return values from the array
+
+const char*
+OptionInfo::name(int i) {
+    checkIndex(i);
+    return (option_information[i].long_form);
+}
+
+uint16_t
+OptionInfo::mask(int i) {
+    checkIndex(i);
+    return (option_information[i].mask);
+}
+
+int
+OptionInfo::word(int i) {
+    checkIndex(i);
+    return (option_information[i].word);
+}
+
+int
+OptionInfo::offset(int i) {
+    checkIndex(i);
+    return (option_information[i].offset);
+}
+
+uint32_t
+OptionInfo::minval(int i) {
+    checkIndex(i);
+    return (option_information[i].minval);
+}
+
+uint32_t
+OptionInfo::defval(int i) {
+    checkIndex(i);
+    return (option_information[i].defval);
+}
+
+uint32_t
+OptionInfo::maxval(int i) {
+    checkIndex(i);
+    return (option_information[i].maxval);
+}
+
+} // namespace badpacket
+} // namespace isc
diff --git a/tests/tools/badpacket/option_info.h b/tests/tools/badpacket/option_info.h
new file mode 100644
index 0000000..a340c1d
--- /dev/null
+++ b/tests/tools/badpacket/option_info.h
@@ -0,0 +1,174 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __OPTION_INFO_H
+#define __OPTION_INFO_H
+
+#include <stdint.h>
+#include "exceptions/exceptions.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Option Information
+///
+/// Holds details about the options that can be specified on the command line
+/// that require values and which control data put in the DNS message sent to
+/// the remote system.
+///
+/// Some of the fields are no applicable to all options.  For example, some of
+/// the options correspond to fields in the flags word of the DNS message
+/// header, so the information includes details about the position of the fields
+/// and an appropriate bit mask.
+///
+/// Note that the class does not hold values specified on the command line - it
+/// only holds information about the available options.
+
+class OptionInfo {
+public:
+
+    /// \brief Array Indexes
+    ///
+    /// The data for the flags options are held in an array.  Although declared
+    /// as an enum, only the numeric values are used as they are the indexes
+    /// into the array.
+    enum Index {
+        FLAGS_START = 0,    // Start of flags field codes
+        QR = 0,             // Query/response
+        OP = 1,             // Opcode
+        AA = 2,             // Authoritative answer
+        TC = 3,             // Truncated
+        RD = 4,             // Recursion desired
+        RA = 5,             // Recursion available
+        Z  = 6,             // Zero (reserved)
+        AD = 7,             // Authenticated data
+        CD = 8,             // Checking disabled
+        RC = 9,             // Response code
+        FLAGS_END = 9,      // End of flags field codes
+        COUNT_START = 10,   // Start of count fields
+        QC = 10,            // Query count
+        AC = 11,            // Answer count
+        UC = 12,            // Authority count
+        DC = 13,            // Additional count
+        COUNT_END = 13,     // End of count fields
+        OTHER_START = 14,   // Start of other fields
+        MS = 14,            // Message size
+        OTHER_END = 14,     // End of other fields
+        SIZE = 15           // Number of index values
+    };
+
+    /// \brief Option parameters
+    ///
+    /// Defines a structure that holds information associated with each of the
+    /// flags field command options.  Not all members of the structure are
+    /// relevant to all options.
+    struct Parameter {
+        const char      short_form;     // Short form of the command switch
+        const char*     long_form;      // Long form of the command switch
+        int             word;           // Byte offset of word in message header
+        uint16_t        mask;           // Bit mask of field in the flags word
+        int             offset;         // Offset of field in flags word
+        uint32_t        defval;         // Default value
+        uint32_t        minval;         // Minimum valid value for this field
+        uint32_t        maxval;         // Maximum valid value for this field
+    };
+
+    /// \brief Return index for command option
+    ///
+    /// Given the short form of a command-line option, return the index in the
+    /// options array corresponding to that option.
+    ///
+    /// \param c The character that is the short form of the command line option.
+    ///        An 'int' is used as the value passed will be the return value
+    ///        from 'getopt()' (or equivalent) which is an int.  If the
+    ///        character is not found, an exception will be thrown.
+    ///
+    /// \return A valid index value.
+    static int getIndex(int c);
+
+    /// \brief Return long form of command switch for this field
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return The long option name (e.q. "qr" for the Query/Response field).
+    static const char* name(int index);
+
+    /// \brief Return header word offset
+    ///
+    /// Returns the byte offset in the DNS message header of the two-byte word 
+    /// holding the data in question.
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return The offset in the header for this datum.
+    static int word(int index);
+
+    /// \brief Return mask associated with switch field
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return The mask for this particular option in the DNS message flags
+    ///         word.  The returned value is only valid for options that
+    ///         correspond to fields in the flags word.
+    static uint16_t mask(int index);
+
+    /// \brief Return offset associated with option field
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return The offset of the field corresponding to this option in the DNS
+    ///         message flags field.  The returned value is only valid for
+    ///         options that correpond to fields in the flags word.
+    static int offset(int index);
+
+    /// \brief Return minimum allowed value of an option
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return Minimum allowed value for this option.
+    static uint32_t minval(int index);
+
+    /// \brief Return default value of an option
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return Default value for this option
+    static uint32_t defval(int index);
+
+    /// \brief Return maximum allowed value of an option
+    ///
+    /// \param index A valid index (one of the values in the 'Index' enum).
+    ///
+    /// \return Maximum allowed value for this option.  If the option is a bit
+    ///         in the flags field of the DNS message hearder, this will be 1.
+    static uint32_t maxval(int index);
+
+    /// \brief Check Array Index
+    ///
+    /// Checks the passed field index and throws an exception if it does not
+    /// correspond to one of the valid indexes in the 'Index' enum.
+    ///
+    /// \param index An index value.
+    static void checkIndex(int i) {
+        if ((i < 0) || (i >= SIZE)) {
+            isc_throw(isc::OutOfRange, "option index must be in the range "
+                      "0 to " << SIZE);
+        }
+    }
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __OPTION_INFO_H
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
new file mode 100644
index 0000000..a6e7229
--- /dev/null
+++ b/tests/tools/badpacket/scan.cc
@@ -0,0 +1,312 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include <stdlib.h>
+
+#include <config.h>
+
+#include <asio.hpp>
+
+#include <asiolink/io_address.h>
+#include <asiodns/io_fetch.h>
+#include <util/buffer.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/question.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <util/strutil.h>
+
+#include "command_options.h"
+#include "header_flags.h"
+#include "scan.h"
+
+using namespace std;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::str;
+
+namespace isc {
+namespace badpacket {
+
+// Perform the scan from start to end on a single question.
+void
+Scan::scan(const CommandOptions& options) {
+
+    // Create the message buffer to use
+    Message message(Message::RENDER);
+    message.setOpcode(Opcode::QUERY());
+    message.setRcode(Rcode::NOERROR());
+    message.addQuestion(Question(Name(options.getQname()), RRClass::IN(),
+                        RRType::A()));
+
+    OutputBufferPtr msgbuf(new OutputBuffer(512));
+    MessageRenderer renderer(*msgbuf);
+    message.toWire(renderer);
+
+    iterateFlagsStart(msgbuf, options);
+}
+
+// Iterate through the various settings in the flags fields.
+void
+Scan::iterateFlagsStart(OutputBufferPtr& msgbuf, const CommandOptions& options) {
+    HeaderFlags flags;
+    iterateFlags(msgbuf, options, flags, OptionInfo::FLAGS_START,
+                 OptionInfo::FLAGS_END);
+}
+void
+Scan::iterateFlags(OutputBufferPtr& msgbuf, const CommandOptions& options,
+                   HeaderFlags& flags, int index, int maxindex)
+{
+    // Is the index valid?
+    if (index <= maxindex) {
+
+        // Index is valid, did the command line specify a range of values for
+        // this field?
+        if (options.present(index)) {
+
+            // It did, so loop between minimum and maximum values given.
+            for (uint32_t i = options.minimum(index);
+                          i <= options.maximum(index); ++i) {
+                flags.set(index, i);
+
+                // Recurse to set the next option.
+                iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
+            }
+        } else {
+
+            // Not specified on command line, so set the default value in the
+            // flags and process the next index.
+            flags.set(index, OptionInfo::defval(index));
+            iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
+        }
+    } else {
+
+        // Index is not valid, so we have recursed enough to process all the
+        // flags fields.  Set the value in the message header and call the next
+        // stage in the processing.
+        //
+        // (In the next statement, the "word" offset of in the header is the
+        // same for all flags options, so the value for an arbitrary field
+        // (QR) has been used.)
+        msgbuf->writeUint16At(flags.getValue(),
+                              OptionInfo::word(OptionInfo::QR));
+        iterateCountStart(msgbuf, options);
+    }
+}
+
+// Iterate through the various count fields
+void
+Scan::iterateCountStart(OutputBufferPtr& msgbuf, const CommandOptions& options)
+{
+    iterateCount(msgbuf, options, OptionInfo::COUNT_START,
+                 OptionInfo::COUNT_END);
+}
+
+void
+Scan::iterateCount(OutputBufferPtr& msgbuf, const CommandOptions& options,
+                   int index, int maxindex)
+{
+    // If the index is valid, process the iteration over the range for this
+    // flags field.
+    if (index <= maxindex) {
+
+        // Index is valid, did the command line specify a range of values for
+        // this field?
+        if (options.present(index)) {
+
+            // It did, so loop between minimum and maximum values given.
+            for (uint32_t i = options.minimum(index);
+                          i <= options.maximum(index); ++i) {
+
+                // Set the value in the message buffer header and recurse to
+                // the next option.
+                msgbuf->writeUint16At(i, OptionInfo::word(index));
+                iterateCount(msgbuf, options, (index + 1), maxindex);
+            }
+        } else {
+
+            // Not specified on command line, so do change anything and process
+            // the next index.
+            iterateCount(msgbuf, options, (index + 1), maxindex);
+        }
+    } else {
+
+        // Index is not valid, so we have recursed enough to process all the
+        // flags fields.  Do the next stage of the processing.
+        sizeMessage(msgbuf, options);
+    }
+}
+
+// Alter the message size.
+void
+Scan::sizeMessage(OutputBufferPtr& msgbuf, const CommandOptions& options) {
+
+    if (options.present(OptionInfo::MS)) {
+
+        // Iterate over the range of message sizes
+        for (size_t i = options.minimum(OptionInfo::MS);
+                    i <= options.maximum(OptionInfo::MS); ++i) {
+
+            // Copy the data into a new buffer.
+            OutputBufferPtr newbuf(new OutputBuffer(i));
+            newbuf->writeData(msgbuf->getData(), min(msgbuf->getLength(), i));
+
+            // Pad with junk (actually pseudo-random data) if the new buffer is
+            // longer than the old.
+            for (size_t j = newbuf->getLength(); j < i; ++j) {
+                newbuf->writeUint8(static_cast<uint8_t>(rand() & 0xFFU));
+            }
+
+            // ... and process.
+            scanOne(newbuf, options);
+        }
+    } else {
+
+        // No packet size given, just process the message as it.
+        scanOne(msgbuf, options);
+    }
+}
+
+// Perform the message exchange for a single combination command options.
+void
+Scan::scanOne(isc::util::OutputBufferPtr& msgbuf, const CommandOptions& options) {
+    // Store the interpretation of outgoing message.
+    string fields = string("(") + getFields(msgbuf) + string(")");
+
+    // Do the I/O, waiting for a reply
+    OutputBufferPtr replybuf(new OutputBuffer(512));
+    performIO(msgbuf, replybuf, options);
+
+    string status = "";
+    string returned = "";
+    switch (result_) {
+    case IOFetch::SUCCESS:
+        {
+            status = "SUCCESS";
+
+            // Parse the reply and get the fields
+            returned = string("(") + getFields(replybuf) + string(")");
+            lowercase(returned);
+        }
+        break;
+
+    case IOFetch::TIME_OUT:
+        status = "TIMEOUT";
+        break;
+
+    case IOFetch::STOPPED:
+        status = "STOPPED";
+        break;
+
+    default:
+        status = "UNKNOWN";
+    }
+
+    // ... and output the result
+    cout << status << ": " << fields << " " << returned << "\n";
+}
+
+// Get interpretation of the message fields.
+std::string
+Scan::getFields(isc::util::OutputBufferPtr& msgbuf) {
+
+    // Header flags. (Note that all come from the same word in the message, so
+    // using the word offset for the QR flag as the position in the buffer from
+    // which to extract the values is valid.)
+    HeaderFlags flags;
+    InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
+    inbuf.setPosition(OptionInfo::word(OptionInfo::QR));
+    flags.setValue(inbuf.readUint16());
+
+    std::ostringstream os;
+    os << std::hex << std::uppercase <<
+         "QR:" << flags.get(OptionInfo::QR) <<
+        " OP:" << flags.get(OptionInfo::OP) <<
+        " AA:" << flags.get(OptionInfo::AA) <<
+        " TC:" << flags.get(OptionInfo::TC) <<
+        " RD:" << flags.get(OptionInfo::RD) <<
+        " RA:" << flags.get(OptionInfo::RA) <<
+        " Z:"  << flags.get(OptionInfo::Z)  <<
+        " AD:" << flags.get(OptionInfo::AD) <<
+        " CD:" << flags.get(OptionInfo::CD) <<
+        " RC:" << flags.get(OptionInfo::RC);
+
+    // Section count fields.
+    inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
+    os << std::dec << std::uppercase <<
+        " QC:" << inbuf.readUint16();
+
+    inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
+    os << std::dec << std::uppercase <<
+        " AC:" << inbuf.readUint16();
+
+    inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
+    os << std::dec << std::uppercase <<
+        " UC:" << inbuf.readUint16();
+
+    inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
+    os << std::dec << std::uppercase <<
+        " DC:" << inbuf.readUint16();
+
+    // ... and message size.
+    os << std::dec << std::uppercase <<
+        " MS:" << msgbuf->getLength();
+
+    return (os.str());
+}
+
+// Perform the I/O to the nameserver.
+void
+Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
+                const CommandOptions& options)
+{
+    // Set up an I/O service for the I/O.  This needs to be initialized before
+    // every call as the callback called when the I/O completes stops it.
+    service_.reset(new IOService());
+
+    // The object that will do the I/O
+    IOFetch fetch(IOFetch::UDP, *service_, sendbuf,
+                  IOAddress(options.getAddress()), options.getPort(), recvbuf,
+                  this, options.getTimeout());
+
+    // Execute the message exchange.  The call to run() will return when a
+    // response is received or when the I/O times out.
+    (service_->get_io_service()).post(fetch); 
+    service_->run();
+}
+
+// I/O Callback.  Called when the message exchange completes or times out.
+void
+Scan::operator()(IOFetch::Result result) {
+
+    // Record the result.  This is accessed when deciding what was returned
+    // (if a timeout, nothing was returned).
+    result_ = result;
+
+    // Stop the I/O service.  This will cause the call to run() to return.
+    service_->stop();
+}
+
+} // namespace test
+} // namespace isc
diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h
new file mode 100644
index 0000000..ca56646
--- /dev/null
+++ b/tests/tools/badpacket/scan.h
@@ -0,0 +1,198 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __SCAN_H
+#define __SCAN_H
+
+#include <stdint.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <config.h>
+
+#include <asiolink/io_service.h>
+#include <asiodns/io_fetch.h>
+#include <util/buffer.h>
+
+#include "command_options.h"
+#include "header_flags.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Field Scan
+///
+/// This class implements a field scan.  Given a CommandOptions object, it will
+/// cycle through combinations of the given options, sending and receiving
+/// messages. For each packet exchange, a summary is written to stdout.
+
+class Scan : public isc::asiodns::IOFetch::Callback {
+public:
+
+    /// \brief Constructor
+    Scan() : service_(), result_()
+    {}
+
+    /// \brief Run Scan
+    ///
+    /// Actually performs the scan for the combination of options.
+    ///
+    /// \param options Command-line options
+    void scan(const CommandOptions& options);
+
+    /// \brief Callback
+    ///
+    /// This class is derived from the IOFetch::Callback class as it acts as the
+    /// callback object. When an asynchronous I/I has completed, this method
+    /// will be called.
+    ///
+    /// \param result Result of the asynchronous I/O.  Zero implies success.
+    virtual void operator()(isc::asiodns::IOFetch::Result result);
+
+private:
+    /// \brief Iterate over flags fields options
+    ///
+    /// This method relies on the fact that data concerning the settings for
+    /// the fields in the flags word of the DNS message are held at adjacent
+    /// elements in the various data arrays and so can be accessed by a set
+    /// of contiguous index values.
+    ///
+    /// The method is passed an index value and the maximum valid index value.
+    /// If a set of values for the field at the given index was specified on
+    /// the command line, it loops through those values and sets the appropriate
+    /// value in the a copy of the DNS message header flags.  It then calls
+    /// itself with an incremented index.  If the value was not given, it just
+    /// sets a default value calls itself (with the incremented index).  When
+    /// called with an index above the maximum valid index, the header flags
+    /// in the message buffer are set and the next stage of processing called.
+    ///
+    /// In this way, all fields can be cycled through without the need for a
+    /// single function to nest loops very deeply.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    /// \param flags Header flags
+    /// \param index Index of the current field to be processed.
+    /// \param maxindex Maximum valid index value
+    void iterateFlags(isc::util::OutputBufferPtr& msgbuf,
+                 const CommandOptions& options, HeaderFlags& flags,
+                 int index, int maxindex);
+
+    /// \brief Start iterating over flags field options
+    ///
+    /// Kicks off the call to \c iterateFlags by calling it with the initial
+    /// index value.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    void iterateFlagsStart(isc::util::OutputBufferPtr& msgbuf,
+                           const CommandOptions& options);
+
+    /// \brief Iterate over count fields
+    ///
+    /// In a manner similar to iterateFlags, this iterates over all specified
+    /// values for each count field, recursively calling itself to process the
+    /// next field.  When all fields have been processed, it chains to the
+    /// next stage of packet processing.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    /// \param index Index of the current field to be processed.
+    /// \param maxindex Maximum valid index value
+    void iterateCount(isc::util::OutputBufferPtr& msgbuf,
+                      const CommandOptions& options, int index, int maxindex);
+
+    /// \brief Start iterating over count fields
+    ///
+    /// Kicks off the call to \c iterateCount by calling it with the initial
+    /// index value.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    void iterateCountStart(isc::util::OutputBufferPtr& msgbuf,
+                           const CommandOptions& options);
+
+    /// \brief Iterate over message sizes
+    ///
+    /// If the message size option is given on the command line, the message
+    /// sent to the remote system is either truncated or extended (with zeroes)
+    /// before being set.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    void sizeMessage(isc::util::OutputBufferPtr& msgbuf,
+                     const CommandOptions& options);
+
+    /// \brief Scan One Value
+    ///
+    /// Performs one exchange of messages with the remote nameserver, sending
+    /// the specified message.
+    ///
+    /// \param msgbuf Message that will be sent to the remote nameserver.  The
+    ///        QID given will be ignored - the value used will be determined by
+    ///        the sending code
+    /// \param options Command-line options (the important ones being address,
+    ///        port and timeout).
+    void scanOne(isc::util::OutputBufferPtr& msgbuf,
+                 const CommandOptions& options);
+
+    /// \brief Perform I/O
+    ///
+    /// Performs a single query to the nameserver and reads the response.  It
+    /// outputs a summary of the result.
+    ///
+    /// \param sendbuf Buffer sent to the nameserver
+    /// \param recvbuf Buffer to hold reply from the nameserver
+    /// \param options Command-line options
+    void performIO(isc::util::OutputBufferPtr& sendbuf,
+                   isc::util::OutputBufferPtr& recvbuf,
+                   const CommandOptions& options);
+
+    /// \brief Get Fields
+    ///
+    /// Interprets the fields in a DNS message and converts them to a brief
+    /// textual format.
+    ///
+    /// \param msg Message for which the header is value
+    ///
+    /// \return A string that holds a textual interpretation of all the fields
+    ///         in the header.
+    std::string getFields(isc::util::OutputBufferPtr& msgbuf);
+
+    // Member variables
+
+    boost::scoped_ptr<isc::asiolink::IOService> service_;
+                                                    ///< Service to run the scan
+    isc::asiodns::IOFetch::Result   result_;        ///< Result of the I/O
+};
+
+} // namespace test
+} // namespace isc
+
+#endif // __SCAN_H
diff --git a/tests/tools/badpacket/tests/Makefile.am b/tests/tools/badpacket/tests/Makefile.am
new file mode 100644
index 0000000..e83c3b6
--- /dev/null
+++ b/tests/tools/badpacket/tests/Makefile.am
@@ -0,0 +1,32 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  = run_unittests.cc
+run_unittests_SOURCES += command_options_unittest.cc
+run_unittests_SOURCES += option_info_unittest.cc
+run_unittests_SOURCES += header_flags_unittest.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/command_options.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/option_info.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/util/libutil.la
+
+run_unittests_LDADD  = $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/tests/tools/badpacket/tests/command_options_unittest.cc b/tests/tools/badpacket/tests/command_options_unittest.cc
new file mode 100644
index 0000000..014618e
--- /dev/null
+++ b/tests/tools/badpacket/tests/command_options_unittest.cc
@@ -0,0 +1,300 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstddef>
+#include <string>
+#include <gtest/gtest.h>
+
+#include "../command_options.h"
+
+#include "exceptions/exceptions.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::badpacket;
+
+
+/// \brief Test Fixture Class
+
+class CommandOptionsTest : public virtual ::testing::Test,
+                           public virtual CommandOptions
+{
+public:
+
+    /// \brief Default Constructor
+    CommandOptionsTest()
+    {}
+
+    /// \brief Check Non-Limit Options
+    ///
+    /// Checks that the options that are NOT related to the message are set to
+    /// their default values.
+    void checkDefaultOtherValues() {
+        EXPECT_EQ("127.0.0.1", getAddress());
+        EXPECT_EQ(53, getPort());
+        EXPECT_EQ(500, getTimeout());
+        EXPECT_EQ("www.example.com", getQname());
+    }
+
+    /// \brief Checks the minimum and maximum value specified for an option
+    ///
+    /// Checks the values for one of the options whose values are stored in the
+    /// class's options_ array.
+    ///
+    /// \param index Index of the option in the limits_ array
+    /// \param minval Expected minimum value
+    /// \param maxval Expected maximum value
+    void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0) {
+        EXPECT_EQ(minimum(index), minval);
+        EXPECT_EQ(maximum(index), maxval);
+    }
+
+    /// \brief Checks that all options are at default values
+    ///
+    /// Checks that all options have both their maximum and minimum set to the
+    /// default values.
+    ///
+    /// \param except Index not to check. (This allows options not being tested
+    ///        to be checked to see that they are at the default value.)  As all
+    ///        index values are positive, a negative value means check
+    ///        everything.
+    void checkDefaultLimitsValues(int except = -1) {
+        for (int i = 0; i < OptionInfo::SIZE; ++i) {
+            if (i != except) {
+                checkValuePair(i, OptionInfo::defval(i),
+                               OptionInfo::defval(i));
+            }
+        }
+    }
+
+    /// \brief Check valid command option
+    ///
+    /// Checks that the command line specification of one of the options taking
+    /// a value correctly processes the option.
+    ///
+    /// \param index Option index
+    /// \param optflag Option flag (in the form '--option')
+    /// \param optval Value to be passed to the option.
+    /// \param minval Expected minimum value
+    /// \param maxval Expected maximum value
+    void checkCommandValid(int index, const char* optflag, const char* optval,
+                           uint32_t minval, uint32_t maxval) {
+
+        // Set up the command line and parse it.
+        const char* argv[] = {"badpacket", NULL, NULL};
+        argv[1] = optflag;
+        argv[2] = optval;
+        int argc = 3;
+        parse(argc, const_cast<char**>(argv));
+
+        // Check the results.  Everything should be at the defaults except for
+        // the specified option, where the minimum and maximum should be as
+        // specified.
+        checkDefaultOtherValues();
+        checkDefaultLimitsValues(index);
+        checkValuePair(index, minval, maxval);
+    }
+
+    /// \brief Check invalid command option
+    ///
+    /// Passed a command with an invalid value, checks that the parsing throws
+    /// a BadValue exception.
+    ///
+    /// \param optflag Option flag (in the form '--option')
+    /// \param optval Value to be passed to the option.
+    void checkCommandInvalid(const char* optflag, const char* optval) {
+
+        // Set up the command line and parse it.
+        const char* argv[] = {"badpacket", NULL, NULL};
+        argv[1] = optflag;
+        argv[2] = optval;
+        int argc = 3;
+        EXPECT_THROW(parse(argc, const_cast<char**>(argv)), isc::BadValue);
+    }
+
+    /// \brief Check one-bit field
+    ///
+    /// Explicitly for those fields in the flags word that are one bit wide,
+    /// perform a series of tests to check that they accept valid values and
+    /// reject invalid ones.
+    ///
+    /// \param index Option index
+    /// \param optflag Option flag (in the form '--option')
+    void checkOneBitField(int index, const char* optflag) {
+        checkCommandValid(index, optflag, "0", 0, 0);
+        checkCommandValid(index, optflag, "1", 1, 1);
+        checkCommandValid(index, optflag, "0-1", 0, 1);
+        checkCommandValid(index, optflag, "1-0", 0, 1);
+        checkCommandInvalid(optflag, "0-3");
+        checkCommandInvalid(optflag, "4");
+        checkCommandInvalid(optflag, "xyz");
+    }
+
+    /// \brief Check four-bit field
+    ///
+    /// Explicitly for those fields in the flags word that are four bits wide,
+    /// perform a series of tests to check that they accept valid values and
+    /// reject invalid ones.
+    ///
+    /// \param index Option index
+    /// \param optflag Option flag (in the form '--option')
+    void checkFourBitField(int index, const char* optflag) {
+        checkCommandValid(index, optflag, "0", 0, 0);
+        checkCommandValid(index, optflag, "15", 15, 15);
+        checkCommandValid(index, optflag, "0-15", 0, 15);
+        checkCommandValid(index, optflag, "15-0", 0, 15);
+        checkCommandInvalid(optflag, "0-17");
+        checkCommandInvalid(optflag, "24");
+        checkCommandInvalid(optflag, "xyz");
+    }
+
+    /// \brief Check sixteen-bit field
+    ///
+    /// Explicitly test the parsing of the fields that can take a 16-bit
+    /// value ranging from 0 to 65535.
+    ///
+    /// \param index Option index
+    /// \param optflag Option flag (in the form '--option')
+    void checkSixteenBitField(int index, const char* optflag) {
+        checkCommandValid(index, optflag, "0", 0, 0);
+        checkCommandValid(index, optflag, "65535", 65535, 65535);
+        checkCommandValid(index, optflag, "0-65535", 0, 65535);
+        checkCommandValid(index, optflag, "65535-0", 0, 65535);
+        checkCommandInvalid(optflag, "0-65536");
+        checkCommandInvalid(optflag, "65537");
+        checkCommandInvalid(optflag, "xyz");
+    }
+};
+
+// Check that each of the non-message options will be recognised
+
+TEST_F(CommandOptionsTest, address) {
+    const char* argv[] = {"badpacket",  "--address", "192.0.2.1"};
+    int argc = sizeof(argv) / sizeof(const char*);
+
+    // The conversion is ugly but it simplifies the process of entering the
+    // string constant.  The cast throws away the "const"ness of the pointed-to
+    // strings in order to conform to the function signature; however, the
+    // called functions all treat the strings as const.
+    parse(argc, const_cast<char**>(argv));
+    EXPECT_EQ("192.0.2.1", getAddress());
+    EXPECT_EQ(53, getPort());
+    EXPECT_EQ(500, getTimeout());
+    EXPECT_EQ("www.example.com", getQname());
+    checkDefaultLimitsValues();
+}
+
+TEST_F(CommandOptionsTest, port) {
+    const char* argv[] = {"badpacket",  "--port", "153"};
+    int argc = sizeof(argv) / sizeof(const char*);
+
+    parse(argc, const_cast<char**>(argv));
+    EXPECT_EQ("127.0.0.1", getAddress());
+    EXPECT_EQ(153, getPort());
+    EXPECT_EQ(500, getTimeout());
+    EXPECT_EQ("www.example.com", getQname());
+    checkDefaultLimitsValues();
+}
+
+TEST_F(CommandOptionsTest, timeout) {
+    const char* argv[] = {"badpacket",  "--timeout", "250"};
+    int argc = sizeof(argv) / sizeof(const char*);
+
+    parse(argc, const_cast<char**>(argv));
+    EXPECT_EQ("127.0.0.1", getAddress());
+    EXPECT_EQ(53, getPort());
+    EXPECT_EQ(250, getTimeout());
+    EXPECT_EQ("www.example.com", getQname());
+    checkDefaultLimitsValues();
+}
+
+TEST_F(CommandOptionsTest, parameter) {
+    const char* argv[] = {"badpacket",  "ftp.example.net"};
+    int argc = sizeof(argv) / sizeof(const char*);
+
+    parse(argc, const_cast<char**>(argv));
+    EXPECT_EQ("127.0.0.1", getAddress());
+    EXPECT_EQ(53, getPort());
+    EXPECT_EQ(500, getTimeout());
+    EXPECT_EQ("ftp.example.net", getQname());
+    checkDefaultLimitsValues();
+}
+
+// Test options representing the flags fields.
+
+TEST_F(CommandOptionsTest, qr) {
+    checkOneBitField(OptionInfo::QR, "--qr");
+}
+
+TEST_F(CommandOptionsTest, op) {
+    checkFourBitField(OptionInfo::OP, "--op");
+}
+
+TEST_F(CommandOptionsTest, aa) {
+    checkOneBitField(OptionInfo::AA, "--aa");
+}
+
+TEST_F(CommandOptionsTest, tc) {
+    checkOneBitField(OptionInfo::TC, "--tc");
+}
+
+TEST_F(CommandOptionsTest, z) {
+    checkOneBitField(OptionInfo::Z, "--z");
+}
+
+TEST_F(CommandOptionsTest, ad) {
+    checkOneBitField(OptionInfo::AD, "--ad");
+}
+
+TEST_F(CommandOptionsTest, cd) {
+    checkOneBitField(OptionInfo::CD, "--cd");
+}
+
+TEST_F(CommandOptionsTest, rc) {
+    checkFourBitField(OptionInfo::RC, "--rc");
+}
+
+// Section count options
+
+TEST_F(CommandOptionsTest, qc) {
+    checkSixteenBitField(OptionInfo::QC, "--qc");
+}
+
+TEST_F(CommandOptionsTest, ac) {
+    checkSixteenBitField(OptionInfo::AC, "--ac");
+}
+
+TEST_F(CommandOptionsTest, uc) {
+    checkSixteenBitField(OptionInfo::UC, "--uc");
+}
+
+TEST_F(CommandOptionsTest, dc) {
+    checkSixteenBitField(OptionInfo::DC, "--dc");
+}
+
+// ... and the message size option
+
+TEST_F(CommandOptionsTest, ms) {
+    int index = OptionInfo::MS;
+    const char* optflag = "--ms";
+
+    checkCommandValid(index, optflag, "1", 1, 1);
+    checkCommandValid(index, optflag, "65536", 65536, 65536);
+    checkCommandValid(index, optflag, "1-65536", 1, 65536);
+    checkCommandValid(index, optflag, "65536-1", 1, 65536);
+    checkCommandInvalid(optflag, "0");
+    checkCommandInvalid(optflag, "1-65537");
+    checkCommandInvalid(optflag, "65538");
+    checkCommandInvalid(optflag, "xyz");
+}
diff --git a/tests/tools/badpacket/tests/header_flags_unittest.cc b/tests/tools/badpacket/tests/header_flags_unittest.cc
new file mode 100644
index 0000000..5a7a722
--- /dev/null
+++ b/tests/tools/badpacket/tests/header_flags_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstddef>
+#include <stdint.h>
+#include <gtest/gtest.h>
+
+#include "../option_info.h"
+#include "../header_flags.h"
+
+using namespace isc::badpacket;
+
+// Test fixture class
+
+class HeaderFlagsTest : public ::testing::Test {
+public:
+    HeaderFlagsTest() {}
+
+
+    /// \brief Checks that all options are zero
+    ///
+    /// Checks that all flags options are set to zero.
+    ///
+    /// \param flags Flags structure to check.
+    /// \param except Index not to check. (This allows options not being tested
+    ///        to be checked to see that they are at the default value.)  As all
+    ///        index values are positive, a negative value means check
+    ///        everything.
+    void checkZero(const HeaderFlags& flags, int except = -1) {
+
+        // Check individual fields
+        for (int i = OptionInfo::FLAGS_START; i < OptionInfo::FLAGS_END; ++i) {
+            if (i != except) {
+                EXPECT_EQ(0, flags.get(i));
+            }
+        }
+
+        // ... and check the composite
+        if (except == -1) {
+            EXPECT_EQ(0, flags.getValue());
+        } else {
+            EXPECT_NE(0, flags.getValue());
+        }
+    }
+
+    /// \brief Check Option
+    ///
+    /// Checks that an option will only set the appropriate bits in the flags
+    /// field.
+    ///
+    /// \param index Index of the flags field to check.
+    /// \param maxval Maximum value of the header field.
+    void checkOption(int index, uint32_t maxval) {
+
+        // Create header flags and check initialized properly.
+        HeaderFlags flags;
+        checkZero(flags);
+
+        // Check we can set field to maximum.
+        flags.set(index, maxval);
+        EXPECT_EQ(maxval, flags.get(index));
+        checkZero(flags, index);
+
+        // Check we can reset it to zero.
+        flags.set(index, 0);
+        checkZero(flags);
+    }
+};
+
+// Set of tests to check that setting a bit only sets that bit and nothing
+// else.
+
+TEST_F(HeaderFlagsTest, fields) {
+    checkOption(OptionInfo::QR, 1);
+    checkOption(OptionInfo::OP, 15);
+    checkOption(OptionInfo::AA, 1);
+    checkOption(OptionInfo::TC, 1);
+    checkOption(OptionInfo::RD, 1);
+    checkOption(OptionInfo::RA, 1);
+    checkOption(OptionInfo::Z,  1);
+    checkOption(OptionInfo::AD, 1);
+    checkOption(OptionInfo::CD, 1);
+    checkOption(OptionInfo::RC, 15);
+}
+
+// Check that the correct bits are set
+
+TEST_F(HeaderFlagsTest, bitValues) {
+    HeaderFlags flags;
+    checkZero(flags);
+
+    flags.set(OptionInfo::QR, 1);
+    EXPECT_EQ(0x8000, flags.getValue());
+
+    flags.set(OptionInfo::QR, 0);
+    flags.set(OptionInfo::OP, 15);
+    EXPECT_EQ(0x7800, flags.getValue());
+
+    flags.set(OptionInfo::OP, 0);
+    flags.set(OptionInfo::AA, 1);
+    EXPECT_EQ(0x0400, flags.getValue());
+
+    flags.set(OptionInfo::AA, 0);
+    flags.set(OptionInfo::TC, 1);
+    EXPECT_EQ(0x0200, flags.getValue());
+
+    flags.set(OptionInfo::TC, 0);
+    flags.set(OptionInfo::RD, 1);
+    EXPECT_EQ(0x0100, flags.getValue());
+
+    flags.set(OptionInfo::RD, 0);
+    flags.set(OptionInfo::RA, 1);
+    EXPECT_EQ(0x0080, flags.getValue());
+
+    flags.set(OptionInfo::RA, 0);
+    flags.set(OptionInfo::Z, 1);
+    EXPECT_EQ(0x0040, flags.getValue());
+
+    flags.set(OptionInfo::Z, 0);
+    flags.set(OptionInfo::AD, 1);
+    EXPECT_EQ(0x0020, flags.getValue());
+
+    flags.set(OptionInfo::AD, 0);
+    flags.set(OptionInfo::CD, 1);
+    EXPECT_EQ(0x0010, flags.getValue());
+
+    flags.set(OptionInfo::CD, 0);
+    flags.set(OptionInfo::RC, 15);
+    EXPECT_EQ(0x000F, flags.getValue());
+}
diff --git a/tests/tools/badpacket/tests/option_info_unittest.cc b/tests/tools/badpacket/tests/option_info_unittest.cc
new file mode 100644
index 0000000..8c061de
--- /dev/null
+++ b/tests/tools/badpacket/tests/option_info_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstddef>
+#include <stdint.h>
+#include <gtest/gtest.h>
+
+#include "../option_info.h"
+
+using namespace isc::badpacket;
+
+
+// Test fixture class
+
+class OptionInfoTest : public ::testing::Test {
+public:
+    OptionInfoTest() {}
+};
+
+
+// Check the values are as expected
+
+TEST_F(OptionInfoTest, FlagValues) {
+    EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::QR));
+    EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::getIndex('Q')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::QR));
+    EXPECT_EQ(0x8000,  OptionInfo::mask(OptionInfo::QR));
+    EXPECT_EQ(15,      OptionInfo::offset(OptionInfo::QR));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::QR));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::QR));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::QR));
+
+    EXPECT_STREQ("op", OptionInfo::name(OptionInfo::OP));
+    EXPECT_STREQ("op", OptionInfo::name(OptionInfo::getIndex('O')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::OP));
+    EXPECT_EQ(0x7800,  OptionInfo::mask(OptionInfo::OP));
+    EXPECT_EQ(11,      OptionInfo::offset(OptionInfo::OP));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::OP));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::OP));
+    EXPECT_EQ(15,      OptionInfo::maxval(OptionInfo::OP));
+
+    EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::AA));
+    EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::getIndex('A')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::AA));
+    EXPECT_EQ(0x0400,  OptionInfo::mask(OptionInfo::AA));
+    EXPECT_EQ(10,      OptionInfo::offset(OptionInfo::AA));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::AA));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::AA));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::AA));
+
+    EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::TC));
+    EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::getIndex('T')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::TC));
+    EXPECT_EQ(0x0200,  OptionInfo::mask(OptionInfo::TC));
+    EXPECT_EQ(9,       OptionInfo::offset(OptionInfo::TC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::TC));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::TC));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::TC));
+
+    EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::RD));
+    EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::getIndex('D')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::RD));
+    EXPECT_EQ(0x0100,  OptionInfo::mask(OptionInfo::RD));
+    EXPECT_EQ(8,       OptionInfo::offset(OptionInfo::RD));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::RD));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::RD));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::RD));
+
+    EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::RA));
+    EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::getIndex('R')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::RA));
+    EXPECT_EQ(0x0080,  OptionInfo::mask(OptionInfo::RA));
+    EXPECT_EQ(7,       OptionInfo::offset(OptionInfo::RA));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::RA));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::RA));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::RA));
+
+    EXPECT_STREQ("z",  OptionInfo::name(OptionInfo::Z));
+    EXPECT_STREQ("z",  OptionInfo::name(OptionInfo::getIndex('Z')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::Z));
+    EXPECT_EQ(0x0040,  OptionInfo::mask(OptionInfo::Z));
+    EXPECT_EQ(6,       OptionInfo::offset(OptionInfo::Z));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::Z));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::Z));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::Z));
+
+    EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::AD));
+    EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::getIndex('U')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::AD));
+    EXPECT_EQ(0x0020,  OptionInfo::mask(OptionInfo::AD));
+    EXPECT_EQ(5,       OptionInfo::offset(OptionInfo::AD));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::AD));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::AD));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::AD));
+
+    EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::CD));
+    EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::getIndex('C')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::CD));
+    EXPECT_EQ(0x0010,  OptionInfo::mask(OptionInfo::CD));
+    EXPECT_EQ(4,       OptionInfo::offset(OptionInfo::CD));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::CD));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::CD));
+    EXPECT_EQ(1,       OptionInfo::maxval(OptionInfo::CD));
+
+    EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::RC));
+    EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::getIndex('E')));
+    EXPECT_EQ(2,       OptionInfo::word(OptionInfo::RC));
+    EXPECT_EQ(0x000F,  OptionInfo::mask(OptionInfo::RC));
+    EXPECT_EQ(0,       OptionInfo::offset(OptionInfo::RC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::RC));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::RC));
+    EXPECT_EQ(15,      OptionInfo::maxval(OptionInfo::RC));
+}
+
+TEST_F(OptionInfoTest, CountValues) {
+    EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::QC));
+    EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::getIndex('Y')));
+    EXPECT_EQ(4,       OptionInfo::word(OptionInfo::QC));
+    EXPECT_EQ(1,       OptionInfo::defval(OptionInfo::QC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::QC));
+    EXPECT_EQ(0xFFFF,  OptionInfo::maxval(OptionInfo::QC));
+
+    EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::AC));
+    EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::getIndex('W')));
+    EXPECT_EQ(6,       OptionInfo::word(OptionInfo::AC));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::AC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::AC));
+    EXPECT_EQ(0xFFFF,  OptionInfo::maxval(OptionInfo::AC));
+
+    EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::UC));
+    EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::getIndex('H')));
+    EXPECT_EQ(8,       OptionInfo::word(OptionInfo::UC));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::UC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::UC));
+    EXPECT_EQ(0xFFFF,  OptionInfo::maxval(OptionInfo::UC));
+
+    EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::DC));
+    EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::getIndex('I')));
+    EXPECT_EQ(10,      OptionInfo::word(OptionInfo::DC));
+    EXPECT_EQ(0,       OptionInfo::defval(OptionInfo::DC));
+    EXPECT_EQ(0,       OptionInfo::minval(OptionInfo::DC));
+    EXPECT_EQ(0xFFFF,  OptionInfo::maxval(OptionInfo::DC));
+}
+
+TEST_F(OptionInfoTest, OtherValues) {
+    EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::MS));
+    EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::getIndex('M')));
+    EXPECT_EQ(1,       OptionInfo::minval(OptionInfo::MS));
+    EXPECT_EQ(65536,   OptionInfo::maxval(OptionInfo::MS));
+}
diff --git a/tests/tools/badpacket/tests/run_unittests.cc b/tests/tools/badpacket/tests/run_unittests.cc
new file mode 100644
index 0000000..624cf6f
--- /dev/null
+++ b/tests/tools/badpacket/tests/run_unittests.cc
@@ -0,0 +1,24 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return (RUN_ALL_TESTS());
+}
diff --git a/tests/tools/badpacket/version.h b/tests/tools/badpacket/version.h
new file mode 100644
index 0000000..dc59b11
--- /dev/null
+++ b/tests/tools/badpacket/version.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __VERSION_H
+#define __VERSION_H
+
+namespace isc {
+namespace badpacket {
+
+static const char* BADPACKET_VERSION = "1.0-1";
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __VERSION_H
diff --git a/tools/query_cmp/README b/tools/query_cmp/README
new file mode 100644
index 0000000..bd3efcc
--- /dev/null
+++ b/tools/query_cmp/README
@@ -0,0 +1,27 @@
+This is a tool to compare two DNS server's response to query.
+
+DIRECTORY STRUCTURE
+
+zonefile
+	The file under this directory is for the testee servers
+	to load before running the test, containing various types 
+	of RRs in the test cases. It is in bind9's format. One 
+	file is signed while the other is not, which you can choose.
+
+queries
+	The files under this directory are the input of the test,
+	involving various types of query cases.
+
+src
+	The scripts of this test.
+	It uses the dns python binding interface of bind10 from the 
+	source tree, so src/lib/dns/python/.libs must be added to 
+	PYTHONPATH environment variable ahead of running the tests.
+
+RUNNING
+
+e.g.
+cd src
+./query_two_server.py -u -f ../queries/dquery01 -s 10.10.1.1 -p 30000 -t 10.10.10.2 -q 30002 > bind10test_normal
+
+./query_two_server.py --help' for more details
diff --git a/tools/query_cmp/queries/dquery01 b/tools/query_cmp/queries/dquery01
new file mode 100644
index 0000000..923ba7d
--- /dev/null
+++ b/tools/query_cmp/queries/dquery01
@@ -0,0 +1,394 @@
+# Fields Description
+#
+#query:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT QNAME QTYPE QCLASS
+#response:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT QNAME QTYPE QCLASS <answer> <authority> <additional>
+#  <answer>     := <rr1> .. <rrN>
+#  <rr>         := NAME TYPE CLASS TTL RDLENGTH <rdata>
+#  <rdata>      := ADDRESS |
+#                  NSDNAME |
+#                  MNAME RNAME SERIAL REFRESH RETRY EXPIRE MINIMUM |
+#                  ...
+#  <authority>  := <rr1> .. <rrN>
+#  <additional> := <rr1> .. <rrN>
+#
+# 
+#
+# Description in BNF (http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)
+# <query> ::= <header> <question>
+# <header> ::= <ID> <QR> <OPCODE> <AA> <TC> <RD> <RA> <Z> <AD> <CD> <RCODE>
+#              <QDCOUNT> <ANCOUNT> <NSCOUNT> <ARCOUNT>
+# <question> ::= <QNAME> <QTYPE> <QCLASS>
+#
+# <response> ::= <header> <question> <answer> <authority> <additional>
+# <answer> ::= <rrset>
+# <authority> ::= <rrset>
+# <additional> ::= <rrset>
+# <rrset> ::= { <rr> }
+# <rr> ::= <name> <type> <class> <ttl> <rdlength> <rdata>
+# <name> ::= <subdomain> | ""
+# <subdomain> ::= <label> | <subdomain> "." <label>
+# <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+# <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+# <let-dig-hyp> ::= <let-dig> | "-"
+# <let-dig> ::= <letter> | <digit>
+# <letter> ::= "a" | .. | "z" | "A" | .. | "Z"
+# <digit> ::= "0" | .. | "9"
+# <type> ::= A | NS | CNAME | SOA | PTR | MX | ..
+# <class> ::= IN | CH | HS | CS
+# <ttl> ::= <digit> | { <digit> }
+# <rdlength> ::= <digit> | { <digit> }
+# <rdata> ::= <address> |
+#             <nsdname> |
+#             <cname> |
+#             <preference> <exchange> |
+#             <ptrdname> |
+#             ...
+
+0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com A IN
+1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com A IN
+2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+3 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+4 0 0 0 0 1 0 0 0 0 0 1 0 0 0 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+5 0 0 0 0 1 0 0 0 0 0 1 0 0 0 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+6 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com A IN
+7 0 0 0 0 1 0 0 0 0 0 1 0 0 0 B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com A IN
+8 0 0 0 0 1 0 0 0 0 0 1 0 0 0 M.example.com A IN
+9 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-a-record.example.com A IN
+
+10 0 0 0 0 1 0 0 0 0 0 1 0 0 0 NS.example.com A IN
+11 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nS.example.com A IN
+12 0 0 0 0 1 0 0 0 0 0 1 0 0 0 NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+13 0 0 0 0 1 0 0 0 0 0 1 0 0 0 NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+14 0 0 0 0 1 0 0 0 0 0 1 0 0 0 N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com A IN
+15 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.multiple-type-ns-record.example.com a IN
+
+20 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.example.com A IN
+21 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.example.com CNAME IN
+22 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.example.com MX IN
+23 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.example.com ANY IN
+
+24 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C0.example.com A IN
+25 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C0.example.com CNAME IN
+26 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C0.example.com MX IN
+27 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C0.example.com ANY IN
+
+28 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C10.example.com A IN
+29 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C10.example.com CNAME IN
+30 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C10.example.com MX IN
+31 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C10.example.com ANY IN
+
+32 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C36.example.com A IN
+33 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C36.example.com CNAME IN
+34 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C36.example.com MX IN
+35 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C36.example.com ANY IN
+
+36 0 0 0 0 1 0 0 0 0 0 1 0 0 0 c.Example.coM A IN
+37 0 0 0 0 1 0 0 0 0 0 1 0 0 0 c.Example.coM CNAME IN
+38 0 0 0 0 1 0 0 0 0 0 1 0 0 0 c.Example.coM MX IN
+39 0 0 0 0 1 0 0 0 0 0 1 0 0 0 c.Example.coM ANY IN
+
+40 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com A IN
+41 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com CNAME IN
+42 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com MX IN
+43 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com ANY IN
+
+44 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA3.example.com A IN
+45 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA3.example.com CNAME IN
+46 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA3.example.com MX IN
+47 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA3.example.com ANY IN
+
+48 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA4.example.com A IN
+49 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA4.example.com CNAME IN
+50 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA4.example.com MX IN
+51 0 0 0 0 1 0 0 0 0 0 1 0 0 0 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA1.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA2.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA4.example.com ANY IN
+
+52 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.example.com A IN
+53 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.example.com CNAME IN
+54 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.example.com MX IN
+55 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.example.com ANY IN
+
+56 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.1.example.com A IN
+57 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.1.example.com CNAME IN
+58 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.1.example.com MX IN
+59 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.1.example.com ANY IN
+
+60 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C0.name1.cn A IN
+61 0 0 0 0 1 0 0 0 0 0 1 0 0 0 C12.name1.cn A IN
+
+70 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com SOA IN
+71 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com ANY IN
+
+72 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example1.com SOA IN
+73 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example1.com A IN
+74 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example1.com NS IN
+75 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example1.com ANY IN
+
+76 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example2.com SOA IN
+77 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example2.com A IN
+78 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example2.com NS IN
+79 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example2.com ANY IN
+
+80 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example3.com SOA IN
+81 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example3.com A IN
+82 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example3.com NS IN
+83 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example3.com ANY IN
+
+84 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example4.com SOA IN
+85 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example4.com A IN
+86 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example4.com NS IN
+87 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example4.com ANY IN
+
+88 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example13.com SOA IN
+89 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example13.com A IN
+90 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example13.com NS IN
+91 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example13.com ANY IN
+
+92 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.example.com A IN
+93 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.example.com ANY IN
+94 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.example.com NS IN
+
+95 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example9.com SOA IN
+96 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example9.com ns IN
+97 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example9.com ANY IN
+
+98 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.example.com SOA IN
+99 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.noexist SOA IN
+
+100 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1.1.10.10.in-addr.arpA PTR IN
+101 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com PTR IN
+102 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1.1.10.10.in-addr.arpa PTR IN
+103 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.examPle.com PTR IN
+104 0 0 0 0 1 0 0 0 0 0 1 0 0 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com PTR IN
+105 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com PTR IN
+106 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com PTR IN
+107 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1.2.168.192.in-addr.arpa PTR IN
+108 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-a-record.example.com PTR IN
+
+110 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com MX IN
+111 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com MX IN
+112 0 0 0 0 1 0 0 0 0 0 1 0 0 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com MX IN
+113 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com MX IN
+114 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com MX IN
+115 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-mx-record.example.com MX IN
+
+120 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com TXT IN
+121 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com TXT IN
+122 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com TXT IN
+123 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com TXT IN
+124 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com TXT IN
+125 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-txt-record.example.com TXT IN
+
+130 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com AAAA IN
+131 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com AAAA IN
+132 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com AAAA IN
+133 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com AAAA IN
+134 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com AAAA IN
+135 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-aaaa-record.example.com AAAA IN
+
+140 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com NAPTR IN
+141 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com NAPTR IN
+142 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NAPTR IN
+143 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com NAPTR IN
+144 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com NAPTR IN
+145 0 0 0 0 1 0 0 0 0 0 1 0 0 0 2.1.2.1.5.5.5.0.7.7.1.e164.arpa NAPTR IN
+146 0 0 0 0 1 0 0 0 0 0 1 0 0 0 b.e164.arpa NAPTR IN
+147 0 0 0 0 1 0 0 0 0 0 1 0 0 0 6.8.e164.arpa NAPTR IN
+
+#150 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com A6 IN
+#151 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com A6 IN
+#152 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A6 IN
+#153 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A6 IN
+#154 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com A6 IN
+#155 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-a6-record.example.com A6 IN
+
+# case 160-163
+160 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com DNAME IN
+161 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com ANY IN
+162 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.A.example.com A IN
+163 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.A.example.com ANY IN
+
+# case 164-167
+164 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.exAmple.com DNAME IN
+165 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.exAmple.com ANY IN
+166 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.a.exAmple.com A IN
+167 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.a.exAmple.com ANY IN
+
+# case 168-171
+168 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DNAME IN
+169 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+170 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+171 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+
+# case 172-175
+172 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com DNAME IN
+173 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com ANY IN
+174 0 0 0 0 1 0 0 0 0 0 1 0 0 0 D.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+175 0 0 0 0 1 0 0 0 0 0 1 0 0 0 D.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com ANY IN
+
+# case 176-179
+176 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.example.com DNAME IN
+177 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.example.com ANY IN
+178 0 0 0 0 1 0 0 0 0 0 1 0 0 0 D.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.example.com A IN
+179 0 0 0 0 1 0 0 0 0 0 1 0 0 0 D.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.example.com ANY IN
+
+# case 180-195
+180 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d0.example.com a IN
+181 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d1.example.com a IN
+182 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d2.example.com a IN
+183 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d4.example.com a IN
+184 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d5.example.com a IN
+185 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ns.d0.example.com a IN
+186 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.a.b.d1.example.com a IN
+187 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.a.b.d1.example.com mx IN
+
+188 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d10.example.com a IN
+189 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d20.example.com a IN
+190 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d30.example.com a IN
+191 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d40.example.com a IN
+192 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d50.example.com a IN
+193 0 0 0 0 1 0 0 0 0 0 1 0 0 0 c45.example.com any IN
+194 0 0 0 0 1 0 0 0 0 0 1 0 0 0 d45.example.com any IN
+195 0 0 0 0 1 0 0 0 0 0 1 0 0 0 noexist.d45.example.com any IN
+196 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d45.example.com any IN
+
+197 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.d72.example.com a IN
+198 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.d1.example.com a IN
+
+# case 200-205
+200 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com WKS IN
+201 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com WKS IN
+202 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com WKS IN
+203 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com WKS IN
+204 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com WKS IN
+205 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-wks-record.example.com WKS IN
+
+# case 210-215
+210 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com HINFO IN
+211 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com HINFO IN
+212 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com HINFO IN
+213 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com HINFO IN
+214 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com HINFO IN
+215 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-hinfo-record.example.com HINFO IN
+
+# case 220-225
+220 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com MINFO IN
+221 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com MINFO IN
+222 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com MINFO IN
+223 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com MINFO IN
+224 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com MINFO IN
+225 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-minfo-record.example.com MINFO IN
+
+# case 230-235
+230 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com NSAP IN
+231 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com NSAP IN
+232 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NSAP IN
+233 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com NSAP IN
+234 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com NSAP IN
+235 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-nsap-record.example.com NSAP IN
+
+# case 240-245
+240 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com PX IN
+241 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com PX IN
+242 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com PX IN
+243 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com PX IN
+244 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com PX IN
+245 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-px-record.example.com PX IN
+
+# case 250-255
+250 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com LOC IN
+251 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com LOC IN
+252 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com LOC IN
+253 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com LOC IN
+254 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com LOC IN
+255 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-loc-record.example.com LOC IN
+
+# case 260-265
+260 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com SRV IN
+261 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com SRV IN
+262 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SRV IN
+263 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com SRV IN
+264 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com SRV IN
+265 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-srv-record.example.com SRV IN
+
+# case 270-275
+270 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com KX IN
+271 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com KX IN
+272 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com KX IN
+273 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com KX IN
+274 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com KX IN
+275 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-kx-record.example.com KX IN
+
+# case 280-285
+280 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com CERT IN
+281 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com CERT IN
+282 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com CERT IN
+283 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com CERT IN
+284 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com CERT IN
+285 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-cert-record.example.com CERT IN
+
+# case 290-295
+290 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com APL IN
+291 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com APL IN
+292 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com APL IN
+293 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com APL IN
+294 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com APL IN
+295 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-apl-record.example.com APL IN
+
+# case 300-305
+300 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com SSHFP IN
+301 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com SSHFP IN
+302 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SSHFP IN
+303 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com SSHFP IN
+304 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com SSHFP IN
+305 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-sshfp-record.example.com SSHFP IN
+
+# case 310-315
+310 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com IPSECKEY IN
+311 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com IPSECKEY IN
+312 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com IPSECKEY IN
+313 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com IPSECKEY IN
+314 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com IPSECKEY IN
+315 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-ipseckey-record.example.com IPSECKEY IN
+
+# case 320-325
+#320 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com DHCID IN
+#321 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com DHCID IN
+#322 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DHCID IN
+#323 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com DHCID IN
+#324 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com DHCID IN
+#325 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-dhcid-record.example.com DHCID IN
+
+# case 330-335
+330 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.example.com SPF IN
+331 0 0 0 0 1 0 0 0 0 0 1 0 0 0 a.example.com SPF IN
+332 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SPF IN
+333 0 0 0 0 1 0 0 0 0 0 1 0 0 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com SPF IN
+334 0 0 0 0 1 0 0 0 0 0 1 0 0 0 A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com SPF IN
+335 0 0 0 0 1 0 0 0 0 0 1 0 0 0 multiple-type-spf-record.example.com SPF IN
+
+360 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0.example.com A IN
+361 0 0 0 0 1 0 0 0 0 0 1 0 0 0 9.example.com A IN
+
+370 0 0 0 0 1 0 0 0 0 0 1 0 0 0 sub-cname.example.com A IN
+371 0 0 0 0 1 0 0 0 0 0 1 0 0 0 www.sub-dname.example.com A IN
+
+381 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-a-answer.toobigudp.com A IN
+382 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-a-authority.toobigudp.com A IN
+383 0 0 0 0 1 0 0 0 0 0 1 0 0 0 toobigudp.com NS IN
+384 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-txt-answer.toobigudp.com TXT IN
+385 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-txt-authority.toobigudp.com TXT IN
+386 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-cname-answer.toobigudp.com A IN
+387 0 0 0 0 1 0 0 0 0 0 1 0 0 0 type-cname-answer.toobigudp.com TXT IN
+
+390 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com DNSKEY IN
+391 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com RRSIG IN
+392 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com NSEC IN
+393 0 0 0 0 1 0 0 0 0 0 1 0 0 0 example.com DS IN
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 authors.bind txt CH
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 authors.bind txt CH
diff --git a/tools/query_cmp/queries/dquery01_no-type b/tools/query_cmp/queries/dquery01_no-type
new file mode 100644
index 0000000..69b09ba
--- /dev/null
+++ b/tools/query_cmp/queries/dquery01_no-type
@@ -0,0 +1,316 @@
+# Fields Description             
+#               
+#query:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT testa.no-type.QNAME QTYPE QCLASS
+#response:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT testa.no-type.QNAME QTYPE QCLASS
+# <answer> := <rr1> .. <rrN>          
+# <rr> := NAME TYPE CLASS TTL RDLENGTH <rdata>       
+# <rdata> := ADDRESS |           
+# NSDNAME |             
+# MNAME RNAME SERIAL REFRESH RETRY EXPIRE MINIMUM |       
+# ...              
+# <authority> := <rr1> .. <rrN>          
+# <additional> := <rr1> .. <rrN>          
+#               
+#               
+#               
+# Description in BNF (http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)           
+# <query> ::= <header> <question>           
+# <header> ::= <ID> <QR> <OPCODE> <AA> <TC> <RD> <RA> <Z> <AD> <CD> <RCODE>  
+# <QDCOUNT> <ANCOUNT> <NSCOUNT> <ARCOUNT>           
+# <question> ::= <QNAME> <QTYPE> <QCLASS>          
+#               
+# <response> ::= <header> <question> <answer> <authority> <additional>        
+# <answer> ::= <rrset>            
+# <authority> ::= <rrset>            
+# <additional> ::= <rrset>            
+# <rrset> ::= { <rr> }          
+# <rr> ::= <name> <type> <class> <ttl> <rdlength> <rdata>       
+# <name> ::= <subdomain> | ""          
+# <subdomain> ::= <label> | <subdomain> "." <label>        
+# <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]      
+# <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>         
+# <let-dig-hyp> ::= <let-dig> | "-"          
+# <let-dig> ::= <letter> | <digit>          
+# <letter> ::= "a" | .. | "z" | "A" | .. | "Z"  
+# <digit> ::= "0" | .. | "9"        
+# <type> ::= A | NS | CNAME | SOA | PTR | MX | testa.no-type...  
+# <class> ::= IN | CH | HS | CS      
+# <ttl> ::= <digit> | { <digit> }        
+# <rdlength> ::= <digit> | { <digit> }        
+# <rdata> ::= <address> |           
+# <nsdname> |             
+# <cname> |             
+# <preference> <exchange> |            
+# <ptrdname> |             
+# ...              
+               
+0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com A IN
+1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com A IN
+2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+5 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+8 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.M.example.com A IN
+9 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-a-record.example.com A IN
+               
+10 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.NS.example.com A IN
+11 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.nS.example.com A IN
+12 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+15 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.multiple-type-ns-record.example.com a IN
+               
+20 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C.example.com A IN
+21 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C.example.com CNAME IN
+22 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C.example.com MX IN
+23 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C.example.com ANY IN
+               
+24 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C0.example.com A IN
+25 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C0.example.com CNAME IN
+26 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C0.example.com MX IN
+27 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C0.example.com ANY IN
+               
+28 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C10.example.com A IN
+29 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C10.example.com CNAME IN
+30 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C10.example.com MX IN
+31 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C10.example.com ANY IN
+               
+32 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C36.example.com A IN
+33 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C36.example.com CNAME IN
+34 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C36.example.com MX IN
+35 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C36.example.com ANY IN
+               
+36 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.c.Example.coM A IN
+37 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.c.Example.coM CNAME IN
+38 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.c.Example.coM MX IN
+39 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.c.Example.coM ANY IN
+               
+40 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com A IN
+41 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com CNAME IN
+42 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com MX IN
+43 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com ANY IN
+               
+60 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C0.name1.cn A IN
+61 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.C12.name1.cn A IN
+               
+70 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com SOA IN
+71 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com ANY IN
+               
+72 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example1.com SOA IN
+73 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example1.com A IN
+74 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example1.com NS IN
+75 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example1.com ANY IN
+               
+76 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example2.com SOA IN
+77 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example2.com A IN
+78 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example2.com NS IN
+79 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example2.com ANY IN
+               
+80 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example3.com SOA IN
+81 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example3.com A IN
+82 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example3.com NS IN
+83 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example3.com ANY IN
+               
+84 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example4.com SOA IN
+85 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example4.com A IN
+86 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example4.com NS IN
+87 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example4.com ANY IN
+               
+88 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example13.com SOA IN
+89 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example13.com A IN
+90 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example13.com NS IN
+91 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example13.com ANY IN
+               
+92 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.example.com A IN
+93 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.example.com ANY IN
+94 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.example.com NS IN
+               
+95 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example9.com SOA IN
+96 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example9.com ns IN
+97 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example9.com ANY IN
+               
+98 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.example.com SOA IN
+99 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.noexist SOA IN
+               
+100 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.1.1.10.10.in-addr.arpA PTR IN
+101 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com PTR IN
+102 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.1.1.10.10.in-addr.arpa PTR IN
+103 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.examPle.com PTR IN
+104 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com PTR IN
+107 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.1.2.168.192.in-addr.arpa PTR IN
+108 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-a-record.example.com PTR IN
+               
+110 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com MX IN
+111 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com MX IN
+112 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com MX IN
+115 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-mx-record.example.com MX IN
+               
+120 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com TXT IN
+121 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com TXT IN
+122 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com TXT IN
+125 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-txt-record.example.com TXT IN
+               
+130 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com AAAA IN
+131 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com AAAA IN
+132 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com AAAA IN
+135 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-aaaa-record.example.com AAAA IN
+               
+140 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com NAPTR IN
+141 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com NAPTR IN
+142 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NAPTR IN
+145 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.2.1.2.1.5.5.5.0.7.7.1.e164.arpa NAPTR IN
+146 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.b.e164.arpa NAPTR IN
+147 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.6.8.e164.arpa NAPTR IN
+               
+#150 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com A6 IN
+#151 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com A6 IN
+#152 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A6 IN
+#155 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-a6-record.example.com A6 IN
+               
+# case 160-163             
+160 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com DNAME IN
+161 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com ANY IN
+162 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.A.example.com A IN
+163 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.A.example.com ANY IN
+               
+# case 164-167             
+164 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.exAmple.com DNAME IN
+165 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.exAmple.com ANY IN
+166 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.a.exAmple.com A IN
+167 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.a.exAmple.com ANY IN
+               
+# case 168-171             
+168 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DNAME IN
+169 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+170 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+171 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+               
+# case 180-195             
+180 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d0.example.com a IN
+181 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d1.example.com a IN
+182 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d2.example.com a IN
+183 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d4.example.com a IN
+184 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d5.example.com a IN
+185 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.ns.d0.example.com a IN
+186 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.a.b.d1.example.com a IN
+187 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.a.b.d1.example.com mx IN
+               
+188 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d10.example.com a IN
+189 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d20.example.com a IN
+190 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d30.example.com a IN
+191 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d40.example.com a IN
+192 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d50.example.com a IN
+193 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.c45.example.com any IN
+194 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.d45.example.com any IN
+195 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.noexist.d45.example.com any IN
+196 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d45.example.com any IN
+               
+197 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.d72.example.com a IN
+198 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.d1.example.com a IN
+               
+# case 200-205             
+200 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com WKS IN
+201 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com WKS IN
+202 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com WKS IN
+205 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-wks-record.example.com WKS IN
+               
+# case 210-215             
+210 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com HINFO IN
+211 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com HINFO IN
+212 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com HINFO IN
+215 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-hinfo-record.example.com HINFO IN
+               
+# case 220-225             
+220 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com MINFO IN
+221 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com MINFO IN
+222 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com MINFO IN
+225 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-minfo-record.example.com MINFO IN
+               
+# case 230-235             
+230 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com NSAP IN
+231 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com NSAP IN
+232 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NSAP IN
+235 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-nsap-record.example.com NSAP IN
+               
+# case 240-245             
+240 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com PX IN
+241 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com PX IN
+242 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com PX IN
+245 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-px-record.example.com PX IN
+               
+# case 250-255             
+250 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com LOC IN
+251 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com LOC IN
+252 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com LOC IN
+255 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-loc-record.example.com LOC IN
+               
+# case 260-265             
+260 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com SRV IN
+261 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com SRV IN
+262 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SRV IN
+265 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-srv-record.example.com SRV IN
+               
+# case 270-275             
+270 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com KX IN
+271 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com KX IN
+272 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com KX IN
+275 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-kx-record.example.com KX IN
+               
+# case 280-285             
+280 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com CERT IN
+281 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com CERT IN
+282 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com CERT IN
+285 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-cert-record.example.com CERT IN
+               
+# case 290-295             
+290 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com APL IN
+291 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com APL IN
+292 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com APL IN
+295 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-apl-record.example.com APL IN
+               
+# case 300-305             
+300 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com SSHFP IN
+301 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com SSHFP IN
+302 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SSHFP IN
+305 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-sshfp-record.example.com SSHFP IN
+               
+# case 310-315             
+310 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com IPSECKEY IN
+311 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com IPSECKEY IN
+312 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com IPSECKEY IN
+315 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-ipseckey-record.example.com IPSECKEY IN
+               
+# case 320-325             
+#320 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com DHCID IN
+#321 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com DHCID IN
+#322 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DHCID IN
+#325 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-dhcid-record.example.com DHCID IN
+               
+# case 330-335             
+330 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.A.example.com SPF IN
+331 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.a.example.com SPF IN
+332 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SPF IN
+335 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.multiple-type-spf-record.example.com SPF IN
+               
+360 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.0.example.com A IN
+361 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.9.example.com A IN
+               
+370 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.sub-cname.example.com A IN
+371 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.www.sub-dname.example.com A IN
+               
+381 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-a-answer.toobigudp.com A IN
+382 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-a-authority.toobigudp.com A IN
+383 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.toobigudp.com NS IN
+384 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-txt-answer.toobigudp.com TXT IN
+385 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-txt-authority.toobigudp.com TXT IN
+386 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-cname-answer.toobigudp.com A IN
+387 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.type-cname-answer.toobigudp.com TXT IN
+               
+390 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com DNSKEY IN
+391 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com RRSIG IN
+392 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com NSEC IN
+393 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.example.com DS IN
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.authors.bind txt CH
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 testa.no-type.authors.bind txt CH
diff --git a/tools/query_cmp/queries/dquery01_non-terminal b/tools/query_cmp/queries/dquery01_non-terminal
new file mode 100644
index 0000000..2bbd9de
--- /dev/null
+++ b/tools/query_cmp/queries/dquery01_non-terminal
@@ -0,0 +1,317 @@
+# Fields Description             
+#               
+#query:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT non-terminal.QNAME QTYPE QCLASS
+#response:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT non-terminal.QNAME QTYPE QCLASS
+# <answer> := <rr1> .. <rrN>          
+# <rr> := NAME TYPE CLASS TTL RDLENGTH <rdata>       
+# <rdata> := ADDRESS |           
+# NSDNAME |             
+# MNAME RNAME SERIAL REFRESH RETRY EXPIRE MINIMUM |       
+# ...              
+# <authority> := <rr1> .. <rrN>          
+# <additional> := <rr1> .. <rrN>          
+#               
+#               
+#               
+# Description in BNF (http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)           
+# <query> ::= <header> <question>           
+# <header> ::= <ID> <QR> <OPCODE> <AA> <TC> <RD> <RA> <Z> <AD> <CD> <RCODE>  
+# <QDCOUNT> <ANCOUNT> <NSCOUNT> <ARCOUNT>           
+# <question> ::= <QNAME> <QTYPE> <QCLASS>          
+#               
+# <response> ::= <header> <question> <answer> <authority> <additional>        
+# <answer> ::= <rrset>            
+# <authority> ::= <rrset>            
+# <additional> ::= <rrset>            
+# <rrset> ::= { <rr> }          
+# <rr> ::= <name> <type> <class> <ttl> <rdlength> <rdata>       
+# <name> ::= <subdomain> | ""          
+# <subdomain> ::= <label> | <subdomain> "." <label>        
+# <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]      
+# <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>         
+# <let-dig-hyp> ::= <let-dig> | "-"          
+# <let-dig> ::= <letter> | <digit>          
+# <letter> ::= "a" | .. | "z" | "A" | .. | "Z"  
+# <digit> ::= "0" | .. | "9"        
+# <type> ::= A | NS | CNAME | SOA | PTR | MX | non-terminal...  
+# <class> ::= IN | CH | HS | CS      
+# <ttl> ::= <digit> | { <digit> }        
+# <rdlength> ::= <digit> | { <digit> }        
+# <rdata> ::= <address> |           
+# <nsdname> |             
+# <cname> |             
+# <preference> <exchange> |            
+# <ptrdname> |             
+# ...              
+               
+0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com A IN
+1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com A IN
+2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+5 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+8 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.M.example.com A IN
+9 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-a-record.example.com A IN
+               
+10 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.NS.example.com A IN
+11 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.nS.example.com A IN
+12 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+15 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.multiple-type-ns-record.example.com a IN
+               
+20 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C.example.com A IN
+21 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C.example.com CNAME IN
+22 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C.example.com MX IN
+23 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C.example.com ANY IN
+               
+24 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C0.example.com A IN
+25 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C0.example.com CNAME IN
+26 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C0.example.com MX IN
+27 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C0.example.com ANY IN
+               
+28 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C10.example.com A IN
+29 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C10.example.com CNAME IN
+30 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C10.example.com MX IN
+31 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C10.example.com ANY IN
+               
+32 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C36.example.com A IN
+33 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C36.example.com CNAME IN
+34 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C36.example.com MX IN
+35 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C36.example.com ANY IN
+               
+36 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.c.Example.coM A IN
+37 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.c.Example.coM CNAME IN
+38 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.c.Example.coM MX IN
+39 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.c.Example.coM ANY IN
+               
+40 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com A IN
+41 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com CNAME IN
+42 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com MX IN
+43 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com ANY IN
+               
+               
+60 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C0.name1.cn A IN
+61 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.C12.name1.cn A IN
+               
+70 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com SOA IN
+71 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com ANY IN
+               
+72 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example1.com SOA IN
+73 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example1.com A IN
+74 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example1.com NS IN
+75 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example1.com ANY IN
+               
+76 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example2.com SOA IN
+77 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example2.com A IN
+78 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example2.com NS IN
+79 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example2.com ANY IN
+               
+80 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example3.com SOA IN
+81 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example3.com A IN
+82 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example3.com NS IN
+83 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example3.com ANY IN
+               
+84 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example4.com SOA IN
+85 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example4.com A IN
+86 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example4.com NS IN
+87 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example4.com ANY IN
+               
+88 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example13.com SOA IN
+89 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example13.com A IN
+90 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example13.com NS IN
+91 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example13.com ANY IN
+               
+92 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.example.com A IN
+93 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.example.com ANY IN
+94 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.example.com NS IN
+               
+95 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example9.com SOA IN
+96 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example9.com ns IN
+97 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example9.com ANY IN
+               
+98 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.example.com SOA IN
+99 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.noexist SOA IN
+               
+100 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.1.1.10.10.in-addr.arpA PTR IN
+101 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com PTR IN
+102 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.1.1.10.10.in-addr.arpa PTR IN
+103 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.examPle.com PTR IN
+104 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com PTR IN
+107 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.1.2.168.192.in-addr.arpa PTR IN
+108 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-a-record.example.com PTR IN
+               
+110 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com MX IN
+111 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com MX IN
+112 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com MX IN
+115 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-mx-record.example.com MX IN
+               
+120 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com TXT IN
+121 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com TXT IN
+122 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com TXT IN
+125 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-txt-record.example.com TXT IN
+               
+130 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com AAAA IN
+131 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com AAAA IN
+132 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com AAAA IN
+135 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-aaaa-record.example.com AAAA IN
+               
+140 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com NAPTR IN
+141 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com NAPTR IN
+142 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NAPTR IN
+145 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.2.1.2.1.5.5.5.0.7.7.1.e164.arpa NAPTR IN
+146 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.b.e164.arpa NAPTR IN
+147 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.6.8.e164.arpa NAPTR IN
+               
+#150 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com A6 IN
+#151 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com A6 IN
+#152 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A6 IN
+#155 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-a6-record.example.com A6 IN
+               
+# case 160-163             
+160 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com DNAME IN
+161 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com ANY IN
+162 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.A.example.com A IN
+163 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.A.example.com ANY IN
+               
+# case 164-167             
+164 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.exAmple.com DNAME IN
+165 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.exAmple.com ANY IN
+166 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.a.exAmple.com A IN
+167 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.a.exAmple.com ANY IN
+               
+# case 168-171             
+168 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DNAME IN
+169 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+170 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+171 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+               
+# case 180-195             
+180 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d0.example.com a IN
+181 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d1.example.com a IN
+182 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d2.example.com a IN
+183 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d4.example.com a IN
+184 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d5.example.com a IN
+185 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.ns.d0.example.com a IN
+186 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.a.b.d1.example.com a IN
+187 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.a.b.d1.example.com mx IN
+               
+188 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d10.example.com a IN
+189 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d20.example.com a IN
+190 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d30.example.com a IN
+191 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d40.example.com a IN
+192 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d50.example.com a IN
+193 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.c45.example.com any IN
+194 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.d45.example.com any IN
+195 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.noexist.d45.example.com any IN
+196 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d45.example.com any IN
+               
+197 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.d72.example.com a IN
+198 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.d1.example.com a IN
+               
+# case 200-205             
+200 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com WKS IN
+201 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com WKS IN
+202 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com WKS IN
+205 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-wks-record.example.com WKS IN
+               
+# case 210-215             
+210 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com HINFO IN
+211 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com HINFO IN
+212 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com HINFO IN
+215 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-hinfo-record.example.com HINFO IN
+               
+# case 220-225             
+220 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com MINFO IN
+221 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com MINFO IN
+222 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com MINFO IN
+225 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-minfo-record.example.com MINFO IN
+               
+# case 230-235             
+230 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com NSAP IN
+231 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com NSAP IN
+232 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NSAP IN
+235 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-nsap-record.example.com NSAP IN
+               
+# case 240-245             
+240 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com PX IN
+241 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com PX IN
+242 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com PX IN
+245 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-px-record.example.com PX IN
+               
+# case 250-255             
+250 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com LOC IN
+251 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com LOC IN
+252 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com LOC IN
+255 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-loc-record.example.com LOC IN
+               
+# case 260-265             
+260 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com SRV IN
+261 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com SRV IN
+262 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SRV IN
+265 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-srv-record.example.com SRV IN
+               
+# case 270-275             
+270 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com KX IN
+271 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com KX IN
+272 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com KX IN
+275 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-kx-record.example.com KX IN
+               
+# case 280-285             
+280 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com CERT IN
+281 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com CERT IN
+282 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com CERT IN
+285 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-cert-record.example.com CERT IN
+               
+# case 290-295             
+290 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com APL IN
+291 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com APL IN
+292 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com APL IN
+295 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-apl-record.example.com APL IN
+               
+# case 300-305             
+300 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com SSHFP IN
+301 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com SSHFP IN
+302 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SSHFP IN
+305 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-sshfp-record.example.com SSHFP IN
+               
+# case 310-315             
+310 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com IPSECKEY IN
+311 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com IPSECKEY IN
+312 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com IPSECKEY IN
+315 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-ipseckey-record.example.com IPSECKEY IN
+               
+# case 320-325             
+#320 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com DHCID IN
+#321 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com DHCID IN
+#322 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DHCID IN
+#325 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-dhcid-record.example.com DHCID IN
+               
+# case 330-335             
+330 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.A.example.com SPF IN
+331 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.a.example.com SPF IN
+332 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SPF IN
+335 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.multiple-type-spf-record.example.com SPF IN
+               
+360 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.0.example.com A IN
+361 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.9.example.com A IN
+               
+370 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.sub-cname.example.com A IN
+371 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.www.sub-dname.example.com A IN
+               
+381 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-a-answer.toobigudp.com A IN
+382 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-a-authority.toobigudp.com A IN
+383 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.toobigudp.com NS IN
+384 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-txt-answer.toobigudp.com TXT IN
+385 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-txt-authority.toobigudp.com TXT IN
+386 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-cname-answer.toobigudp.com A IN
+387 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.type-cname-answer.toobigudp.com TXT IN
+               
+390 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com DNSKEY IN
+391 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com RRSIG IN
+392 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com NSEC IN
+393 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.example.com DS IN
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.authors.bind txt CH
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 non-terminal.authors.bind txt CH
diff --git a/tools/query_cmp/queries/dquery01_nxdomain b/tools/query_cmp/queries/dquery01_nxdomain
new file mode 100644
index 0000000..aed1ceb
--- /dev/null
+++ b/tools/query_cmp/queries/dquery01_nxdomain
@@ -0,0 +1,316 @@
+# Fields Description             
+#               
+#query:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT nxdomain.QNAME QTYPE QCLASS
+#response:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT nxdomain.QNAME QTYPE QCLASS
+# <answer> := <rr1> .. <rrN>          
+# <rr> := NAME TYPE CLASS TTL RDLENGTH <rdata>       
+# <rdata> := ADDRESS |           
+# NSDNAME |             
+# MNAME RNAME SERIAL REFRESH RETRY EXPIRE MINIMUM |       
+# ...              
+# <authority> := <rr1> .. <rrN>          
+# <additional> := <rr1> .. <rrN>          
+#               
+#               
+#               
+# Description in BNF (http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)           
+# <query> ::= <header> <question>           
+# <header> ::= <ID> <QR> <OPCODE> <AA> <TC> <RD> <RA> <Z> <AD> <CD> <RCODE>  
+# <QDCOUNT> <ANCOUNT> <NSCOUNT> <ARCOUNT>           
+# <question> ::= <QNAME> <QTYPE> <QCLASS>          
+#               
+# <response> ::= <header> <question> <answer> <authority> <additional>        
+# <answer> ::= <rrset>            
+# <authority> ::= <rrset>            
+# <additional> ::= <rrset>            
+# <rrset> ::= { <rr> }          
+# <rr> ::= <name> <type> <class> <ttl> <rdlength> <rdata>       
+# <name> ::= <subdomain> | ""          
+# <subdomain> ::= <label> | <subdomain> "." <label>        
+# <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]      
+# <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>         
+# <let-dig-hyp> ::= <let-dig> | "-"          
+# <let-dig> ::= <letter> | <digit>          
+# <letter> ::= "a" | .. | "z" | "A" | .. | "Z"  
+# <digit> ::= "0" | .. | "9"        
+# <type> ::= A | NS | CNAME | SOA | PTR | MX | nxdomain...  
+# <class> ::= IN | CH | HS | CS      
+# <ttl> ::= <digit> | { <digit> }        
+# <rdlength> ::= <digit> | { <digit> }        
+# <rdata> ::= <address> |           
+# <nsdname> |             
+# <cname> |             
+# <preference> <exchange> |            
+# <ptrdname> |             
+# ...              
+               
+0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com A IN
+1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com A IN
+2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+5 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com A IN
+8 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.M.example.com A IN
+9 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-a-record.example.com A IN
+               
+10 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.NS.example.com A IN
+11 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.nS.example.com A IN
+12 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+15 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.multiple-type-ns-record.example.com a IN
+               
+20 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C.example.com A IN
+21 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C.example.com CNAME IN
+22 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C.example.com MX IN
+23 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C.example.com ANY IN
+               
+24 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C0.example.com A IN
+25 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C0.example.com CNAME IN
+26 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C0.example.com MX IN
+27 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C0.example.com ANY IN
+               
+28 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C10.example.com A IN
+29 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C10.example.com CNAME IN
+30 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C10.example.com MX IN
+31 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C10.example.com ANY IN
+               
+32 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C36.example.com A IN
+33 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C36.example.com CNAME IN
+34 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C36.example.com MX IN
+35 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C36.example.com ANY IN
+               
+36 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.c.Example.coM A IN
+37 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.c.Example.coM CNAME IN
+38 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.c.Example.coM MX IN
+39 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.c.Example.coM ANY IN
+               
+40 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com A IN
+41 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com CNAME IN
+42 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com MX IN
+43 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com ANY IN
+               
+60 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C0.name1.cn A IN
+61 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.C12.name1.cn A IN
+               
+70 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com SOA IN
+71 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com ANY IN
+               
+72 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example1.com SOA IN
+73 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example1.com A IN
+74 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example1.com NS IN
+75 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example1.com ANY IN
+               
+76 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example2.com SOA IN
+77 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example2.com A IN
+78 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example2.com NS IN
+79 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example2.com ANY IN
+               
+80 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example3.com SOA IN
+81 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example3.com A IN
+82 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example3.com NS IN
+83 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example3.com ANY IN
+               
+84 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example4.com SOA IN
+85 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example4.com A IN
+86 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example4.com NS IN
+87 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example4.com ANY IN
+               
+88 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example13.com SOA IN
+89 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example13.com A IN
+90 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example13.com NS IN
+91 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example13.com ANY IN
+               
+92 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.example.com A IN
+93 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.example.com ANY IN
+94 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.example.com NS IN
+               
+95 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example9.com SOA IN
+96 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example9.com ns IN
+97 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example9.com ANY IN
+               
+98 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.example.com SOA IN
+99 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.noexist SOA IN
+               
+100 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.1.1.10.10.in-addr.arpA PTR IN
+101 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com PTR IN
+102 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.1.1.10.10.in-addr.arpa PTR IN
+103 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.examPle.com PTR IN
+104 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com PTR IN
+107 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.1.2.168.192.in-addr.arpa PTR IN
+108 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-a-record.example.com PTR IN
+               
+110 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com MX IN
+111 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com MX IN
+112 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com MX IN
+115 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-mx-record.example.com MX IN
+               
+120 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com TXT IN
+121 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com TXT IN
+122 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com TXT IN
+125 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-txt-record.example.com TXT IN
+               
+130 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com AAAA IN
+131 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com AAAA IN
+132 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com AAAA IN
+135 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-aaaa-record.example.com AAAA IN
+               
+140 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com NAPTR IN
+141 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com NAPTR IN
+142 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NAPTR IN
+145 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.2.1.2.1.5.5.5.0.7.7.1.e164.arpa NAPTR IN
+146 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.b.e164.arpa NAPTR IN
+147 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.6.8.e164.arpa NAPTR IN
+               
+#150 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com A6 IN
+#151 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com A6 IN
+#152 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A6 IN
+#155 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-a6-record.example.com A6 IN
+               
+# case 160-163             
+160 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com DNAME IN
+161 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com ANY IN
+162 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.A.example.com A IN
+163 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.A.example.com ANY IN
+               
+# case 164-167             
+164 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.exAmple.com DNAME IN
+165 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.exAmple.com ANY IN
+166 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.a.exAmple.com A IN
+167 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.a.exAmple.com ANY IN
+               
+# case 168-171             
+168 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DNAME IN
+169 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+170 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com A IN
+171 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com ANY IN
+               
+# case 180-195             
+180 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d0.example.com a IN
+181 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d1.example.com a IN
+182 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d2.example.com a IN
+183 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d4.example.com a IN
+184 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d5.example.com a IN
+185 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.ns.d0.example.com a IN
+186 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.a.b.d1.example.com a IN
+187 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.a.b.d1.example.com mx IN
+               
+188 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d10.example.com a IN
+189 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d20.example.com a IN
+190 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d30.example.com a IN
+191 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d40.example.com a IN
+192 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d50.example.com a IN
+193 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.c45.example.com any IN
+194 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.d45.example.com any IN
+195 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.noexist.d45.example.com any IN
+196 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d45.example.com any IN
+               
+197 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.d72.example.com a IN
+198 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.d1.example.com a IN
+               
+# case 200-205             
+200 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com WKS IN
+201 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com WKS IN
+202 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com WKS IN
+205 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-wks-record.example.com WKS IN
+               
+# case 210-215             
+210 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com HINFO IN
+211 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com HINFO IN
+212 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com HINFO IN
+215 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-hinfo-record.example.com HINFO IN
+               
+# case 220-225             
+220 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com MINFO IN
+221 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com MINFO IN
+222 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com MINFO IN
+225 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-minfo-record.example.com MINFO IN
+               
+# case 230-235             
+230 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com NSAP IN
+231 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com NSAP IN
+232 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com NSAP IN
+235 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-nsap-record.example.com NSAP IN
+               
+# case 240-245             
+240 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com PX IN
+241 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com PX IN
+242 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com PX IN
+245 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-px-record.example.com PX IN
+               
+# case 250-255             
+250 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com LOC IN
+251 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com LOC IN
+252 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com LOC IN
+255 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-loc-record.example.com LOC IN
+               
+# case 260-265             
+260 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com SRV IN
+261 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com SRV IN
+262 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SRV IN
+265 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-srv-record.example.com SRV IN
+               
+# case 270-275             
+270 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com KX IN
+271 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com KX IN
+272 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com KX IN
+275 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-kx-record.example.com KX IN
+               
+# case 280-285             
+280 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com CERT IN
+281 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com CERT IN
+282 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com CERT IN
+285 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-cert-record.example.com CERT IN
+               
+# case 290-295             
+290 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com APL IN
+291 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com APL IN
+292 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com APL IN
+295 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-apl-record.example.com APL IN
+               
+# case 300-305             
+300 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com SSHFP IN
+301 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com SSHFP IN
+302 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SSHFP IN
+305 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-sshfp-record.example.com SSHFP IN
+               
+# case 310-315             
+310 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com IPSECKEY IN
+311 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com IPSECKEY IN
+312 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com IPSECKEY IN
+315 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-ipseckey-record.example.com IPSECKEY IN
+               
+# case 320-325             
+#320 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com DHCID IN
+#321 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com DHCID IN
+#322 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com DHCID IN
+#325 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-dhcid-record.example.com DHCID IN
+               
+# case 330-335             
+330 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.A.example.com SPF IN
+331 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.a.example.com SPF IN
+332 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com SPF IN
+335 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.multiple-type-spf-record.example.com SPF IN
+               
+360 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.0.example.com A IN
+361 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.9.example.com A IN
+               
+370 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.sub-cname.example.com A IN
+371 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.www.sub-dname.example.com A IN
+               
+381 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-a-answer.toobigudp.com A IN
+382 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-a-authority.toobigudp.com A IN
+383 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.toobigudp.com NS IN
+384 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-txt-answer.toobigudp.com TXT IN
+385 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-txt-authority.toobigudp.com TXT IN
+386 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-cname-answer.toobigudp.com A IN
+387 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.type-cname-answer.toobigudp.com TXT IN
+               
+390 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com DNSKEY IN
+391 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com RRSIG IN
+392 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com NSEC IN
+393 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.example.com DS IN
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.authors.bind txt CH
+#0x1000 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.version.bind txt CH
+#0x1001 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.hostname.bind txt CH
+#0x1002 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.id.server txt CH
+#0x1003 0 0 0 0 1 0 0 0 0 0 1 0 0 0 nxdomain.authors.bind txt CH
diff --git a/tools/query_cmp/src/lib/compare_rrset.py b/tools/query_cmp/src/lib/compare_rrset.py
new file mode 100755
index 0000000..737d761
--- /dev/null
+++ b/tools/query_cmp/src/lib/compare_rrset.py
@@ -0,0 +1,285 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+import struct
+from pydnspp import *
+
+# Some position parameters used in the formatted output report.
+POS_TOTAL = 80
+POS_TITLE = 14
+POS_LEFT = int((POS_TOTAL - POS_TITLE) / 2)
+
+def get_header_field(msg):
+	header = {}
+	header['id'] = msg.get_qid()
+	header['qr'] = msg.get_header_flag(Message.HEADERFLAG_QR)
+	header['opcode'] = msg.get_opcode()
+	header['aa'] = msg.get_header_flag(Message.HEADERFLAG_AA)
+	header['tc'] = msg.get_header_flag(Message.HEADERFLAG_TC)
+	header['rd'] = msg.get_header_flag(Message.HEADERFLAG_RD)
+	header['ra'] = msg.get_header_flag(Message.HEADERFLAG_RA)
+	header['ad'] = msg.get_header_flag(Message.HEADERFLAG_AD)
+	header['cd'] = msg.get_header_flag(Message.HEADERFLAG_CD)
+	#header['rcode'] = dns.rcode.from_flags(msg.flags, msg.ednsflags)
+	header['rcode'] = msg.get_rcode()	
+
+	header['qdcount'] = msg.get_rr_count(Message.SECTION_QUESTION)
+	header['ancount'] = msg.get_rr_count(Message.SECTION_ANSWER)
+	header['nscount'] = msg.get_rr_count(Message.SECTION_AUTHORITY)
+	header['arcount'] = msg.get_rr_count(Message.SECTION_ADDITIONAL)
+
+	return header
+
+def header_cmp(buf, msg1, msg2, diff):
+	""" Compare the header of msg1 and msg2. 
+
+	@param buf: the formatted difference for output. 
+	@type buf: dict
+	@param diff: the key is each flag in the header, the value is 
+		     True for different and False for same
+	@type diff: dict
+	"""
+	
+	header1 = get_header_field(msg1)
+	header2 = get_header_field(msg2)
+
+	list = ['id', 'qr', 'opcode', 'aa', 'tc', 'rd', \
+		'ra', 'ad', 'cd', 'rcode', 'qdcount', 'ancount', \
+		'nscount', 'arcount']
+
+	for header in list:
+		diff[header] = header1[header] != header2[header]
+		
+	buf['header'] = ''
+	for key in list:
+		if diff[key]:
+			buf['header'] = buf['header'] + \
+				'%-*s%-*s%-*s\n' % (POS_TITLE, key, \
+				POS_LEFT, header1[key], POS_LEFT, \
+				header2[key])
+
+	for key in diff.keys():
+		if diff[key]: return(False)
+
+	return(True)
+
+
+def output(sect, buf, rrset, isleft):
+	""" Format and return the rrset according to which section 
+		and which message it belongs to. 
+
+	@param sect: section name
+	@type sect: string
+	@param buf: passed by parameter, to store the formatted string
+	@param buf: dict
+	@param rrset: the rrset to be formatted
+	@type rrset: RRset 
+	@param isleft: to be compared, the report has the content corresponding to 
+			the 1st message printed on the left, while the one corresponding
+			to the 2nd message on the right. This is a flag to which one it is.
+	@type isleft: BOOL
+	"""
+
+	if not sect in buf:
+		buf[sect] = ''
+	if sect == 'question':
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'name')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * POS_LEFT
+		buf[sect] = buf[sect] + rrset.get_name().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'class')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * POS_LEFT
+		buf[sect] = buf[sect] + rrset.get_class().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'type')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * POS_LEFT
+		buf[sect] = buf[sect] + rrset.get_type().to_text() + "\n"
+
+	else:
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'ttl')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * int(POS_LEFT)
+		buf[sect] = buf[sect] + rrset.get_ttl().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'name')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * int(POS_LEFT)
+		buf[sect] = buf[sect] + rrset.get_name().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'class')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * int(POS_LEFT)
+		buf[sect] = buf[sect] + rrset.get_class().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'type')
+		if not isleft:
+			buf[sect] = buf[sect] + ' ' * int(POS_LEFT)
+		buf[sect] = buf[sect] + rrset.get_type().to_text() + "\n"
+
+		buf[sect] = buf[sect] + '%-*s' % (POS_TITLE, 'rdata')
+
+		i = 0
+		rdata = rrset.get_rdata()
+		for item in rdata:
+			if i > 0:
+                                buf[sect] = buf[sect] + ' ' * POS_TITLE
+			if not isleft:
+				buf[sect] = buf[sect] + ' ' * POS_LEFT
+			buf[sect] = buf[sect] + item.to_text() + "\n"
+			i = i + 1
+
+	buf[sect] = buf[sect] + "\n"
+
+def array_cmp(sectname, buf, rlist1, rlist2):
+	""" Compare each entry of the question section of rlist1 and rlist2.
+	    Compare each RRset of the sectname section (can be answer, authority, 
+	    additional) of rlist1 and rlist2.
+	    
+	@param buf: store the formatted output of difference
+	@type: dict
+	"""
+
+	diff_flag = True
+	while len(rlist1) > 0:
+		rr1 = rlist1.pop()
+		find2 = False
+		for rr2 in rlist2:
+			if sectname == 'question':
+				res = question_cmp(rr1, rr2)
+			else:
+				res = rr_cmp(rr1, rr2)
+			if res:
+				find2 = True
+				rlist2.remove(rr2)
+				break
+		if not find2:
+			output(sectname, buf, rr1, True)
+			diff_flag = False
+
+	while len(rlist2) > 0:
+		rr2 = rlist2.pop()
+		output(sectname, buf, rr2, False)
+		diff_flag = False
+	return(diff_flag)
+
+def question_cmp(rra, rrb):
+	if rra.get_name() != rrb.get_name(): return(False)
+	if rra.get_class() != rrb.get_class(): return(False)
+	if rra.get_type() != rrb.get_type(): return(False)
+	return(True)
+
+def rr_cmp(rra, rrb):
+	""" Compare two rrsets: rra and rrb """
+
+	if rra.get_name() != rrb.get_name(): return(False)
+	if rra.get_class() != rrb.get_class(): return(False)
+	if rra.get_type() != rrb.get_type(): return(False)
+	if rra.get_ttl() != rrb.get_ttl(): return(False)
+	rdata_a = rra.get_rdata()
+	rdata_b = rrb.get_rdata()
+	rdata_al = len(rdata_a)
+	rdata_bl = len(rdata_b)
+
+	if rdata_al != rdata_bl: 
+		return(False)
+
+	cmp_flag = False
+	# Iterate rdata in rrset a, find if there is same rdata in rrset b
+	for ra in rdata_a:
+		for rb in rdata_b:
+			if ra.to_text() == rb.to_text():
+				cmp_flag = True
+				rdata_b.remove(rb)
+				break
+		if not cmp_flag:
+			break
+	return(cmp_flag)
+
+def resp_casecmp(msg1, msg2, num):
+	""" Compare two response message, and print the different part
+	    in formatted report. 
+
+	@param msg1: 1st response message
+	@type msg1: Message
+	@param msg2: 2nd response message
+        @type msg2: Message
+	@param num: the id of the query case in the 1st column of the input file.
+		    Used by output report to locate the specified query case. 
+	@type num: int
+	"""
+
+	diff = {}
+	buf = {}
+
+	query = msg1.get_question()[0]
+
+	res_hdr = header_cmp(buf, msg1, msg2, diff)
+	res_ques = array_cmp('question', buf, \
+				msg1.get_question(), msg2.get_question())
+	res_ans = array_cmp('answer', buf, \
+				msg1.get_section(Message.SECTION_ANSWER), \
+				msg2.get_section(Message.SECTION_ANSWER))
+	res_auth = array_cmp('authority', buf, \
+				msg1.get_section(Message.SECTION_AUTHORITY), \
+				msg2.get_section(Message.SECTION_AUTHORITY))
+	res_addi = array_cmp('additional', buf, \
+				msg1.get_section(Message.SECTION_ADDITIONAL), \
+				msg2.get_section(Message.SECTION_ADDITIONAL))
+	
+	# If there are any differnt comparisons in the sections above, print the details
+	# contained in buf formattedly.
+	if not res_hdr or not res_ques or not res_ans or not res_auth or not res_addi:
+		print('=' * 30, '  BEGIN QUERY %s  ' % num, '=' * 30, sep='')
+		print('%-*s%-*s%-*s' % (POS_TITLE, '', int(POS_LEFT), 'SERVER1', \
+			POS_TOTAL - POS_TITLE, 'SERVER2'))
+		print('-' * 80)
+		print('Query:  ', query.to_text(), sep='')
+		print('-' * 80)
+
+		if not res_hdr:
+			print(buf['header'])
+			print('-' * 80)
+
+		if not res_ques:
+			print("QUESTION")
+			print('-' * 80)
+			print(buf['question'])
+
+		if not res_ans:
+			print("ANSWER")
+			print('-' * 80)
+			print(buf['answer'])
+
+		if not res_auth:
+			print("AUTHORITY")
+			print('-' * 80)
+			print(buf['authority'])
+
+		if not res_addi:
+			print("ADDITIONAL")
+			print('-' * 80)
+			print(buf['additional'])
+
+		print('=' * 30, '   END QUERY %s   ' % num, '=' * 30, sep='') 
+		print("\n\n")
+
+		return False
+
+	return True
+
diff --git a/tools/query_cmp/src/lib/handledns.py b/tools/query_cmp/src/lib/handledns.py
new file mode 100755
index 0000000..e33ce9e
--- /dev/null
+++ b/tools/query_cmp/src/lib/handledns.py
@@ -0,0 +1,284 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+import errno
+import sys
+import select
+import socket
+import struct
+import time
+
+from pydnspp import *
+
+RECV_BUFSIZE = 65536
+	
+def _wait_for(ir, iw, ix, expiration):
+	done = False
+	while not done:
+		if expiration is None:
+			timeout = None
+		else:
+			timeout = expiration - time.time()
+			if timeout <= 0.0:
+				raise socket.timeout
+		try:
+			if timeout is None:
+				(r,w,x) = select.select(ir,iw,ix)
+			else:
+				(r,w,x) = select.select(ir,iw,ix,timeout)
+		except select.error as e:
+			if e.args[0] != errno.EINTR:
+				raise e
+		else:
+			done = True
+			if len(r) == 0 and len(w) == 0 and len(x) == 0:
+				raise socket.timeout
+
+def _wait_for_readable(s,expiration):
+	_wait_for([s],[],[s],expiration)
+
+def _compute_expiration(timeout):
+	if timeout is None:
+		return None
+	else:
+		return time.time() + timeout
+
+def _send_udp(q, where, timeout=None, port=53, source=None, source_port=0):
+	""" Return the response obtained after sending a query via UDP. 
+	    Refered to dnspython source code. """
+
+	qwire = MessageRenderer()
+	q.to_wire(qwire)      
+	if source is not None:
+		source = (source, source_port)
+	
+	udpCliSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
+
+	expiration = _compute_expiration(timeout)
+	if source is not None:
+		udpCliSock.bind(source)
+
+	dest = (where, port)
+	udpCliSock.sendto(qwire.get_data(), dest)
+
+	while True:
+		_wait_for_readable(udpCliSock, expiration)
+		rwire, r_addr = udpCliSock.recvfrom(RECV_BUFSIZE)
+		if dest[0] == r_addr[0] and dest[1:] == r_addr[1:]:
+			break
+		else:
+			sys.stderr.write('Got a respose from: %s instead of %s\n' % (r_addr, dest))
+
+	udpCliSock.close()
+
+	resp = Message(Message.PARSE)
+	resp.from_wire(rwire)
+
+	return resp 
+	
+def _connect(s, address):
+	try:
+		s.connect(address)
+	except socket.error as msg:
+		(exctype,value) = sys.exc_info()[:2]
+		if value.errno != errno.EINPROGRESS and \
+			value.errno != errno.EWOULDBLOCK and \
+			value.errno != errno.EALREADY:
+			raise value	
+
+def _net_read(sock, count, expiration):
+	""" Read the specified number of bytes from sock. Keep trying until we
+	    either get the desired amount, or we hit EOF.
+	    A Timeout exception will be raised if the operation is not completed
+	    by the expiration time.
+	"""
+
+	msgdata = b''
+	while count > 0:
+		_wait_for_readable(sock, expiration)
+		data = sock.recv(count)
+		if not data:
+			return None
+
+		count -= len(data)
+		msgdata += data
+	
+	return msgdata
+
+def _net_write(sock, data, expiration):
+	""" Write the specified data to the socket.
+	    A Timeout exception will be raised if the operation is not completed
+	    by the expiration time.
+	"""
+	current = 0
+	l = len(data)
+	while current < 1:
+		_wait_for_writable(sock, expiration)
+		current += sock.send(data[current:])
+
+def _send_tcp(q, dest, timeout=None, dest_port=53, source=None, source_port=0):
+	""" Return the response obtained after sending a query via TCP. 
+	    Refered to dnspython source code """
+
+	qwire = MessageRenderer()
+	q.to_wire(qwire)
+
+	if source is not None:
+		source = (source, source_port)
+	dest = (dest, dest_port)
+	tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+		
+	expiration = _compute_expiration(timeout)
+	tcpCliSock.setblocking(False)
+	if source is not None:
+		tcpCliSock.bind(source)
+	_connect(tcpCliSock, dest)
+
+	wire_s = qwire.get_data()
+	l = len(wire_s)
+
+	tcpmsg = struct.pack("!H", l) + wire_s
+	_net_write(tcpCliSock, tcpmsg, expiration)
+	ldata = _net_read(tcpCliSock, 2, expiration)
+	(l,) = struct.unpack("!H", ldata)
+	res_wire = _net_read(tcpCliSock, l, expiration)
+	tcpCliSock.close()
+
+	resp = Message(Message.PARSE)
+	resp.from_wire(res_wire)
+
+	return resp
+
+def send_req(query, server, port=53, timeout=5):
+	""" Return the response message obtained after 
+	    sending the query.
+	
+	@param query: the query readed from input file
+	@type query: dict
+	@param server: the testee server ip address
+	@type server: string
+	@param port: the testee server listening port. The default is 53.
+	@type port: int
+	@param timeout: the number of seconds to wait before the query times out.
+		The default is 5.
+	@type timeout: float
+	"""
+
+	qname = query["qname"]
+	qtype = query["qtype"]
+	qclass = query["qclass"]
+	edns = query["edns"]
+	dnssec = query["dnssec"]
+	qheader = query['header']
+	protocol = query['protocol']
+
+	msg = Message(Message.RENDER)
+	msg.set_qid(int(qheader['id']))
+	msg.set_opcode(Opcode.QUERY())
+	msg.set_rcode(Rcode(int(qheader['rcode'])))
+
+	if qheader['qr'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_QR)
+	if qheader['aa'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_AA)
+	if qheader['tc'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_TC)		
+	if qheader['rd'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_RD)
+	if qheader['ra'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_RA)
+	if qheader['ad'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_AD)
+	if qheader['cd'] == 1: 
+		msg.set_header_flag(Message.HEADERFLAG_CD)
+
+	try:
+		msg.add_question(Question(Name(qname), \
+                         	RRClass(qclass), RRType(qtype)))
+	except InvalidRRType as e: 
+		sys.stderr.write('Unrecognized RR queryeter string: %s\n' % qtype)
+		return None
+
+	if edns == 1 or dnssec == 1:
+		edns_conf = EDNS()
+		payload = query['payload']
+		edns_conf.set_udp_size(payload)
+
+		if dnssec == 1:
+			edns_conf.set_dnssec_awareness(True)
+		else:
+			edns_conf.set_dnssec_awareness(False)
+
+		msg.set_edns(edns_conf)
+
+	port = int(port)
+	if protocol == 'udp':
+		resp = _send_udp(msg, server, timeout, port)
+	else:
+		resp = _send_tcp(msg, server, timeout, port)
+
+	return resp
+
+
+def main():
+	query = {}
+	query['qname'] = "A.example.com"
+	query['qtype'] = "ANY"
+	query['qclass'] = "IN"
+	query["edns"] = 1
+	query["dnssec"] = 1
+	query["protocol"] = 'tcp'
+	query["payload"] = 4096
+
+	query['header'] = {}
+	query['header']['id'] = 0
+	query['header']['qr'] = 0
+	query['header']['opcode'] = 0
+	query['header']['aa'] = 0
+	query['header']['tc'] = 0
+	query['header']['rd'] = 1
+	query['header']['ra'] = 0
+	query['header']['z'] = 0
+	query['header']['ad'] = 0
+	query['header']['cd'] = 0
+	query['header']['rcode'] = 0
+	query['header']['qdcount'] = 0
+	query['header']['ancount'] = 0
+	query['header']['nscount'] = 0
+	query['header']['arcount'] = 0
+
+	resp = send_req(query, "218.241.108.124", "4040")
+
+	if resp == None:
+		print('timeout')
+		exit(1)
+
+	print('qid -----')
+	print(resp.get_qid())
+
+	rrset = resp.get_section(Message.SECTION_ANSWER)[0]
+	print('name-----')
+	print(rrset.get_name())
+	print('type')
+	print(rrset.get_type())
+	print('class-----')
+	print(rrset.get_class())
+	print(rrset.get_ttl())
+	rdata = rrset.get_rdata()
+	print(rdata[0].to_text())
+	
+if __name__ == "__main__":
+	main()
diff --git a/tools/query_cmp/src/lib/read_query.py b/tools/query_cmp/src/lib/read_query.py
new file mode 100755
index 0000000..01d64fe
--- /dev/null
+++ b/tools/query_cmp/src/lib/read_query.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+import re
+import sys
+
+def read_query(file, querylist):
+	fh = open(file)
+	while True:
+		query = {}
+		query['header'] = {}
+
+		line = fh.readline()
+		if not line: break
+		line = line.rstrip('\n')
+
+		if re.search('^#', line): continue
+		if re.search('^\s*$', line): continue
+
+		fields = line.split(' ')
+		query['header']['id'] = fields.pop(0)
+		query['header']['qr'] = fields.pop(0)
+		query['header']['opcode'] = int(fields.pop(0))
+		query['header']['aa'] = fields.pop(0)
+		query['header']['tc'] = fields.pop(0)
+		query['header']['rd'] = fields.pop(0)
+		query['header']['ra'] = fields.pop(0)
+		query['header']['z'] = fields.pop(0)
+		query['header']['ad'] = fields.pop(0)
+		query['header']['cd'] = fields.pop(0)
+		query['header']['rcode'] = fields.pop(0)
+		query['header']['qdcount'] = fields.pop(0)
+		query['header']['ancount'] = fields.pop(0)
+		query['header']['nscount'] = fields.pop(0)
+		query['header']['arcount'] = fields.pop(0)
+
+		if query['header']['opcode'] == 0:
+			get_qtuple(query, 'question', fields)
+
+		querylist.append(query)
+
+	fh.close()
+
+def get_qtuple(query, sectname, list):
+	if sectname == 'question':
+		count = int(query['header']['qdcount'])
+	item = {}
+	i = 0
+	while i < count:
+		query[sectname] = []
+		item['qname'] = list.pop(0)
+		item['qtype'] = list.pop(0)
+		item['qclass'] = list.pop(0)
+		query[sectname].append(item)
+		i += 1
+
+def print_query(querylist):
+	keylist = ['id', 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z',
+		'ad', 'cd', 'rcode', 'qdcount', 'ancount', 'nscount',
+		'arcount']
+	for q in querylist:
+		for key in keylist:
+			print(q['header'][key], ' ')
+		print_question(q)
+
+def print_question(query):
+	i = 0
+
+	while i < len(query['question']):
+		print(query['question'][i]['qname'], \
+			query['question'][i]['qtype'], \
+			query['question'][i]['qclass'], \
+			sep=' ')
+		i += 1
+
+if __name__ == '__main__':
+	qlist = []
+	read_query(sys.argv[1], qlist)
+	print_query(qlist)
+
diff --git a/tools/query_cmp/src/query_two_server.py b/tools/query_cmp/src/query_two_server.py
new file mode 100755
index 0000000..13e234a
--- /dev/null
+++ b/tools/query_cmp/src/query_two_server.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+import sys; sys.path.append('lib')
+from optparse import OptionParser
+
+from read_query import *
+import handledns
+import compare_rrset
+
+def getopt():
+	"""
+	get options from user.
+	"""
+	usage = "usage: %prog -f <file> -s <svr1> [-p <port1>] -t <svr2> [-q <port2>] [-e] [-u] [--bufsize] [--edns]"
+	parser = OptionParser(usage)
+	parser.add_option("-f", "--file", dest="filename",
+		help="specify the input data filename")
+	parser.add_option("-s", "--svr1", dest="server1",
+		help="specify the tested DNS server 1")
+	parser.add_option("-p",
+		help="specify the port of the tested DNS server 1, default is 53")
+	parser.add_option("-t", "--svr2", dest="server2",
+		help="specify the tested DNS server 2")
+	parser.add_option("-q",
+		help="specify the port of the tested DNS server 2, default is 53")
+	parser.add_option("-e", "--dnssec", action="store_true",
+		default=False, help="turn on dnssec")
+	parser.add_option("", "--edns", action="store_true",
+		default=False, help="turn on edns, if -e is set, --edns will lapse, it must be True")
+	parser.add_option("-u", "--udp", action="store_true", default=False,
+		help="if set, query by udp, otherwise by tcp, default is unset")
+	parser.add_option("", "--bufsize", default=4096,
+		help="if --edns is set, --bufsize specifies payload of edns0, default is 4096")
+
+
+	(options, args) = parser.parse_args()
+	
+	if(options.filename == None or options.server1 == None or
+		options.server2 == None):
+		parser.print_help()
+		sys.exit(1)
+
+	return options
+
+def main():
+	opts = getopt()
+
+	qlist = []
+	read_query(opts.filename, qlist)
+
+	for q in qlist:
+		# initial query
+		query = {}
+		if opts.dnssec:
+			query['edns'] = 1
+			query['dnssec'] = 1
+		elif opts.edns:
+			query['edns'] = 1
+			query['dnssec'] = 0
+		else:
+			query['edns'] = 0
+			query['dnssec'] = 0
+
+		if opts.udp:
+			query['protocol'] = 'udp'
+		else:
+			query['protocol'] = 'tcp'
+
+		query['payload'] = opts.bufsize
+		query['qname'] = q['question'][0]['qname']
+		query['qtype'] = q['question'][0]['qtype']
+		query['qclass'] = q['question'][0]['qclass']
+		query['header'] = q['header']
+		id = q['header']['id']
+
+		# send the query to the 1st and 2nd server, and store the
+		# response in res1 and res2
+		res1 = handledns.send_req(query, opts.server1, opts.p)
+		res2 = handledns.send_req(query, opts.server2, opts.q)
+
+		if res1 != None and res2 != None:
+			# compare res1 and res2, print the different part.
+			res3 = compare_rrset.resp_casecmp(res1, res2, id)
+		else:
+			sys.stderr.write('Empty response.\n')
+
+if __name__ == "__main__":
+	main()
diff --git a/tools/query_cmp/zonefile/example.com.txt b/tools/query_cmp/zonefile/example.com.txt
new file mode 100644
index 0000000..5154014
--- /dev/null
+++ b/tools/query_cmp/zonefile/example.com.txt
@@ -0,0 +1,1298 @@
+$TTL 86400
+@	IN	SOA	NS1.example.com.	root.example.com. (
+		2010091701	; serial
+		3600	; refresh
+		900	; retry
+		604800	; expire
+		3600	; minimum
+		)
+	IN      NS      NS1.example.com.
+	IN      NS      NS2.demo.example.com.
+	IN      NS      NS3.noexist.cn.
+
+NS1	IN	A	218.241.111.236
+NS2.demo	IN	A	218.241.108.15
+
+$ORIGIN example.com.
+minittl	100	IN	A	10.10.1.1
+
+a	IN	A	192.168.1.10
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	A	192.168.1.10
+
+subdomain	IN	NS	ns1.mysub.com.
+subdomain	IN	NS	ns2.mysub.com.
+
+subdn	IN	NS	ns.subdn.cn.
+
+NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA A 192.168.2.1
+
+NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
+ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE A 192.168.2.2
+N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M	IN	NS	ns1.N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M
+ns1.N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M	IN	A	192.168.2.3
+
+C	IN	CNAME	A
+C0	IN	CNAME	C1
+C1	IN	CNAME	C2
+C2	IN	CNAME	C3
+C3	IN	CNAME	C4
+C4	IN	CNAME	C5
+C5	IN	CNAME	C6
+C6	IN	CNAME	C7
+C7	IN	CNAME	C8
+C8	IN	CNAME	C9
+C9	IN	CNAME	C10
+C10	IN	CNAME	C11
+C11	IN	CNAME	C12
+C12	IN	CNAME	C13
+C13	IN	CNAME	C14
+C14	IN	CNAME	C15
+C15	IN	CNAME	C16
+C16	IN	CNAME	C17
+C17	IN	CNAME	C18
+C18	IN	CNAME	C19
+C19	IN	CNAME	C20
+C20	IN	CNAME	C21
+C21	IN	CNAME	C22
+C22	IN	CNAME	C23
+C23	IN	CNAME	C24
+C24	IN	CNAME	C25
+
+C30	IN	CNAME	C31
+C31	IN	CNAME	C32
+C32	IN	CNAME	C33
+C33	IN	CNAME	C34
+C34	IN	CNAME	C35
+C35	IN	CNAME	C36
+C36	IN	CNAME	C37
+C37	IN	CNAME	C38
+C38	IN	CNAME	C39
+C39	IN	CNAME	C40
+C40	IN	CNAME	C41
+C41	IN	CNAME	C42
+C42	IN	CNAME	C43
+C43	IN	CNAME	C44
+C44	IN	CNAME	C45
+C45	IN	CNAME	C46
+C46	IN	CNAME	C47
+C47	IN	CNAME	C48
+C48	IN	CNAME	C49
+C49	IN	CNAME	C50
+C50	IN	CNAME	C51
+C51	IN	CNAME	A
+
+CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA CNAME AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+A2	IN	A	192.168.1.12
+B1	IN	CNAME	A2
+
+a	IN	PTR	1.1.226.159.cnnic.cn.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	PTR	2.1.226.159.cnnic.cn.
+multiple-type-ptr-record  IN      PTR       192.168.2.1
+multiple-type-ptr-record  IN      PTR       192.168.2.2
+multiple-type-ptr-record  IN      PTR       192.168.2.3
+multiple-type-ptr-record  IN      PTR       192.168.2.4
+multiple-type-ptr-record  IN      PTR       192.168.2.5
+multiple-type-ptr-record  IN      PTR       192.168.2.6
+multiple-type-ptr-record  IN      PTR       192.168.2.7
+multiple-type-ptr-record  IN      PTR       192.168.2.8
+multiple-type-ptr-record  IN      PTR       192.168.2.9
+multiple-type-ptr-record  IN      PTR       192.168.2.10
+multiple-type-ptr-record  IN      PTR       192.168.2.11
+multiple-type-ptr-record  IN      PTR       192.168.2.12
+multiple-type-ptr-record  IN      PTR       192.168.2.13
+multiple-type-ptr-record  IN      PTR       192.168.2.14
+multiple-type-ptr-record  IN      PTR       192.168.2.15
+multiple-type-ptr-record  IN      PTR       192.168.2.16
+multiple-type-ptr-record  IN      PTR       192.168.2.17
+multiple-type-ptr-record  IN      PTR       192.168.2.18
+
+A	IN	MX	10 	mail
+mail	IN	A	10.4.0.1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	MX	1 mail1
+
+multiple-type-mx-record    IN      MX      10 mail1
+multiple-type-mx-record    IN      MX      10 mail2
+multiple-type-mx-record    IN      MX      10 mail3
+multiple-type-mx-record    IN      MX      10 mail4
+multiple-type-mx-record    IN      MX      10 mail5
+multiple-type-mx-record    IN      MX      10 mail6
+multiple-type-mx-record    IN      MX      10 mail7
+multiple-type-mx-record    IN      MX      10 mail8
+multiple-type-mx-record    IN      MX      10 mail9
+multiple-type-mx-record    IN      MX      10 mail10
+multiple-type-mx-record    IN      MX      10 mail11
+multiple-type-mx-record    IN      MX      10 mail12
+multiple-type-mx-record    IN      MX      20 mail13
+multiple-type-mx-record    IN      MX      30 mail14
+multiple-type-mx-record    IN      MX      40 mail15
+multiple-type-mx-record    IN      MX      50 mail16
+multiple-type-mx-record    IN      MX      60 mail17
+multiple-type-mx-record    IN      MX      70 mail18
+multiple-type-mx-record    IN      MX      80 mail19
+multiple-type-mx-record    IN      MX      90 mail20
+mail1	IN	A	10.4.1.1
+mail2	IN	A	10.4.1.2
+mail3	IN	A	10.4.1.3
+mail4	IN	A	10.4.1.4
+mail5	IN	A	10.4.1.5
+mail6	IN	A	10.4.1.6
+mail7	IN	A	10.4.1.7
+mail8	IN	A	10.4.1.8
+mail9	IN	A	10.4.1.9
+mail10	IN	A	10.4.1.10
+mail11	IN	A	10.4.1.11
+mail12	IN	A	10.4.1.12
+mail13	IN	A	10.4.1.13
+mail14	IN	A	10.4.1.14
+mail15	IN	A	10.4.1.15
+mail16	IN	A	10.4.1.16
+mail17	IN	A	10.4.1.17
+mail18	IN	A	10.4.1.18
+mail19	IN	A	10.4.1.19
+mail20	IN	A	10.4.1.20
+
+
+A	IN	TXT	"ms-dos 3.0/6.0 ?" "google-app_,;!@#$%^&*()[]{}=+|\`~'<>,."
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	TXT	"kkkkkkkkkkkkkkkkkkkkkkkk"
+
+multiple-type-txt-record  IN      TXT       txt::1
+multiple-type-txt-record  IN      TXT       txt::2
+multiple-type-txt-record  IN      TXT       txt::3
+multiple-type-txt-record  IN      TXT       txt::4
+multiple-type-txt-record  IN      TXT       txt::5
+multiple-type-txt-record  IN      TXT       txt::6
+multiple-type-txt-record  IN      TXT       txt::7
+multiple-type-txt-record  IN      TXT       txt::8
+multiple-type-txt-record  IN      TXT       txt::9
+multiple-type-txt-record  IN      TXT       txt::10
+multiple-type-txt-record  IN      TXT       txt::11
+multiple-type-txt-record  IN      TXT       txt::12
+multiple-type-txt-record  IN      TXT       txt::13
+multiple-type-txt-record  IN      TXT       txt::14
+multiple-type-txt-record  IN      TXT       txt::15
+multiple-type-txt-record  IN      TXT       txt::16
+multiple-type-txt-record  IN      TXT       txt::17
+multiple-type-txt-record  IN      TXT       txt::18
+multiple-type-txt-record  IN      TXT       txt::19
+multiple-type-txt-record  IN      TXT       txt::20
+multiple-type-txt-record  IN      TXT       txt::21
+multiple-type-txt-record  IN      TXT       txt::22
+multiple-type-txt-record  IN      TXT       txt::23
+multiple-type-txt-record  IN      TXT       txt::24
+multiple-type-txt-record  IN      TXT       txt::25
+multiple-type-txt-record  IN      TXT       txt::26
+multiple-type-txt-record  IN      TXT       txt::27
+multiple-type-txt-record  IN      TXT       txt::28
+multiple-type-txt-record  IN      TXT       txt::29
+multiple-type-txt-record  IN      TXT       txt::30
+multiple-type-txt-record  IN      TXT       txt::31
+
+
+A	IN	AAAA	2001:dc7::1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	AAAA	2001:dc7::2
+multiple-type-aaaa-record  IN      AAAA       aaaa::1
+multiple-type-aaaa-record  IN      AAAA       aaaa::2
+multiple-type-aaaa-record  IN      AAAA       aaaa::3
+multiple-type-aaaa-record  IN      AAAA       aaaa::4
+multiple-type-aaaa-record  IN      AAAA       aaaa::5
+multiple-type-aaaa-record  IN      AAAA       aaaa::6
+multiple-type-aaaa-record  IN      AAAA       aaaa::7
+multiple-type-aaaa-record  IN      AAAA       aaaa::8
+multiple-type-aaaa-record  IN      AAAA       aaaa::9
+multiple-type-aaaa-record  IN      AAAA       aaaa::10
+multiple-type-aaaa-record  IN      AAAA       aaaa::11
+multiple-type-aaaa-record  IN      AAAA       aaaa::12
+multiple-type-aaaa-record  IN      AAAA       aaaa::13
+multiple-type-aaaa-record  IN      AAAA       aaaa::14
+multiple-type-aaaa-record  IN      AAAA       aaaa::15
+multiple-type-aaaa-record  IN      AAAA       aaaa::16
+multiple-type-aaaa-record  IN      AAAA       aaaa::17
+multiple-type-aaaa-record  IN      AAAA       aaaa::18
+multiple-type-aaaa-record  IN      AAAA       aaaa::19
+multiple-type-aaaa-record  IN      AAAA       aaaa::20
+multiple-type-aaaa-record  IN      AAAA       aaaa::21
+multiple-type-aaaa-record  IN      AAAA       aaaa::22
+multiple-type-aaaa-record  IN      AAAA       aaaa::23
+multiple-type-aaaa-record  IN      AAAA       aaaa::24
+multiple-type-aaaa-record  IN      AAAA       aaaa::25
+multiple-type-aaaa-record  IN      AAAA       aaaa::26
+multiple-type-aaaa-record  IN      AAAA       aaaa::27
+multiple-type-aaaa-record  IN      AAAA       aaaa::28
+multiple-type-aaaa-record  IN      AAAA       aaaa::29
+multiple-type-aaaa-record  IN      AAAA       aaaa::30
+multiple-type-aaaa-record  IN      AAAA       aaaa::31
+
+A	IN	NAPTR	18 35 "Au" "siip+E2000U" "!^.*$!simmmp:information at cnnic.cn!" mb
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	NAPTR	18 35 "Au" "siip+E2001U" "!^.*$!simmmp:information at cnnic.cn!" .
+
+sub	IN	ns	ns.sub
+ns.sub	IN	A	218.241.111.236
+sub-cname	IN	CNAME	www.sub
+sub-dname	IN	DNAME	sub
+
+www.a.b.sub2	IN	A	192.168.1.1
+
+A	IN	DNAME	sub1.cnnic.cn.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	DNAME	sub2.cnnic.cn.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE	IN	DNAME	sub3.cnnic.cn.
+
+d0	IN	DNAME	sub
+d1	IN	DNAME	sub2
+test.d0	IN	A	192.168.1.2
+test.d1	IN	A	192.168.1.3
+d0	IN	A	192.168.1.4
+d1	IN	A	192.168.1.5
+
+d2	IN	DNAME	d3
+d3	IN	DNAME	d2
+
+d4	IN	DNAME	d5
+d5	IN	CNAME	d4
+www.d5	IN	A	192.168.1.6
+
+d10	IN	DNAME	d11
+d11	IN	DNAME	d12
+d12	IN	DNAME	d13
+d13	IN	DNAME	d14
+d14	IN	DNAME	d15
+d15	IN	DNAME	d16
+d16	IN	DNAME	d17
+d17	IN	DNAME	d18
+d18	IN	DNAME	d19
+d19	IN	DNAME	d20
+d20	IN	DNAME	d21
+d21	IN	DNAME	d22
+d22	IN	DNAME	d23
+d23	IN	DNAME	d24
+d24	IN	DNAME	d25
+d25	IN	DNAME	d26
+d26	IN	DNAME	d27
+d27	IN	DNAME	d28
+d28	IN	DNAME	d29
+d29	IN	DNAME	d30
+d30	IN	DNAME	d31
+d31	IN	DNAME	d32
+d32	IN	DNAME	d33
+d33	IN	DNAME	d34
+d34	IN	DNAME	d35
+d35	IN	DNAME	d36
+d36	IN	DNAME	d37
+d37	IN	DNAME	d38
+d38	IN	DNAME	d39
+d39	IN	DNAME	d40
+www.d40	IN	CNAME	www.d41
+d41	IN	DNAME	d42
+d42	IN	DNAME	d43
+d43	IN	DNAME	d44
+d44	IN	DNAME	d45
+d45	IN	DNAME	d46
+d46	IN	DNAME	d47
+d47	IN	DNAME	d48
+d48	IN	DNAME	d49
+d49	IN	DNAME	d50
+d50	IN	DNAME	d51
+d51	IN	DNAME	d52
+d52	IN	DNAME	d53
+d53	IN	DNAME	d54
+d54	IN	DNAME	d55
+d55	IN	DNAME	d56
+d56	IN	DNAME	d57
+d57	IN	DNAME	d58
+d58	IN	DNAME	d59
+d59	IN	DNAME	d60
+
+d70	IN	DNAME	dicarl.cnnic.cn.
+
+d72	IN	DNAME	sub01.d72
+;sub01	IN	DNAME	sub02.d72
+
+cname-point-to-multiple-type-a-record	IN	CNAME	multiple-type-a-record
+multiple-type-a-record	IN	A	192.168.2.1
+multiple-type-a-record	IN	A	192.168.2.2
+multiple-type-a-record	IN	A	192.168.2.3
+multiple-type-a-record	IN	A	192.168.2.4
+multiple-type-a-record	IN	A	192.168.2.5
+multiple-type-a-record	IN	A	192.168.2.6
+multiple-type-a-record	IN	A	192.168.2.7
+multiple-type-a-record	IN	A	192.168.2.8
+multiple-type-a-record	IN	A	192.168.2.9
+multiple-type-a-record	IN	A	192.168.2.10
+multiple-type-a-record	IN	A	192.168.2.11
+multiple-type-a-record	IN	A	192.168.2.12
+multiple-type-a-record	IN	A	192.168.2.13
+multiple-type-a-record	IN	A	192.168.2.14
+multiple-type-a-record	IN	A	192.168.2.15
+multiple-type-a-record	IN	A	192.168.2.16
+multiple-type-a-record	IN	A	192.168.2.17
+multiple-type-a-record	IN	A	192.168.2.18
+multiple-type-a-record	IN	A	192.168.2.19
+multiple-type-a-record	IN	A	192.168.2.20
+multiple-type-a-record	IN	A	192.168.2.21
+multiple-type-a-record	IN	A	192.168.2.22
+multiple-type-a-record	IN	A	192.168.2.23
+multiple-type-a-record	IN	A	192.168.2.24
+multiple-type-a-record	IN	A	192.168.2.25
+multiple-type-a-record	IN	A	192.168.2.26
+multiple-type-a-record	IN	A	192.168.2.27
+multiple-type-a-record	IN	A	192.168.2.28
+multiple-type-a-record	IN	A	192.168.2.29
+multiple-type-a-record	IN	A	192.168.2.30
+multiple-type-a-record	IN	A	192.168.2.31
+
+multiple-type-ns-record	IN	NS	dns1.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns2.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns3.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns4.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns5.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns6.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns7.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns8.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns9.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns10.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns11.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns12.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns13.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns14.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns15.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns16.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns17.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns18.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns19.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns20.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns21.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns22.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns23.multiple-type-ns-record
+multiple-type-ns-record	IN	NS	dns24.multiple-type-ns-record
+dns1.multiple-type-ns-record	IN	A	192.168.4.1
+dns2.multiple-type-ns-record	IN	A	192.168.4.2
+dns3.multiple-type-ns-record	IN	A	192.168.4.3
+dns4.multiple-type-ns-record	IN	A	192.168.4.4
+dns5.multiple-type-ns-record	IN	A	192.168.4.5
+dns6.multiple-type-ns-record	IN	A	192.168.4.6
+dns7.multiple-type-ns-record	IN	A	192.168.4.7
+dns8.multiple-type-ns-record	IN	A	192.168.4.8
+dns9.multiple-type-ns-record	IN	A	192.168.4.9
+dns10.multiple-type-ns-record	IN	A	192.168.4.10
+dns11.multiple-type-ns-record	IN	A	192.168.4.11
+dns12.multiple-type-ns-record	IN	A	192.168.4.12
+dns13.multiple-type-ns-record	IN	A	192.168.4.13
+dns14.multiple-type-ns-record	IN	A	192.168.4.14
+dns15.multiple-type-ns-record	IN	A	192.168.4.15
+dns16.multiple-type-ns-record	IN	A	192.168.4.16
+dns17.multiple-type-ns-record	IN	A	192.168.4.17
+dns18.multiple-type-ns-record	IN	A	192.168.4.18
+dns19.multiple-type-ns-record	IN	A	192.168.4.19
+dns20.multiple-type-ns-record	IN	A	192.168.4.20
+dns21.multiple-type-ns-record	IN	A	192.168.4.21
+dns22.multiple-type-ns-record	IN	A	192.168.4.22
+dns23.multiple-type-ns-record	IN	A	192.168.4.23
+dns24.multiple-type-ns-record	IN	A	192.168.4.24
+dns25.multiple-type-ns-record	IN	A	192.168.4.25
+
+;demo	IN	NS	ns1
+
+a	IN	WKS	218.241.108.4 TCP (telnet smtp domain)
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	WKS	218.241.108.5 TCP (telnet smtp domain)
+
+multiple-type-wks-record	IN	WKS	218.241.109.1 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.2 TCP (telnet smtp domain)
+multiple-type-wks-record	IN      WKS	218.241.109.3 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.4 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.5 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.6 TCP (telnet smtp domain x11)
+multiple-type-wks-record	IN	WKS	218.241.109.7 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.8 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.9 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.10 TCP (telnet smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.11 TCP (telnet ssh smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.12 TCP (telnet ssh smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.13 TCP (telnet ssh smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.14 TCP (http ssh smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.15 TCP (http ssh smtp domain)
+multiple-type-wks-record	IN	WKS	218.241.109.16 TCP (http ssh smtp x11)
+
+a	IN	HINFO	VAX-11/780 UNIX
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	HINFO	SHARP "PC-1500 1983"
+
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4000" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4001" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4002" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4003" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4004" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4005" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4006" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4007" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4008" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4009" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4010" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4011" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4012" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4013" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4014" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4015" 1990
+multiple-type-hinfo-record	IN	HINFO	"DG MV-4016" 1990
+
+a	IN	MINFO	root.cnnic.cn. error.cnnic.cn.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	MINFO	root63.cnnic.cn.	error63.cnnic.cn.
+multiple-type-minfo-record	IN	MINFO	sun00.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun01.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun02.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun03.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.dn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.en. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.fn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.gn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+
+a	IN	NSAP	0x47000580ffff0000003210999911112222333343
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	NSAP	0x47000580ffff0000003210999911112222333344
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333345
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333346
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333347
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333348
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333349
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334A
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334b
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334C
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334d
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334E
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334f
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333350
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333351
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333352
+multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333353
+
+; zebra don't support NSAP-PTR now.
+;47000580ffff000000321099991111222233334444	IN	NSAP-PTR	a
+
+A	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	11 ab.net3.it. 1-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	12 ab.net4.it. 2-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	13 ab.net5.it. 3-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	14 ab.net6.it. 4-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	15 ab.net7.it. 5-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	16 ab.net8.it. 6-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	10 ab.net9.it. 7-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	10 ab.net2.it. 8-ab.PRMD-net2.ADMDb.C-it.
+multiple-type-px-record	IN	PX	10 ab.net2.it. 9-ab.PRMD-net2.ADMDb.C-it.
+
+A	IN	LOC	32 7 19 S 116 2 25 E 10m
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	LOC	32 7 19 S 116 2 25 E 10m
+multiple-type-loc-record	IN	LOC	32 7 19 S 116 2 25 E 10m
+multiple-type-loc-record	IN	LOC	33 7 19 S 117 2 25 E 11m
+multiple-type-loc-record	IN	LOC	34 7 19 S 118 2 25 E 12m
+multiple-type-loc-record	IN	LOC	35 7 19 S 119 2 25 E 13m
+multiple-type-loc-record	IN	LOC	36 7 19 S 120 2 25 E 14m
+multiple-type-loc-record	IN	LOC	37 7 19 S 121 2 25 E 15m
+multiple-type-loc-record	IN	LOC	38 7 19 S 122 2 25 E 16m
+multiple-type-loc-record	IN	LOC	39 7 19 S 123 2 25 E 17m
+multiple-type-loc-record	IN	LOC	40 7 19 S 124 2 25 E 18m
+multiple-type-loc-record	IN	LOC	41 7 19 S 125 2 25 E 19m
+multiple-type-loc-record	IN	LOC	42 7 19 S 126 2 25 E 20m
+multiple-type-loc-record	IN	LOC	43 7 19 S 127 2 25 E 21m
+multiple-type-loc-record	IN	LOC	44 7 19 S 128 2 25 E 22m
+multiple-type-loc-record	IN	LOC	45 7 19 S 129 2 25 E 23m
+multiple-type-loc-record	IN	LOC	46 7 19 S 130 2 25 E 24m
+multiple-type-loc-record	IN	LOC	47 7 19 S 131 2 25 E 25m
+multiple-type-loc-record	IN	LOC	89 59 59.999 S 179 59 59.999 E 1000000m 1000m 1000m
+multiple-type-loc-record	IN	LOC	90 S 180 E 0.01 0.01 0.01
+
+_http._tcp.a	IN	SRV	0 2 80 www.movie.edu.
+a	IN	SRV	0 2 80 www.movie.edu.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SRV	0 2 80 www.movie.edu.
+multiple-type-srv-record	IN	SRV	0 2 80 www.movie0.edu.
+multiple-type-srv-record	IN	SRV	1 3 80 www.movie1.edu.
+multiple-type-srv-record	IN	SRV	2 4 80 www.movie2.edu.
+multiple-type-srv-record	IN	SRV	3 5 80 www.movie3.edu.
+multiple-type-srv-record	IN	SRV	4 6 80 www.movie4.edu.
+multiple-type-srv-record	IN	SRV	5 7 80 www.movie5.edu.
+multiple-type-srv-record	IN	SRV	6 8 80 www.movie6.edu.
+multiple-type-srv-record	IN	SRV	7 9 80 www.movie7.edu.
+multiple-type-srv-record	IN	SRV	8 10 80 www.movie8.edu.
+multiple-type-srv-record	IN	SRV	9 11 80 www.movie9.edu.
+multiple-type-srv-record	IN	SRV	10 12 80 www.movie10.edu.
+multiple-type-srv-record	IN	SRV	11 13 80 www.movie11.edu.
+multiple-type-srv-record	IN	SRV	12 14 80 www.movie12.edu.
+
+a	IN	KX	20 kaku.google.com.
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	KX	20 kaku.google.com.
+multiple-type-kx-record	IN	KX	0 kaku0.google.com.
+multiple-type-kx-record	IN	KX	10 kaku1.google.com.
+multiple-type-kx-record	IN	KX	20 kaku2.google.com.
+multiple-type-kx-record	IN	KX	30 kaku3.google.com.
+multiple-type-kx-record	IN	KX	40 kaku4.google.com.
+multiple-type-kx-record	IN	KX	50 kaku5.google.com.
+multiple-type-kx-record	IN	KX	60 kaku6.google.com.
+multiple-type-kx-record	IN	KX	70 kaku7.google.com.
+multiple-type-kx-record	IN	KX	80 kaku8.google.com.
+multiple-type-kx-record	IN	KX	90 kaku9.google.com.
+multiple-type-kx-record	IN	KX	100 kaku10.google.com.
+multiple-type-kx-record	IN	KX	110 kaku11.google.com.
+multiple-type-kx-record	IN	KX	120 kaku12.google.com.
+multiple-type-kx-record	IN	KX	130 kaku13.google.com.
+
+A	IN	CERT	65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	CERT	65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+multiple-type-cert-record	IN	CERT    65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+multiple-type-cert-record	IN	CERT    65533 65534 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+multiple-type-cert-record	IN	CERT    65532 65533 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+multiple-type-cert-record	IN	CERT    65531 65532 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+multiple-type-cert-record	IN	CERT    65530 65531 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+
+A	IN	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+multiple-type-apl-record	IN	APL	1:192.168.32.15/14 !1:192.168.38.0/28
+multiple-type-apl-record	IN	APL	1:192.168.33.15/15 !1:192.168.39.0/28
+multiple-type-apl-record	IN	APL	1:192.168.34.15/16 !1:192.168.40.0/28
+multiple-type-apl-record	IN	APL	1:192.168.35.15/17 !1:192.168.41.0/28
+multiple-type-apl-record	IN	APL	1:192.168.36.15/18 !1:192.168.42.0/28
+multiple-type-apl-record	IN	APL	1:192.168.37.15/19 !1:192.168.43.0/28
+multiple-type-apl-record	IN	APL	1:192.168.38.15/20 !1:192.168.44.0/28
+multiple-type-apl-record	IN	APL	1:192.168.39.15/21 !1:192.168.45.0/28
+multiple-type-apl-record	IN	APL	1:192.168.40.15/22 !1:192.168.46.0/28
+multiple-type-apl-record	IN	APL	1:192.168.41.15/23 !1:192.168.47.0/28
+multiple-type-apl-record	IN	APL	1:192.168.42.15/24 !1:192.168.48.0/28
+multiple-type-apl-record	IN	APL	1:192.168.43.15/25 !1:192.168.49.0/28
+multiple-type-apl-record	IN	APL	1:192.168.44.15/26 !1:192.168.50.0/28
+multiple-type-apl-record	IN	APL	1:192.168.45.15/27 !1:192.168.51.0/28
+multiple-type-apl-record	IN	APL	1:192.168.46.15/28 !1:192.168.52.0/28
+multiple-type-apl-record	IN	APL	1:192.168.47.15/29 !1:192.168.53.0/28
+multiple-type-apl-record	IN	APL	1:192.168.48.15/20 !1:192.168.54.0/28
+multiple-type-apl-record	IN	APL	1:224.0.0.0/4 2:FF00:0:0:AAAA:CCCC:BBBB:9999:5555/48
+multiple-type-apl-record	IN	APL	1:224.0.0.5/8 2:FF00::0/8
+multiple-type-apl-record	IN	APL	1:224.0.0.9/12 2:FF00::888f:0/24
+multiple-type-apl-record	IN	APL	1:224.0.0.13/16 2:FF00::7777/72
+
+A	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67891
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67892
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67893
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67894
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67895
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67896
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67897
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67898
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67899
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789a
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789b
+multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789c
+
+a	IN	IPSECKEY	( 10 1 2
+		192.0.2.3
+		AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	IPSECKEY	( 10 1 2
+	192.0.2.3
+	AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.3
+	AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.4
+	BQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.5
+	CQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.6
+	DQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.7
+	EQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.8
+	FQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.9
+	GQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.10
+	HQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+multiple-type-ipseckey-record	IN	IPSECKEY	( 10 1 2
+	192.0.2.11
+	IQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+A	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( BBIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( CCIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( DDIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( EEIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( FFIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( GGIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( HHIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( IIIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( JJIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+multiple-type-dhcid-record	IN	DHCID	( KKIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+
+A	IN	SPF	'sfasf'
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SPF	'asdfghjkl;'
+multiple-type-spf-record	IN	SPF	'asdfghjkl;'
+multiple-type-spf-record	IN	SPF	'sina;'
+multiple-type-spf-record	IN	SPF	'cnnic;'
+multiple-type-spf-record	IN	SPF	'jkl;'
+multiple-type-spf-record	IN	SPF	'c=sina.com.'
+multiple-type-spf-record	IN	SPF	'fw=fff.com.cn.'
+multiple-type-spf-record	IN	SPF	'ibm;'
+multiple-type-spf-record	IN	SPF	'dell;'
+multiple-type-spf-record	IN	SPF	'google - microsoft;'
+multiple-type-spf-record	IN	SPF	'leibusi;'
+multiple-type-spf-record	IN	SPF	"v=spf1"
+multiple-type-spf-record	IN	SPF	"v=spf1 -all"
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.0.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.1.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.2.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.3.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.4.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.5.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.6.1/16 -all "
+multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.7.1/16 -all "
+
+testa.no-type	IN	A	10.1.1.1
+testaaaa.no-type	IN	AAAA	::1
+
+test.non-terminal.minittl	100	IN	A	10.10.1.1
+
+test.non-terminal.a	IN	A	192.168.1.10
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	A	192.168.1.10
+
+test.non-terminal.subdomain	IN	NS	ns1.mysub.com.
+test.non-terminal.subdomain	IN	NS	ns2.mysub.com.
+
+test.non-terminal.subdn	IN	NS	ns.subdn.cn.
+
+test.non-terminal.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+test.non-terminal.ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA A 192.168.2.1
+
+
+test.non-terminal.C	IN	CNAME	A
+test.non-terminal.C0	IN	CNAME	C1
+test.non-terminal.C1	IN	CNAME	C2
+test.non-terminal.C2	IN	CNAME	C3
+test.non-terminal.C3	IN	CNAME	C4
+test.non-terminal.C4	IN	CNAME	C5
+test.non-terminal.C5	IN	CNAME	C6
+test.non-terminal.C6	IN	CNAME	C7
+test.non-terminal.C7	IN	CNAME	C8
+test.non-terminal.C8	IN	CNAME	C9
+test.non-terminal.C9	IN	CNAME	C10
+test.non-terminal.C10	IN	CNAME	C11
+test.non-terminal.C11	IN	CNAME	C12
+test.non-terminal.C12	IN	CNAME	C13
+test.non-terminal.C13	IN	CNAME	C14
+test.non-terminal.C14	IN	CNAME	C15
+test.non-terminal.C15	IN	CNAME	C16
+test.non-terminal.C16	IN	CNAME	C17
+test.non-terminal.C17	IN	CNAME	C18
+test.non-terminal.C18	IN	CNAME	C19
+test.non-terminal.C19	IN	CNAME	C20
+test.non-terminal.C20	IN	CNAME	C21
+test.non-terminal.C21	IN	CNAME	C22
+test.non-terminal.C22	IN	CNAME	C23
+test.non-terminal.C23	IN	CNAME	C24
+test.non-terminal.C24	IN	CNAME	C25
+
+test.non-terminal.C30	IN	CNAME	C31
+test.non-terminal.C31	IN	CNAME	C32
+test.non-terminal.C32	IN	CNAME	C33
+test.non-terminal.C33	IN	CNAME	C34
+test.non-terminal.C34	IN	CNAME	C35
+test.non-terminal.C35	IN	CNAME	C36
+test.non-terminal.C36	IN	CNAME	C37
+test.non-terminal.C37	IN	CNAME	C38
+test.non-terminal.C38	IN	CNAME	C39
+test.non-terminal.C39	IN	CNAME	C40
+test.non-terminal.C40	IN	CNAME	C41
+test.non-terminal.C41	IN	CNAME	C42
+test.non-terminal.C42	IN	CNAME	C43
+test.non-terminal.C43	IN	CNAME	C44
+test.non-terminal.C44	IN	CNAME	C45
+test.non-terminal.C45	IN	CNAME	C46
+test.non-terminal.C46	IN	CNAME	C47
+test.non-terminal.C47	IN	CNAME	C48
+test.non-terminal.C48	IN	CNAME	C49
+test.non-terminal.C49	IN	CNAME	C50
+test.non-terminal.C50	IN	CNAME	C51
+test.non-terminal.C51	IN	CNAME	A
+
+test.non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA CNAME AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+test.non-terminal.A2	IN	A	192.168.1.12
+test.non-terminal.B1	IN	CNAME	A2
+
+test.non-terminal.a	IN	PTR	1.1.226.159.cnnic.cn.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	PTR	2.1.226.159.cnnic.cn.
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.1
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.2
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.3
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.4
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.5
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.6
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.7
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.8
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.9
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.10
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.11
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.12
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.13
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.14
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.15
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.16
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.17
+test.non-terminal.multiple-type-ptr-record  IN      PTR       192.168.2.18
+
+test.non-terminal.A	IN	MX	10 	mail
+test.non-terminal.mail	IN	A	10.4.0.1
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	MX	1 mail1
+
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail1
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail2
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail3
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail4
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail5
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail6
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail7
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail8
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail9
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail10
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail11
+test.non-terminal.multiple-type-mx-record    IN      MX      10 mail12
+test.non-terminal.multiple-type-mx-record    IN      MX      20 mail13
+test.non-terminal.multiple-type-mx-record    IN      MX      30 mail14
+test.non-terminal.multiple-type-mx-record    IN      MX      40 mail15
+test.non-terminal.multiple-type-mx-record    IN      MX      50 mail16
+test.non-terminal.multiple-type-mx-record    IN      MX      60 mail17
+test.non-terminal.multiple-type-mx-record    IN      MX      70 mail18
+test.non-terminal.multiple-type-mx-record    IN      MX      80 mail19
+test.non-terminal.multiple-type-mx-record    IN      MX      90 mail20
+test.non-terminal.mail1	IN	A	10.4.1.1
+test.non-terminal.mail2	IN	A	10.4.1.2
+test.non-terminal.mail3	IN	A	10.4.1.3
+test.non-terminal.mail4	IN	A	10.4.1.4
+test.non-terminal.mail5	IN	A	10.4.1.5
+test.non-terminal.mail6	IN	A	10.4.1.6
+test.non-terminal.mail7	IN	A	10.4.1.7
+test.non-terminal.mail8	IN	A	10.4.1.8
+test.non-terminal.mail9	IN	A	10.4.1.9
+test.non-terminal.mail10	IN	A	10.4.1.10
+test.non-terminal.mail11	IN	A	10.4.1.11
+test.non-terminal.mail12	IN	A	10.4.1.12
+test.non-terminal.mail13	IN	A	10.4.1.13
+test.non-terminal.mail14	IN	A	10.4.1.14
+test.non-terminal.mail15	IN	A	10.4.1.15
+test.non-terminal.mail16	IN	A	10.4.1.16
+test.non-terminal.mail17	IN	A	10.4.1.17
+test.non-terminal.mail18	IN	A	10.4.1.18
+test.non-terminal.mail19	IN	A	10.4.1.19
+test.non-terminal.mail20	IN	A	10.4.1.20
+
+
+test.non-terminal.A	IN	TXT	"ms-dos 3.0/6.0 ?" "google-app_,;!@#$%^&*()[]{}=+|\`~'<>,."
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	TXT	"kkkkkkkkkkkkkkkkkkkkkkkk"
+
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::1
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::2
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::3
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::4
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::5
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::6
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::7
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::8
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::9
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::10
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::11
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::12
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::13
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::14
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::15
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::16
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::17
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::18
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::19
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::20
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::21
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::22
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::23
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::24
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::25
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::26
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::27
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::28
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::29
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::30
+test.non-terminal.multiple-type-txt-record  IN      TXT       txt::31
+
+
+test.non-terminal.A	IN	AAAA	2001:dc7::1
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	AAAA	2001:dc7::2
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::1
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::2
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::3
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::4
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::5
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::6
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::7
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::8
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::9
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::10
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::11
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::12
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::13
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::14
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::15
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::16
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::17
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::18
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::19
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::20
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::21
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::22
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::23
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::24
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::25
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::26
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::27
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::28
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::29
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::30
+test.non-terminal.multiple-type-aaaa-record  IN      AAAA       aaaa::31
+
+test.non-terminal.A	IN	NAPTR	18 35 "Au" "siip+E2000U" "!^.*$!simmmp:information at cnnic.cn!" mb
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	NAPTR	18 35 "Au" "siip+E2001U" "!^.*$!simmmp:information at cnnic.cn!" .
+
+test.non-terminal.sub	IN	ns	ns.sub
+test.non-terminal.ns.sub	IN	A	218.241.111.236
+test.non-terminal.sub-cname	IN	CNAME	www.sub
+test.non-terminal.sub-dname	IN	DNAME	sub
+
+test.non-terminal.www.a.b.sub2	IN	A	192.168.1.1
+
+test.non-terminal.A	IN	DNAME	sub1.cnnic.cn.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	DNAME	sub2.cnnic.cn.
+
+test.non-terminal.d0	IN	DNAME	sub
+test.non-terminal.d1	IN	DNAME	sub2
+test.non-terminal.test.d0	IN	A	192.168.1.2
+test.non-terminal.test.d1	IN	A	192.168.1.3
+test.non-terminal.d0	IN	A	192.168.1.4
+test.non-terminal.d1	IN	A	192.168.1.5
+
+test.non-terminal.d2	IN	DNAME	d3
+test.non-terminal.d3	IN	DNAME	d2
+
+test.non-terminal.d4	IN	DNAME	d5
+test.non-terminal.d5	IN	CNAME	d4
+test.non-terminal.www.d5	IN	A	192.168.1.6
+
+test.non-terminal.d10	IN	DNAME	d11
+test.non-terminal.d11	IN	DNAME	d12
+test.non-terminal.d12	IN	DNAME	d13
+test.non-terminal.d13	IN	DNAME	d14
+test.non-terminal.d14	IN	DNAME	d15
+test.non-terminal.d15	IN	DNAME	d16
+test.non-terminal.d16	IN	DNAME	d17
+test.non-terminal.d17	IN	DNAME	d18
+test.non-terminal.d18	IN	DNAME	d19
+test.non-terminal.d19	IN	DNAME	d20
+test.non-terminal.d20	IN	DNAME	d21
+test.non-terminal.d21	IN	DNAME	d22
+test.non-terminal.d22	IN	DNAME	d23
+test.non-terminal.d23	IN	DNAME	d24
+test.non-terminal.d24	IN	DNAME	d25
+test.non-terminal.d25	IN	DNAME	d26
+test.non-terminal.d26	IN	DNAME	d27
+test.non-terminal.d27	IN	DNAME	d28
+test.non-terminal.d28	IN	DNAME	d29
+test.non-terminal.d29	IN	DNAME	d30
+test.non-terminal.d30	IN	DNAME	d31
+test.non-terminal.d31	IN	DNAME	d32
+test.non-terminal.d32	IN	DNAME	d33
+test.non-terminal.d33	IN	DNAME	d34
+test.non-terminal.d34	IN	DNAME	d35
+test.non-terminal.d35	IN	DNAME	d36
+test.non-terminal.d36	IN	DNAME	d37
+test.non-terminal.d37	IN	DNAME	d38
+test.non-terminal.d38	IN	DNAME	d39
+test.non-terminal.d39	IN	DNAME	d40
+test.non-terminal.www.d40	IN	CNAME	www.d41
+test.non-terminal.d41	IN	DNAME	d42
+test.non-terminal.d42	IN	DNAME	d43
+test.non-terminal.d43	IN	DNAME	d44
+test.non-terminal.d44	IN	DNAME	d45
+test.non-terminal.d45	IN	DNAME	d46
+test.non-terminal.d46	IN	DNAME	d47
+test.non-terminal.d47	IN	DNAME	d48
+test.non-terminal.d48	IN	DNAME	d49
+test.non-terminal.d49	IN	DNAME	d50
+test.non-terminal.d50	IN	DNAME	d51
+test.non-terminal.d51	IN	DNAME	d52
+test.non-terminal.d52	IN	DNAME	d53
+test.non-terminal.d53	IN	DNAME	d54
+test.non-terminal.d54	IN	DNAME	d55
+test.non-terminal.d55	IN	DNAME	d56
+test.non-terminal.d56	IN	DNAME	d57
+test.non-terminal.d57	IN	DNAME	d58
+test.non-terminal.d58	IN	DNAME	d59
+test.non-terminal.d59	IN	DNAME	d60
+
+test.non-terminal.d70	IN	DNAME	dicarl.cnnic.cn.
+
+test.non-terminal.d72	IN	DNAME	sub01.d72
+
+test.non-terminal.cname-point-to-multiple-type-a-record	IN	CNAME	multiple-type-a-record
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.1
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.2
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.3
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.4
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.5
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.6
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.7
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.8
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.9
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.10
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.11
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.12
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.13
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.14
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.15
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.16
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.17
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.18
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.19
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.20
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.21
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.22
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.23
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.24
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.25
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.26
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.27
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.28
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.29
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.30
+test.non-terminal.multiple-type-a-record	IN	A	192.168.2.31
+
+test.non-terminal.multiple-type-ns-record	IN	NS	dns1.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns2.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns3.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns4.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns5.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns6.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns7.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns8.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns9.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns10.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns11.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns12.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns13.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns14.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns15.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns16.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns17.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns18.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns19.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns20.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns21.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns22.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns23.multiple-type-ns-record
+test.non-terminal.multiple-type-ns-record	IN	NS	dns24.multiple-type-ns-record
+test.non-terminal.dns1.multiple-type-ns-record	IN	A	192.168.4.1
+test.non-terminal.dns2.multiple-type-ns-record	IN	A	192.168.4.2
+test.non-terminal.dns3.multiple-type-ns-record	IN	A	192.168.4.3
+test.non-terminal.dns4.multiple-type-ns-record	IN	A	192.168.4.4
+test.non-terminal.dns5.multiple-type-ns-record	IN	A	192.168.4.5
+test.non-terminal.dns6.multiple-type-ns-record	IN	A	192.168.4.6
+test.non-terminal.dns7.multiple-type-ns-record	IN	A	192.168.4.7
+test.non-terminal.dns8.multiple-type-ns-record	IN	A	192.168.4.8
+test.non-terminal.dns9.multiple-type-ns-record	IN	A	192.168.4.9
+test.non-terminal.dns10.multiple-type-ns-record	IN	A	192.168.4.10
+test.non-terminal.dns11.multiple-type-ns-record	IN	A	192.168.4.11
+test.non-terminal.dns12.multiple-type-ns-record	IN	A	192.168.4.12
+test.non-terminal.dns13.multiple-type-ns-record	IN	A	192.168.4.13
+test.non-terminal.dns14.multiple-type-ns-record	IN	A	192.168.4.14
+test.non-terminal.dns15.multiple-type-ns-record	IN	A	192.168.4.15
+test.non-terminal.dns16.multiple-type-ns-record	IN	A	192.168.4.16
+test.non-terminal.dns17.multiple-type-ns-record	IN	A	192.168.4.17
+test.non-terminal.dns18.multiple-type-ns-record	IN	A	192.168.4.18
+test.non-terminal.dns19.multiple-type-ns-record	IN	A	192.168.4.19
+test.non-terminal.dns20.multiple-type-ns-record	IN	A	192.168.4.20
+test.non-terminal.dns21.multiple-type-ns-record	IN	A	192.168.4.21
+test.non-terminal.dns22.multiple-type-ns-record	IN	A	192.168.4.22
+test.non-terminal.dns23.multiple-type-ns-record	IN	A	192.168.4.23
+test.non-terminal.dns24.multiple-type-ns-record	IN	A	192.168.4.24
+test.non-terminal.dns25.multiple-type-ns-record	IN	A	192.168.4.25
+
+
+test.non-terminal.a	IN	WKS	218.241.108.4 TCP (telnet smtp domain)
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	WKS	218.241.108.5 TCP (telnet smtp domain)
+
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.1 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.2 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN      WKS	218.241.109.3 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.4 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.5 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.6 TCP (telnet smtp domain x11)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.7 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.8 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.9 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.10 TCP (telnet smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.11 TCP (telnet ssh smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.12 TCP (telnet ssh smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.13 TCP (telnet ssh smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.14 TCP (http ssh smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.15 TCP (http ssh smtp domain)
+test.non-terminal.multiple-type-wks-record	IN	WKS	218.241.109.16 TCP (http ssh smtp x11)
+
+test.non-terminal.a	IN	HINFO	VAX-11/780 UNIX
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	HINFO	SHARP "PC-1500 1983"
+
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4000" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4001" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4002" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4003" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4004" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4005" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4006" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4007" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4008" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4009" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4010" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4011" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4012" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4013" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4014" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4015" 1990
+test.non-terminal.multiple-type-hinfo-record	IN	HINFO	"DG MV-4016" 1990
+
+test.non-terminal.a	IN	MINFO	root.cnnic.cn. error.cnnic.cn.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	MINFO	root63.cnnic.cn.	error63.cnnic.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun00.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun01.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun02.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun03.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.dn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.en. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.fn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+test.non-terminal.multiple-type-minfo-record	IN	MINFO	sun04.abc.foo.bar.liu.zhang.han.cnnic.gn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+
+test.non-terminal.a	IN	NSAP	0x47000580ffff0000003210999911112222333343
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	NSAP	0x47000580ffff0000003210999911112222333344
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333345
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333346
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333347
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333348
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333349
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334A
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334b
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334C
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334d
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334E
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff000000321099991111222233334f
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333350
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333351
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333352
+test.non-terminal.multiple-type-nsap-record	IN	NSAP	0x47000580ffff0000003210999911112222333353
+
+
+test.non-terminal.A	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	11 ab.net3.it. 1-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	12 ab.net4.it. 2-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	13 ab.net5.it. 3-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	14 ab.net6.it. 4-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	15 ab.net7.it. 5-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	16 ab.net8.it. 6-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	10 ab.net9.it. 7-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	10 ab.net2.it. 8-ab.PRMD-net2.ADMDb.C-it.
+test.non-terminal.multiple-type-px-record	IN	PX	10 ab.net2.it. 9-ab.PRMD-net2.ADMDb.C-it.
+
+test.non-terminal.A	IN	LOC	32 7 19 S 116 2 25 E 10m
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	LOC	32 7 19 S 116 2 25 E 10m
+test.non-terminal.multiple-type-loc-record	IN	LOC	32 7 19 S 116 2 25 E 10m
+test.non-terminal.multiple-type-loc-record	IN	LOC	33 7 19 S 117 2 25 E 11m
+test.non-terminal.multiple-type-loc-record	IN	LOC	34 7 19 S 118 2 25 E 12m
+test.non-terminal.multiple-type-loc-record	IN	LOC	35 7 19 S 119 2 25 E 13m
+test.non-terminal.multiple-type-loc-record	IN	LOC	36 7 19 S 120 2 25 E 14m
+test.non-terminal.multiple-type-loc-record	IN	LOC	37 7 19 S 121 2 25 E 15m
+test.non-terminal.multiple-type-loc-record	IN	LOC	38 7 19 S 122 2 25 E 16m
+test.non-terminal.multiple-type-loc-record	IN	LOC	39 7 19 S 123 2 25 E 17m
+test.non-terminal.multiple-type-loc-record	IN	LOC	40 7 19 S 124 2 25 E 18m
+test.non-terminal.multiple-type-loc-record	IN	LOC	41 7 19 S 125 2 25 E 19m
+test.non-terminal.multiple-type-loc-record	IN	LOC	42 7 19 S 126 2 25 E 20m
+test.non-terminal.multiple-type-loc-record	IN	LOC	43 7 19 S 127 2 25 E 21m
+test.non-terminal.multiple-type-loc-record	IN	LOC	44 7 19 S 128 2 25 E 22m
+test.non-terminal.multiple-type-loc-record	IN	LOC	45 7 19 S 129 2 25 E 23m
+test.non-terminal.multiple-type-loc-record	IN	LOC	46 7 19 S 130 2 25 E 24m
+test.non-terminal.multiple-type-loc-record	IN	LOC	47 7 19 S 131 2 25 E 25m
+test.non-terminal.multiple-type-loc-record	IN	LOC	89 59 59.999 S 179 59 59.999 E 1000000m 1000m 1000m
+test.non-terminal.multiple-type-loc-record	IN	LOC	90 S 180 E 0.01 0.01 0.01
+
+test.non-terminal._http._tcp.a	IN	SRV	0 2 80 www.movie.edu.
+test.non-terminal.a	IN	SRV	0 2 80 www.movie.edu.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SRV	0 2 80 www.movie.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	0 2 80 www.movie0.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	1 3 80 www.movie1.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	2 4 80 www.movie2.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	3 5 80 www.movie3.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	4 6 80 www.movie4.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	5 7 80 www.movie5.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	6 8 80 www.movie6.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	7 9 80 www.movie7.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	8 10 80 www.movie8.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	9 11 80 www.movie9.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	10 12 80 www.movie10.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	11 13 80 www.movie11.edu.
+test.non-terminal.multiple-type-srv-record	IN	SRV	12 14 80 www.movie12.edu.
+
+test.non-terminal.a	IN	KX	20 kaku.google.com.
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	KX	20 kaku.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	0 kaku0.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	10 kaku1.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	20 kaku2.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	30 kaku3.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	40 kaku4.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	50 kaku5.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	60 kaku6.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	70 kaku7.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	80 kaku8.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	90 kaku9.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	100 kaku10.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	110 kaku11.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	120 kaku12.google.com.
+test.non-terminal.multiple-type-kx-record	IN	KX	130 kaku13.google.com.
+
+test.non-terminal.A	IN	CERT	65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	CERT	65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.multiple-type-cert-record	IN	CERT    65534 65535 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.multiple-type-cert-record	IN	CERT    65533 65534 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.multiple-type-cert-record	IN	CERT    65532 65533 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.multiple-type-cert-record	IN	CERT    65531 65532 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+test.non-terminal.multiple-type-cert-record	IN	CERT    65530 65531 PRIVATEOID (
+			MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi
+			WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl
+			d80jEeC8aTrO+KKmCaY= )
+
+test.non-terminal.A	IN	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.32.15/14 !1:192.168.38.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.33.15/15 !1:192.168.39.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.34.15/16 !1:192.168.40.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.35.15/17 !1:192.168.41.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.36.15/18 !1:192.168.42.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.37.15/19 !1:192.168.43.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.38.15/20 !1:192.168.44.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.39.15/21 !1:192.168.45.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.40.15/22 !1:192.168.46.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.41.15/23 !1:192.168.47.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.42.15/24 !1:192.168.48.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.43.15/25 !1:192.168.49.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.44.15/26 !1:192.168.50.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.45.15/27 !1:192.168.51.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.46.15/28 !1:192.168.52.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.47.15/29 !1:192.168.53.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:192.168.48.15/20 !1:192.168.54.0/28
+test.non-terminal.multiple-type-apl-record	IN	APL	1:224.0.0.0/4 2:FF00:0:0:AAAA:CCCC:BBBB:9999:5555/48
+test.non-terminal.multiple-type-apl-record	IN	APL	1:224.0.0.5/8 2:FF00::0/8
+test.non-terminal.multiple-type-apl-record	IN	APL	1:224.0.0.9/12 2:FF00::888f:0/24
+test.non-terminal.multiple-type-apl-record	IN	APL	1:224.0.0.13/16 2:FF00::7777/72
+
+test.non-terminal.A	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67891
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67892
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67893
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67894
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67895
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67896
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67897
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67898
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67899
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789a
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789b
+test.non-terminal.multiple-type-sshfp-record	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef6789c
+
+test.non-terminal.A	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( BBIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( CCIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( DDIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( EEIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( FFIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( GGIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( HHIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( IIIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( JJIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+test.non-terminal.multiple-type-dhcid-record	IN	DHCID	( KKIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= )
+
+test.non-terminal.A	IN	SPF	'sfasf'
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA	IN	SPF	'asdfghjkl;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'asdfghjkl;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'sina;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'cnnic;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'jkl;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'c=sina.com.'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'fw=fff.com.cn.'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'ibm;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'dell;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'google - microsoft;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	'leibusi;'
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1"
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 -all"
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.0.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.1.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.2.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.3.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.4.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.5.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.6.1/16 -all "
+test.non-terminal.multiple-type-spf-record	IN	SPF	"v=spf1 ip4:192.168.7.1/16 -all "
+
diff --git a/tools/query_cmp/zonefile/example.com.txt.signed b/tools/query_cmp/zonefile/example.com.txt.signed
new file mode 100644
index 0000000..a269535
--- /dev/null
+++ b/tools/query_cmp/zonefile/example.com.txt.signed
@@ -0,0 +1,6858 @@
+; File written on Wed Mar  9 15:16:51 2011
+; dnssec_signzone version 9.7.2-P2
+example.com.		86400	IN SOA	NS1.example.com. root.example.com. (
+					2010091701 ; serial
+					3600       ; refresh (1 hour)
+					900        ; retry (15 minutes)
+					604800     ; expire (1 week)
+					3600       ; minimum (1 hour)
+					)
+			86400	RRSIG	SOA 5 2 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					e192JzLhvELznlN3LpQfVh6L1ZYsL0maA39A
+					CN3hH6sorsleyLMX8imUmK88yCo/QaxLC+yx
+					sSe3wJT7W+Jv2dBQFb6HoEBYp0ESXvwoGz9k
+					IJOB2bEs9fwXmrnb/Km+T4HvS0yqUwCt+/06
+					yoCX/S95h4a6vexPpNZhhzVvpLw= )
+			86400	NS	NS1.example.com.
+			86400	NS	NS2.demo.example.com.
+			86400	NS	NS3.noexist.cn.
+			86400	RRSIG	NS 5 2 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lxHd2KDisaKQgOO8Kc1eWr9PO+sWp4fUEWCb
+					+TUhy3iEvW+zLmrn+QUpN/dT4PM2t9kMtJRx
+					i1uB+tm6pD2sbCGaVTkW/k+mJeCBfLsQmlqK
+					qXIRX91AhRrFhJZtmK3yB/dT5zhdRxZGIviC
+					kL7BhU8e+RzIxli6bdJmkKFYcqA= )
+			3600	NSEC	a.example.com. NS SOA RRSIG NSEC DNSKEY
+			3600	RRSIG	NSEC 5 2 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pU4PI8k+ay11yVQXuA8W6vjqGKod1wBIr20B
+					ZSK+nIAzpULXJ5CjcGxKSOkTglPDFQxY+UVY
+					ry4w6wJUF7tYNrGQYfRpOxgVLdv7NGNS+0fn
+					DXf9PsHj7V+5uacDo2peby01pmU5S6Ji0Wwt
+					iNxmbk1/GP7icCsFLGuO3jrPrlY= )
+			86400	DNSKEY	256 3 5 (
+					AwEAAdCIGyYHX9ul1AYjflqR2dKMsCPoxt3+
+					nuUDCf2M9jxlY5H/ExPw7GcFAtNqbTN9fA50
+					d3zQ6z4wjR9T9kuEdfUgcRR5+RcgIkONZe9e
+					0ULSOUgsVp5Jyx6avWBnI6RYGp3Vozs2HL7E
+					MobFrj5FWg4ipW9Cpbzgi+QR/ZM8bwEr
+					) ; key id = 27366
+			86400	DNSKEY	257 3 5 (
+					AwEAAZpJP70EU7QWkGo6r7oB1t/jYwt75b/G
+					qVS+a4KalZQK2WJul4dwQXoxg3byRKuYy6l8
+					03UoFP8NtyTWPr8omGopeyZ0/0jN0QdbngoI
+					Bt2kC3i61fDGGoslIjnFK4ucWVXk+qROoqOu
+					4ZFSOuULNItJl0j1Zb6bwCzhXx5Un0/E3Qnj
+					Xj2QTgmMDbZCRpa1Uv8XUc0VGluluB2YLXBT
+					6BrN5YsVBK9TUNky0b9pUX8S7bfxXcyPd/9d
+					gJYkSZ6tShyctfmgRpeSa/BgYTOD2ymsQv6N
+					RdGk82LTHY37N8h1VDGIN/X+gfRZzm5VPCZS
+					CT+e/8sknTH5pctKwsQxnxc=
+					) ; key id = 12133
+			86400	RRSIG	DNSKEY 5 2 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NrkXeHhw2VCgU4KA8Pk8XBMisWb+RyQGSaAO
+					hk1Zkc0skthKEcCquu9z+zQ5G7lVc8zws8F2
+					3dOdKEa0o/TFlmSH1XM5W3xMdHS+E0/gqEhK
+					y3qX8w9sj/eA0f6tNguQ/iCZtwKsLJsLxCYy
+					WPcg7sjsjKUO5tJ7EFsAFG8jdiw= )
+			86400	RRSIG	DNSKEY 5 2 86400 20110408061651 (
+					20110309061651 12133 example.com.
+					WaHcL7AXsql6tPtnSudQT/wZnYNRKnMLSF5t
+					IcUgJaRGd8gZ/wfJR4lumwc+4NBDvyL8kNs+
+					FscFXQ1izXlPePvsCi4Tw6KYIj/wNoBNF52n
+					DprUpDIjGjXyZdQ2yWu57z8MQD4jx1xt5DkP
+					hRrdNPv3yeDIvY9/s1SsXscIY5SuEt5OpP93
+					67Igc75uHxZFjBjQVaetf4zvwupafuRmlg/6
+					LmiGp0lGE9VTsG3PC0bCx2umzfv6LLX+Ibtk
+					XrEOc4S2YtJ5HbY43n9hH0Pg5eEOahDhlJSQ
+					tt7sw3NxgGMRbMYa+CGJ3GOBvHBhjNayCvxd
+					sMD+GHt4XBto4GCmQw== )
+_http._tcp.a.example.com. 86400	IN SRV	0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QcFXkDEyx+Hv6b3jN6+T9MHNGX5hPsGmqxCy
+					7GHjbJ8wvz2AJHEb4YdLnaRrXO6fIotY4I07
+					1ArIDlUPcF73VP6Hw5+U8vAeKc1Tye5L3920
+					lXNFkWmO1qif6qlvAeLwJEbb03fhNvUcSS4K
+					6InXSaWu4Jqap7psqchJqgqxLrM= )
+			3600	NSEC	test.non-terminal._http._tcp.a.example.com. SRV RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					r5EXPMKrr5vRfjFvsgO79Bvd1UPVmP8TipWq
+					xly+WeQT7GkO3T9i3md3c7/JpJGy+cMErfzm
+					qkt70lmHkY3+e869hQE5F2YqOi7fZm/KRy/C
+					28rw155VWfdWIZDcmXlPJA1EsK08B1/9Xio/
+					F28cMr7hN4ehtSy/kMDWIMFQ2hY= )
+test.non-terminal._http._tcp.a.example.com. 86400 IN SRV 0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 7 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CXIgvla4xVw4B+QRaARIeBupTwGwD4eZGrM/
+					v4urp7jGUrkPgqAJmk7Q4oAzN2szcWYFfawh
+					JRaMetY2HLocSDLvZDZcVWGvUM8RU1pu+SDD
+					u+h0Lwwb1AJghkCnpvudXR1K9cV0k5xStxXA
+					nJ5QYEvqKmvJ4Yo7hWfiq4RImfI= )
+			3600	NSEC	test.non-terminal.a.example.com. SRV RRSIG NSEC
+			3600	RRSIG	NSEC 5 7 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					OpgVpnelCCcv8mhJenxv/tFhTz85nT0X0NVa
+					HWJWpIuKzQQ3MwthdywY7Ugnm9FX+W4uWhyA
+					/VGzYHkoZz9Rf7Fm43lk6JO8lu9B3vC6lqZo
+					PBzYgvAWtjxKOrAuaDGPtHVhN31JHl0P0NUb
+					T1Bgqaa4rQUnYqQeWJdQs72Rnv4= )
+A2.example.com.		86400	IN A	192.168.1.12
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CymhsyPRk+xv+OuaedapHOXJUf940neNT32N
+					DHyXirUBitJdbVzzilQBc7xVdbNSuwNcfNwC
+					PpwyAqFzmQ0JkzEpiyNxDHR/5weAkolKK5RT
+					1Inne9XtZmf9z7Q1zDOBoXqLA8e4ZcnlQDhl
+					FsuxLTVp3XkuMJOszJVO1Gpi49A= )
+			3600	NSEC	test.non-terminal.A2.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					gfKvkjuJaKOuHyvrLX7YPbiEvz4W1hc962co
+					7VrGrNa9qMAbW32zuLCirMefFbE/k19tJ6QJ
+					4bmmi7m3NXGFbrTyk3vRTX+G75h4SneG/fzT
+					qGTCNzjCxYGSFIn2RKUNZmoIRa8yu4PAjnDf
+					KUgTsWBk4+JpAnvtjhLlP9otQpU= )
+test.non-terminal.A2.example.com. 86400	IN A 192.168.1.12
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EFVi2Os1Vd/mEYv6HKVUeR+GeMHS9NuqHfSQ
+					M9LXZ0jpSRO9sdTqxg+tscacqmO/JOcGy1nM
+					1mtSVnEWPj5KGdWOcoab2/JZSKaK+EnYQ9VP
+					OQbu8jMn8c0WL8L4QmWzbE1PQO/8nlHVCCwf
+					hzBtBmsn+btfAtD51h98phvU9B8= )
+			3600	NSEC	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					I+nGXCfTaUS3sSFm6cVEvVJV5MxZ3BKkUV+z
+					0JGZjxsNfrFJLh2lN0B4SyPVRIFri5cS7wPA
+					bhNJKILBelGpKo/nbsUuJTU56Dh6iRBqkI5F
+					HThZeRfcn3aSiBNU8FN2gl6Q++3ITwPbG/Cr
+					0vZNVR3J767S67znc5m6IbhAHWo= )
+test.non-terminal.a.example.com. 86400 IN A 192.168.1.10
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					fZ2hxEo47ZfBk8yyZpkGlqkzopHpU2NUNsX2
+					OPL9fHbhjOs0KCKs1dLH3csTmXyc3bTZAk8O
+					CF5ZX4UHHP9CsOYZULDTdgi3H43tzb8+XrRn
+					flJnwl3sPUEooPfaeC+YYKYwvBCuoIeM3HOr
+					IFWJplCI+R321AoeCdiEKZE0HCY= )
+			86400	WKS	218.241.108.4 6 23 25 53
+			86400	RRSIG	WKS 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PTSaoyVOsTqxymccZOPbFEXJ2xhYiOYBoYAE
+					JiPJxb/vUNxPoJpQJlRwbvqylKhC0WmSSvkp
+					r1+8dCjvt3bOq/1f9vAurG1lQu1yoC7Dy5Mm
+					ybxMBqDjxH+XReiE14BiRAhPBrIOH1s+5Boh
+					WqkOFjwhr99l47eAOlxLSN/iIsM= )
+			86400	PTR	1.1.226.159.cnnic.cn.
+			86400	RRSIG	PTR 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OVlX74fHDc1A6uq7j/oTzC9BUNuPgGjxh6oS
+					T8XoH8NEQRAcUpd+7b4Usm5lI3mAVK2+0OtS
+					dt3jdfKXgMVAOeGA5iM7HZSgsUMxle2oB5ET
+					5Nn1RpNOvGdMswuvEdlSc4GmSoGxTlB2MFkj
+					g3nBa0H3TTZCZSBRg+FGLIh9LRQ= )
+			86400	HINFO	"VAX-11/780" "UNIX"
+			86400	RRSIG	HINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					y5U+AM4RKKDRgvetODc+KSA0sfIdBg9QPW+M
+					kPKkRhM1yE+bCn+/68+npVMPYOis16E1FYCd
+					qrrWaiEUSjO62RBeKLLEkgiMhstMUYXhxHue
+					daKWN1dKQ01D9jMQbtsmrHs6cl//xunWhej1
+					qQjY0lRtxv1GVky4xfQdom6LR1I= )
+			86400	MINFO	root.cnnic.cn. error.cnnic.cn.
+			86400	RRSIG	MINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					H8krZdNDu6MbrnKUVk2+KQLQhvVgQBQ44Zqn
+					vF66Eek0huDgPqgeBOV8VNYrrNbKmWMqjstu
+					zZgC3fJRQ7Y/yYAulUkwQOEQ2ihBWmFQYIK0
+					JyWJEaFe5IKYe0j/nm9jbSQezv1AxfumUpfv
+					GDqpd9POZqo1lB5fglkXCdtvEHo= )
+			86400	MX	10 mail.example.com.
+			86400	RRSIG	MX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lyq50HUzixKIl4Yl1LgPb1g8LWI7dG2mFhdU
+					2a5Hw7t0Sm+NkZdmiV+xc0hyzAaMXAJj2FOy
+					sMOj/X/jolaFP3yMo5sC5IdIufioudbmmhSI
+					62u+D5/EOb1ccDvnZvIzsEGaSJkF0ImeRSSp
+					g28NZiDsInPfT8BYGYoVE9aV8kc= )
+			86400	TXT	"ms-dos 3.0/6.0 ?" "google-app_,\;!@#$%^&*()[]{}=+|`~'<>,."
+			86400	RRSIG	TXT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ytPnH7CKSUlhysvADRzna3JjFjv7qmsm+hcx
+					J2hUqu0DDpfDqE1OLqbXh+Egka4GO38T45IS
+					QfCkEB04wKJIsTVI5gHhJCclr0hPNWUtHudu
+					lVe107AVodRtRBu4mI6CQZko6/eOPDY5bA6s
+					0ngLEv5paCGqhSMdScUzMTl5tDo= )
+			86400	NSAP	0x47000580ffff0000003210999911112222333343
+			86400	RRSIG	NSAP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					WCWGjMGQ0mLM9rJ8MrzW8Oh3ifigxg5L/bYA
+					0OVoy6qHUHgwJKQLFPywBeK0MFvN69U6iYkC
+					rEspFiN6Dvpu0GvIonFHSNrlzK5R8AiNHo1m
+					9WrdcljAti7pdIwlqJvzPJ0uxMZ+FbdVgXl1
+					FgigqOvzFk1hs+6MdFtgrcB4sEY= )
+			86400	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZXO5G1J9CcoF6hGd+gZzD8T/nF1MIz5JqAEE
+					qIpDX72dfHEVginHhzm41aSS/R2krjwJKt6p
+					ny/2af/e9nq3PkKHDtZug5frLkf1pkJko4RF
+					u5Kj27gPKfKuxUIRRp095nk45MVk8B0+eiMb
+					rsNAdOO/g2/BLnxqpXj78BdCpjY= )
+			86400	AAAA	2001:dc7::1
+			86400	RRSIG	AAAA 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MnTVEK0eSa1lPIpYJ6O1laVlrs4OLvJXZzKj
+					awNcWQOZVpaPkPH33ktGGfpY+CdsvHaTRgv/
+					me9Zw0+dlq9Z8prGi/a6ip1gR6wkONY4Jo06
+					l5YHvDt7P/43wisGsc/dl+TRS3njH2ZOdipo
+					hsYPBQIQem/PS6IziuiY+jgk59M= )
+			86400	LOC	32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	RRSIG	LOC 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					iG0R8q8YpHJGRSjpopJzPEwflaKja+04lnX8
+					kEm99VZzqOniwmiNhMGZTovRq2XwnAT4TkTv
+					g2Uak5vhAZG7CfTSwlM6Iw7IJWtEtH5hqRFZ
+					pjvm/DVlSb/Id4gyqxggrgbI+39VinJ0XSXV
+					lx7hy3hwJ/QvU9Qa0TCbwpPkOrM= )
+			86400	SRV	0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hCqwgDea7OtI2Hcxm7Apno/MT2h57VzxwvfU
+					Je1dOXkD2lQUzwY4EneOG5bbyybt5QaZ7gy1
+					WjwiS/mJGREj4LPpgefH+UDr445OjYEimO8t
+					3y0mMkun6O/pUhH1siaE0NibNVUJhTkd4h2o
+					Qoen+g9qHy9sltBugqPlmnJorNQ= )
+			86400	NAPTR	18 35 "Au" "siip+E2000U" "!^.*$!simmmp:information at cnnic.cn!" mb.example.com.
+			86400	RRSIG	NAPTR 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aoJZOwZeZxhNLM9Mo1imybr9y0C7wTwiUNbe
+					pgjjYUC+gy83gq+bCH/K3dvr6spU/FleNOEg
+					GuM5VYW6UqAo/S7baLj/xrT+5F3W649E2LAK
+					0l4q9PQhZOaMnj/+LNBDeqG2bqOYTcNjDFvb
+					fvzvCJZ8jmLzlwlVq37k+HsZuMs= )
+			86400	KX	20 kaku.google.com.
+			86400	RRSIG	KX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OKmV0m/7w+qPNWdVE9PfjoTSffaECcKfraMT
+					ALmtgpJCXDa9UsRyUDmPdeMX90J65p6yyO57
+					Lgta+5x5qrslmJR8EyBdUHv8Stp+lnOOgI4r
+					niPkUN//MhzcC9NXX05S3bTEyYR/COpoqwKU
+					pGymTYS7rC/LmizMEcWa0/JstH0= )
+			86400	CERT	65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QXp2HLZU535WhcxbJjkvbnTFv30VmEa5STm3
+					k1daniwZm0enyaFfZ0TnuxFCgGYBGnOo/E94
+					AUxQ/pvRBxbtaqLaDLKJ6bnTrhjT6onaffXZ
+					rgV4tXSBWSYrQR33fowzXwjbOWzhYT7RyI6z
+					vj/Tm33hr2hxjbChXZivR3SRx5c= )
+			86400	DNAME	sub1.cnnic.cn.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					jTN7VyQTJ040YKb75yXhTsOIa4Y4arJFKEp8
+					RFV2U3OT6e/BP8unmO9mYMTJqwdRkxA0ZBJx
+					viH400eZ/4OBntXHz+iTE+JsBwFo+KOQuZQb
+					WqTNJGUFyoSKttWw3c6T8SiExmGV48wXj+xO
+					dVtHIpNTrgFCOkSpg8Y8LuC3MRs= )
+			86400	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+			86400	RRSIG	APL 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FSLqGFSxKyRNgAS8q0vyMJZpLvDPiB00DLC9
+					prD8SsIjRytdltqQQnpZWyE3d12OapOkC+6N
+					ONCvTBqDSb4GHXfDmqMeIStAc6ef9LeqNEMW
+					HkinGJgnvZTakSKWkdvauJw9mEhCvjVtT4ah
+					oRpTRR3cmakjM/mZaXwahejfj5g= )
+			86400	SSHFP	2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	RRSIG	SSHFP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Js5Zk0o7ZllVXt0wLGGDtTzK0MFOa9vk8i71
+					ihCVh9En+z9+4ZeV4fWliO+4owS4G+H3z5qu
+					8iQTPCx3VAAIJzSuAxxO8KR0Fg7PXsfcxQHR
+					YgZatXLuXmUf3rSUI79YCMknwVdL1jnK3P0H
+					3VS7iAQZ6rnln6yoMOHfN8dHMIs= )
+			3600	NSEC	A2.example.com. A WKS PTR HINFO MINFO MX TXT NSAP PX AAAA LOC SRV NAPTR KX CERT DNAME APL SSHFP RRSIG NSEC DHCID SPF
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pTbeGiHI1nPV2vKXOXMI+v/vXGZoiK12hveH
+					p6fnnffBdbkHn9ZMaNvdeUlsDy3zPVgra9On
+					LjDonIqej3Gw7heEatRG3KEez2e/WIY3+sIs
+					PD2IctkxPOoaJgb5+3WZDserCIm0qbHeVu3u
+					4sSZxh1KPKpRKzES3Y5EBAkTShA= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48830 190 32
+			86400	RRSIG	DHCID 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					UP4csgLTkvDnicg2qF0NO8daixH1IWQJ9Xqp
+					OMos806bqSvKhyn/Egh6QVNe+UAmnRpSobEC
+					h6jKWcEVFjhM2EtbOUUlfjNaWwRrqlPIHhl1
+					urWsWm1x+kOrQcgd8jREbXtsq65kmlTTwZU7
+					2PR18hHvCljIHbrCkZy3WC+mDk0= )
+			86400	SPF	"'sfasf'"
+			86400	RRSIG	SPF 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					g0zsyxQnbYfe9mcugFcY6u8aBmesbWr8+BfG
+					7NN2gCDSON8zUhW3fC9XRSL7AfDm5gHYyQv8
+					a6yNwOVNSjK6jZgaiHLarVo+RZCp9Fxe/rcj
+					TajZEfALjJXuA10nJ6d7gfpQMfGzy24bpsKZ
+					lVUZa2xp5TGdZoQS/8YkS8j7RNg= )
+a.example.com.		86400	IN A	192.168.1.10
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ElzDQoY56Lqw1pcMpRU3mQIfvDVbal2ZGcHs
+					9wJAWOHHKdHsFLUjW2S9ouw4Sh8/9orWdlsf
+					TjsOdLnwtbRS+dPAJW5LvFsnURtUAPzr0/fH
+					scBNgZQPeqQs79B+qudK62Ut8WP6ZtvvY6Go
+					1NLlZN7svt2D6KONYflAPi5jbPg= )
+			86400	WKS	218.241.108.4 6 23 25 53
+			86400	RRSIG	WKS 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xX9GEZOOAhRdohwFTwzcFSYCV/GiTmAHx5uA
+					c7XSZ/+Tp7POJw4WAXNdYPBFb6rELOCdfjrj
+					MK79Nm6mQYp94BBd3CULyrvZCrPFOrEyXda+
+					LVCXrV1WAnedZPqyQqsCivoUBMDCHXgFA4EG
+					t4rZFFr9YRIkiD1XMD3eNYgrPXE= )
+			86400	PTR	1.1.226.159.cnnic.cn.
+			86400	RRSIG	PTR 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vYg08ocmOC1FF1Ws75r6TLX/3QpD5WA2/KEb
+					SnTtlEf7scvN4piy8XR4F40ujvGTVZqom/Zu
+					gt1CZ1RL38A+PdGsbUU03VBPxUHmY0DsMlxW
+					H9fVbFU3GxF3hfabOSYSRL7qU1xOmnz+a7R7
+					r2nL7YWDRJ1ogjA/G8+YKvQeWeo= )
+			86400	HINFO	"VAX-11/780" "UNIX"
+			86400	RRSIG	HINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vC57e5vliWEWZuqBL8U5NChvNxqJM+3xgem1
+					scN8zllo7wrScrlKDVwjVwbxDOs26iAcMkrw
+					C/iPV5cNh4JQwL4zjALWtwZWm9ndvprQjzex
+					9HteKJj7YPWZC37BaUAhoC0z4E+RkW+1Ao6e
+					MP1HjSr6jL5VafrgqKApT8XWQxM= )
+			86400	MINFO	root.cnnic.cn. error.cnnic.cn.
+			86400	RRSIG	MINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ePWNl3irfoaR9Vh5SfkL1nPi8kWqDLXhZUzo
+					Qqjs71fV3Pudc2iMLXLjO54VlikjnfKVwXLk
+					QVbjdGfVQne5EbgsSif44ulb6cIB/NDj3pwa
+					A2L7VARae55qHCdJ4VPHYOlHdvLkLd14U480
+					grKhu8jACjKhFbIzRo1ZNidRizE= )
+			86400	MX	10 mail.example.com.
+			86400	RRSIG	MX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					JlFRRzmvOeBaOETnpTrWAgTSYr8CkX8mhY9e
+					Cm7/RdfAn43o2TeZLvMYQcKsu5oBw3NfUWnw
+					UKr0Glsu10ca6029Z6y81m4+tRtmH7XYOPsC
+					vCPxMMyyTi3kszMwLky5Ac2IrPucZYszYf9f
+					a8fekbydJTBhnHqFM+9RjwmYbMs= )
+			86400	TXT	"ms-dos 3.0/6.0 ?" "google-app_,\;!@#$%^&*()[]{}=+|`~'<>,."
+			86400	RRSIG	TXT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					uU8x5VUArAYXSK4D6ivpwJmvmu9kHTAPSFkk
+					4Yph04dWDV5Ae+6KIy1QidHPiQPZ7dX6ZTIW
+					lPaGMD/yH4gg9xKTM0vaB/SmFQnZhb3GMEYu
+					Ucx9G45jm0BOQs0eEhK+juo+dCOYWdfUb7sl
+					GqOtB/DBkal9+voLqsJOdcgjEco= )
+			86400	NSAP	0x47000580ffff0000003210999911112222333343
+			86400	RRSIG	NSAP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aA0ZJlKJW7iv0NFwmZEJmvaNJ71hI04MIhaf
+					KELGz5IgnIdqntxCHebCcgjW0fvGMF8FgtqU
+					NqBgjW2lXBiJGGxRIxgJXUmohREN7LlnGpNx
+					816yK3SGTYrxecpub0nZeXb1mbZKHcb+W74a
+					opelKvJioG26vIC7MkxwkawsAW8= )
+			86400	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					uvJp85WdHc3ajrwC9vGedFEpQgQgXrEs77CD
+					sNo9wUyMaCjVHHxoslLsy+eOYY4BqIxapck1
+					pgwZ02osNrBNKjfvkXwP2ttA2GsG4Gutwgk8
+					B1fyZWe4prvQd3WEPkqkRTgQhc/nEQ6DKQ2N
+					vTyk4pUVHEX/CxIZIGE+kzBx6gk= )
+			86400	AAAA	2001:dc7::1
+			86400	RRSIG	AAAA 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QEq+y/E6z8UjAfmzaTSwjrdTpnv4kUmWbv5+
+					oDUybEVVKulj/kDpVb+tzBTRUfqUHuVQRe12
+					b6fChfcTZlBi01nEXkAbFUoo0RGCY9GFCf4M
+					wDSomX0LzZHBtlPVG3QQ8Z1vNSN0efrJ3SWT
+					Yu7bOpughjQ4dP3Sc0LGQN4lLbw= )
+			86400	LOC	32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	RRSIG	LOC 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Sp20GwyCuoEnQL31m29xkm5mjiEWKGNm7DGc
+					04As336Y6BoSKsXUnliuyIMoZ1a5XrW/3Yxu
+					FrKk+XRSCafO6Fi9MxnrSdGBwgthwrEb2GgL
+					v6tAAHthmaDJCA5DAA+GZnMGj3bKIq1Lneez
+					xexMWbPbtFK1w6gqeygY8pgLMOQ= )
+			86400	SRV	0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pqpYwqtFQBWB5F2plUrBE3D1VjdK5gr3qn0Q
+					VnYsGwCUo8LCpmxCpn009KgXf91RcSVZwRJ0
+					sexp50fh8Oo+so4M7C0sCSxe1XqhS/oEBBxK
+					z3tpM+ylYADwJMmMfMmflTM4je6FQIK5k8yO
+					dVYPJ2Y6Xkd3uuUDYIk4NOu1iyM= )
+			86400	NAPTR	18 35 "Au" "siip+E2000U" "!^.*$!simmmp:information at cnnic.cn!" mb.example.com.
+			86400	RRSIG	NAPTR 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OmJUFic+v8NWX0OxDm9U8+ZBtspVquQFXvee
+					iEhrPN8ms6/zKOqe71rhnS9da/9Gs+bDBSde
+					yARIDxYWRYSU5x2dR9nrWqWY+XIoqYI+vdqW
+					cg2HrHa5dCWzvI2MIcyp+A1m64g4pBF5xhUn
+					9mOusmK7YLi22e472GXgtAWh2Nw= )
+			86400	KX	20 kaku.google.com.
+			86400	RRSIG	KX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					SBkT8DPqeIW8+qEVjgHRWJSdMqucv3bA/TBh
+					eNFVyp6u6VW0Dq2YRKIibVOqGYIAchFq5Ifp
+					YwqV8vZxskQQpmSgKKZhNYEtSoou3ORG3N27
+					ntyDCQY0f3j8+6N2xcI16TyhgDjP8WYKx2Mr
+					zWPyLHCfptWHL4OSKn4LmmxMeLQ= )
+			86400	CERT	65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YqH31YUxUbrlLoyNCuHFLow01TqCqiflwGqK
+					nnjzEpHF5dbR8gkCHRp31UMed1WcoHxpoBeg
+					JfpD2yAqzyfATYaknu5s/l1zoYiOl+kU/pN7
+					PqquasRTNKzo9PSfD5NmXgLQ2I/hOjpxHNvy
+					NwT5VxCU5TKGIMZw1EA2Gfgw6pI= )
+			86400	DNAME	sub1.cnnic.cn.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					DXSCV9RKokxzfbsgvDXIRTpBvMpWK5FozrMY
+					giy7qDSoU3akrReo7O35psp2+8Rihvq5HyLJ
+					zAO0MMZXIyW2Bd2FxLfSxpLtAtDkdeQ1/waj
+					dDkK/dMkY5uz+rVFnt16/g2G7ShDyInc8Nlf
+					4HH3nIU2YClg05mjeI3VtdRM5zM= )
+			86400	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+			86400	RRSIG	APL 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					If5+oBn2NU31TDxoKb6MusC5RFVX1hWah7OJ
+					oXHkP33tEU70Ovdh0n1JLPMjzdnedrspjYee
+					prQjpiW+/KaCfS7+xugXZ+45FWfzQm5Ocs+/
+					+iydvftx4RrwFLih0jUjVfBTodCpA1dLb0Z5
+					9x5O8S1b6iAQZXyQLn8+0mCAN9w= )
+			86400	SSHFP	2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	RRSIG	SSHFP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PidCLCkvs9HUMw1w6bsUvdsT16a2mG2bQqhY
+					YqmUOnZ+cCntfnbcHFeQGHm2fGm7THqpPIL8
+					pwr0do+lV8Sf5YnWJer9p2KCFFsLpnZJUY5Z
+					UyRQkRm81dWPR2F7+huR8S78m9dEvoDisDDX
+					Fw5t3oSFLkco8N/vaDDThnp6dc0= )
+			86400	IPSECKEY ( 10 1 2 192.0.2.3
+					AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	RRSIG	IPSECKEY 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					L8ztcLWUE8f53+4DMwE8nqQoJhVK6ywwamHZ
+					2xltOoAzkZoYWxZsqvysxXlA8IxfG7nNYmPO
+					0u0Ia3flUOQeI+xmAahxFCa5ztldTAfc2PkG
+					7vMxa+qN/tubWZ77SWnxVml9xPBjPwtJ3kl8
+					tuRgiWwATeVXIinJGIr/Fl0r7Ik= )
+			3600	NSEC	_http._tcp.a.example.com. A WKS PTR HINFO MINFO MX TXT NSAP PX AAAA LOC SRV NAPTR KX CERT DNAME APL SSHFP IPSECKEY RRSIG NSEC DHCID SPF
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					w6YvWWARxQ761+8wUd+lcuW3KNibOGqCX2Kn
+					efA6I1OLq9KrAQY9KF5Qvn3u2xUBLt7p7ePl
+					cS/47WkRSysSJ18j1LnrAOyMKEUUBmZZq60J
+					P8j4Zvsspj5jjj6IwaU3EtNVravFmLzhku5s
+					/IbU1PvVvcaeGh7lnKs/0raKj+Q= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48830 190 32
+			86400	RRSIG	DHCID 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					BV2VsatEe1XAb3nUR68y0eg0HdgWzSMhfVJ9
+					w3rVj6Gccz/aJsLeBl+XFRqp8RzNvYVOkSTy
+					swWK4ddHJMng1SkdmR5e57/jSjjkqRtJ52us
+					AFgs+2/Up+0iAiaeyv9J/cW9EtXMxNJh0cKw
+					+OPdwi1Yy+kSCHS4qinfWHbRLF0= )
+			86400	SPF	"'sfasf'"
+			86400	RRSIG	SPF 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					GSHy+0Bwoe7ypHO4KBAMn2J3IoN60QR0mald
+					T8xdz0cBDR/T1EVTAeP0DAMEx+xW6E8NcOHJ
+					U3tnyR7yFmXEqMUl/2HKEZLxAQ9+sdJtVgy3
+					9UzpygeXY43MYjPebSViPw/PUfQklXm8yyi/
+					VFGFnO8L+9zCaCwJpce5uGP+GRA= )
+test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN	A 192.168.1.10
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Q0zTGD3auYV/zpg18kfQlAugNsqdRqq0mVQs
+					ubZwjeVtUBjm2b96y6+h/BtxkPCKZbJrVGke
+					44jTu0HCfLTuC8c0+OTpv6BXyi9XiFVfSl7Z
+					SnTM+mqfEDv3DlTmrGSmBuaCNnf+biMBUVdO
+					mCDpORNeLHJIwSApZsM9apJM0aM= )
+			86400	WKS	218.241.108.5 6 23 25 53
+			86400	RRSIG	WKS 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					u4A5zuAlFFMfuVRSINxZKXIBM4Nm7okA9Wn1
+					8kWv3K+Ec3xU82wxehQpk5qWagC4VCkNiEVw
+					WgDuvBsPcinueD+GdlNeVJ59wTKU6cqgj2nD
+					VqjB4EnSwadpqFuW+mMe8MJJYriJP+Tzolt2
+					kowEc9w15TYX3ITJNQqsRx9++Oc= )
+			86400	PTR	2.1.226.159.cnnic.cn.
+			86400	RRSIG	PTR 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					k4DEnKmI20oKcU2oefuEhFI6axkTG+tnnl6O
+					rLKegw84qAqGT6GDKf7MCZrV1eGYR2PfjhPX
+					9L+prQyWBKbqfPgWkzJ87mGwx8n9o9Q00URn
+					4WDYgs7bSUyIPvzKvYHXkx+01kIhD+50BfHS
+					t69Z4Q6/PfTYwW7TfSOzuhLzPGs= )
+			86400	HINFO	"SHARP" "PC-1500 1983"
+			86400	RRSIG	HINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZCZilAKkXyQr9+hs/BlvS9zMdtpYNzbfx2dK
+					wznvSe/G63jthJufEA6N2K1rp7nWd9Z6Orob
+					dRZc1NfUIRlyD10/RQPSCFCxBg9OlHciTLQV
+					NW4KsS4kQanWTfC5DhZl6+dIy0GtNzedJdSX
+					V9PHPwJALlDBXcbsSLI3TkCrrDE= )
+			86400	MINFO	root63.cnnic.cn. error63.cnnic.cn.
+			86400	RRSIG	MINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					f9NUDLDsNiu9icsi8YfmxhV02Fld7T4zptql
+					vipbGv3ovRWIOxOkFTXtz4dXVvnaZPy5IVFR
+					LbZWfFMmwsdDe/Z62BhGCfpva+e+jGpDso5X
+					t9r6JEnJKoY9d8RScTxYnh6EC6PYLxRVbdBN
+					cLaKVvZzJlI6eYdJtlBMGGr0jeU= )
+			86400	MX	1 mail1.example.com.
+			86400	RRSIG	MX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QKs1t6oEUaG4p4icapLonCSxyNhwZl3DPsKm
+					KnIc5E39G1G3CNakvAPB+Ifatd/Rf/Z00Bo7
+					ChGSHeAx3fAKs4wpnM0DZNOf1D+2P94ZmIKi
+					nmadgIqAdejFWpZZP/GJq1nEyyfMlCKOIYdc
+					LMn2uM26K5SV/DrLgYU7mCiYKCk= )
+			86400	TXT	"kkkkkkkkkkkkkkkkkkkkkkkk"
+			86400	RRSIG	TXT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Uenb1BTI/L347qz4Gxv0aZ1cHKGYIeAR/vtX
+					7IVMEMys2aTdgVcShVmebZfpPPD/YIsEWvLF
+					u5LMbC4mSkzknkikmDCpI8sGPFHkWePxM5Re
+					gUMPPwd+3Vo42EPgrx5RuynPu93MJgN0EGuQ
+					pm6TS0xQ0XeCtjYpb30P1E/5K/4= )
+			86400	NSAP	0x47000580ffff0000003210999911112222333344
+			86400	RRSIG	NSAP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					a9jbOAcpAEnVMaLtCNrabbuBr65CzlhWfdBP
+					5iG3nDi4R5UDg91u59emAHsad0CiKcryGo4R
+					GGjoTXkvirsw9huWxqNi1L6QKSU7b3kMRvBL
+					sG2RA/ivTo0rrwkWwuKDY7GFGVjfyIF4cBqK
+					tW70Iyql/rj9B8wLWRpVbLkgi9U= )
+			86400	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					krWoX+41uSgfMZaJP64PI1/z5nUHWgL0xGS9
+					uFUNJYhzv5MO6NFlwfs+10kXk/oHY8TwdvpC
+					ziFREwZUDYX3BWt80WZnch/zUA9tkldU505k
+					EjWHiDjyQ2NC15Dox+nAtkBz+XoINcepdBlr
+					uxCzzPwYgE4s23Sr0lnp4wQRTbY= )
+			86400	AAAA	2001:dc7::2
+			86400	RRSIG	AAAA 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PehLeS+MGsMJHjgJKPmptn/v2KA1yKDtTQ+P
+					sbK4QvaPz2S6H4tOBCYzvC0kwFoO0ZlReDQ6
+					IJBw86j7pQyHjspWsw3ut40210sIJjooAk/8
+					NGRUX1w2FKs1bxFLNj7CZia64dGsmTZdgCfR
+					UjHfmoLmuXMELzS6hWWvMWMnWvg= )
+			86400	LOC	32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	RRSIG	LOC 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oV2omi7AMXSjzcjLSeSS5MeCdCed2vqrQGwy
+					HugFFpJyWn1pgrvFvKkLRlScLrL/naDe355i
+					/E7CxwtdYiBv5/n9sY4XA8j1aMCW9qoOb4Ei
+					4PP24c2PwPrSP1FydcvoNQVuLd5ppDCC4aOB
+					fcb8mAJJ941nhSxihZTnrQeKwus= )
+			86400	SRV	0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					egtegXH6TootY47XJ4REvaZo9QQWOlcd7C/V
+					IDgfDu74QIPiDXtRNc/uXsNunBK2+R5bReoA
+					RPiO8Q+LxV9y63kJpY2Os6y3MQgjopO6WT8e
+					814Jixx+5ObvLHee1Usac6dEH+4uUcPDugVL
+					PhQqKphpGPlFbdFEW6kCkDMBPxk= )
+			86400	NAPTR	18 35 "Au" "siip+E2001U" "!^.*$!simmmp:information at cnnic.cn!" .
+			86400	RRSIG	NAPTR 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					kq7iyWWH6807fM9vOmP9nSGLjHU1VoEFHzGq
+					KYEDnqysgPbfdyQtr+omnG0gKxjDbQanJWUl
+					IG3b994/ruJeALSotx6hFdskQDQ4J+hU8Wuh
+					GrD0Zb6oZxME0hGn70ViJdAkc+qHMdSrH6e6
+					7JazF0jmUhK1S7/EPvv68wPLcas= )
+			86400	KX	20 kaku.google.com.
+			86400	RRSIG	KX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xVLr9xd5+UjL2g0Kir2DzHYzJSMMeg9X09DO
+					TutD4dDuCKVxUw81PRxPpps6Pdo++Bhh1Yd3
+					Nd9X5uM7kUBpmQeL2AY5zdOX8q6l/NZCW8/+
+					EXEnw6BOiQcT+eqyFAFEKBE6QfadbQ8eDCK9
+					ArRf4Ht/hctk+YVgW6bHh+WF4Zk= )
+			86400	CERT	65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					g1xXDzfVxOqpLVpaSoyD8ayuqHaJWJeC3q1Y
+					wuve/6oblmigWBJ8GpFUutNBF66xcBoGq47A
+					5Wp3wTtFkh6uGPQCjGj165R8SRtwfNFMqEov
+					PkWQ3PjwzXuvvchAU90FpGAs6zbIfTpJ5CBY
+					f5A6NAjkWnMJcatsCgDZ03sAzRM= )
+			86400	DNAME	sub2.cnnic.cn.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZGNJLjdUhhfQ0B4SJGACKtmFtXsJwbxeixB4
+					z1/6NW2cQmxRj04+oc3IVvIdysnCYIHgTJ6b
+					249w4gxEg4kWXrwynH2Q2EALXDKXHtr5Sxv1
+					xypNN90HgeZIort0z0IHHf1KFGprVRpvhOoD
+					H7MKV3/IjxIG6hOfIkqRCORdAlg= )
+			86400	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+			86400	RRSIG	APL 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vPoOy1Zm3riVKMtYRW3QhHhedDEleIUQwec8
+					0vH2duS76faWAhPJ2OR5xyUo6rrNG8CyAirB
+					egV2nRb1m6yCvaOllaFkreftfh3gqtquy9Di
+					OTeGa2JUzx5ep0DZwLdTTEOMT8ZEy5HJI9a/
+					v/Gj55XfX1qpdTYcwNKk5fph044= )
+			86400	SSHFP	2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	RRSIG	SSHFP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Bq0jac6ocgBfp1jVfoz0zuXUhZCInKuqRo6z
+					FME0kCDLlkdDdvmuzZ9wff+33IkUO0Zf6vgd
+					wp+Q7MOcFEQpQnAdJ2UWLFR3o1GA6VIycMLj
+					m5vVBHVafsGA5UVrUaPWQCBv0dFcywOxPhWq
+					N4ml4uyj2NxzKZDfVk71q/tl8FE= )
+			3600	NSEC	B1.example.com. A WKS PTR HINFO MINFO MX TXT NSAP PX AAAA LOC SRV NAPTR KX CERT DNAME APL SSHFP RRSIG NSEC DHCID SPF
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					MeXmHsliVtd/jfTmHHFMHMMx5IOU5upT6tfh
+					QvtLrHMgump6L7h4tPlWf7qu/RPORoK2ScHJ
+					2WQ/vABTjpqRaPAZ3naf/C3NdvQNlxiF4QCt
+					qqozoDt/80SKBjCYSYYQUnPLVzuHlhEhVqa9
+					ZQiXMPDt81veOFBIfCzLipXres0= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48830 190 32
+			86400	RRSIG	DHCID 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Wb+zYKQqaL53cmm95v5TlojhNY10lBDrfm9B
+					uNu9IxNxwFFyoLKa1SX4f+vtwNlBJegUlGPa
+					DmSbyWEc99mJsrmF1Op5inC4zTxT+8YWc90c
+					6S7poPNt3tm2E0RR4XJCq6X2yD20rUUE329G
+					oH1oTAn2kSaGTAn7M8tdLXnz92U= )
+			86400	SPF	"'asdfghjkl"
+			86400	RRSIG	SPF 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					o3Z3KK/4QQDSwRvOsMRyln15uzMKKi7z4lE4
+					AnMd2GIAJRUeSBNL7fEFf5QWX4XEMbZsZe4a
+					j1M+vM2Q+BkR72Qyd2Rgpo87JQ/hxjRFRetE
+					Y6sYfXJT0Ijm4TGk10PAsmS2M14CMhuOI15p
+					TbcAUkb7/KkpxQJ1NRkFbS/ecEE= )
+B1.example.com.		86400	IN CNAME A2.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xMQqlscw/ifphV6hGrGaiEjfqEJCJ3Zh0eSd
+					VcSpVw7gH+MLraVt46XLoLdhEfAE0ZQy+AIn
+					xlZ+JkI5Hvn7esajI3K8RgJ3ojVEm6/wFmke
+					8VazBgNTI6Zy36sy7Jf4LKrReDCOt9HpJWGw
+					sHqhrNiPg3KthOXDuBpoxKA1kMs= )
+			3600	NSEC	test.non-terminal.B1.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vm+bqEPs23rL8rAuXudjU9nz/iadsrpRoJ59
+					ROTRA+k9Ekz6MlZ3pKT3bnQxbOq6v292qJeZ
+					5QZDCf+yrxrJDvxtGzFTI8m0bq/jARGXNVbH
+					ukX9aYNNz3MoXfkQKroFF0xlngQ8MZ8qh+TG
+					t1xjI6GKU0MtdQ/iZ421DTCqwrU= )
+test.non-terminal.B1.example.com. 86400	IN CNAME A2.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					LFlxD9dqqHc/HMUDa+gSI0x2M3XzH0cgxe8q
+					WjGh9GvAnB9UP1fpvWM1iHtGJ1DAmQlpt1yj
+					F7HOwh+JOvqi78Gsl+kteE9wK/ByxJ/DCXhj
+					Sq772P22kYI7XTq03TdK5L5ndfxv5kSBBefj
+					BhSnulx4t1Ril1kGvq6TfFoww20= )
+			3600	NSEC	C.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PN1EanRRN2EjhbwuS4j+icsaAlG8q2TquN1e
+					SDikRfzScbE+xv9UYObEKG64Ee0vmf7FbRhU
+					MT72kHNrBYgsoFS/eCn7xoB03UBZt48BPiKE
+					yR6BzCKSziPTpEGZNj+NNWdQVRPdbGU3MHAO
+					Jm0qec4CZOVOXkZG58TSGwdayDM= )
+test.non-terminal.C.example.com. 86400 IN CNAME	A.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YEuFEc9D8bozRPKXShr0B6O3HNAGT2KXMIQ4
+					3QyyPQ8Qv7zV0ReUdwYukiVhSJ1Xstx7vk9k
+					uwtTtvEk+eqp5743sFnJO3gkoWtlTnfouG4j
+					Yk6JQoB7w0z+hgwsE+xKr1Z2bsnJ34otufNR
+					oejNWmnEwoSmRWg7xSI8lYrFjzE= )
+			3600	NSEC	C0.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					w07IQQxLsnQ8W+B47Fz2QoxFKWrclBl4+Lzz
+					NZ5Lp8u7XOiLiHPHXp/5938JPpUEb1ldcANE
+					vKBz5fhNFNriSYa/WfV/JTGRv9UnilPepv9Y
+					cas6TNMdz/y3QUazB1bzkwnbKLoMklubRVPN
+					QgBLndRN/hSqaZ/2ePNE95kfZck= )
+C0.example.com.		86400	IN CNAME C1.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					eSc7WW63CbLiH+2kG9YcP/f1E3zNPSFy2CDe
+					dTeZ/FsyoxsOVVEKBUcaIgndTtJNUCk26GPR
+					9dwLYxsEvdZZ1tKbfHlkqlmGAu4nzdetGLtK
+					uOpMdFboNEgh8AXB2phRn0EJNsuhHQFBmX9W
+					pjN01eJksOOSv/znnrBReFObbaY= )
+			3600	NSEC	test.non-terminal.C0.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pZtzNxFYvEv34K+8Gi6fwr5SOAEDsshZ13tM
+					tW9Sr0oM3Ea9AAjfKd66eYbLF6nq/FOYQRfp
+					t56NX2zYtT019mX1KbEouoAJCrkcmnns4aTc
+					unQE9yGMk8moKXwRH+rQSflemTHO9aeD1SVv
+					It8kxXfalR3otJIrr1HdYvXPVv4= )
+test.non-terminal.C0.example.com. 86400	IN CNAME C1.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					szsFYsg8E77ew6WNUuLIqnDrGz1l6OuxP5TM
+					woVGsDwGc7E6gbzbcXMTNPKSSDLa7dchjKv7
+					Kd+ORNcCVBu8qtos7/TfpSsH0hbea0k2E7EO
+					U3QeZ8EsNCd3MSXBLpn1016/+EUGML5U3dRs
+					kmcWyT/iM86rpz6Gby4KPIcULlU= )
+			3600	NSEC	C1.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					UJxr9cwrOEfFo3dd32fV5YJ3FM4TqyqEBeBk
+					WKU+Z7Uc2x6+U5EO2GDY0Qj8jVEwVugZ53V2
+					hwh+85CuwfbFX5LkCLbmSOH3jte5SdHAdayL
+					s1iDNJ7hCji86n8bIZzmBsxlRgC9swfwO0vk
+					YjHGuigrb/Cv4XnYnr4PuTnBgP0= )
+C1.example.com.		86400	IN CNAME C2.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					KZy5KO3IZZ/9PbyHj8DEas8yJW9bJTcyFbb/
+					fC3kk6iBhkmcKfdK3fF1M6ARf7DC0uoQfEcz
+					RSoaVn2Eb5EMEEriPSFvUk5GxDObLM0fhLS3
+					E/H13bdXR4v4swxkV+0PBQQiu1GEK0WRoXVm
+					C6dF3pM4JYEtRgqc/RxY82s+Mks= )
+			3600	NSEC	test.non-terminal.C1.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					KJNedKMxaPWxtwSKthu6+vanXp4Sc5vMvgxs
+					UObrVIhoxTUvcy+pOD7x0/bQtQYUILfwO4X9
+					HXElIDqA/XENZKjb+PQoD/Yz0G/63mBAHYEi
+					VSdUGCmbdNJ8LTkr/mJSLBmdP3xo23Fv+uIZ
+					lkErdo/LHUT1n2Y5tmfyvmUvwAw= )
+test.non-terminal.C1.example.com. 86400	IN CNAME C2.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					h3NccjYD8iWBjbbKf58ksZtm9a4FJxWqcLsl
+					RUytSY27B5mC+R6Pyf4s/pzYPIGioubmnYAO
+					kU0of8wQ5r0HA7Fuwm1OU3xVJVVOtRBb5OhS
+					bShf6S4uanb6oYgModWWdkuo3fFP5uQIT06n
+					6/kC13Q6XCprmhjzfuQB4j0T1Rc= )
+			3600	NSEC	C10.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					rjjq6NZ1RSwBrNgpNAFbsgi6RCLQ4Os8DhQ0
+					NblY+u/XuzVC0QvRERNY+mUFsKP6BpKcjFSn
+					mZnwUB33qEh4F4kVwaFPToSYSOQLlODWClEy
+					gM6+2xZ5eJzLj3tnZ3PipI/hY1DdOAhuvCZi
+					8fJIDi52+nH+CoddYKn/V9LUgrE= )
+C10.example.com.	86400	IN CNAME C11.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QfKnR859+8/BBOKUnTxi7LKj6Pf7hzYFUNV9
+					xuNJaIHrWGAWixW8zcgd2EfEk9ec47UHP3TS
+					+opYiujwFRLbOcU56Qn8dffBU43fWSaQ74ra
+					tKqgq7U8qpMc3567CqdZKINqMQQaJSpw6Gu0
+					kHbc2X01ZEJFecUQuGzv73sXrzw= )
+			3600	NSEC	test.non-terminal.C10.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					g5GR8P3cLs7xX4R5imA1qoklOXvj7bcyj5FX
+					xz6qcnKudO+iivT5+Tp8wbxv9RXzgurndozI
+					q/g/PiSt+NWV4R4A+kqhCuZuBQ1QZfRPGqAz
+					PSCpQ4pko8jJC0qAMGZ9SdM1R0s1aMEaIcg5
+					YMQd7U9zDVgWXOW7q1L54eLuwX8= )
+test.non-terminal.C10.example.com. 86400 IN CNAME C11.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					afPyrqIU9RdgUUrraxxzvqY3b1PWPI1AhZpv
+					W/u8BU9UzBGlEyGSIO42D8qmwgJ3KPiNy/2M
+					55orqBYqKtjWHjuxZHpwRTvz+r4q/v0AEyV/
+					pPNHZg0Nw5J47CulFYiYhw0j+xKf0oLzXXCD
+					ndgvR8m79JZy1crI2LJqRTwQKiY= )
+			3600	NSEC	C11.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					r0Af/Nk6Kvnx1egV4d1uIKR2Wz3AjGbpuXSF
+					DcYZvIK0OqpT3eLbpHOWi1+hWsqf1lBsXQaC
+					si+rBLnEMlJfTQbvLHJ2z28/1CTFu4cb+wMm
+					37P2Ss6sJhv9iTz392llnoQ97kkpmUxMKdeC
+					fOsehff6le3ZMpNhVBROdLoeXaQ= )
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN A	192.168.1.10
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CNvJP68kKf1Th5pvbU08zEWfDsY3mKbom/fy
+					gOJhbQ7SvZhWom9e5eNj4B+tsnoUGM5DheoC
+					RWdTMtaj7dyGGdM8HvyReVgb2841VcpaDPmV
+					RnniANnePU7rZeN89BUqat5lrOu2At5pVnz1
+					BBqMxzobM9isuJzFYpZUsn3QO6Y= )
+			86400	WKS	218.241.108.5 6 23 25 53
+			86400	RRSIG	WKS 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					kxFeJoJ6fkNBZ/wzqK1CEK0eOQK+R9SBi6eW
+					cFii6EJRcAlwoD+zneCAoXpcBoqOFGxbVCQB
+					F+P7qXStE40WvDn6KyrLpFoqJYRBzSC430ov
+					KT/2OVhkJrzypYAm91zoxo4EC2iPT4BYyyv7
+					axx7ABNnDcnuPA3ox6heXG3Fenk= )
+			86400	PTR	2.1.226.159.cnnic.cn.
+			86400	RRSIG	PTR 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Xh4hhbpAtHKUg4JiUx5Lnp2i8GBbjrDnLY1z
+					Ga7Y0rJfzqK3BETsyjjJyvkjQSXiGju0+I38
+					mwc34rZTVxmx6wFd9V9oK74T9nPodQdmqOYu
+					dEMdEk1rfMCA7pvj9pbiMpGOZRHdZ4KT2mMc
+					MrQtVRJh3kFhuLhRDAT9Xa3/NE8= )
+			86400	HINFO	"SHARP" "PC-1500 1983"
+			86400	RRSIG	HINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					fuakGfnFU5L6F+novql1ep/d03IiLQGNwvew
+					GvVuNpVKjTWmUi5DIpBJT9MkPjk2mdo1FKWO
+					gRBvkLU82/6dyA9wjzq3vbinVvD3f5+iUPqu
+					uvDXgzlQaT8k5bVkNHtwCfJXbjw4Vc4/8omi
+					gkTnl8Jdf6VmCShXrZ2Y6TK5uzY= )
+			86400	MINFO	root63.cnnic.cn. error63.cnnic.cn.
+			86400	RRSIG	MINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					WJylyrzRUPDYqF36lOX6BM57HWvzzE/2dXJY
+					xSua252Pk1UZrN9yiDJRttQTmqkU3DxtE1KB
+					vOkCsdOc8R3dr8BsgN8m2PQAvCQY8cuqDG31
+					le4yKF9DE0BcdXbu3Ic5bp3huSY4iuaiutvA
+					fuovrtzelaUUvhkZYA9+0EHy4JQ= )
+			86400	MX	1 mail1.example.com.
+			86400	RRSIG	MX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					dRQ0vpIrS+qhzSOnmbiiJqdyOLCTjlp2LdV+
+					dSTcplTwtRRYcW9/MUoDzh2kfEk5m3loSrH5
+					7HrsMlt8d2chhCJo/tF4radCDBTZuK7i+OEv
+					P17QFhd6DMw5S9dEM/o5j1ijUZv7/QgsbjbF
+					6Unv34bQSidfUqi0JoC5O+VuGLk= )
+			86400	TXT	"kkkkkkkkkkkkkkkkkkkkkkkk"
+			86400	RRSIG	TXT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ziSZV9Y3JQ7zh3h50cymTtW0tzJE3i9CLO0c
+					ofJJaHBP1Mx82MMRDMS4tNejRpY/vYUFwrrb
+					y7H6vUTWJFHH4DhqNQrqndZbqxLatuUtkmEH
+					raIs2zUYMIgS2aT96E23+kTmPIXDGvIQ0SVG
+					d8vDsm0wnpz9OL0R/1pv17hRIg8= )
+			86400	NSAP	0x47000580ffff0000003210999911112222333344
+			86400	RRSIG	NSAP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Eyj3aQnd4lBNfUtxZpPlEFFTZUYGiBrnX25r
+					PHgK55h5M226SWWtyv/JYtJjcMntHqq7fbON
+					r/8NKCO6dAZra5LYtdRLVO6t7lJBxsWHI6ce
+					cDTVE3PWxk1niK9LBCwdckOwONp635Iukmbt
+					sdfEadu9Aw9BMmOT83QUJyjW3f4= )
+			86400	PX	10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					TEIjyOUWJ6OaOHnRSus3ytt+p5R/t0PnPJwd
+					TyfYrLfXaA2z9G4L7OWcT3z7wf8g55WVR28p
+					PmXiTBNL6LFQH+1ASX+YaDZNx6Dc2b7bOKql
+					5dIccxMLWi/jiWEaPp/y58Pz9t/qOF9ZNGVg
+					+w+Rul+6HaX6Dc53uokFKc2xtKA= )
+			86400	AAAA	2001:dc7::2
+			86400	RRSIG	AAAA 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					sqigB9U+/ncUGao2Eai2Ykkyx8cZfbPcWy5l
+					9771JB4coWudFuK6gj9dXowjgHtN+1VulzQ0
+					vSUM0GIZjGcJe8hXrQsOOClQls75z5bVYVTR
+					0Mu1t5nXhPtCD1mgzyzStHtC4jiXmyAw3K2U
+					G1UJFlHYzZyBYQMLx0qLC+gRS+M= )
+			86400	LOC	32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	RRSIG	LOC 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wM51Zvyo9rTgJ3GokcU+AKxZGiDQDuMGuo/V
+					P/sa9nlHSoNIL885Qzbdn91Ur0NFReQAo+9m
+					s60Jk8S0eCafQrlKit9/fPBMZuO/7HDnkavG
+					QiIe1GvIZPQwqaj0z31MpMG7TqF3wi/c0NlY
+					qz8VfjrkNoEEZGIzJFJ/EWghLK8= )
+			86400	SRV	0 2 80 www.movie.edu.
+			86400	RRSIG	SRV 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					XAb5QB77kd8LUWKP6k8DshtBvKSR1n6HtS4t
+					qSic2+Cek9sldt3h9KAy5gL3LwzWUVRHprJC
+					KthF2ZTlA79uoRLbiBpA5lnmanDArO9+Csz9
+					FMj2zRG7bQIpichZIJbGBgzsidnE6cuCsrXQ
+					j8RqPdPYuBL8hBIdKpW+24YhXEw= )
+			86400	NAPTR	18 35 "Au" "siip+E2001U" "!^.*$!simmmp:information at cnnic.cn!" .
+			86400	RRSIG	NAPTR 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					iv9JeJd/Z/4ASBeZj7yWIPxL4SnvEGJQuONm
+					hqvmxr7QtvltBhlGZnYZj8rBixrc8A9lubjK
+					W3Li4/QCF5CJ/ivoeTLQzn1Ca/hMpPLMJ4/N
+					WfQoeOzn4n+4fVIrsVfbdVM7rJV6+d2nHQaE
+					79uwSTwm1pja2jkMtVo2/9AgYw0= )
+			86400	KX	20 kaku.google.com.
+			86400	RRSIG	KX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					qPQPZDruP4UD7ORY7dw3hdWHVD8MllW/DEj4
+					WYi3F4eYolclA7u/9cebt8UJii8cigY+24TI
+					sbfRIIqvkhOg+UjBtiUQsj7x0XxQXEbim571
+					aj2HLvBHO6I991c6ndatShQ3d0jYNyE1qhCD
+					v9i1SkmjfuSRVWiIdpQLUO9qz40= )
+			86400	CERT	65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YM+IPkTYsPTqNajmdirxCd7NRCB82AtDIYgc
+					qn6vCRGM/2v6vb+tciYnRl85uoAGysS+bmiF
+					lqB4OGCydIVhS4KTMXwDPPf1d91nqy8BWz7Y
+					ei+B2qhTnSGQu96sSBdJ2ceU6E4/6/u6LY5a
+					lAVt8Vk0B2WjTAjUi0VIDqhL3HU= )
+			86400	DNAME	sub2.cnnic.cn.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					SBDS/nWt3HswZJxW2jRGzCsYgxCBofEeuhbq
+					QmNSGR2bHojp59AYZR00B3aAOdA0RGhdZKuU
+					yLCqNdFyDmasGtdc7CP1Bd6Ey0hVCM9wbLV8
+					QaOWo/vgsWcNFMAAxR7YqUfiRaTJLV+IouDH
+					uHodkILrgsOqpXvdGaZLe3wTQPI= )
+			86400	APL	1:192.168.32.0/21 !1:192.168.38.0/28
+			86400	RRSIG	APL 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					VEqPOVp4Nc02haMJeh4YTHDoVGmuTt6cz1fo
+					Lp89B62/L1KGFHXE6FrB01fLcwT43FbOHVLA
+					zi4szJ9YBC+rqSbVBwm1lo/TskBTA0VLrbEP
+					9iEYpPtqn03I1upG44cdfcXyNKx3fZGEOeaw
+					TJL9dff4O08LCvJlKj8DkpZ4Jgs= )
+			86400	SSHFP	2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	RRSIG	SSHFP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oyelf6+jY+6hoW4151v7TP+9er86PVXpd48R
+					m0o0pxU4ICOR4fvc55BVrseXAzI9gGCgX5Xd
+					bRIVuLP9+8qxQ+lGJHNn6y5916awS+RPVWeh
+					dAJvOF+xnNjSiO2JXfGuM5jXrawr4/mrwzK+
+					YKGzMSsqeqDA+V1NOYvfzM9CamQ= )
+			86400	IPSECKEY ( 10 1 2 192.0.2.3
+					AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	RRSIG	IPSECKEY 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZDlc09VMM2ctWqF6pLelK7xOKjQl3KRb1pk0
+					W7tmrHh7TZb+0KkwkNl3LxRA75/xLPqlU/ts
+					iV8zEh7gM7XEv6t98+eqRo9XwIJKeKRo9Dbi
+					F+2EP5q2B/Ja/T9g1aYx84CIe4pNV5lwxFTc
+					RYCAnMs9p+w6di+bVFUkxT9MISs= )
+			3600	NSEC	test.non-terminal.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. A WKS PTR HINFO MINFO MX TXT NSAP PX AAAA LOC SRV NAPTR KX CERT DNAME APL SSHFP IPSECKEY RRSIG NSEC DHCID SPF
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					zrLyk32zZZwqj4EUGGH03gVAyksBeBYAQMpp
+					yH3MGvQniG4o+VvCw6WR4TgmErskBhhOZ/Ky
+					GtFqN2Uorcl8bJnMYVgQHRC14cPXEYzIRdz7
+					R3/GkEiyoYKrgsbPzLU9HTZoa6l/0Gr6thzs
+					ruZZwhavLR9Y66O5Q/PU/4S0oeU= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48830 190 32
+			86400	RRSIG	DHCID 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					u7CgSI0G8k62LtPdEPwhu7y+TMIpxVM3IO6T
+					ZhbPR2/6rMez4b5GdNbLkXs5K4mxz3Q5JiUM
+					SNSq+l83GXl3n2qKQzgfKCAyK+4E5/lI799h
+					VPnMjdSjQpUr3SBPqYKVb2mT3zXrYxksp6IT
+					b9m6FzNlGWCC90yY1d+nGT3x8bU= )
+			86400	SPF	"'asdfghjkl"
+			86400	RRSIG	SPF 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CqVJZgqFQKjUOGfIzuMvoSlSzKhwP7l4kQX4
+					ayUrpMnqaHyQfHJxni/tfa9OwvxExfnY/B/c
+					vh98DFNmAc8FOPAMH6PLiZfxVzDX5Sgi0RrZ
+					+GYDccb7rAP7FsUAcsFreLyKFUTCycVQ7Rj4
+					OK48YTA5EG2cKpFc5dxq6+//RHg= )
+C.example.com.		86400	IN CNAME A.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					JeFX32cJ7aBtb4rUwhcOjmtn5/bG0yEJhyt0
+					n2xJPs2SMZyBvsVJP/9sAhpIu8zSXo1l5Cyo
+					aI6zwonJmnmyHU76jgXjSq0aom6cu6paxzEW
+					fhTbGGfCQ7NsPKgZr+TGNC+cfM8my4+yythX
+					+YDqKajBegulcAsHzEgYWmUoVx4= )
+			3600	NSEC	test.non-terminal.C.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					JqmFzLtyfWfcHMKC5k+5Jrf4DqXCg8PBpq7I
+					wv7ifztFYfg5VhXnp28hrE8QqSfLYv17CzNc
+					TH3hDhqAldwsjPG0vyhQB67zGkOYVk0FbfWW
+					GiY7sP59aKv3ZI27ZhJmf6uA8WotkD2QjCYc
+					XV8x7qTErkf/vi1UiGgMsS3WtuI= )
+C12.example.com.	86400	IN CNAME C13.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ydvCKZnNj+3eaicVopOYSqklt++EOi9eKEcY
+					rD5KZM3trEPRM9RAQuVx1U6/JOnvX7EkgMEx
+					x6FvA4mIS86H87N6R//CSc3ngOy7QU7sSZ2Z
+					f/x7WbOaqCfjYRsxeKkzuIGati5yraxhowkm
+					OHR9XwB0d4ZlX68mOFXuI+ENGXs= )
+			3600	NSEC	test.non-terminal.C12.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iq36ylDsI3HYqZc2Fu762yVwg7eUm0SMceM+
+					x8xOWdDvR9Yt/hbZDGKLRHGby0TEZgWkERbV
+					CWbcCZWyOdyhB/b/ZSkjL9vM8S9fIODqOPXa
+					azbwjgV2T/kJeJSoxA+ocJLdRZynsBpHpk0Z
+					6NKTtvCIwPDP5W39S511mXl22kA= )
+test.non-terminal.C12.example.com. 86400 IN CNAME C13.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wOnjiR6iShlEBNMYQBZMFRPlOvLnd5kn4TqU
+					01AwGBdIRUm4dSpmIT8LQc1/xiE7QzyfXdkr
+					UsFtSRGaPG0NsUTRz8tIecfsLZNssJUDyg0h
+					puEiTnampZMmHW2NYnPHq5gkKLWeDuan7hZi
+					JRgMAWApVJyYDmE8rY5pbcrFnoE= )
+			3600	NSEC	C13.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					g8p7p9I+6D1fN6mj20dNRAyb1G8Thg7rCZXZ
+					xmgkdEu48imlNVR9sgX3aO6GL9v7BUNc7Vt4
+					3tyx8y2nSdkM1aGTYpt2DfaiTtYDMlNbPONb
+					9/i+3LpzDWzczCAdCxWNHtoCDcPi1w+Q76AL
+					DPtARgFO08OeAVtfkSdJu8+a0Gc= )
+C13.example.com.	86400	IN CNAME C14.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					SDz4/RI39SKfiE3EJ9RRn6FfLw8ZPB9DzE4V
+					a0VOrTiYS3KxvJqkBEUwFH2oJfnkc8b5HMpj
+					ECC0ifDLrwsRctXfpw39EEiwQ7n4bccBj9L5
+					9fhNvBYn+qIWRILSFj3cA3qL6gvPRNTGZHQA
+					ENgwtF5/b6bHIpDb0UFzvIK4L7w= )
+			3600	NSEC	test.non-terminal.C13.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QoBrwTsEMKvZrWVWOjLO2gJ+X2G6pxwZZMGT
+					/m72nrpeIiYNL10V3/3Chtw0bDVfzUapOdfk
+					weM/i8qpYWxpznWbd+c03tXTqqi5gCIVfRcN
+					3k5nQxX2nS2mC3oBcmI8BzMi7wX/boNTczGd
+					EmqbnrGnn4qn2vz2tduiwW804io= )
+test.non-terminal.C13.example.com. 86400 IN CNAME C14.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					z8p6Mh7YjvAjBOZhi04dAP/phrBoWSavdj8/
+					RHBgzyOyeG6hRvmmaZPx0GPcHEDI0xMv+H3L
+					tdoMlrMKF3U74u93xsf3B3SAmE65oSISunYC
+					9R/UNE772S+ga6FU8ufjY0/EFFjctj13RiKk
+					9Kndb0e5RdWXKApB0N/haIe3fPM= )
+			3600	NSEC	C14.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Na8tko+ZwvXp0z4figIvFX5tqflE99k1RYtb
+					RkhDzZze1S1+nLS+c+NgKrty2PowiWNgTGbP
+					EB6SgLn0NkF/I5a7pl8lrXcgg34leuhinFT7
+					pBD+3ampYx8LGt/2uBfUg6clrnbOkIxsf8aS
+					GVQyRV2z9cRN9DfKBmtkSBoP8zU= )
+C14.example.com.	86400	IN CNAME C15.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hlmobxbczJOv/RjwIvLccuRRdIxZ4IJghtlR
+					5dTJ4YLeu9IwCo4eZlLoR3uXRv7hqbIS8mhr
+					n8eqcWnTaFRWJ4G1dRwx8d5YaN5ATgxnH4g7
+					CDTOZAAY8/cS7Ybr+abPVLay20y2Iheq6eOK
+					+dWRCJpgVnEM4zUHrS3XOOVkx2U= )
+			3600	NSEC	test.non-terminal.C14.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					m0JRA/8wf4QtKtI7BGBw31uebJCj+5RQLKx9
+					sBvdjCL1yK9n6kp0OuapzxJUcC3kL/jb47MC
+					CyJtKcc65Ocoj4jGds8Kp7yNrDjIAb7WJmds
+					HnpQcgNyGgQHqkiEuAPwhulHjdIV+NKcPXec
+					4FnRRErGq8DYg5qPXIguPmeyvwI= )
+test.non-terminal.C14.example.com. 86400 IN CNAME C15.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QQ5yqUlmn9mgtmacEw9xEQMAh8Ecr92SWROk
+					cVrWavhQfSsSDSmM4ftlHjLHFZiJ7YZxa3F/
+					13IHGcHesFaKNicknyzJNvqHJvkVvDkLDnt/
+					uos7G/+WDskV8QOZ/OkVWZwYuNlw40z0ex5Y
+					3miSs89/A192AgVGK11YinQPL2o= )
+			3600	NSEC	C15.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ly5nI7uorIvY3o8mcDgVRQQnxiFLAZjYRlIB
+					aVD/ldd2iSy8AG2hfocWXHhLbXzO3CTjXjax
+					36TwLR41UpuqXURTG0Qzfyq0WPej4irAwdac
+					O0JV6gc9JJHFKOQ2kWFN05cBKJyjk/h/3y3B
+					gfv4icRVezRM21p5oy9zKSSP7fM= )
+C15.example.com.	86400	IN CNAME C16.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xvrk7027MrYKIUHknMmn5TX9F2LMRE1n7Ujb
+					VM1e0OwWWrlnInqvRqs64P1mTdast3q7KzOU
+					n6WSNvIyJtVkJLFnFL2dtm+lsUpkh9tJKyzE
+					DyNPn5PVPya85Yo+P+LQd08k/RhCPgSpe2IO
+					4GIPCZWVnnNBZQeMgLbIEMm5yHs= )
+			3600	NSEC	test.non-terminal.C15.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Vx6oWYWNXU8lvZbcdFpR2gZlfdabwOz131U3
+					fuQ25ftTekNfDn896eXhwRi2II8LyraUvWDm
+					Bo6PqzqlDdeHyExHYywZ7wqoGZP8afrqLMNQ
+					pLnv9U+ZyXnYoot4A7uhYm6d3ho1yTyneXn+
+					CWWZOcw/ZRON+xWMwFjNXZZPabY= )
+C11.example.com.	86400	IN CNAME C12.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					VY2iUA8etZcNv4qMVtrvN6U+PO6irU2pET/o
+					rufaMqlq7TMryp9mdd/1Ef235TqjSGDT7NqL
+					VAMvtgVvsHTuFCeWIMuDkVEe7KXjdRrYK9a8
+					WohgExsI26dPMy0R/JGtPmeTTSIiS00SjVk9
+					wdCQjSbZ0xl/T07rZZ9fu8BaVvY= )
+			3600	NSEC	test.non-terminal.C11.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QUm2o5cNBZNmZe0sJ8kS8sgUJga4HXerSgxv
+					WKx0ofCTl7N1J8tNYH9U5KmeZ7fu+lk537aU
+					bmB8CftQX2GxjA8pIxpaEn+Ublf6FIcMtsWM
+					F0MPf9ZXPgbL+Q15RLVX3KbMuXTLuFogUYPL
+					BetQ8cYF77EK7iNKwcMRoKCvIDc= )
+test.non-terminal.C11.example.com. 86400 IN CNAME C12.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OHWsmRgm1zSThs8F7BZWYghWHBR0kQsj5FIr
+					CP03dzgXwz2UNFYRLcZM9YYc4f8xCQh5IO/9
+					mu8oj+py6zIqbsUsSymsUomT3+JR8UoZ3aeq
+					2t/YJ7I6LDowZF+KOp02QgOJAl+sEe0ah9vw
+					MbOnwBYlHv40GE80gjsCmzOezuA= )
+			3600	NSEC	C12.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					HefpT1HMMFFsQFpMlqTZ6v9ZtFw8IdSoHVBJ
+					nRnJujLODn4N20eWEbIN8FLlSY4apd/mnE6/
+					dKqSgT7zFTVzGf2KE6iXlnC4xOWZ37LqOS1y
+					JsfQCe3Ryw/l/bbVynhMq64pEL6yCeX6HXt0
+					MFDq3x/9yU7A+DWAS3cEDLBN/Qs= )
+test.non-terminal.C16.example.com. 86400 IN CNAME C17.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Lotbl0F3UliW5IPKJL9SOuYXkqouvoaFmblQ
+					KD091v192vQqUDadt1V2KS8TehyIvoc2XF6n
+					lluDceffB5DRYdGhmC0hEtEilkPaik86lKoU
+					Bx3dSn6K70L+hArtRM7nPTSBY3kEmqcC8jN1
+					JiLR6KRIw5HbFcwHvcQTjdEtlto= )
+			3600	NSEC	C17.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lkK8Fo2AlF4KnoOPBWV74/8KErQ/6A5qecft
+					Fop4nBvpejfm/M5Y/ABExo7wTyd4E3ZKoMVw
+					ueGQJ/YpuuhPxZOnl8EQFIobNJc7VGZMBwuk
+					UJpVBesp284nVI3bBenuutFZiZk1pQTou1dX
+					m0ei7lYhiavsG4eBSZgZu5nwcUU= )
+C17.example.com.	86400	IN CNAME C18.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HM2B4S1E3fDwYps9fmPTvONEumtH5mYW+mFK
+					s7W1Kk+E5igkwk4T+eF5BxmGrq2Bq2XIC81S
+					8USbaYiKzgGuZiiVRg36EotVq98AGFFdgxKU
+					GBy6qjpZBuXNIMZKudsKLOiAK0Sf83xbPw6p
+					BTqhxAlgJsOhu++dDjo1IKhlMQk= )
+			3600	NSEC	test.non-terminal.C17.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					t3N8fQf6TkQW6CIYqao2sYsDGst7YTz6EwIy
+					RGuUz4opWh0S98zCflxkwZ/aIyiaZ8My4502
+					+8LWZ/mXF3E/M5ZjZwnCOk4OdvYcnf/hGBRO
+					+OpAlaWTpj5Bnqr4yqKgo8sayo3sGd8GHO2M
+					KxBXHkRBs29zEoxcWpcRLfr4Bu4= )
+test.non-terminal.C17.example.com. 86400 IN CNAME C18.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					zwLtl1GpP83GN0jN9Gbg/GU3MESgLafA8ttI
+					z+/SgZewG0d3vJc31g/QAGZBhtfAwwgwJlbS
+					46i05026B7gBpQtdK4RG3l5gM/s4e+mg4xF9
+					i4n5reqqxfmATmTT8u3OlL4aCxfsmUlgSQor
+					WaBoy5mTRh2PuV/2hSkpCGVaY5E= )
+			3600	NSEC	C18.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tLTNHgrQVp+b/hZLlsUT3nUopRPNqkWfrKa/
+					xO5+Bdpw1VTo05kmGagKmwfMrH0wtOiyjhZE
+					yEkSpAfolVojPw4oDRp4eK+toWwecnkXb4H2
+					E0EWnJJ0BJy1DZeB/qQRQowzE33kQ4KYAjJn
+					2mmNHFH09qcgq/AFOIsBAYKDVcw= )
+C18.example.com.	86400	IN CNAME C19.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					KoMMbFb+ylh3p1s6JMPBkc5csxvEKd/Z+pLh
+					3sfb9ImkqqBMnwBQ3sCb4HTenqC8nUJGp2UZ
+					pK/KblgXDTJpt+pC6Mu19TiBmTUZTfJtcetx
+					Z6Me8cjXw5e7/jGToKWE+E+b8sK6amH89Y8g
+					MmAG4bjG797YgIHAE1GgIhYnPR0= )
+			3600	NSEC	test.non-terminal.C18.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Jt2JVG/TPDhXrRtt8x7aYeCBZyr1GprcmlkW
+					SHwdatCkYnckrs4k9xJqKag4EneiDO8sVy29
+					J0WrZDweOasI6LQq5Uh433TrfunUqFRoj7Yp
+					0Q200jlZpuvHvY0nGXBQeXSWNURNrGZ2Lmt5
+					vTXt/Iu19dWk3DmUijKR1/LqRA0= )
+test.non-terminal.C18.example.com. 86400 IN CNAME C19.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					XLoGu1RuEmIXDuxkqGeIgd5CVX8Z6xc1Bu+i
+					zrgboAj2BHbUmnxPht874ydyMgVD8gbzkGa6
+					Zsh+jG9SILdk37U2HptBQYW1Umj+HvIM6E7q
+					TFVUMe1/OLj619V/HqCXUTjW61MhiHTolPcF
+					6XLEv+n4xwMY/Or9X5UELmV+1EM= )
+			3600	NSEC	C19.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oIzaSmiBiPOKv2gsFyD0m2tGyNNzqmoHPUVs
+					idIenLp1uMuGOnz/uhsdsm6t/EFvkU4R43sa
+					tYeCKhJwRKPlA4mMjmPm3NzBgLPrd95Wlj27
+					PupY++Lh4EV9Br61jmWKxQeVnP9hxHaOmOp8
+					Y7OQvVAjvx9iQqCUIkck1BKLB20= )
+C19.example.com.	86400	IN CNAME C20.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					k1mkYGbVDvKjvrQdcnYxqbpJfAQWJISo34Gz
+					IlBrRYiba5f5cWPoN8oMJ843DwoXlSK/OPzE
+					JnnIkfuf5KbOP/3W655dhBLutsT5G38YZcTN
+					E2thTk3R7uYAJWrOfGCSC+csRlpHklVwurSg
+					YUBuN/wE1oi/Cc3y1c2+bZq4AZ8= )
+			3600	NSEC	test.non-terminal.C19.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					FTop6JDiTZ3GtheHGkIV6/tXXjZcCr8CPDYN
+					UZ1pfbc/RFX11X6TZ83H609AMn1oWOcTUKHG
+					SfYLh/amBnesJp9KnGbUrhsHRSK/kV4PTDB6
+					YWdYVDtG1oKzhhcVXL4XmWUd+iIvvVqnk8T9
+					soD8e9GOvmA/GfUkWKkMnEICNTM= )
+test.non-terminal.C19.example.com. 86400 IN CNAME C20.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					enAAqg9puOt2xaStJb64WyKdl6G8HBKR5Gz2
+					W8TdA0RoQzwA4BC3XSfdRgeUkSzOibJdvNKd
+					l4xreSSAzg6G1tBsoAHtNscK9ef9QjrjVQZ1
+					vyN5jJxcxXX/UBOmYfJ5B9ZbqKHnb4DK/2t7
+					agFAzUuTsVKTsYi0MXSdPXknYMU= )
+			3600	NSEC	C2.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					HMkTP0BU2mdNcvqgllQ/ic+nmiI6538k5Bsy
+					vazQu5d8y4yPPMVY9AqdJxgFeRu8YRJOSir+
+					nWTuxWN2I2jYM914Y/3j02cyHyZEOwXVYJ0O
+					Lm6AWBLBhfIOk3d9ZBtnutcWAmKcXRUNkCoN
+					FTaEsRuSyVwAIPrarivykS1jVj8= )
+test.non-terminal.C15.example.com. 86400 IN CNAME C16.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					cjZHkWghypr9G7e8uOddKw6ytvFR8CeMu94n
+					NPKy7LrZV8j6QFqynwM05QIKslV6/QsrzEXV
+					eM/GEi3IOwlAvbQEa9+2kbfs7AylzuFmyFK1
+					ynh7nl+RW9HjDwCuRm1FnTuZ/y8jv3j7upAv
+					2tM49y+plw7R4JWKB3fZfu2YuaY= )
+			3600	NSEC	C16.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vX+0BrR270LUJA6xoUCEcE5rb7fUDb0ltRBw
+					AerhoGqRfoS2yqwjjwmHjs4udrLsj+RIFmzC
+					Vbr3UxrAm7bGpVH/HqZl8BhJwKHDb/FaubMe
+					FcGgaYIgk/tn+pbv1DSeTKxQNQm/vM2lHwgS
+					k4MilTSLAe72SJ4mPfvZXFsMf3g= )
+C16.example.com.	86400	IN CNAME C17.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					qsA6SUZ8gTgWy2VoliH9MzqCedp0A7mNUs3U
+					Q9+Uk43DKN78+0FGm3Q4HlBRBKmXZqMeJyLq
+					GiqzMb+kQxhNbPgsvDbtIeRPfftcmhHRJLKW
+					QBsBK2+Be6/1oP0Sm2HjEwVEh9x3TatyIPOL
+					5Dre2U4ZJ7ZQWeuYUO/JH+SCydY= )
+			3600	NSEC	test.non-terminal.C16.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ayyG42+mcw7rwv4PWFUQSZ4L9pG4RXcrGzBH
+					44VkGJ9WRhfdCpClU5i6WkgkfVe4ibm2eXo+
+					KTNDnbM2KQBTTgEiTmxr9DCBeZs+GeYLHMbD
+					GgDYzfGArXkNBRdpHt5QznpU0SXfnca9o4NX
+					dkYS9hGPnuy+2nTi/BW/ZgxXvY4= )
+C20.example.com.	86400	IN CNAME C21.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					q4g+4O6Lyv8wKtzUoGz5ENQk1b1z2kKJmQ9l
+					11LUkcfVZjvl5X82YBCJ1YP2tGkWuw5xRcCw
+					0NtfuFWJLlz3i8jpkXs9DMK/a4/X0VACHsES
+					vDckUJwzjcFyowiBA8kFINElTNNxpSuLpX9p
+					eLypUHHAbwDsmMkd0jz/vXIvdDk= )
+			3600	NSEC	test.non-terminal.C20.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					IcKJz0EM6mMQGc5qQ5dk3jLP+DzCJlz5Qa24
+					k1wwvuN+RJ4I39rMDL/i4syQoMAN78EZE4Sv
+					66a70MdaPv+AZOTguWbFSSXNHBXW5BUJanMM
+					+Qpgf53jZ66sF2n2v9t4GEIfm6frBjnRveDT
+					iOU4JIdX6eJtM86jGtqheTrgRew= )
+test.non-terminal.C20.example.com. 86400 IN CNAME C21.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					D3fsqLSsTxpQ4cC5IJVVKPyjwhoLEF7xj7bh
+					Bh2h4j6Xl/KP8sHfm7Yd+A0Gxz7noBCKfP2t
+					2YRmFw5k0niIndF2SR2w11vSWCPxEj+H6rmC
+					JMjf0iRf9rA9HBDXzk3vIFZHVZPHs3B7yeXs
+					GVWKsHJujtuCSFATNOg4STckDsc= )
+			3600	NSEC	C21.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					YiY6Jble2NqfWdokFvKFW4tQ0CJCq7XyvicN
+					DO65NuR4xfcC5k1h9J/CPxPbCa8+rDuyFp72
+					L0d7ZYIYWoM0ZsanuLHqlAwg5bDDt48tc0oz
+					ZYKvP4iAw17tJ3O21H8u541HOVwWRF5Tlwu6
+					OlPVENGjxDafkZgHo1yfeAxfP7w= )
+C21.example.com.	86400	IN CNAME C22.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					dJ7gGAPeLC1rGaxG0R7lg3u0DoGwvRHQO4kX
+					DcqwWmG6q8BImKSYKrD9Wwdb1iPUJKTR68Mt
+					czYJE23fLWKWCifefkSRFx1Ff9M17Z4M5zH0
+					LNYsQ/6AJP+76oJXG7bx16vZuvPXWWxrUQZO
+					pcLdExCW0FxLaVbGQMgCNEdunW4= )
+			3600	NSEC	test.non-terminal.C21.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					rlSJ6AY5BSOY4f22caJQRbbMTp0r/tBQCp1z
+					Fy1r10KPygh5H1EdsyUreEUyaDDjG4NLE2Dv
+					HqGKvoE77WYbqBI5m5eoVMsxKfp/WnCbUpuI
+					exzlYpeAUSTEDOcpmwGqIhGLcVv/sVaeQRp6
+					sdsAhkeGOlzbVeuD7RiNS5yFUjo= )
+test.non-terminal.C21.example.com. 86400 IN CNAME C22.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FmKXcpj6HAdwgsoTR09fVo7a5NkY1cuSFSWr
+					FS6IrPdiP8oDM4kOlP55FmlowttXzl9/X2nc
+					uS1CrQCehRFg/+lC7BivvrrPBYK0SITtd5jy
+					0OESphgETllNINqh7MbUi7QGEMW7GQlCZpAh
+					iRBpttRhgvJP7GNj8JmB2/+0acg= )
+			3600	NSEC	C22.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					z2AH/FZiUXFzdp5qc9/W8VjFlG7ZKnR98mt4
+					3rjD9OphTxn9AQlmIFh/u7ajd8h5pI4n3yXW
+					pBIIU6IskNAOTsuOQEHlaoUPJExC3YFOaf2U
+					OouvqNaUuHiE+iGLxUjAi5w8TEkOgHV85ogC
+					yXkec/COhgmzlaio/WtttXYhVA4= )
+C22.example.com.	86400	IN CNAME C23.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					d0pPwKiMl/Bzz5CEYJNxcn/y+SRwhWC3kFHG
+					xaO8dN8uJTtUpGgHGKEMuf4Ao7CbzHUElwaR
+					wINGv0/M0OEqNBy97ZBn1BA3auhVVREucykU
+					/40J3ANNNUqBPtQtodHkoy3bI93MwVO2QLoJ
+					WFXy15HQDvY5b/I0ckblx3dPYAU= )
+			3600	NSEC	test.non-terminal.C22.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					jzZYz5wBV+mnTfubFCSEq3GSLnVU6mEMNoT2
+					jd7xiOSQO1oP2QkuIfF/Ezpg9uSTPtjW6N1I
+					UNQg/6A9Et0xEEkrr3CSc60IHKdJxR+JyANp
+					zO2GmfR7XgFBOeVSOlQYYwGSUvKg7KxNjr9Z
+					U7/yGg3ajiO9nXijiovasjy1dfg= )
+test.non-terminal.C22.example.com. 86400 IN CNAME C23.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					rRWV4phWhoPhmdbUMnmHYJQ5547AJKUVz3mC
+					b0dsrfnFNhXmqPBRdYEDjW1XpbjMlPtd93Cs
+					xnBgpDjZWjPbcolIEhxategjesg3hMTQW7Bx
+					jfOUBJtTVDVok61mYvE/S9WCiXYnKGwpIlMB
+					z/y5jYnlQx9/funI/fwGJG/PGNE= )
+			3600	NSEC	C23.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					aVmG/m+uz3RjMgb6J8NxicDTIW10znm7ml2t
+					bowN2abPf4vda/gEqvJ6d8Aps57eitzWxAtx
+					hzyntAk0ksrNe5Yfn3b5i2fAxHa2r6gno4Vl
+					SerXbceSU05nMbcKfFWgZvJC+ejE3X5WivwE
+					T6V8dMsUsbJbHMxNQ/MrF0b/KCQ= )
+C23.example.com.	86400	IN CNAME C24.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bLE+a7u73Ijwk+WaRbat7Ag/KsXP8lXcAzj4
+					rJwY3WtTRTJqlfZ9+pVxyWqP7rDKl+rADTKD
+					uFW0xVksNJB/ilmhnfo06EEIke1e4Y+7nYfq
+					13vUR273fTyMXdc6420Mq0iRPMeIj9/uDEhK
+					BtoUOhh6woC2EaW9voPPI0yj+u0= )
+			3600	NSEC	test.non-terminal.C23.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					htCIng073i73nHFSbMT8i7WMUIksfl6e4/WC
+					6VVBfsFJf+PAQtkNMgT8cr6C9m+6Mny1vUIz
+					hEIqGCUMis+AuvW65t37mf6oSYNsCaGKGaE6
+					1oTLeRdrj+wt3OEPLuYVFFZjGB6f6hyg4lvL
+					RoEJX2WZfefNyb+rMs+tU3/Oy4s= )
+C2.example.com.		86400	IN CNAME C3.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					kDrNGh4/FUMAF+2ye8ARKEkmDBxxadg/bETX
+					t0QYC9YDWzI6lGsEtLBDN3ZJzAaZUac9FgU2
+					N+1yrrvJ/iCbQEwuylqGH/CExBUtFAF1ZEsr
+					GIuuoGuwXG8nnTgVzGyWc9vW4s8u1SNaNjS9
+					LHvGGM/B4UIXk0h/I46y8c5pwDo= )
+			3600	NSEC	test.non-terminal.C2.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					CFQkWfGMyaEB0orFpQEzOW8C0ecGOFiwv2DJ
+					ZrtgppkNQ22BUymk67inwyCE6/u/tOPgS0uc
+					+R9NymZ1h13J9RH+c+WevHNBkwMa8IqsI0Pl
+					LKqRDQXcJJG/MwERMP6UMmb4Wz9rU7r/DhN5
+					7dlXK0mkP6C9jBj66tvIEYluJJg= )
+test.non-terminal.C23.example.com. 86400 IN CNAME C24.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hkJQ0Ywvm3KiZgSboYZkxyB111oyYwITWLTo
+					Wo+oDpFbk1GTqkmqpUDPJjrSDew9DUr8S1AY
+					uWjEsulDMIyrYXIcNYNKPKs4AssZ8GSqQRoj
+					n+46k6a7FJQiV5XERF1Hk3aRMqR0bRhZ2MQG
+					7iYaee8aTxDbmp7rRdE0P4O2C3Y= )
+			3600	NSEC	C24.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					VBaNTeTbLKnJs4/RRgRfhYMapIVINw6S7eT3
+					V2YjZwJDzGOvO/nEutzuuVno1KphWPEVC8OG
+					6Um9szauRT2WTaBcCChZPc4zk0VWjO6b42bl
+					ntgrKZFJfZLKBTDcB3VD8njuhtx66ehLVzlV
+					zhCZbKrnbZ/OOAxhnxWTfVWpe9k= )
+test.non-terminal.C2.example.com. 86400	IN CNAME C3.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Klk2lGfcXAEYBqpgDP+5Z2ynqO/o6v3JYRcp
+					T/+GGCy6wiq4XuoB6Ure+qo419aqzvc3jIcO
+					5qC6UoRACYzqnJi3VGixxaV1G5Abwj1n3ZQ5
+					QNK8TzQYGqLfokwJKZVSxLfD1v2OBb4Mvn9c
+					gfcBtl24Ze0H2rA3mrrTRFitoXk= )
+			3600	NSEC	C20.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					HIycCOnTJkJ0839MwneKccOlUB1GtAv6ZXVl
+					x/VQOWkA1TnRt9OTEuliQx/DJTh9guj5Tys5
+					aOL2KabztzbxOdxGH88sjtoXQqlOu2KEj8Bp
+					mh7rrT/+F0DM9OQy/q0ifeORu82oJX6Fpg9C
+					KdRmNJ8hHkwOIJxYjGWSzJ9jNBg= )
+test.non-terminal.C24.example.com. 86400 IN CNAME C25.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Czmz5uU/4n/H/aq/Fwr+VWWdt7U9nkIVrE0N
+					7pKIa/rNFBgmR9IYaeSLfxQ8NxrJl5fSxuXv
+					A+rGKEDeqJxorrgq1OtazjyZBOJm1OEHJCDo
+					ZxX0i3GPxVT+Zb1+bdiPB6Cbw8tbtLSxsb0A
+					uW+212VEA/xDv7GUlSvsrIoUFkE= )
+			3600	NSEC	C3.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Cd+pBopnixnDuHMHwuY1zD6uWhvy80VQ/UYk
+					i5vd5hN07O0LtNC14JbQD7GATxf6KxnV+tom
+					sK0vo+uA6Wnt+Qo+FoRN6/5srI78d3paUaxK
+					o0R9X5jg+U66ahLDxGW8O8ox1Om68m235ofN
+					apDCHjM9XNlMHGqfqQinUmXsuEE= )
+C3.example.com.		86400	IN CNAME C4.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ORfJIaFI/tGBHur1ocpNzDvmQBlO8aVhSllq
+					GSvj8S151MdlUYeTI9yiYzD4hpAuLDv0pTbM
+					iMJ7197eL+cCoDynTqaucPoESOWxMw+RxcTQ
+					820KIrYgwD7rziDqmnK+N9CCLI0BHy/nzHmi
+					7gEPRj/4bTZktdsvpTZC+PV6gX8= )
+			3600	NSEC	test.non-terminal.C3.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xFnTbPQYvJ9t/i3ODFPnIO2BLdXI/kzuO753
+					CQ71ss0J3KNMhhS9SFCtChX4RhWIAhi+O5C+
+					7P+L7FrAFcENI5AwYlE/Lm+Vqf3xsDKwMW/f
+					HJvpRnDueJPEtUNF1a2hjT9MLQXJb3yIXi3o
+					+c5wicLZE2WI+0tKicA6opLauGw= )
+test.non-terminal.C3.example.com. 86400	IN CNAME C4.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NcXIcilgrWIGQI6T++wpWj3Vnu0z39Vm6qbh
+					FPFm1gFk3S6cmz03rNsCJhOgu8y/Tto1G4+P
+					XOdzJmxrXUTQbHeWNnx4c4bbUIkuRwNXiIBc
+					QgW180LAhsfezm+5AjhwgrEX6s4WikNq4d51
+					sptd8qI0ijOiCcZMR590HTkAA6Y= )
+			3600	NSEC	C30.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					VPeffKas0zgidVeRLbKPfT3wD/tvB8r6XReh
+					Rkikc+NAAQxUg+AEKC5tNU0aoGdgdoCD4T6K
+					r12ODG4fZkfE1/SiZ34TADpvhn0PvTjrhxgw
+					FbgPPBfUh0Awin/Z8+rjBxBA3OGqzRP7GPLb
+					s3tD/COb2ooBgf/rBZ6EB/8Bz70= )
+test.non-terminal.C30.example.com. 86400 IN CNAME C31.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					jw35unduyitnUCo/8qjjlT36iC8fL0P2Hcm9
+					4/zubFGVC6yQlsf1P3DeTIbdBhj/3JjTEpY6
+					YUuyZlLWL+az0dvtPkl2jbIs1m4wG0qOv0jO
+					8Q+MqWwoZ8dpCplK3vnlj7F/05TokEoDx/BJ
+					8Jx7Qg1Q2okgZQsYGxxQqOXDiHE= )
+			3600	NSEC	C31.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					hcQLdxXw+uXejfACrSBSJmws57Ci3fw3woxv
+					+CG7zI4U1rPqNpyMMxGYjDYSEC80+nWFCKzR
+					GYZD3THGw8NynuMWiGZtu7DOFdNNSOLnqIJG
+					18sqlRa3eGuy53BtBCps8LW7dzfuhVC7duPA
+					oBV3sKxs+1HN+IMjWLVlyPSLAn0= )
+C31.example.com.	86400	IN CNAME C32.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					GGl6maOnsNFhokQQuSb0Ck87IPPluz8cUj7B
+					R1YO9CFnJHfvNXEAq7wxCKlmIPjk99IYGoXs
+					Tye3fryV3QVDQe2f0IlvpRs8sIjjZaEU4V8H
+					XZeED0qM415txff3l0Qdg3UdL0xf6WwWDuOs
+					Z50zdYe0SM1qzJAHxO46q9b1UhU= )
+			3600	NSEC	test.non-terminal.C31.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wvlFSmXb5OkMvxyJhb2UELMzsMC2XMeByum3
+					XmTf22cPWVBL3HKllq6U8pdQhnfhMcUOnoRw
+					bnHRfW9xcyyGIGTK+lvrN/JuzzkmrgFo45dd
+					L6kWT+CpO0SzFIST7Af8EmDvJHI6/M55yogF
+					U9eXLkj39EBYNgxmCFftn9wUvZY= )
+test.non-terminal.C31.example.com. 86400 IN CNAME C32.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					XSJZfqQ77v4x6mxmhAw/U80wuuoRcdoitAyR
+					vzKcw+F1wSr++h0R8RAUZAfma9IPYn1NHMAQ
+					IArJNwBDrBpJCApzlaumwVUEG7HrgmFZcgZc
+					Z8ejXwi1A39xelRoOd31gcGMXpkPco6mJtJu
+					avAE0xXKeASA4eEPm2SMtZwJHi0= )
+			3600	NSEC	C32.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					j24n7vF4UFd+DTHb7wVJA08Y0IpWR6oxhDBf
+					XBwUUsGQGTxBWSCqlY1xkrZuuL3ALxVJrSTH
+					UUwVoRcP6jCj7nxyS+GlxUWugyCRC08DbWCV
+					hKztNB2Zw510sZLYQxDZR1OyMaz9QvjCyvUY
+					VEkTKjmJFMMgMiG5dgg5Rao/wkU= )
+C32.example.com.	86400	IN CNAME C33.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					i2xzsyFQG6YcMxBeCx9gqm+D+4U5uPau3VMq
+					LYO2PVnmiatCuzZ8CMbjoWpmkccZ/NuIGo+B
+					eHT81oQEuJ67HEoqqjptEdcaD5roHDjdYQM0
+					VW8xihhvrWevSvFAf3TJvNtx0ExC5dgBxVLD
+					oqLmMfRLC54d8/EkT121lt4JcwE= )
+			3600	NSEC	test.non-terminal.C32.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wIo0ME2jtQSjmcAc4tFcslj3wYWtMSvxM5Yj
+					jFuZCoY77ymekfyKJihzkKUwNK097/vgGgaG
+					tz7BTa5YYbPVAOfpXKlTMyTCK88Dz4z4omDZ
+					bL5Xqi2JsCy+ShspDV45MIjoySeljHUIzjj9
+					uxUzx74CA60CbeOOwxHOdOaC4II= )
+C24.example.com.	86400	IN CNAME C25.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					gYBVp1OcHWe4LPdhDSFevDGOwvWbgPdzsEIQ
+					RZrkeF8NOSKfn8dzVrQZRYK5Gd8EhCRdL0O7
+					fuWtRu52L+mUI3/E5COBdkPn5VEvnevEgTlD
+					zyNx4kTCKUatkclfolpiMmqpmgb1yFJfe5tQ
+					s79tl1E4d+WbADMn7lIgbCug9aw= )
+			3600	NSEC	test.non-terminal.C24.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SOxr/8bXKZ2PNb1YkRcguxddLhHI3Xh1+o1e
+					8LFR2YgCRA3bNespLCfjs/DM4PLs0eDUzlhz
+					1XskwOkWW0pd1pKZ48gw81395lV/hEbl6JJO
+					ZXHBGcT0dUyv7BwQIlK8SuJCWNeNewRE1hgr
+					yz835L1Ko3PLV13NcXp68B/rqQY= )
+C30.example.com.	86400	IN CNAME C31.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vxCyho6UPn6+5gDMLOd0zmGpX7ED5VlXzn4h
+					BYzZ/IGkjS2BwcFu5jChY2hWx1jCVY6y+C26
+					OO13EZKaHuPWGxTylSTCNa0Wdk/FXy/srpHu
+					LAf81EAonAnAnA92YUWaiJ84YOjKAbGTK0to
+					bkO6pkXpansUqCYJACFyNoSMjCc= )
+			3600	NSEC	test.non-terminal.C30.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					auPELGv/GyAaTK5t6pf+nnWsokGem8HL2mYS
+					iKLMc3ZOGcPsk0rXQmy+ZlzFmxkk8ngF+cER
+					GdZHYxvMMdcJ5eSvrj3YoFAddsaUSQF6x18b
+					pEjaNR7Zz2CkKK8Ypv2vhdxe1XmlhV3JugYm
+					7qDSKFVZ9C9PVZcFaMK44O3F9uQ= )
+test.non-terminal.C33.example.com. 86400 IN CNAME C34.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					l9XLuVwibT3kXc8zJQjY1gODdslxwCuDw+th
+					AaE9cy81zOfeQPUOyktmpmKMAiHHpMThAdoo
+					kclMMat83pl9j2DXKtxF6Uw6mp6Z/so6Gpf1
+					zRnqnZs0kJPLn832GgrMBFiGVxFqK5y6AS/v
+					ZtOrztOAoVWFxn8XOQW3g7DJ3rM= )
+			3600	NSEC	C34.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					o83bvjC8XhVPLMKInfawkI8xjdOWLREsraOp
+					s7QNkWkC/UKZ7vjr+21V0zupS7DywkQ0Emds
+					wrHoUEE4a3lx/MOlzwbGggsRtJMh+Msx+KbC
+					PGD0ADeqzDibR/GEbsqlicsPbN6bBJSMJAtg
+					hHmsFytnX1ybsmNN0ZAhnXr9wfo= )
+C34.example.com.	86400	IN CNAME C35.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					gC0+tgCyO3wyru/vzEejh1WTjRF7hnyp3PFL
+					TbNko7au3dHNmE3jrOX/IHN4E/t0EaqM1Cfq
+					znI+phrcSyjH/joNLFxjWo94pef1uJ2g4noM
+					DvKTyBLfImQcSATLDNXTDDaSkDhSg/yFR1qN
+					sbfllYSzcFLvhXQWoVsRfnHB0UI= )
+			3600	NSEC	test.non-terminal.C34.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ZSgGLRY270uVjBx8w720q4ZMfxhG9hNctL1t
+					mZT2AoUGp7EiUEam6XbOXAsqsuBu0MkJqYbc
+					k5XZs7upPnIpwXf1zroF1yaRP3eNRj16/D10
+					cSxWf4CZ1rfmawxfKw0GyzLsaBZKLlq8XYI9
+					XgnkDdZYuEFI5bEhCJOLiI4J0hA= )
+test.non-terminal.C34.example.com. 86400 IN CNAME C35.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NZosaFeYVy8lnQXgyb2NbQqINWjjqnMUrREV
+					6LGp1bdoQy1+qtKpy9H6xGdDYeBxMCKhwIib
+					ZyKDj6TgG7x1rZ/GCXXMbcfH8txDaa7RlHlb
+					z6dr4v2ZdsKsdhFG3PVAlkESRMsu5CJuSEMo
+					gSrGiNnj06mYqYEVyUSlfI8+ZEg= )
+			3600	NSEC	C35.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					NzEV8w/88q4ERTDiKRXVxzUWcvg0a6bTvGAs
+					2vwWaoNtcPfy9U1EQyJfC4k7tfaoMGR0o4b+
+					GLbnflDpS9wRgNxbZA1cxvynh2gEvFanq3JC
+					gaqslersgKviH4fuRLmWeSRA6y9Pq9qq8y+9
+					wilw0/1hLj123SV8uUyhl/jZezE= )
+C35.example.com.	86400	IN CNAME C36.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EvBJOfv+jFIjrknKU7VV3Wq1qXAfG6SnpOkM
+					f7+I+uK+kzdd65RubuPXfccFiiRero5l1upL
+					xLNao5B56AvJruxqgE8BNsid5wFRRmkhKJMk
+					WwPhwp9sZWrNuplSf/kX/TgPrGclUBiEv+CA
+					orZcgkEFmClsgA4hGq4kJtJP6Ro= )
+			3600	NSEC	test.non-terminal.C35.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					i5QQPM0qG1rT8xWdx1QJHBYnmBBNZCVt+V3V
+					n+XG1UtDoEMFBAELuXoEjDPT/Kyau5rlLP6Z
+					Gltcl69c1fyglHLguY8CdyuPJHJ9XbarxQeo
+					ImJzamI6X4AB0S0kjw74L+rTx5STC4uDXFtF
+					iOi4wiJ+rVsegIpLzJumr0K1FNc= )
+test.non-terminal.C35.example.com. 86400 IN CNAME C36.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MLXJpaqizl8qstAUaR3QkSDfl/TQisMzC5QS
+					3oMbQkyte3BdI8s1fAKHGtRZPv+OUmT/UFdx
+					uxrzka8JebOlJ1cJ/vdx6pd0M/zlGkn6s0eX
+					8AszjuZs1/c/TM3chLLVZeDFOqo7BOMCmG4y
+					2SZb7R0G/AH5y0y+ha2URh63OAo= )
+			3600	NSEC	C36.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					bUoJf9G3DOPWZw9kQgH1yCd5/72avRoatYzo
+					MN3EwobQJZQXuQnPuXWAPRsm/ANBkmM6+LHQ
+					vgJ1Gz2UDtQHbis5HXwH0jUuJ95Fv+GhLn2D
+					udEkyvU58XvTa7BoZATVqwoLkaTkWyd5hEML
+					caOcV4HJHDbmTkKG4wl6tY5Z9p8= )
+C36.example.com.	86400	IN CNAME C37.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					J62s/WL8A6SulvprsP/qMcA4vPFSQ8h2dpZG
+					MxsmOpJ4x7FqLRV+0Fh9ciVPG3L7O5hHulDp
+					5zr/06hsLoOiPbnvnKhN+zAvtyXDVS+PILXd
+					i9C1O6Mao1tKTzZog5aNkqpSEVt4E/9jHwA+
+					TS2tEvTSCGjwJ6G+jBxJs6xOvtE= )
+			3600	NSEC	test.non-terminal.C36.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ypj/z27uzSZGZcLkGNbGwOe0Ezkx6RGggxe0
+					GmMkFxT9OvjPFgkRO/icpJZaGhJ6X2suo92i
+					i+igDOUYSqOkMZ5hY4YZvy2OkJ/RuHN1Ll0h
+					E7lQctKQ9X/w/KXVJk2biCdTbhYrsnUz0NXz
+					q08k1n+f0sUvn02eyzqd8a4It8s= )
+test.non-terminal.C36.example.com. 86400 IN CNAME C37.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ni0UNWDF115kUidL4E/bXxStuW7a5dVq4K4N
+					VgvYoZSColMl6FrSAPY6x8YgtGH5pALMePvg
+					590V5l38jnMM+WwkcK6namX9W9QXApwc4uF3
+					6F4nqyK1NFNmlbQzvi+DZwbbvExd93LcUvLr
+					jyNy54BGZfvUlNa+wTCsDaqmYrY= )
+			3600	NSEC	C37.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					LRStYbub6UIPA/aHLr4/Oty2bSiaoyZr3JW3
+					Mrp4oEaUXJF4ANn7Ca68GCLDKeU5aM/hQV1K
+					gh8Ms/Fll4Bf54/2z6YcZr0WU09aL8xSxwCC
+					tn/qZNtzxzAxJbCFwZcJtlGP9vsG03d+qUys
+					vfb7yOuZsxudhXAOt+SGl4FGPa8= )
+test.non-terminal.C32.example.com. 86400 IN CNAME C33.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oX/R+pBjcH524Znqm/m1yDmPpjaQze2mtQd/
+					/Abd3Slt66b2crTO+fWz9SQ7zfJQzmtaMcgm
+					lbHf70ggM3i/DcC0ATFBCQJvuX7yoFcNLhze
+					20x1ft0XDAQkbtQweT8/H0l6nwg3PraZ7Svx
+					0rt9lkKj/FZ5KcLnHtWN9Lrl5sY= )
+			3600	NSEC	C33.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ceYE7iiMcQsT7eXJ5QKH3mHzIGWUBTt0smFr
+					p1Jca9UUxfn2loS6q0hTKsNy4b8LNodhLj6I
+					5MeWhjYeL8W9kXRudYFa0BcoEjVXtC5vb4qD
+					IR8rICG5zWmKvGDOrf4fFE6I7yGtNa7tpMO4
+					cds9eCUae/eKDe5geRZ0jHaAIn8= )
+C37.example.com.	86400	IN CNAME C38.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HB+SVyFK98BpF2Isk+hS/mHgsZAHPKBAXslz
+					8vlq86yyVEV0Ns3rRSjtzc8HcrcZNoikNTaM
+					Zp7p+qCOO288kHbOqDY5O/qHgHa/CTapaEcv
+					Fkrpgo6LKPeIg+uHZM+I+CEaB7W3nyti3vCY
+					I7z1xecNt/9+BSMghEX8EkbUeI0= )
+			3600	NSEC	test.non-terminal.C37.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wZ0D6paF53u/yRQuJrvDCqgAKFe+eo+KRTSj
+					pnZG8Vxgvt9rtG3Cm17ftIuuuEjdm84A97Xo
+					FSnLKEOwjQoV7nKZa5dYJ9Ay6/EKKMw8q9JZ
+					lXZZ4gzJLRuy+cEVJ9waKeE0F9s9d4sGk/s1
+					yEmPdXIe2wJ472uRMIg1M1o8BIY= )
+C33.example.com.	86400	IN CNAME C34.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					dVYcj/YiNH/bwwUEd8i0nweQw3xSvN32/+sx
+					0Z0zhoMhIOvYpjZbsE52D3jJG4EDcREumEQP
+					Ye2I2CPcBWCJEr/Z44sjEmX3Z7ltHdlYxIc8
+					tEyLZvgzT6PJAoU5/wB8SIpHIFV/lzE2S+96
+					RJE8rp0JzB/1EnhaGGqjbrxrJfQ= )
+			3600	NSEC	test.non-terminal.C33.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					JhjpFtrCwQtDofrZUxcocJr6k4JtNTkQvP/P
+					xOpRxnQz3E/9dY8hUogtKZC0HJVGAuTBwTie
+					+2Qu/PfDxwc3EEWtbcjflDJCbpY5oy5LKr5l
+					6BUdDaGrWKf115WsJspVROrp2fNfZeVRD0Si
+					4ixv9JQ3f5QMcbE8FMX3Igpklbg= )
+test.non-terminal.C37.example.com. 86400 IN CNAME C38.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YgdM1snnCkbeQw5Q2YWqIp8dI7BsSabEIk8y
+					qZkuwfidM2tPTnBJlt9Ry9wg3Q9aHogPu7GA
+					QSBCM0NfsDrtncsxGzX40bIDStT1dIsr6BJE
+					jzijiBlyldXRdPX0rWnluf2d93rTMh+ZVE47
+					llnMs2sjtM4eRqBsBDcZoR6f04U= )
+			3600	NSEC	C38.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					G+Q88jVXynkL8sfXsIuzllJ9FTtXb2o74zZJ
+					5gTlxVVarNwO0lYTpGqgbZ6K58RXE9krNz0o
+					qIKsigz1wA8ZDJ/emQcsWyIw8Gdf507sydn8
+					3N9xFLvGivBCsuMUQeN42gOBNhmmncajTsFp
+					ywtNJBu+GXAADduGQAmo0Tjp4lQ= )
+test.non-terminal.C38.example.com. 86400 IN CNAME C39.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Dc5ZnZoMZ2Lk7xIXFPu9JQAzr94TdmYsosFB
+					Bkm9bBMb+ZV8g9GKXTXYpKD22N5J50g5w7EP
+					gXbs4SKUQ3aYlQE6rJzcEucGtYAaTWaO8cPE
+					tOzvXcn/RCeif7GuPUlh14M6PDAForLcoasC
+					le4O6IjOF0v3136T0HqVTK9VdV4= )
+			3600	NSEC	C39.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ztZlnI1vVUKhtR16eZNhWkJIUU57ue7Am2Vi
+					IhkGV2NER65r8CU2RB0w9StqinasQlDnj1l0
+					2kuFpn+/RkxZQ3NjXgpPLoCFS9P/ffPAeN6c
+					sLxbpV85RDZxa4x4QaZwp7Mxu1lnI6kM41L1
+					bTjwM85A3A/AZfgMIzxQ5YFMRHg= )
+test.non-terminal.C39.example.com. 86400 IN CNAME C40.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EpkJIeFKf50ZZwAe5JGnIuIlCGNNL6D6oJax
+					6FPa2N4GvC1Ppfs/eixEC/IKiclTUWmh0oBk
+					zZff7s8joTD47cPkQ+a6eY+6pNpn29h8vEkA
+					uhRgWKi07XR/FUVfCEY0h/fGCgKgDoEfxbsD
+					OGAlbRFnEHoimdzxnUU/suYZogw= )
+			3600	NSEC	C4.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pOEucUBeuxkb7uvaJH/FyVxu4sqGM6GsI4+J
+					ltaKcwu1ucEp1GHCrUFmSFP1y8pAPJlq+yg2
+					IcnHy2BcRz6QlByKRO+iRwMn7HU9+GflrcK9
+					3vbDhWFzkkT1kI9KflVUtgvxbwoIyN8R9kxL
+					t1+2l1crLIrs1fiKxKSbpLtL01I= )
+C4.example.com.		86400	IN CNAME C5.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xlPwlgE5cuXCKPFYnA51jNLUz3QgnhjkzB2V
+					jH/xQEU0osobcTq8oqNS65dPps8xMdU4LkZ6
+					fJlXgTUfQ92tx0BAQiVJcmGnOp5rb/eiompJ
+					eGwzkZj89i80lD1GiehfvsCN1zdIIdZDQiUy
+					XHJv2QbF72crF6OcM7DoZfK5wCg= )
+			3600	NSEC	test.non-terminal.C4.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					DCX2xmdfjVSQ+34Iyqze0HAVWR1UlJQ6bvQm
+					hueDYIjRqjtog+7xLKsD0XyFGkYokNMm/gDs
+					eMTX0rfM/MEjhGjSG1Jqf4uyz7aLwcogDWII
+					k/9hiu1aabJ/2M5uNUYR7VD0ndkC4aGvBePl
+					0d4nGMe3LXXhcpSUfHEblbj39Ys= )
+test.non-terminal.C4.example.com. 86400	IN CNAME C5.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					JAHcZiOe20fnNheDf4LJDcUZxgHTBRxmxYAc
+					FbRN8Lh3rMrF53p22OE8sMwy7nqnq5Dn7X91
+					ay2HzyDvDv6izvkaNxl81WEX8cklUmFRTa+c
+					orgs7FVzxajnOwC/TH+hKMk3aQGodra+B1fb
+					gPpugnaaAnTTzPq4HH5Z5/Z1dxQ= )
+			3600	NSEC	C40.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Q62qdAcJM+OQ1e658d/5D7PhjWEzGD1U8kVw
+					0dyqBjHTmD2dGT8fuN0jTRzXSLo67v24i1XV
+					35tPrVlEO1TNc3hrvlqyteXtYo8OKC9g1hiJ
+					CueAiedTlhGVLNOVCz1N0gD+XmlZfFVmMQsb
+					WP2an9mtc06wf7OqOPbdRVBYey8= )
+C39.example.com.	86400	IN CNAME C40.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ab2D01aHm4cPobTq3k4FzbYstK+aop5Z2fbI
+					7ljP5p/7Cvp659QuU1B4bqkKjS2wx8IHIlpy
+					hZCYk7/ic/nbGp7oAnEENhExurbdFQQJU3Dg
+					dDuzvzPEayQYIXy/zqPLAXZcTfHuAWwjuSlT
+					5M4O25sq00aSGrLjeGo+2zVlIrw= )
+			3600	NSEC	test.non-terminal.C39.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					k4qZMnzndAT3rPPZO7hRURZpEcQupg+b1v7M
+					YFQ8Zp1br7A9e/jNdQziDONB6y4x8khxTGSL
+					lbgJuq4BHwvigd9n9PZYlNqvGBLd4XdUihBw
+					nwRe5fV1S6dJj2mbQiZtGvuK8udFf/XCzSUx
+					uMRSAJmYJyH9+06FjdNt8hpL3dg= )
+C38.example.com.	86400	IN CNAME C39.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MCE23pfK6/YRsNynpFofte/Q5/LgXzw6Irfj
+					qDKHaA9Vs7KAFq51v6Dtbo57OemiRlnebGwi
+					gpmqdzlapPbcuSh2zEgSUdZcnzjd8YSDb9Ay
+					6Rme/4qxhUR7CMCUhVvOAH093neTrgNgRVcu
+					IaKpeVYiAW/45G0rOwL5/saBtbw= )
+			3600	NSEC	test.non-terminal.C38.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iYlWNucYfq3tYnqjGtPu4qRWdXwGpHGlGVsG
+					aVnnb5F3V5191PocNAlY1K/ORxR3JxwBYi6H
+					UjZYrEvK+1UuLRjYTLdJWg66gp4kY1tpTl7I
+					YHIrQ1WFPWWqDXlPDR93bFCJ8oV+WSyknuyF
+					Iat1WCkT2f2KbJkCWUlOmS7HQ2o= )
+C41.example.com.	86400	IN CNAME C42.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bSuvVTFqytT4NtNkEsLDcO2xvgpmaEZOED23
+					wCpEFTjkZQT3qS8cnowGshWGIT57v1YTH6S4
+					uA92zvBOHsgT6RljRkLlkdseRBN8I+EJcOUU
+					1KTvRO90FQjpuxDVAkt4BrYvV5JtOpKMFC1c
+					NceY2aLJNOR5Z2dFJPALBykhIH8= )
+			3600	NSEC	test.non-terminal.C41.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QypweRP8qWSerm9LvRqNWSXyfc6uJmAlgBr+
+					lc9YY1+JYHCsa8QgolF7vkZnBn/Ck5/vFvt9
+					ZZxer6kb/D5b3gT321hS1JosX/YUU7oiJp5d
+					Fgbt+6DLwB/sqAF9NmbY4s3W6VaWYg+Bl6Yb
+					VesIf5gMAezJtPkCBbkcjr8eq+E= )
+C40.example.com.	86400	IN CNAME C41.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Ol8L9Sy5CbpadEvyeVhsfxSCRTxOynPPCGei
+					tSNazmU3Jr+aDidycVCvbIZj5lX3RYOIF3QW
+					s8by2rvv2P8ceFjNk91Vn3rZeZASOZHMRjql
+					K0Cxv40Kd2qF9N6v+3JCNk3DqNsTNHb0HlhL
+					LgEHOo6mKaIafgDDZAc/FiUiAUQ= )
+			3600	NSEC	test.non-terminal.C40.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					s6zkrFyugb37qm28cvzQEuRdrTqv5lyIknE0
+					1Sa4alTuP08hyaJQ2jvLjIJCxNekonJAFvM/
+					yGoBxr8UstaKkLVYo4f3wZ3BH69rcHR0CA2B
+					JGJPFjbFBevQrWJTkbyT/0viBEOvs9kqJXZL
+					VqukkkcpZw0KyWEjjH5NC8CGLc8= )
+C42.example.com.	86400	IN CNAME C43.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZxaQ98LVaS9NvP+w36TC5WhcsHuzPVbRB6Y0
+					DjeARYJL1hGgUEK7XNFN6LqkXZlDZdXIxDHE
+					fp4lJCplId/k7z/0GCioZ2136nch6aZN18xu
+					enr5jpnzDxaYioJz1BFU7ybRnEB1XhiknREM
+					8/+jdF987gCIk7wEur7vllgujMo= )
+			3600	NSEC	test.non-terminal.C42.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					O75FzIadBOmR0C7qdlCOeCkEMx/jJiI+b21J
+					ZPbxI46LEnbrTjPsBdU6a4g5lHurSINJel4y
+					Ya5khpxigAjtsunmOiHr3NrR8efr/Bz0JKKN
+					bSRZZCmoymIiGGM3AtbSN/n8bGMyz+C1W2Mx
+					taLB6Z75uxTH7RSaKoR/BNRLRkE= )
+test.non-terminal.C42.example.com. 86400 IN CNAME C43.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oXYGbtjYBTpMxLiuDZ8N48trN3jUzcWSDQXj
+					1+lfNtaJYBv0+50duql1uW3DVtNE9B9VSJen
+					KEinAe6aUti81vZb4ZMGO4L4V8E2cfmLeQNK
+					fGh2NLFb+oNiJMPk966I7WOEjCohYi8ELfCo
+					HH6wBOZqDB3E/FdTJJ7mAnUjJtQ= )
+			3600	NSEC	C43.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oqkkYLvd3e7/4WJ8pkUqohpM1aCOOsIYRved
+					h/7F3fnEDIM7SviE68wP90ch1UZkn81T0iWU
+					meUJoesWhTBpA2mM29teJvNamEh8tFUcfT5x
+					ZE6t4fwNpNUiOU51UJu7p2rVIZ0kzQ1c+AsQ
+					G3YEcuSmOEJV6/p4uGIqvfbXP04= )
+C43.example.com.	86400	IN CNAME C44.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					RzZDlADhgkcbBMlcRF+b9Jobh6Udvs0ks9Mi
+					vstPki65zmQW9gZWUasgUMIRAXz5+623b9IF
+					WDivqFm4pUYq1iiweW41YGbL6oR70em1zH46
+					w8q486jUNlWbZGFSOT4ltIopwlYUQSAyJPfE
+					IxD7JzMSfpJ25hnpL6TG3YlmCKw= )
+			3600	NSEC	test.non-terminal.C43.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					bw/Z22tfd3MPJYoXsPIrKzWgl1osKGAPjJsN
+					Ls6KnXsQOfR1rv/REwq7Kb3Tna8QRq6wL1sg
+					4K6ZTIKT7vj9vAJDB5ovY0pVeJTpCjdqJO3R
+					l/UXpUZiaxwmAtWUH8dBV/fvuJz+eZElM4WN
+					PO9Ob2GQq5z3tRcfP75HpZjMnDY= )
+test.non-terminal.C43.example.com. 86400 IN CNAME C44.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					F+3JubBGS2XBVUWbhVFb1aW3zreH07h8huCJ
+					9qtyo1070x3k/h/8UPZb6l/eAr1WwqT0WPn/
+					1BRhSJskwLfHJLz23YnKf2SFY9H3mdGZgZcm
+					+IELmPJaExn1hNsHlLeq+e1Nel0JmerFx91h
+					bPMZdLGuuYleMP6/1Ns/SuSy5JQ= )
+			3600	NSEC	C44.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					e639nuGt5Dbl/dmpRdXqekvtbfPD6To6SQJD
+					9VXZaMRHsX5TXhw2b7XOyexG8hMpDOf2QMIb
+					DIWrxE0XqfETV7akV8I270jwjRiIbFYDEgdl
+					COtNJBYhZuzNSznzt7iT7fU6HlswUnFQYDSN
+					ipsToO4Bv7gnHjpmGtCJVR5xwTE= )
+test.non-terminal.C40.example.com. 86400 IN CNAME C41.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					TaV4mzo70lt3aY+oa1tTFBWBMhRVoc70WCHq
+					NMUOJRoQRdrPhZPADX2ZogSTi+exMisSt+Np
+					2rKkkS01teSjd52Y3kM40lNyZ+ZURzPBJ+qi
+					LONsmE/9pUWX/NZ2xPohgqx/FNITIqgl+7hr
+					uozte8zWDe5rxVOO3YSHXSUM6wQ= )
+			3600	NSEC	C41.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QNcQZqfrJJZ9ND0RKXdbcBjVE0szVlf+DCln
+					oIXbEg70K9RBtx7+kowL7UxSER6sDCq93ztk
+					wZWgPrskMZpSoXcSRSZyGVPtNC8Va/jUvX12
+					Lh4U0S2kRdpYHPw0ijcSagTWclMttngSMviX
+					iIV3YnTdVV0FBsHJ4ZyTT3yMNJ4= )
+test.non-terminal.C41.example.com. 86400 IN CNAME C42.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					O4uILstkjzBIKDcvGNTjEduKZHQcR3oBJlfy
+					ACXDaTFyShj4LtQHCbgm8bJVEcTxNTwyRAeH
+					MtbwmzAZ5L5hCiy+DBYvzBDdwucmFrkPV3iu
+					tfeV1V99NEEVFVjJGqtEyl2eHb+s6Ube+NKE
+					vW2E4gFG64sZaLTkemQuxqF2bOM= )
+			3600	NSEC	C42.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					GpGTUeRPOOweU8o5XDLCgO02Z/D1oRmXg4te
+					ajEf425NpmDNo9x2FS8K+jm6i4280sAyobk2
+					Zuq5hrA++vPzqdZtX1JNXl2u3xGMMEhb6FbL
+					/DnjUtDIH6H0pp675mVokj6MGG5k0H2TthyE
+					pvJ9ZR0CBb+RsROGuFKfCjH3x9U= )
+C45.example.com.	86400	IN CNAME C46.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oEOm+BV0/vojmQfvSN4K41s7bKnJE1Z3B3Ic
+					dQj5cOL+AIZchO4DiDwVpgaMI8ks4rEjjaAA
+					AiOJ5LceWNva2YtCU4NtQQhKoTN1g5g9ZYy+
+					1Y+B0szCi42ZuRm5kjp/l+dtgYHfuHD1ZvIA
+					qSuooxE7MwsCZn+jiT4WVHzhIQc= )
+			3600	NSEC	test.non-terminal.C45.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EnMq6VpLuTKEXl3rinyCDTb7GcflpPIKOYkr
+					MaqZSul7MJc+Ro9e43CFTvL+M8QyZ2XPrdx9
+					Ln4as0gnza3N185srCdBMOIZh9GZjTYJaV4F
+					4fqIkm43r3ORebu4Y0/J4GjV46TEtOFaUv0d
+					InbqXvzxhXDnAW6HLqIkKDKJqSc= )
+test.non-terminal.C45.example.com. 86400 IN CNAME C46.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					P9fzyX/6o9pbuCZmQOWLrY0LwMk0MPnG3syV
+					zWLAlrl+7VptGu4Yg6fLSeJmGyc/OM6xJ0np
+					PPL7+taPfSaWyblDLW9SAQqe0WOzJV37Hj4V
+					BIZfVUfUT7sICFSxi9gUnR8607/wrWFvIn38
+					5pbym/Bb/cGj79b0gSkdzZyk1lU= )
+			3600	NSEC	C46.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Sx776XCx7j4qqUYZN3dmzKU78U9O45iQq4zt
+					5RT8K/8zZRjVSk5/PTPJsifOnHVpfcCD54ZT
+					WG4RqkeDinH46jUk1p62x504+4gllJvprJhd
+					5sc76X5gzeSqJc9rvWHpFjqVQz2DLtAQwZza
+					uXuMtBtzzVBjWi3QRgrmDZCLK10= )
+C46.example.com.	86400	IN CNAME C47.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					V6SYuepLYiac1xs2cB+uAXa+HaxyqiIFu4ju
+					+f4xYdouR2TXfW8Zf2LFM+vh0X3cE8S64I27
+					TJd7Ddnhate2FCvBSHkylRaC8L79ENIU2U4Z
+					T3CyF4fT7WHShKzgoqmpyzi1K+2lYfFqe75w
+					WQvSDmDZTTlnrTrUatmyTWiUrjA= )
+			3600	NSEC	test.non-terminal.C46.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oEsrxq/nWiqkbSVr3FDwAtktF1ywiqg3eg0p
+					DzNlVsffOW9HOuOoyhzkQ7ZfpLP6wRq1sWLO
+					R9T40PnSw4Cnmv6Q1p4m6ekUJ76sdOsMw6Fi
+					L+f7ZOKumceVKKxRReJddjPigWITmAPCZ4zP
+					+/2TihnruNI0I1g4nCRrM2dzuXU= )
+test.non-terminal.C46.example.com. 86400 IN CNAME C47.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					giiqTT4lruXdmDYKZPOaxVn2pk8XymS/aIyp
+					aHlRfV5uGAKofzmMAbbPE0VYHBDZaJWilGOa
+					UnqybuF1uiHIx8u2HpOPCV0TV0LUpDVCVC/R
+					EF+Gz6Ppp31R4/v1fQLUmWpuscuic+t8QcnK
+					US769b/ioMhRDDEhNa1u3OMFA1w= )
+			3600	NSEC	C47.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					jpDaUkBcopAD480T3rt3VlsbbwqL7opc4YCi
+					FzY1StUu3emj4D8jr3NfWBVMWNE350tOQQZV
+					IrZtUhTWuv6YMPUbV5Q1/lt3ICVLDueRSXWv
+					MovnC2EBBVHzI9qom1PPIgNxU2Sh48Y7iTtI
+					UEn+g+mzQeCRTV0F71bjU/Ioxj0= )
+C47.example.com.	86400	IN CNAME C48.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					TJzeQuCUrzmTEHZ8QSzrMh6z/GFOX7g71Sx0
+					zB0rngSYY923lKS1PxMx93+i0XcW8q/1w9+d
+					ReM+qUIIJCaa7yEDZI1qplBVXYKbEdOO7uKc
+					pPlN9jTN6SyEMfGIKRK3nHfuFPVWN2WCy6Xr
+					fTlqW+ctq3dGpHplxffV4N0jyY0= )
+			3600	NSEC	test.non-terminal.C47.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					e5UJH3Myw0x8JReinOHQ/x29hgSS3YZMKiX7
+					BvHJmhsDuNiElFEvAfVqZijU8IS3TwqQRJq0
+					qefqNtnW6jY38GsyQ7B9fJjcnC+KIVnNtrOA
+					q8xTcGjILf2ZtYtT8uUvQ7CIldh8xWFmt5XL
+					ePxUnWXbQzZBVUj6hgg+qGCjuUU= )
+test.non-terminal.C47.example.com. 86400 IN CNAME C48.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					DlRuPxygmP5m/dHI/LLFwmnYBpgbnbcyE91F
+					8D0A2lENUsny3OGjtwR0F3Z06JK+PsX+tEmK
+					sTwix5i67R9rAuMef4+BXEVYnsCSayWx+cSh
+					QXAHI+2OxOt0zy2dtAjid6FwAsfUqg+JmsJT
+					k4d0ddJ2DEiQdjSu8oiNpyN6sWQ= )
+			3600	NSEC	C48.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					YOmrIVOWSLCphgFPU6VlghU/+1Rd78yKkL/C
+					I4iHB9Ts/dmymVWdDH4f6R0s+NtUj98RxoWi
+					wnJ4mxSi95ZJvxRqAgf5al5Q/23hTM+IIBA1
+					uc+6lWXMk51xhEjAovENFBd1VPHG9U9dhooo
+					MQgDm1RVBsJ6R7X/MUvUuJ7CXec= )
+C48.example.com.	86400	IN CNAME C49.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					mstE8tIJelsNslY+HEk8T+S88IF96MEctQ4I
+					96/Dg6qJ6aj1pRgId3Y8GgXgrHKDqmdrzgJM
+					g//rYXCL0nctFXZevrXLG63ZXVgcAJ381/tU
+					ulP5VfaFRYGN65Yje/NzHPQaWuMshnODbjQj
+					sV8SQWNkB+7jZFIFlMCQH+B0CJU= )
+			3600	NSEC	test.non-terminal.C48.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Jq5at4SpvTRt0XIEGr+F9EynvMUMDRvwpi3Z
+					0dtq3525j/bEiDiXJsH8CPsrrrAonIFFKcYU
+					2RbtS3SiRbrHmOWuXHRlyinEdZsFlzM9jc0R
+					g9+1kNwnOV4SvrNdQQbm9MYqHwIjWwUi5k5Z
+					VDfsTkaBVCOH+qxqNzv/p0vGqfQ= )
+test.non-terminal.C48.example.com. 86400 IN CNAME C49.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CNI+oxTaXWMQGarEpaZiY2G5mrUwMsmC9e1k
+					xV8HxEpt1STVrohXagCdBJIqaf3MWj0NN3Vi
+					suC3fXtJ72OfkxJtKe0PRk4AjbCZyeB+C0a1
+					R7QHl3RIFll9NEUTGtz7P0dodWV336YkDZ5y
+					fzEtrecwyeX8+hOZ/iv1vFcX2vI= )
+			3600	NSEC	C49.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					TrOIztZBcvyT93kbLDtfBTQFsxBpytWAjUCO
+					FPc6xb82vd0qq1tkjkY7GXzbb4cX1V+2FYmR
+					gBLHLal9TlIrdJVOTQdHQKwnHo6aadGd1ayi
+					QsJvZ/400WCDPVvE8pQEK8MKWR18r5YpWa5L
+					cQQKgKlvQFozX6CzJ6ItlJYq5FI= )
+C44.example.com.	86400	IN CNAME C45.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					BfFkRZHcn+j8Mxe1Xg4vRkBl6YdAyeJUo4cO
+					3+K8dlLr/dL1C2xZQmwOePkhG5udeMMG/PJN
+					469UTII+woyX6tHfXYoP0wmsRLruu+wv++0C
+					zlkcTXdrR7KYyZZ1+sm+VeQl12n3f3aXLQq3
+					36LpQALyvtHBZ1Ccph7zk1h+Aog= )
+			3600	NSEC	test.non-terminal.C44.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					gCTROnakx0cguzal+4is88aIT3szhqm0PlD4
+					2gSCSNthro2YyEA1x9anQ5t3d+M+iebLokyN
+					RpDqY2WLyqknI9iPFSpVYilMl7G+JWBt5o3D
+					0tB8nhVlA4B83VqnQsQIU4Cdz04JrhHo7Qq6
+					bPO+uU1EFiSC0q9lTqcAKvbeikc= )
+test.non-terminal.C44.example.com. 86400 IN CNAME C45.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					tLav4jfnrXhG9RDhgXfFdV6PzZs+HdjxV5gs
+					arEP/L2RLnahWcpcAGDvtzBYNTr7mYIkr9+I
+					M9nLtKNtyWT4THtPTJFjizLh+HaC49J5AVSH
+					Y7cM6m1uwhqvPBDj4LINsR/xz8SvQx2MZMnW
+					AIN8+KlDog+VxggDtMuMxBVevsU= )
+			3600	NSEC	C45.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Gw6d74fziYMXchEMuCKvBbgUbHFYCytfTpcz
+					msEU+7EWjncgPWkTHwHejkjbmYDL8v6dByOu
+					hB890KlGkINTXp7nD8T9B4efttoE7OgnIqYC
+					S6mpqhzMg9Bf2Cd+e7s1Ok5siREZNO1AZIG2
+					izAqkLq4l1j1ug415YIOUWcyKuE= )
+C5.example.com.		86400	IN CNAME C6.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					H0KhqMgZZNHLAYQg2x4EWkrfLjhZo2M64nOq
+					mLZNgDr2ubtlCvc1RmchGLwzglEicA6D/lfn
+					u/+etbbJHfNq/6ERPzRwje341l+OZ2TKXp8z
+					IbtOd8m7m1KVTOcdsQPjqLzjpoM5/DZTJqbQ
+					nK7sSKJuT5tVLUcfQ293zEXMIVA= )
+			3600	NSEC	test.non-terminal.C5.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XBzbnJBPjiNe0aqf9i++JBNkVgfKzJSOWxbK
+					WdGBAE+1oqrwkngVCADRBhCVIqQMUKfJtaYV
+					R6yncIT6CNR78idmVGCZ5Da1yJGQYL3HsF7s
+					gMuTkBp9cO6xFuFkOqsRfc8lN+oeas5Z1msV
+					Deh04viwZMfoKgFWpL2MtC0ohd0= )
+test.non-terminal.C5.example.com. 86400	IN CNAME C6.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FDq6kVPWy+nYGNwmgV6roNqzHyyh4HI/R4zU
+					VDNIdTqR+ItRvhHjh3g7gc9II6TLPDhgefAi
+					7sehznPvCn7h1I0YixtoDrflj+IQ/iYxJLTA
+					h9bVLUfmpfuBCxmD4KZYbSnVeVdVHvtepruL
+					tg6/YvVbtfRRcroVpXlTr6kGJgk= )
+			3600	NSEC	C50.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ecs97WZFw5MGHB+zUvO6jyKZ+ysP1+agTLNB
+					hjBirXZwOowbmC/CekUcWvuCPkSIpCRzYBFR
+					b6kY3Q25wikZKjwW8tPR0qYKBR+0UzFVXjG/
+					ZHyk+4s1Osn7t/ly4yu7FmihAldhAzyZrMDX
+					P/Q0R0tewwQbKlHqtxos6mVPyGw= )
+C50.example.com.	86400	IN CNAME C51.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oiIkJXCUD53GZK7WEyfSi26asLcAG/XTWXY1
+					mKkz1iUvJNYfu/P2AM0wYutS5tzPUb4ZB4Y6
+					ODti0WQy2ycW4bRvPUZI4Yjh+eHWCAi4slPd
+					cQoQ5GSx/ddGy8ryRgggQH3mfSSZcylw2MDv
+					CJkcNqmG8jbyC6W8295lHx7Btb4= )
+			3600	NSEC	test.non-terminal.C50.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ngPIRnRpksfj6eLSAWH4srqirM0+0wTbpBr1
+					1TF1FjLCvjEQ5ZmB3f6vrZAQaTmrQIa8jVpY
+					5gTPB8hpnLOnkgA68Z3oSLlbAQ678XaoOHEx
+					EBaiQhryl5krfDhMgNqD2U/5804u4lDveiv3
+					ZSB/SQVmDepFS5ZmmVIhwDqn5+U= )
+test.non-terminal.C50.example.com. 86400 IN CNAME C51.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					tKZzKPoJekvNQK7D1l0aa3b4zKh4u/X3GY01
+					wpLZzlto3YiDMINWJN3E0/KdFojFEPzGHrYp
+					SHkcuypmdthaKfOS73qqiXulW4MyC/c87zlo
+					epBmzf7mcpaJicDdYuuYXcVrJg1w2wYWcQJf
+					7cb48UeY395LnG0O3nG7w3VJ4fs= )
+			3600	NSEC	C51.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PeiickCPthoAdhf83mJ8wIgJz/dp8q8RnsqQ
+					2GHWnrRgVly2PRPcCfw/eLLjxF/QzM841bcS
+					ts/awWM6vQBXlYp7g1+Nyn2gEazc8/Uxdz80
+					3DU5RB650jkOetG2D0BMDCQhwMqYW055Crkl
+					zwEGhuuk3u8gWdqnYV+/MjKCA64= )
+C51.example.com.	86400	IN CNAME A.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					uYXTGlmDyvUA8cur8NjK9SfKU3rd6/hgM5vk
+					fZ+8cpYtolMH0cno/miTU5vIFYrIDzWM0vYM
+					VToNDGRdDTpr6R0zozJ1/tdFbuuyUAkkf4DO
+					5UGwQ+yxr79dGiiblPM4xA9+dxHq0/VPwT3P
+					ydGYJ2amf4uow/tiqkyEHqp+FvU= )
+			3600	NSEC	test.non-terminal.C51.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					nAJDYw8PW8PucLWxBiM6tRqVp9E1PFyUQZBE
+					msVtpk8dlsx/1Lro1BtWAYYLjq5p4Sz23220
+					ntbtjkvGTQ8JhPbCYI+MlZPGqhUQnyXKkDaJ
+					SMVBcfP8H1J/qB6BFapOGHj4X0DzwV9yw3rf
+					owwNiYRuY3CQ/huDquMLpGDr5z0= )
+test.non-terminal.C51.example.com. 86400 IN CNAME A.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					USwIlYP0qfA6t4qTDiYeOQ/eIKyNRkcj4fxs
+					GVwGf+3z1dPfwlJn6aDaDtSag3gSNqOVYc5E
+					6EdDE/g8hkGLMQe14qDzXulCTpG8eeuGhFJg
+					zYA7JECxj7a3whIIyogLV1vLeb4ps3jOatQG
+					8sFmcsbybikTOKFbZekJ7ZLSgkw= )
+			3600	NSEC	C6.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vPoy5ruzXlnKfKolW5Prtr5b9seVOiQ0Jd1X
+					Z323gO0MYyPbR+QmedhbMas7UT6tQdSAqyk/
+					BBb60ZcCXGLLqE2QtSUJSjo/ggGSgKcKiEd5
+					APQbiitXL3LSdqW9swQO1WQYcZcvfrKo6RUl
+					+56K9UBDsBU8ZvMCurGPwwMH3js= )
+C6.example.com.		86400	IN CNAME C7.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					U3WdoX39xgpI6TU2FpTQ4ukCRbpqwYD9Jtu+
+					WBFSUqieidiYWBA1kQMuBKKdr23JFc9xUMx8
+					2H6dDDadKK56Bs/lc6lB+GVFHP2g4cgkQRzY
+					5hl2GLhV8NV7j9h4qZ/RxfCAzRaN2aTS2+oy
+					OiQu4yCjj4XlavN5yoZkwcU0DHQ= )
+			3600	NSEC	test.non-terminal.C6.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					mytT+aw2B+FSYEdT/fHfNIbkuRFXE1Sg77K9
+					0fxuBk/EtXC24ESHFGezdSvc+c0kzujU6DKj
+					4ZK0WEGuoPF4NF8MPU2pzzwIuv0QzaCpm1g2
+					qsCZaEJd0e3BggYwUx/SNnmOPP5nWvVmH71c
+					I9Lj1//Y5djz3ticeLSVAT7kTyA= )
+test.non-terminal.C6.example.com. 86400	IN CNAME C7.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CYLp5AzdlO5+RZTj4UIZ9YqnXM7vXtttEPq0
+					rnXRZjn68xrN6o4X6qhY7C2lswlz7d//e59O
+					nxoJQrwsB6EDbphecQd/kWDMYA9Ss1FLRU3x
+					0lfONg2eaclZMexNuiNgR4tiF5dpytoCWRLk
+					eeyk5JP4tC6KzkzYmqGQuHDimXw= )
+			3600	NSEC	C7.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					K8D/dJf24FcM3T6ywA7yN3RvKNKjZHSkVZtQ
+					oQtEbJXF1UaTm2C3B5Z2X4r9P6B6nZvtd5ur
+					P7RikH0oKn2zqDPfYrOaO7SZJf7QQtCmaiaB
+					/uXusM9wSxT4Fsgc5CZyFHfkMMsTKO/3oHuT
+					PBNHiVu5g8yKn3E5X6UZiSXoj1A= )
+C49.example.com.	86400	IN CNAME C50.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xYTSz+cEvrlbVeS5HFTLad8VVOvNldTgZeqX
+					egmtynhDx6stG5rGdaD51zdmi24smEYo8BPQ
+					jtCU8moyFKbnIAscv6V/re4KGP4YPyRzmPUI
+					ihoNAUSaP5jksxUmS3+DWD8PaSfA74L+PVZr
+					SOsZM+cGzGnVQ5/Ejp1lUWn2y6A= )
+			3600	NSEC	test.non-terminal.C49.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EJEqqBgAtQNULlby/XYv4/G7fly7PAJ/+F5t
+					hhydTQW+ey8By32q3emn0Anquww5BKz5qIni
+					cfZ9z/lKvuO3syuE+VPMlber4/bipZOEIuZB
+					GjzPlJbTr4bCt7V88fTCLKLKVSzPr33o33K6
+					7l9tsW8LvqgIKFKolYLGaOMqgkw= )
+test.non-terminal.C49.example.com. 86400 IN CNAME C50.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZhPb7s9CoPsBWUq+IGnga13wYRqk0BYjpnpp
+					bsKai4kgQM1zUXDF1nu+wn0jEL6kPz7kcxkk
+					hWRD21AHli8FKJix0sKI15sHHbl4J/NUgtU2
+					tZNqulcYgmBhIblKUK5IAz4RWITAP5LN0yN5
+					ToLSPY+jIplvhESXHDkpaQl+eCY= )
+			3600	NSEC	C5.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ywRHS4r57DkU7gj/UFVoQMRmbZbyxRaLwjeu
+					FqN2gFrQCkmGTMRNul5HfOfsPI9x43a6Nugs
+					0TqKVYBB2/06/5QBz4minnNHkQ1uJH3FD5z9
+					PEeaXVpZu9MFLw2a8jK/xpSg++x3SO/F537O
+					n1ogyfuaserb7IvI2yx3ly4CSEs= )
+C8.example.com.		86400	IN CNAME C9.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					JQhBCOWrOMe9jGuLF+f/paJ40YYPIVV8uqDk
+					Hc575+FNz5JvqVNkgAx1bJvd8gPtCaF/FR3Y
+					WhXkOOcAtPMjhrY7T/XLvLvgdn8aTgn6fZ8u
+					6caWLoNeT3OKLPitIDnESe34VLWCQ/UlCgSp
+					YRHFKwNrhQ7+OmOeGpgLT/9HiDA= )
+			3600	NSEC	test.non-terminal.C8.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QcnC1ITlSYRwTkOo1OH9HEctrQOvxdrN6tQr
+					HTOBRUzyXRo2Y1h3C26jOYRJByr7qXKNawjN
+					Ter6n6IADEPWRYV7Zg0Vt4+qwJuMQjqfuSY7
+					1O22AohxORNNWwTN0xY/VZ32ijaQSt2o7BhB
+					WihKVAfpESOYX1jtQ8W6F5zFDSw= )
+test.non-terminal.C8.example.com. 86400	IN CNAME C9.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					kdd1XSlB+0KJnqo7un4RkRkv6+K7gOH+s6fV
+					FK0vycWI2O+q2FADBbmwv8q8kOv9vd/QsO76
+					lNXgXRMzklgxBBY8XRHQ2yY1ZGW0RabQtKFF
+					YGI3gcyKrkZ4YztYLrUIuylC/aPHQpJ1f3g9
+					dTakqNvJHenZyR4di5CTRoC6mAA= )
+			3600	NSEC	C9.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					G0si7vZjW87SMbVguQyB3akDnM9gAbIXks11
+					BwwvPFkKqdUxMP2Qs3IrzIKfhvQ4tADv7Voi
+					XRB/soteQwhjyYhPB0v78JfwCW+QwpDvxDRz
+					rSGeyv6eVB3gvBVcrM4RHzl6nFj5fmNUzmoK
+					CFdIfGPUeX6JLUO3W+xKURG1Nao= )
+C9.example.com.		86400	IN CNAME C10.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					LGxxUe4DNITcidfQR650xyr1DVBp0D/rUCDG
+					u2oTV0Xb5ouVH0gwgXhgEsJvcOrEgk4MiHy4
+					jhw4XAC/gmQ4meR4TmmRwsas7LaNbW2QKItU
+					DsWMw+YZEOZ7KhLgmWZyQpYleXffL+8uKUrP
+					fOdwL8Ww9OBF4ETlnju+rdEc1VQ= )
+			3600	NSEC	test.non-terminal.C9.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Lvswqag0N0AEJ3kFXHQrM2Kz5wUFVcq4zDQV
+					ZtcJ/iIb2QPDPG5yT3pxU5HIoZ1gjOeXfNCv
+					lJ7pyvtRpW8bGQj0HLd2gOuUEh70+qo2aekv
+					8QJazPnS5CBPjWZvtSGmP8QAuj9OdHirnLRm
+					uKwac+IOo3oZfWGq+s8as5Fyoww= )
+test.non-terminal.C9.example.com. 86400	IN CNAME C10.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					D4ky0PqnI0bp2ktdwXEZ80xYFkMGcLLANsIr
+					LqZvATEMOjuVzbUjJMdNLKfLmBlmGgRr5sVf
+					6gaXA9/eo3JcPH8zMVqmyvY6gD7TJcXtwaQM
+					RP3jbZkSiGCtWMICKLj907KJmgDnMXDQCVtt
+					RYbOGuYLCbHVL5rYJMRlCESUNTQ= )
+			3600	NSEC	CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EuEUuQ4r43JFOIPkECbzhAcYpaGriljm6pDj
+					rJy1KVDR/wxXTH8f/uQ2u+BtcxpjyyYcG5Kj
+					k71Rt2WC1Flsn6eE+2yKL/n8LQOetoq4waAF
+					6c/lndg5DHzk7Y7GyI5wzbXdA091dyDblaS3
+					+AhdIja5AST2+Z+969qqDcf0/oc= )
+CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com. 86400 IN CNAME AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					C7doptCNcuiuKJ2GrVAt7Qy+5LCN7FZi1E2C
+					Vqs66YPNUOb72yqT+ecRaNhHLiHIqwbMN/+o
+					E9S4wfs9q2CwVwvyocJTKPyN0K0yddn6qcnP
+					BRHrUgKJISxNMcYJVSwdK5+hBUbgUpObWt+3
+					EOlwPcpUrKHfKm5XzllM0DLK9KE= )
+			3600	NSEC	test.non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iDV4P8UjilQqgiPtMpHLM8o+HRinfsZh5zqP
+					/4O8JDb6f8qVsqe0DV/h0sxVOjfV34Xf995y
+					xI/Unu4aG6YKrZOjuXxd2LWvyuKMsPGXMoxg
+					gRS6OnFdCQ7+KTHOOed6QVkCZIB6w7FdkKOn
+					KSn8QQnuL33RFPkPDeCWdZaEGXs= )
+test.non-terminal.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCA.example.com. 86400 IN	CNAME AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pd+sc//VDkJp1+BlbFho303VkO93Xt4X5Qgt
+					ONFE+VKy7RQZO6/1rZhrLjg40ksy/z0XJR8a
+					/jcF1Er2uyNOvPnTwkrhlgn+QlvbCv8I0PX+
+					kbFpfCEBLJf2LIrVm5hVUj90b8eMJPVs+NEQ
+					W0SjcTleg1I65tbc/EWrR0pKvck= )
+			3600	NSEC	cname-point-to-multiple-type-a-record.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					OGTyOmiqHSbO4VTI1ud+uSjCMaCNTFU4htwX
+					QaOxwgZp7vRuwXWmm4/bcULrEGO0ApbfO/dB
+					Qjqht4tCubrfohjTCKgrdtnW1oTDCX0WEbny
+					Z7FiyfkiWGWVPkkeR5Yp/jbvLNfpq3d1gwuf
+					Gan+0OJn6SOHXSidukU0OUmxvVA= )
+cname-point-to-multiple-type-a-record.example.com. 86400 IN CNAME multiple-type-a-record.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HRwBdthTRu9uCH0bRVbhESMAMklWD++Ays3w
+					px+IJ5BNFUncLiN4tOF4B0/7fYoMnUA4Abvg
+					+Ge4La3iDNmEZf+39jVpg1rd7q4xpGk9Z4+K
+					IL2gGxfDKbPv47GBhyr+p3KliUMgSiXmM87j
+					0N23b36G+/pMplZU7WHaQRIYjjk= )
+			3600	NSEC	test.non-terminal.cname-point-to-multiple-type-a-record.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					erY9Qx8ZeDbt5bKHRc9AUDbHCMZh8z4ojg6R
+					alodTp9OnabVliXc2ISy8jadyQy0JCt2ESFC
+					sxL44/MysCk/R+Nwxy8iwME3BaPjURwzwERV
+					NXoi6sw9nNZiecI9gMelVzH2BsNNf942/zsc
+					xJvymebJO+5Tu2eEGbWS423gU4o= )
+C7.example.com.		86400	IN CNAME C8.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					InFwe62Y4wTPpTE/YwJvm1ZgdmRLfF3TSmk6
+					mIgPYhBicymtPKdgnwV12GYKOdhbz/5Zvr69
+					AneCf2nM3amgUkgBe6aD8U599MIu9ksuLkfA
+					NoKdaIt3XQHFzGar+mvf83xnJNSTm8VvHQAf
+					h9KkrBB+N98zYsq8YclkJxgrwBI= )
+			3600	NSEC	test.non-terminal.C7.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					weOiGDryL0M7nv1pju83+o+SsE6Jmsi8+Fdf
+					PO7dXTqCbCQdANicrF3dgRqK3QkHcVzKgf40
+					R3UFoG8aX3fyYKlEInCpfO7dOADGnzbtZ5v+
+					L9qgHC4yIvJgIcBAVx2/xOVol7BcWyUYkDQN
+					g+C01TRDP7ogAHJUjwPLaHarXbk= )
+test.non-terminal.C7.example.com. 86400	IN CNAME C8.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hH80bLwy2ntrP7ZHkkkvUf/S/vQWx4SYNlyX
+					/KihAsyT6wGxDsQ2RH/iIMTzsHUdLcDMf4gm
+					dqg3BgJSMnM53xbmjjJroTdM1lz4TcE+doiC
+					KO+ikqNOS81WnjV8l7ivqcJEJwGPb4TXoOos
+					FTQHBIIT2sVTRnGYcG+BYx0xLLc= )
+			3600	NSEC	C8.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					t8/6dGfb90qFvsKF76Jv1K3tHNt2pIFw9iX2
+					fvM/GRn5zJqALRpDJX1CTQTSTitHgPkGn34q
+					54rrssOha4mfnd8E4VSL6FNP7+R3fXadB9pZ
+					Krozgbq4MJBFFSI/OlYucFSpK0rxXuDZZxlX
+					dQi68ViBp3Ghx9B02YbuHP4Rtbo= )
+test.d0.example.com.	86400	IN A	192.168.1.2
+			86400	RRSIG	A 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					d7amEXl2t7Fltx2oqQzhgIXUGF4zpU3PGJ06
+					K2qZPJ5PwzQtrpAiywNKFuk2F4sGInSjPNwg
+					SBWiL0h9DDKNwc9iKtlPEcSZ1q6nz/9+V0IG
+					d0nF7EJhDGAsC0Is0/ljZLfJcliKz+NeZy+7
+					H+q28Aywpu5mEv/fd0o6vjgbuFY= )
+			3600	NSEC	test.non-terminal.test.d0.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					eD4bO3QmM8GdweXtZ9tXTexxJMIEY53S7meD
+					VLkmpXZsFYpHXJsbWiEJ58yf2pfl+XvcSTbx
+					xMaqaCih/8wWY9XTH45FUUf5MMZpZNSWo/es
+					gMxc9h05pL8zb6P3EdCYSvHqpnWESiKxOuR/
+					Kmc2Gwa9e8dmiuDp4x+/RARlaNE= )
+test.non-terminal.d0.example.com. 86400	IN A 192.168.1.4
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YeKJu3vDpMw9BcUtEWqm1BpKfRfUW18Rd13k
+					j0Cg2TgdcnaGmDwwXUdksrGkB5L/eeSlOkx9
+					OJUjnNM3LmoaDkN5OK80vqiQZf/JxTyySyYi
+					wo9b7pPr+jADB2PdXZ1bJcPClfD297B2//3+
+					BZVRHL6FN0FaPlToapzZvmsaPhk= )
+			86400	DNAME	sub.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bAcOYw3hxMzXkRwMEzJ/ABMEEdNmg/LDozxR
+					3zElZoY65UP/wkZuCeP1pIvguEc8iGZWeg2x
+					b08B6BjFfvIg1A57v/FAoOXFpAPpw4o4pa9e
+					XbyA/BKuM2jRvkj2EBFV5rf2M5pTT1GF1ttJ
+					DdVxM2zb4XfI/WVJURIlb+6ucug= )
+			3600	NSEC	test.d0.example.com. A DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					uexyxqwdJTN2si0SJjP0Rk96XS29y1jJauEn
+					/xcPSP1oJJapU6L5SzFu7Z8orT8CB4ALw91Z
+					YdPQm2epXRYomyj3Kq5R5zXGjwS6gIv3B+1J
+					mp+zHclVRsYY7QLDQAyOHkK+NA74seHPgD0b
+					YefqdzOI3QOSkQJNvUqTISAriaU= )
+test.non-terminal.test.d0.example.com. 86400 IN	A 192.168.1.2
+			86400	RRSIG	A 5 6 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QYOdM+npbMtsFSB+JeoR5JXk29yxjAcq6IoX
+					sqGKkKkyToC98o50/XH8bAxFj0q15r0TvuEO
+					e1G7dIJM00fF+/fBYIOJcXJ47Qu7xASzBYA7
+					chF3hB94cvNV7kABKFNA5E1+DFSwFIfFmClK
+					JLe2E5+SGwZfQFaSb2b6tjJaMj4= )
+			3600	NSEC	d1.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 6 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EJQmAI7vp33hdzMgolypa9+qbqyxIspqIwYH
+					iCgs0TFxPQpXc1lY9SMhZX+8VoSZEArwgTsf
+					Mx0UkrlMC6sXi7A79Rdwmd3r4BrK4bdMrBKu
+					IrVLv7MCRUzUkHdVHYAbi2+3IA2l+/6En6Jm
+					msRMZCOJNR72sLqs60bURgXI8CM= )
+d1.example.com.		86400	IN A	192.168.1.5
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					sBA6L5PbxANfhF5YNHD8QHVPrjQGaymqnXlA
+					nIEN3w4wWf27y/+slfvyGDg0dL07+NkmJnMM
+					7GXYljy7m+i5TDVzrVjvUyw5r6ML+/jXD6cF
+					DhUcozPWBPn/tGHQJm8W5ZYW7yyzeaBQZwT7
+					IJkYZ0bINEQ05apv2gd4GHnYmak= )
+			86400	DNAME	sub2.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					M6Dy+pDGgna7f8jB+DbPEz203TGCYYZijbYw
+					TlTw62kUbRUPrJbL/fQkE0rU9Pc3GJEtX4Yl
+					nhye2+iPZIelnQblQcF9Zcg8mCWx/P2HT8UH
+					B2xDuH7HN0yuvHSXWVebEdlR4xhGAyXSCRkP
+					rM4giGRyMaKuwl85WFdrDeyL/tU= )
+			3600	NSEC	test.non-terminal.d1.example.com. A DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					R6E/AnwSdFbKYMf0khvZ5GlmWhtzbkTkoirv
+					0whLSIhHvM24jUt3ZbtcIn6xi+hcnBs0MSO0
+					wnsoJhGvM37cJH/sdYrwkC/W9jajToJuydhG
+					fe7jwv0jw3WcyeG2BCoktpx2ooaFciCxrU2T
+					2ncR/dKM29LQzVULPBP4rgcXtkk= )
+test.non-terminal.d1.example.com. 86400	IN A 192.168.1.5
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EITEKYUvoytFHIeie+a+hKTi4T24/CCMV65M
+					qG52AKrHK9x+LQ79FMFcSAmMgh3z2DDQ9dzy
+					jy8KxUVuC67AsXNcoGEehtup1GEmTAMV6BlD
+					vAYdgupQjuhcgZRix2HXDkxpW+fy4wqjbJz/
+					3KeUWWIglCLBipPPjNwckD7zmvE= )
+			86400	DNAME	sub2.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Ati6eUZSBzXnqy+TQPkqhqdMngsYJSZo5vxx
+					JSMieiy5+vSptViQanXzkEGJeYMYg90TcpBm
+					fUGj/p5vvK5OtNZvawM1sXR3mLBBRSibUO5D
+					RhmzNWuJ2vGCZn7/CEDZ9X75Yq4cbg7A3+AU
+					g6RATYnQ2WptsSukGV/LBL/qBQQ= )
+			3600	NSEC	test.d1.example.com. A DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					q5n4L+3en23tfTmj4ZmQvBq1KTB4KL//Ipjl
+					IrIHk71WV1jjnVHFzr9/baas33nDMgnCsAWi
+					x+wmB9tPRfHqdJrbW0f4LGBM6cTvc574RYTK
+					36CWvPmTy2GwaY5BTZEzqililQjOJWpzGJG1
+					jaWb26cNeZdOGmTviCsbMkk4d8s= )
+test.non-terminal.cname-point-to-multiple-type-a-record.example.com. 86400 IN CNAME multiple-type-a-record.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					s2YVJouV6wX0PRwEl2QHeHk6nFLNxNhdrxgC
+					HcfpI2RHamYHK0eaZfiuEUfXMRcht9Lds04Q
+					qpv03hEl95MxRhH8PqRuXBDf5QY8Sym+WEL3
+					/g+UgoSSpJZ3FAdFCa4iOx4x9Ms6WH9E9n1h
+					KMr7L5AhXVMexoY5a3VEhmGzPx0= )
+			3600	NSEC	d0.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					UAxKCgnQ4DK144UA7qjlFZJsqbbZCPEa1YRE
+					5rdt2j1oxYstEFrfYIJlm0SDqQ3MZxSnwsQW
+					oW51G65Asb15F2lhYeEf4b+haXDa+dYW7xPL
+					S38QEKfPlUjb5Tp+Bzv5TT1phE0nalPWgz/7
+					FH3beyLu+Evk7YxyL0qJHf+F04w= )
+d10.example.com.	86400	IN DNAME d11.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					N8yrn1MJ0KvV68ZB8FQIYFbmH4WQgRqjuolh
+					QU5PGbdNHPHftS9OtqIRmJ67TtX353V2HYrk
+					j11gfQDOJhXAPkmpbcocNE99270xPJlNgvoX
+					85v6T6K7MT4k+AlKwNPdiutjHlrJnVqr/lvy
+					NszBTro5qZuKvt90xguql5trIH8= )
+			3600	NSEC	test.non-terminal.d10.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xU/8mB/Wj7cpidggEOGleDIolVYXx4pLjUhR
+					HM4AV8TtH/A4/mlxPbdOP6ZQ58O6yt5ax7VX
+					LxYVf466byp/zbBxgQFiXoCYfGmSFR5szdxw
+					6REV1VMQlQEiERXJrr8OkNhf3mF75TufD5Oy
+					VqLwVXCrNlDk8wNhs4KbiQa1LVQ= )
+d0.example.com.		86400	IN A	192.168.1.4
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oQ88aQZo4/NrYU3CLYAs0dZ/nky/sab5qMMI
+					QhlAQ1Cke24EhXg1qDKqDs2VxmlXU4G737Pg
+					i16mMrZh4pJpTcnbk48MKJxN750OsLjuPseu
+					mzsjUuJF3qRxnCxgVzJeM6BkLjN3ws9Nt2KG
+					YppKHvg/vAdm6AcKMhS/LKVWvJY= )
+			86400	DNAME	sub.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					VUYk+8Cc9GVU6urdV9NQ8sO7J2LHdEhN5QP8
+					k1TCiibxXulrhn2EDKhoEqfYHJkChZovlNDH
+					RlfNoiYvXCjpm8En/5G2hmpL+DdSbUKJO0fC
+					wOgzfoS3u3AUCgUBVTA8U5OBPHzoctp7/J6q
+					jhRxjVhz02mLNXh43dELM9dQeQA= )
+			3600	NSEC	test.non-terminal.d0.example.com. A DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					kY8OOpMJfUPQ6rfHeOhtE5DNKqXDKrXbIcXc
+					E8NA/M3c9Wpw00d/VEzSqPP1+mNXX9fJoaOe
+					ukWZjsCkv5QJMBTjYQVt1UzQmDbVt4Un/nJW
+					eA39f/ZXzUm04xVm+EOhSN8SV9It7w1RMX94
+					t9S8xI87nZi9+SeI/+49jeb6j78= )
+test.non-terminal.d10.example.com. 86400 IN DNAME d11.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					maQTzVPNfa+5C9Rsp3VWjNuQ4FuRjJ9SnIDj
+					xWv4KeMekO1qZBhgwME7OwViVlTpbIZje5lG
+					o/NoHwb8GhQLn3tsh1VpnAuD7hifsnQX1tyv
+					LVYee2VZ4H0N5N+qtfdoZvmuAghbxDOybLJX
+					eZZddeEx+vDMjK0rNiEtn/P5Os8= )
+			3600	NSEC	d11.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oSGx7H72TvxwlepMMJeG6Dhy+QERBE+6iDDU
+					ufYYmwVT5QbTW3cETV2ZEmhztVSXU+8QnyfQ
+					dnSWeCPSBtE8wy9F11ID8JL19H6GhsIM51Hd
+					yYwphYDjakzemv6AZIpH67p6O/FOnLIDwJFs
+					/N3uOriCS15WJE1XjcxSbJwHrZw= )
+d11.example.com.	86400	IN DNAME d12.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pQcnUhuzKnyV1dz/VU8TfsAZ+nPhbqVrPco2
+					MTbDaPSLCvZS0ulKr9Xd+7b7QFtTxNiX9Sm6
+					fMzVImTeJs9B3f52yIww83fnHMBNMC4kGgaQ
+					HuiNuuarYYx/r1fEXl32lo641DimcwzkdvXI
+					hJdRHFMLc4cc7G9mur7Jz6E/2u0= )
+			3600	NSEC	test.non-terminal.d11.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					sFRbkTOCCwr4q6uaRJgXv/CuFG4soo2KX3ry
+					KhannLCoaIj3ubwBlCODhEBfEVLvfkGUjoPs
+					6DsXaJZAgtKuienXGHF+N6xruqAivCAuerF8
+					UK1pI9WKRaGMop9ZhzUtPdTSYho+2b9oCVQ8
+					fJ5zJuCTWCOJUl1pVQf3cYpCIJs= )
+test.non-terminal.d11.example.com. 86400 IN DNAME d12.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZCsTTfwiwj0ZEbYFvRLUFrCbV3Cf4/vv4Cm3
+					ruCXQgW3FNwbBTors3SmPdGj/iZt7XJCezKU
+					IojMdcKvD2mYZz9GxcA1wEGa9H5bDT888Oyj
+					9Lg7PNdx2zF+13t6Sx8VqS3c7A5cStnxQVXb
+					9lqDxeGEI2cDsqc1lb5ZgqxkpoM= )
+			3600	NSEC	d12.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					OJG1fogGzZ1j2y/5n8dIwl0YmcPXDLN02lqe
+					b3/YkF+CXHhbCKxhNT1YWM0q1Ex97SMSsKm+
+					HtgO9Lt3bIxMTkz0NyffspS7YkQYh7LBS2E8
+					KhwEXgX1G/FPeC4F5d+7kPdoIWaztLtE6Lr3
+					UlbN0LlRTaPC7fey9X6n3K+8DPA= )
+d12.example.com.	86400	IN DNAME d13.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lz7yCcwp7T5q+EEuvANyZGkTu3aksTx4xPz1
+					DabQhnaJTagbLobu00sKMsCEHEQ/m6HNXJ2c
+					Rak4p2JS6T2GIOyDSurRiWbiMmwHEb/wuOOX
+					Q1JKM8zwrSzkZ43sp6OStotN6NpTSRFOxTyS
+					cWGl/O7YP1JTms1SmvEui9oY1TY= )
+			3600	NSEC	test.non-terminal.d12.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XF2aBu99ZxNwTtBXg2vlhcYJgo1p5JU03JvW
+					iCnjEVUt3W0Tveh0qvjuM18y6bK2PMbmSW/i
+					aiJWf6A+f/LkcmrkIFWSOOO5OMISy1ew1XtI
+					zHQOvVQQN20q0zrVpJPUjheYoTyBDXG0NAt3
+					JVxWsrxdNwuX0rfk6IAvlZQyGEA= )
+test.non-terminal.d12.example.com. 86400 IN DNAME d13.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					RVwECJFNIUFt+LUau5wq7zH5I8wESLQOj4mx
+					QRAunw5SVIr/KNyyFA8QAtKn+H0gefywZyjk
+					PyYmDKIbIPu8hnBBcrkPOztKUzvIzV/MParQ
+					DnlLlXDw2JQVE6HE97MPw7mPtnb8Bf+4ti0L
+					QKDQ7dhU5A2TsW5VMlgZAOWKQdg= )
+			3600	NSEC	d13.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XOx2kjlmwt/F7sNwR70hKcWNOuxLBO+sG6Ec
+					fQoZy5dq+U7DUk5opqHBnTgLTpElu5xpt4yB
+					UdLrZ6Yw9RgYWyualSjRl8KlarQfb2G+UzoC
+					K7yj35zj3zVq39dz7EMB5J7JxmMFIsNjHdsY
+					RWA+UVOZFvDkG8rUpWrUs5yKVnU= )
+d13.example.com.	86400	IN DNAME d14.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					jtsqmXsjCvfCRTfoUM+slQHIuAUNWawsExt0
+					kM5CcGfN1pZ+ZZtDPbU+JEp3A0WrVyRhXghu
+					QYHm0aRxJgeKoqyOuw6IEpzE5BuPj+VEJopp
+					1Q8ie+Bcl+NBr4RvWhje4v7df4WQ1ViqeUey
+					+DT/n5l5BCLR9E1mz5OhQaobHSM= )
+			3600	NSEC	test.non-terminal.d13.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vugIOlfbCi3BSPxGVKivU3W/lxneaodwLxFU
+					qI6MPkrerZSa1keH9RQpomM/pTbttE2iYeCg
+					yna0JeheXgZDUDMb/Ck57IVFUy4HyJzWOC2m
+					ZoPq7TktRPJLcuKD7iYTQKNO2FnWztQT4j4z
+					WpqisRrvcnPAmPqWYKYqxOVKW2A= )
+test.d1.example.com.	86400	IN A	192.168.1.3
+			86400	RRSIG	A 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NpI0Q1mX4EZwg5pWP9qVCEYFUbmJ/PUoTIC0
+					mnkw1qvsJZnSQScZNogcC1HSQ6fcLQEWmwWP
+					992edBYI8rCHku0jFm5FG2C7rro0eZFYGs8A
+					irix6jJO2YQfyxlWjl+WW1T8GSvB1NctlNf3
+					Zbpg590SaPcTOx/3B862E99rjJU= )
+			3600	NSEC	test.non-terminal.test.d1.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					F6m1X0oeLpcz8Oksun80lQQn/frSOkK6isrl
+					q7u/lO+JaLEhmpRPcFVz0zjO0yX6gVFG2pOA
+					/UuqiIPpGsUui2uDPPPiVFF1kasI0tS4jBeO
+					50QfJX08DjOyHAxxMcZJSrInFBFfW+Yp0jL0
+					S3/yPXpz4ziNdJpP5C4u/tgKoM0= )
+test.non-terminal.test.d1.example.com. 86400 IN	A 192.168.1.3
+			86400	RRSIG	A 5 6 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					KMVn/uUWxGkIRnzcsfNadUu2Xirgh2p1Zjm6
+					TSyGtOUTf1Y5JImsHOmlJbbg1JH1bzBVOvGi
+					P31QZAKn7XdkZQVcnMfEzK/KjYhinYeWCAxY
+					2UrQrsdakduooGDRKcYFNrs6ZWazwLA/QwnQ
+					CAp18msA0xlYvwWwVAnKi+54Kt8= )
+			3600	NSEC	d10.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 6 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ka9/TNblKzcJYDkV90jalAvXZcNDQbnr1aXZ
+					1yeHGNtBFvO+RAJgq1nE0BV5tT8BVD1KC7iQ
+					mR2ejl7i+06aJS16sn60kwT9fRr9/Mkk7WRU
+					k375Xej29lM3+JgWTyWcP1iHVhzYOpuPomsd
+					N/HORL0HS5ymMvXlk0UetLQQQQQ= )
+test.non-terminal.d14.example.com. 86400 IN DNAME d15.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QH/eV7byBiJKnouQxYqhFJz1DNCS4Uy8kvDV
+					9zohKkVlqxEq3HzE2RdG+2DpqJPJhpkMdhnb
+					wWmxsquHv0P4d9HhS3AIrNiXiP2fujh9sIiN
+					1ySkWFsldgsF2QupkGbeQtKLVU3cf+JrMnOI
+					NjCMBG93uXw2sZeknPszq1s5OlA= )
+			3600	NSEC	d15.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					V5n+CIgwa04IVSIwa9gPekLzJp7rECoPWx8Q
+					ia3S8ZghzLAKT99vVcbvUdckbB/Qsh4o9jyV
+					pFb7sTzALBoOc1CqDx32anol3qIVNel3LJ+w
+					2kGoAY5XEWC5TYr7O3P0IFsAP6miLaEjX26H
+					bmHaNF7omRtFmL7RigRLJQiNiQE= )
+d15.example.com.	86400	IN DNAME d16.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CyLqrwZuL5yPAsxRIwqXk6jsmMIhgVNOqpNi
+					iuEeYjSSG+gFFBxeC34dX9/6kn6pla9fEa5q
+					+dxcKGqBbI6W2EuTLkvX/Z77JJBVD0Om0qmH
+					U906M9R5GZdmT/2VpYgjR6Tw5jGsxlczMhQI
+					6zAhR/M2/TFgKex+rGMMBRDH0Mo= )
+			3600	NSEC	test.non-terminal.d15.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					MOJen55j8/qZFSNur74yJOZvkz3ECUDyRTiY
+					y9NgRCcMpweHzVk4WyA1+QyqpApakV+Lks4c
+					gJlwCDg3Zbi+9dDiSq1B8wmvTXlpHPDOO0rw
+					hK4o6Dlyc40UDddv6YJNF0jmsX1F6jcGHn1g
+					hyl+xn2IkeqBk3hIph9quhF18+A= )
+test.non-terminal.d15.example.com. 86400 IN DNAME d16.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					i7j+ye/1m4ZWC+1RYOcBENaSp06JadRLkagM
+					EUIws2vhB9SqtfjDog/qalHm8dVZwfFhzKrQ
+					NSo+A1Ft3sC1NfilIvi0yYqwsT5j1WRpeV0Q
+					T7Qe1SBL7DcDOIoVsyKo7QDabLJbF060e0Wg
+					Emfzm/J46/jDtHhOm/KFpsFZJJ8= )
+			3600	NSEC	d16.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					UHG6zpseu3ud73F/HWeU+MQPVpBgQp2z/hO5
+					HcqM56Af9CXBN2c9s/WuEtqAi4KMOxM9YriW
+					RAembvuikFRV6JQ0H+ftCoI2waF4Zu1kLcwU
+					Y5NA/xS1xLgKSdrO6JgA8RlwcOVENt33tG9m
+					UVkV3XyI8Ppxjc7tneTJhEoiGo4= )
+d16.example.com.	86400	IN DNAME d17.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Mrs5QfcEbOCIuJPVSlErmXgH628g9VuPHugW
+					TQRp9yB9oWO710r0mQzagWfK/9VFA5cPnoNY
+					MxrBWAN3a6O0Qwo2BBUmPgxUsWUJ4sITCDt6
+					ystNF2BsYqMv0h7tYnbLMM+AfuojoHY1Z8TA
+					AISB2lEn0xa8HI6X3CXjrNIJxco= )
+			3600	NSEC	test.non-terminal.d16.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Hbdv3SdJolh0xmSKWSLdqZRzo7V2nWAL7ykn
+					5RAWJveZvpeZNLAafdePTqygEfUb4FrM2dqr
+					jm1P1OY9s3ECWUngYn6+2Twn1hS1IiWs1TkQ
+					0cf8egUDmrQ3jkNU213GjRaj2/ir6EL/Y66V
+					7sI6DXH/pVIY3JBfgGXbferkn5U= )
+test.non-terminal.d16.example.com. 86400 IN DNAME d17.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					P3L9ijIF7sdq4qbsFz2+wshgtrnL1Xj1CgxT
+					sOv24t8YBfUSJz9udgg71rqEJcmYHsdRxyh3
+					m6A3pCvWLW8CSMfedp4AAner+2WFYZ1CUJlm
+					XdCNDnOVQNKagEur4yUjLLZRjuTtD5JRkVp6
+					qu4EM5u/4FR8TGPg6orpC5wgkJY= )
+			3600	NSEC	d17.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lsG2m7m5cPvmyqOcMiUKRsoDwnLs92Lz4lbR
+					41lsyaKxk++AlegRyeaHW40e+yIj0Nk20olb
+					LzJopJfTgLsjUOf7ClMoQkXz8+yCsDWqbmlj
+					ifM1EODugwoxIq4K+N2zQ4tGMvNLxUvwqMPw
+					j+q669F0vkZPezOPuVWS+kTSrP0= )
+d17.example.com.	86400	IN DNAME d18.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					BaabmIcyWNJcSmaDlM7/HF7u1ZgyPVxwJCTv
+					V2L8KN5YVQaNwiVJG4zyoe0mZ20568eMxIVr
+					4KRMVdv/NXhhKJDy3pVaWdqViSftBpudIooZ
+					TBy9SgIe2FU4nU8KbS0qAjRzrfJ9vNktKSTm
+					ZeXCxNd5HD/6//F4T+DUkS0usUc= )
+			3600	NSEC	test.non-terminal.d17.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					dUzhCcQvrhwUt06MySWxzwGK5sAmLhR0XKHk
+					XQotzD7u3kRwmSbiCH8BL9cynW0kiTZbdOSC
+					RToEgEPRFLiwrOYPxWVLzgcXuoXZxvHgnFRh
+					8TaEispFkSFRqCCPqCSetKuV5S1IohCDGqLq
+					yXJ0Vi7H+8dKchGgnDSjJKRSWWI= )
+test.non-terminal.d17.example.com. 86400 IN DNAME d18.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CJNF09vYxJ0UbkjJsd9P04a8Jpu7/kSKLOG3
+					67ftUASZoalm1uGIvJMjcXidBUod4XXT0ljh
+					LTuezFj2kKbZw1YKcqDNv+Hy86Zhi07v4FnC
+					75n5Rm2IgyfunvaBV4VnckiDRduFbSKJQaqx
+					GhUBQFzdApDuvaUcrdw41aLFpuQ= )
+			3600	NSEC	d18.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					KJFyF3FBlv5nkj53t8xoUKf5P6aWFQmKgqxW
+					fts6nY8fjbmAvOaf4iPwgx3VrnQqAiuOBDcL
+					oiLnY6YN7mnn02Hs8YLH8qVUB+BaPnRGaFZM
+					/8BY0ssr+oWihGlgZpXJjuNgC6kWNEbbrI11
+					6V+pImV4fBODjh1TM0wrnjSvm2M= )
+d18.example.com.	86400	IN DNAME d19.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aF6mM/YQOWcrjMTe7MBaSDmuO7/6qFwHAUkn
+					hooppu+GWnuYr0O2tKvHJ+01/Nq3GbVPddno
+					Qcg6zYk6Zy8cfzaifo/b3HbY7/sHKBZjhW4H
+					CkqApNcBu5bj1DvcaNudKKzu6EEfN9JzDXZt
+					sfSkTW5rSneiz065dhGrbm+LD+Q= )
+			3600	NSEC	test.non-terminal.d18.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oJgKUcyZVatFOgKIu/jq/2nazUHSk9yYiEWj
+					mCh6J/Qvy8REFqWrpkeGu0jEw+Pclaal8QKY
+					XFaMCXHogWucpwulzuFDS9r0VMHxIjPdUAoL
+					8M7oxBV3cjQogG29tay8L67XCEnQ1jhNW8t1
+					1oJ/VgTvsCZbilvCtRYEjKOcLqY= )
+test.non-terminal.d13.example.com. 86400 IN DNAME d14.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					neQfJMo/qebAeLx42Lb1u7u3EBOnlumBB3EM
+					uy+6lk8Xvxvj9mHmcGhD8E6VNhJz20fG2Cdj
+					pCctrOFr+Bt129aNALiYFvy7SllM9t/i2Fca
+					OH7UnTX3ZGotmAlsEDOevZwrC6Q78KCB4Glo
+					CHMBE8r1LkHZML5zIJJ60LKqVpo= )
+			3600	NSEC	d14.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					txarW5KbElkJuR0U583IVm3vNRUK6U8PP2oH
+					fAJ0f0gEJ8QrRnc5xOpFLnT8bCzZKpvpTCAG
+					gVEqLzO9scIajvMXM/MrWNFI9D7V3KTSHAmR
+					FlhqpJnN2agXMduEGxqBowKpGxFqFjISPg+5
+					AiPlg3drmWqO+0KZW6LAR83nj40= )
+d14.example.com.	86400	IN DNAME d15.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QIprPxslxv/sZo3JS/sykg/RS8z9ZP7F3b9L
+					YBJBfTQ4vLaqnfUY6EA7cf1vvL8eigHJNXBw
+					MZGsp5S8O9dgUhc/TtBkiWXn/Q14/Wdy1l5b
+					gZKYTOcGhD+tlTgUooyNU19APMX3vEDFp345
+					JQyVw3zi96zX/Mw6dIzBcVPlKkw= )
+			3600	NSEC	test.non-terminal.d14.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pP2JMjQ5Zgc2AWXkTlN6qCVl1SXfgIk04e0a
+					IEsqJyEIvVZdzPCskvOc2GHvaDJ4pLS6mTQ9
+					V4OWdkDC/jNesmdsY9MFbvArp31pHng/sYv4
+					RSg+cC1ZjhXxv9HZcQ+SjYiDZNpo+ASokpR6
+					XBXiZZKAZJFH+GE/HtjRIr67K5I= )
+test.non-terminal.d19.example.com. 86400 IN DNAME d20.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					D8CYk/S6rFMD1jFoTxBWIj2HQsyvFas+MgR0
+					gHGMjv7qgJizcay8CD4Pa2bBv4r1pGeFzL0o
+					OE8L6nrbGdklEDilJ1vnMZLSadybVFx+rfjR
+					35g3oJhF9pxx6Q9mSKA2XGKMj37J/+VSlwNF
+					ktW8QfN9xw0htvcQ/ovy59L6YQw= )
+			3600	NSEC	d2.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					yhfqS6E1PTtvR+6uxLuce1dAASE+WIBXIxqb
+					Qqu1gdor2LJZdhNo2oYADJNOpaO9ZUNURB0x
+					UE0UdDaGF2EZlaA5chh1BzNkHhPvx5vfUHQy
+					7+jupjFFDmjeq/R2m2VKD/hzstFElmOgrRND
+					wIcZSTehIOEZp1m02Fyq+NCayvo= )
+d2.example.com.		86400	IN DNAME d3.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					jGJ0gTTY1xQ0jKTXs9h/9NQYZufrY2wJj6+N
+					CZhLQFAIOETNBrgLiglcBde+4b8YMTFIb1vv
+					jX8dOZWQdDdmzdkHTOrp9zmFQ01E/hOMvDuQ
+					xrQzRDWer9ekzyvedkX1KOlWnoegs79t4KSr
+					ZILTZDUJXhBvn5T55DNHJq5WYN4= )
+			3600	NSEC	test.non-terminal.d2.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lo4Vm2n0t1q07yfsHscXC2XwBdqzsNTJqy0F
+					OEG6oXDCujR+q1DwFyWwZ2iK2FjFfrmpus6o
+					wE8PkxWCJlAhlGandab77MwIAD0Qv1z2fgjd
+					eMKhN2tqdHIGScr8/NszhC5Tlz939iB3FQyL
+					BTQecjH3bb3mE/GjASjKKP81AIw= )
+test.non-terminal.d2.example.com. 86400	IN DNAME d3.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FiOhlWNxdC2WCLplysnKFSXko84vNOUS0bDp
+					LX+d3oBHBN/+KKyiIwWJdwfFQ5ZhThsOQwGD
+					eTU3jdXddMU3L3B/XgPDeFAYjocyzKc5LI1t
+					Yjga70MUEcO6BUojB2QG/TcNDtdVEYiv7l5b
+					d/P/YefpjKGyqGtuyqV3RBNqPNI= )
+			3600	NSEC	d20.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pd4iRs4YDj/nR7rcJxeRUOFwHcbXDwA8IZ/X
+					WhO7W6M+6wfYUU6VW8dAF+rUqHcUd5+p2l+M
+					LT9hjUxqI/nvufcAtOO0Wd1JGvKlI70s9vR6
+					/VAbIg20abuK9tWdjy8pyh3kY1Tkdn2Ah/7d
+					yG5O86DDTRrVsz5SGTecj4w/RE8= )
+d20.example.com.	86400	IN DNAME d21.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CeRBWcoTPJayf7tSPHYoHafVkFfDaI3z7XID
+					/W4f0f0LWluOdljl2k/9bXk8OY4ajv1Pc5Y5
+					IPAQ6XMUhVYxWe5o0U3NhCP3QZoissiN1a+z
+					GUCDCREsn/OvuXdvN9tIfJmbqnb7SC6fDTZh
+					aEZ9iqRVNk/N5yrxWHFMFLyXuSg= )
+			3600	NSEC	test.non-terminal.d20.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ntRzsAX8hoSRRTd1eXlDeVbuWjH4xw/BKx5K
+					Gz0JtcvbOkf3cmq6RjJs7lsEG0J+Noptbawh
+					vW2yj/nLWantQQF5b5t36LWrfsTLLPOZypQE
+					m+dpzV/GpJURrwgDn0uxm7Y+68RRildmzSqz
+					C7UDx1p2PswGGIXh3Dm/2fVrWiw= )
+test.non-terminal.d20.example.com. 86400 IN DNAME d21.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					kV6a/gXbO0vLbS02YAs8+hf+NKblK1v2INBx
+					JhLbJi0sM66LxnoJIke4910DrKXQtojP2eqN
+					1KP9dt8ND9iWmGhhJMYqfQMJRDzzsl8yocbw
+					5sPHv+ZkZb5YhNal1LRJtXBZrIF73CIr//nA
+					UBZdn4SJBp/IW5aEuUeboGpBLJc= )
+			3600	NSEC	d21.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Lu7Wt0xdCaEyXHI0fZWf+ePvmw+aop6NPVoW
+					xjuf/YBLqJsUoIFYJAiFtuBPHbdhIxRHVvN0
+					oq2qdV77lw8jbHLEgnoLdlP9DX88cTioJfs0
+					vuLmYhe7ncex9jRttJWPyhF3PwMuIkNILeU8
+					f26nDo8nlLay3ikFLqZGb0Mgip0= )
+d21.example.com.	86400	IN DNAME d22.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pqtitqFpSeaB07zL7eZ9RQVVW4VOzlFNyZjL
+					cE2KtU5mcTWUhr1zukR5GeHbK5GyoLQwnPyU
+					cFJBLt6XfTnXZ70kZ1w+YfFl/+skBgPRDY2C
+					9Qc2knigQo7noQlYIWjamzCdp9zGf1Q+jb7+
+					iWq7+qLElbcgUrb4cwX/g7i5xMo= )
+			3600	NSEC	test.non-terminal.d21.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Z8+2YtdqGek0KWucd+dFVa1D9IEyFdTOtijr
+					1erfz9TNnNJqT7oMmI2EWVMOLNfkRTzghUGG
+					CwXTZzHrRlKs5Y2ImUaTqJ6pZY6AjOKmBwQF
+					uPJK3Eal+mrWwOfKwPZy99z+1JwKrPP4GfGC
+					30CoJAfpU++EfGB+Yi8CaeN/IkI= )
+test.non-terminal.d21.example.com. 86400 IN DNAME d22.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NouUFKVMDc2EFJzTKaStH7y2SK5idF5XhVqp
+					jsp0A1ArQJ/OumvCHP/EDuZh3nazfjlRmGWe
+					xXPtjKVQ9mo6MPEs3C4y5H/hkyfHr0SLBJPh
+					ca5Lu2w5YssTH0ycqVcR7vaE1FITxF1J1m+O
+					WUNgzJ8C1Iaa9NvBuxIJTxVJb2E= )
+			3600	NSEC	d22.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					C8sQzFd+I4yQcCjiYQ/Ml1WL4g24qN95wuJu
+					14KNhLoDIaJdlrAOgIACRT9RgSWTM69eeFVk
+					iYn4L7t55gj9eBwAqHY2bWWVqkQ4WkAmD596
+					B1zLhRWFL0c0RNkLgWpHuxkPg2qugWCSHdjU
+					nbXhNKfhAWYYE7PmZC1r6cLasHg= )
+test.non-terminal.d18.example.com. 86400 IN DNAME d19.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Euf38MjyhFOhK4YGImOfcfXajRNocQr+04zT
+					gjI5O4lzb+tYJKL5nYSgXLEZ0KdNCttabkT/
+					JEa7Sgfc3B7Ggi6f/dt1VbsR4eYcX0qd2Mol
+					lUNaa2kCdpkFcWPtvhTuHiFcsxacZumk93zM
+					CFkI5H9jbF42E/ngB1kRDOiV51k= )
+			3600	NSEC	d19.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ao23NWDq68jedx4get+cBEPZlYVNb8Kf7Zer
+					GcrGth44a34Tp9gOUJeMlhmp6UzmMIo4BK0/
+					0rf3FuLsReUfUGQjEJKY8FTgsHpM2sKhV8QE
+					gPvlLlzmCrIz+P9HqPsEhnCDgCBM/Dz5iZzQ
+					h5ScTjYMSuTpdf1fTHrFBvjGVMc= )
+d19.example.com.	86400	IN DNAME d20.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					N0HT/PTQBnVNU4A9eBQUTyumrav6Ri+C8cy4
+					tgL4Uw1wcll/H3ruCsDqERZN4RA8xKCl/C0I
+					DjAchaz6BeFUZRp7ETgWJls/qmsH62LCnIhO
+					pE4mW39A3J1tB4a+3C0ZnbpaQxU51PhJanPt
+					xWDDw/CoyWfwOhL7dMtk7cULpuI= )
+			3600	NSEC	test.non-terminal.d19.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tseJRrkaCddU99/+haOo7Y5v6pBj9+H8kzIo
+					9WR3n3EkyA9fuRVVad2Iv4OIkuJugeCFAOb8
+					otWAH8LSAMc4cGZ4qndAtGz+/Bo9rgTShAvk
+					q7ClqBDzQd+G1rmMp+VdiWJyWC28/oaE+Xhx
+					zx9bHoILa0Js+eUKGxC/QrAb1VA= )
+d23.example.com.	86400	IN DNAME d24.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					JQgGS3/ep1C33sdFynMolV09rQiB1bvIU6JY
+					DDd4zfdg6gARv3Yldzz5imAtZDuPsLqMOC3T
+					X0VsQDoqtPZ+rxMtF5U6KhYcyAhzk8o0XhaZ
+					nkyky/jPrh8/A+ZDqg4uDyTZ1yQjWHzQNtKX
+					eVyrdovSoorPhxIChMv8C2JzjYI= )
+			3600	NSEC	test.non-terminal.d23.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					R+6R821usGq5plO1LRKnAhr3TVPG1xVOKpJF
+					RahtcPiOgoSt/FbnuW97VEjmZybVzOq+ndV6
+					3mJE5Q+/eIHw2WegGP/t+gA4/9q+GEyI8MCK
+					nRtoRN/hRzKkx0Vu2S+0xUcJ706S2rHNgUfx
+					QAR+ZQI9ziD1wKwmqGrezpTIxKw= )
+test.non-terminal.d23.example.com. 86400 IN DNAME d24.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bcaFCvHpwUr9kCxPk0IPISNyyoOsut3IU6K0
+					fvxJANFVZSC5v1qhw8xI4wXKwIfgDseuvV0A
+					nVkS51MhOBufduGzrDEEJdJo828vslVqfZq4
+					M1cONAp5dTwHnd0IBB0xpiPKy7X/eVgpu+TU
+					htZa7vHOtSbPsg93PzBUDxu4Yr8= )
+			3600	NSEC	d24.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SZjgbOAcBDMqbl98hQioFaBdclLDvPJbY19h
+					0LapWiC+Ul2hk7Df4606+VV65EQhng/emr6W
+					PmG+wejcalWnfldCruIZ8Qp7HK3YobtpkxRP
+					FZcq1T4ye5kTSay1FMV5exqMnYKmKT4heZKC
+					034OjugQbpwBt4bC7FngmlliVm8= )
+d24.example.com.	86400	IN DNAME d25.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QKTiVsUl1e6CXgJ+dwuTnvLZiw0VVmQwe4cU
+					JDXLtdUepOYadkKrzds6sf5ryozOrImuKear
+					c8HY3PwCv4wh0OPpwm1moTTlj6qhNsnJZn3b
+					n/INtiSe1Um/LzOrdSVSDJDoX1LU9xivbQk0
+					O1gfIylB5E1s73QgrOag0PX67Vo= )
+			3600	NSEC	test.non-terminal.d24.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					f1FbCR1voPyT2gOIOXlWXh726ghR2WgHux7N
+					bT+EqTAdd1luHnclhU3Uvl2/00k78JBjwYID
+					CM3q0IHHN4A1A2OSEQCcPVJEHb0bXzCsZS/Q
+					fyNprb59q0aJQ8mUtO6UpvRbJu5oXcgDXbSQ
+					pRJhrM5NyUe0UsPkG5pSRC7byqk= )
+test.non-terminal.d24.example.com. 86400 IN DNAME d25.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					AvgJxGCFXcJPQKBfo+wgLP9UDEKafiG4SmXp
+					gZrXhomFJVwe7MSlogv4p/sH4NoBFjywB+gD
+					pTZfpT1WeMh4t2mgp9OeTyo+OKWocnwtee1s
+					tadIlU4d2MO2d0Eab95JkvacYUFNnpkQ8V7q
+					ChOUt6nHYrfveEz/j57dSsuGCho= )
+			3600	NSEC	d25.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SLYSGumPiZQGIm7sZWyL96JheM79UcNL8Jby
+					8Cjtfanxj15Zz8jKnDUyWzeJIHGd6uKjXi/K
+					il7LLGm4hxknlWLM63WG9argPYHDkSDYlI8l
+					ov1fzhrmFW04P8tHgebaD+Om20QALnUVEda0
+					MITe4fWITnel5NsdHDMPLEGZbkE= )
+d25.example.com.	86400	IN DNAME d26.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Wi0oXidrnrmUW8YRMi8lY2ldrW8fkO5OYjNh
+					UNefjH2hua7EesiT44ddHepmYCSTpXlOE6bq
+					JV5kjNZjnsmz3bp1mypx4AAqK8j1t5y0XTdQ
+					o/uMsCeqIGZdiDE/3GZXBfZUUDv90Qx7VzVA
+					n89hAFyTNOx75vuBBY5XqDgkoVY= )
+			3600	NSEC	test.non-terminal.d25.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					kyLYfp2vu7r/VJ4r1KUy9fM1naHRfzz4u7tK
+					A/FmiEahM0ta/W94Rgw5N1FjTetvLY+y0hGH
+					cqctmOofwY+2p9GN3PAnDNIp3LPr1YIGzHa3
+					k/KhbtSgUuIl0ZfcYEBfMSNg1IEEl0sywkQT
+					UuP5mKjLyvgKkuJQRjfpwElY+Mk= )
+test.non-terminal.d25.example.com. 86400 IN DNAME d26.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					zUyM847QI5r3pGcqbmGdtqnhSMsD2FwHdhKZ
+					ckRsy658jtUad1RLS3B6B+3XKzZDWZWi6SvZ
+					E0buEaY/FLkFT883K4W/fHq08Q6CChvzuTO7
+					DqX9HL+EkwHzzUUL5DlVVarvGQLP7ffwZ6nx
+					N6OSnIevJdG7z9gdiEOJfLo+JfU= )
+			3600	NSEC	d26.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lUdwjulwBDjxnKePZOWPD/J0AUHL8e3phH7Y
+					XHiG/pIf3AyzvLNEGaZadW8ClAzzxh1nNF8K
+					IS9wKoAe9deOYFFgQuzyGtStawUu6t5QUfgA
+					ByIhZ6HCAyLIuDdmCDSSZ8O2gFlxPwAQA9tj
+					7iToyq1Q069cfQgcxXg2RmMn5Oo= )
+d26.example.com.	86400	IN DNAME d27.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CmrEWa2V9yzrdZc9JZBQT2+YZK0WUPpI9tpc
+					78RPO3yODziMMO+2SiJCYJL3ZMaLKhmBwAWG
+					tAe9KUpRbJX+JG9hj8Mn3V4NqsiIkV7oBQSn
+					4GqoP0SstezG16XO08QRjzjxPI67e5BePAnA
+					hozhSzzEJGnSbS6DkJYmhl6hX2k= )
+			3600	NSEC	test.non-terminal.d26.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					l/j9Rb6vuKOSEEhjh6iWUrEYoXgyEuQr/iYK
+					aVcYO2ngJj+NKvj+VYuUr7JN7YVbDsJS1i16
+					Dw1zKrOWFWqwcSNRU2nR3g8r/VLMIJWf+Akj
+					XMB44pAKSfzsbwVgvosLqFkzqWK1URrxL145
+					i55JBk1VkxcC4w2nhkVkgpvd4e4= )
+d22.example.com.	86400	IN DNAME d23.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HdJSKEfomKEEZv+V/pu+rJuyzLCD4DjVK3Vc
+					ZPh1oF51SghRi7wDwma5saguexv9HJhmhIvh
+					4lpHD69xvGvr92vwkOzsQcmqCAn0MdRQKsPi
+					QERsDU28Ln5AopdCN9HqceEoR5ydP0jNvhll
+					leaEs7KHl6GPOC5nX9RTCRyX9h0= )
+			3600	NSEC	test.non-terminal.d22.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tEydzSTde8y5Q+grtET7M/H5Edc3URPonUdN
+					83vhA4DlseCHIUfcn2KVlJHis1HSJj3ZOrDz
+					E0ulwuiIpAojuIDPuuvmdokqkX95gPdxcVEu
+					OJVsghY4ZNJv7gTY041+QRY2E12tp3RsrJRd
+					HLFMbS6g3OzK0f99mcahOPoshrU= )
+test.non-terminal.d22.example.com. 86400 IN DNAME d23.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					s2nQeFH7qxKNgI8p6/oNqHMrUvzqztAFEunW
+					N7TDFuhAxqGHHdXUXcQ5iLaG+nXlHqZjVhbZ
+					g5XFU1xyKzvr3QsiGxMcCbfMbimNFUBe96+O
+					wlEH6zH6LeS2TfU6RbXWv5cly7mKwAB2OZZ4
+					JqSGXh8+VST7cMdgQTEyOsCst58= )
+			3600	NSEC	d23.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xD7AHNZABsho/o3YWgedJz5mGH2WkAqTPOKK
+					0xuUB0q9q32Gfwe1irIzz+luKEJTUf6iZwtC
+					O/a7TqE9xxVvPwB1eHd8tTfqkPpsTn+EwPFC
+					gWjcn0cWzXJGf/YCHEN0A7g1LD2JbsuWKePm
+					5Mbk0/VtV7yLGQDo4GnHseCelAY= )
+test.non-terminal.d27.example.com. 86400 IN DNAME d28.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PjMS1OoEIDXiYsozP8j27urT+eg4UjN3ZY1p
+					RagCESTRBSAJMWwK+1DEvCnWUZejVR9C+nwf
+					DDBaStF0BlEi8SHWjcKz31G5Wp7feKvefcWX
+					t+iHl/dg2yOeNzQZqtpDNnz1fk00APItOe48
+					XHw5pAmPJj2TSj1ku+EfKlN9Yns= )
+			3600	NSEC	d28.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ZySZ8MSmvWeJR+tRt0Z+UUArRdNH9srsPSe2
+					gzJrncABd5zHmclMxZzv3P7C6Wpyp+ZqAIHx
+					8b9bsLaHSxojmcexKUu03KLgxRmUIGufD9e2
+					vz360CdkWSae+Stn7i6qquaHFxPqrrrdHLDz
+					N/El76yaHLCYEia96ZSSJp1lJXE= )
+d28.example.com.	86400	IN DNAME d29.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MGLs+RhDBLpNZ6TzL8qCeQEoNUvbg5IU9vb4
+					aWE7yJC3jB5HsgMLxmGTB+MVEUfbzoEl0vu2
+					XFFfIogNOxg6MMwfTc53ca2q0Sm4Kvy8U/Wn
+					AP5BQBjr2mW38UFwSnrcWDN/NPuqt8iuw9Pc
+					xm99tv0BK6oninzVMlr4VEdUv64= )
+			3600	NSEC	test.non-terminal.d28.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PHnJMjYlMKrKoIffBA/zqr4Je8IZn0UZvKoL
+					I/mO0Mv3wSItH9EhbH25DMz7VZAFykAUbBBE
+					nDUYGeKAp7iCHcToOiaLSAghasipw3W9ONK5
+					rtxnUVh7z0Ha8OgrzWbHJjb2qGJFJnT052KK
+					8lcG5IIghBOZsWJzRmmtYLC3bls= )
+test.non-terminal.d28.example.com. 86400 IN DNAME d29.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					h1Hvv9sNDqbdmHnpfRMi7AhMmKL9/79/7g2L
+					/8uKxI+T5847tpV8xmAXONjTDFKvqY+cSESY
+					QuxxeZm0ONkPi8eZ0UsibkYBbVrzWoA3p2wO
+					NmUXCgozIPfWJ6+qb+S3T/Zllo2x3LtIDqjg
+					jR8wiuBHno5Y11dD/1RsyZxgFXI= )
+			3600	NSEC	d29.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					RsxrQxaCgsM08RuCavXBFAsvCXhSqM539ptz
+					c3Z25DX4YX1sdKb2klsu3S8u2V8dqm/lWeOL
+					YNvtrt1h0QwZV1AbbGL8MD4bRx/FKwc6DDbT
+					Hu8HwIz1Rif/hj6ah0ZBPe4NX+xF975iUCk3
+					3algCJt6TJbOeTGpm3Qhs9iVXi0= )
+d29.example.com.	86400	IN DNAME d30.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					qbj0MsF0osT4ljhUHI4vcCLXH/mRyY+tzhF2
+					GD70++n053GA4XRhFIVmTkPDf6jMi5KeBng2
+					PCjDKqZ075sagw1KgJ863vFgvVtDFqpcZyMv
+					p/8YoAGGZ6tfzesdyQNsqvvv0IsFlyKMbmf8
+					VwEMu5w46lN6d8cdkgcpdu1qIeU= )
+			3600	NSEC	test.non-terminal.d29.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					g8NPe9d272SXcBLtLSa12a4MwPWaLCJo0L7C
+					0oHI48Mf5hFYgd6c5eAus63H2xadWVVIO6Kp
+					dtRMVh+7Iru7Ttr7p8MQd7a/1kHKJUypQGnK
+					nc7kO1EZw1zSlr67xlky67BnVGtPpdTEv3xX
+					7GlKQYikDhkS4y50TXMdgu3Xubw= )
+test.non-terminal.d29.example.com. 86400 IN DNAME d30.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YMZYBk0UsQKvcUKCNoHB0Vr01SlJUNJKFeWw
+					1m8ODQvM7iBD/98P/0blFJhRpU+8L3luMOQH
+					jw2WusX6tiQ01GigPId1Hx3fffRPMgFinUSU
+					Zqdbblxkcq0G/LS+cMw0U+P0FrYY0RLbG0g3
+					t3BFNIvc4zp93PLpNkoANvjkPuE= )
+			3600	NSEC	d3.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SMPFxTYXw5SCCpGZN6iX/LXGchmLhYpkVF0W
+					eMTpE1b8qXNSEYOX/GcoPTKpq8vC1b5uDsTC
+					csQQvfw109jVQTQKDvj9FcTdBROCqu3+fMoA
+					NqOpQ9myqWlJRqh/j4/Ma5LXAPyjHl7bn/LR
+					/qm5cEOUuFmKN9SxCnt4P3wX6b0= )
+d3.example.com.		86400	IN DNAME d2.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vLfN0um7RTzBYKsBXcKhjE16JHQbT4KWYMdG
+					8OY80qoDPyJhOwh/IVwyphVx1mJYKGo/xSme
+					1H5krPXDQAe1nHOzm+ccv/zxDtOe7bSZdKqG
+					/vwTx+HmFOSI/fhW9vDR5lzlvY9heK2NCYfc
+					ZJKpI6cu/kF2ERZLycBHfWBszXs= )
+			3600	NSEC	test.non-terminal.d3.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					H0nHHxU8yoDmQKxIvRTBQERmc7TlWmKT08HZ
+					4Q0annmyAYwEmcMS+825ldWmv6kb7q/zdsA8
+					+h7In0slgBDh4m7MSQpl/1h6zkTWugBRZUso
+					GIn3XfX6GKtPfQAWLOdPjH7yoTmV4vHCgJZe
+					StXXGYpy5MCfBIC4pymdRouuydY= )
+test.non-terminal.d3.example.com. 86400	IN DNAME d2.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PbkvKAx1BU8RKRQhD1KWxhuOYE6VMbvfh16S
+					uCeBr0Wlp0ldtnaq2UXxormGLVBNVVWpet5m
+					OaRY3FviXV09+55vBimJHkpsrD/q5y39JqF3
+					WUd9SufzwaH5lGR6FnQqpZytrHDFRHJdymwy
+					/xbmVB+iiMCpy17yAIy/iOj53l0= )
+			3600	NSEC	d30.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					b0IxpO3mLEovw/45lknt9Du/YmsCr0+tBGuF
+					TcXB+6GII00Az+Gwkg5/NWMJuDphGCvsxdJ3
+					52dbP3pBaZSsfZrLjPHoUwF/8jziuAvsxE1L
+					CVFwtKuKh3aKP5WBav/pJ/w/KRryXqvXtGR9
+					Yvx2zQ8bpmX5EC03/Bv/t4rFoAY= )
+test.non-terminal.d26.example.com. 86400 IN DNAME d27.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oQFooT2ajjBwlLFYJyT4M4dEYfcQZ+1YZdBK
+					YU4fDY5O3XaLW16ysOy4QSk35LJ+NudKb/Gn
+					5+EFyOuqQ0FO0nSWb5XDFUv8bHcqkcxLixZH
+					Otz/gTKBBOG8ox+FKG93/oQLabaaDXnvagFR
+					9p7zJagqCBGkV+51yyOf2UCOKeA= )
+			3600	NSEC	d27.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XDEw3+UJZOdBknx0nXnPSCbdJ0g/oyLvV944
+					zmc2D53GYPUCw8CbY2ue8xs9SiIRMmlJVWv0
+					4iaeRzDE1OEK8lgRYmPQ8A+I3PrAOZacEdLI
+					cZQTFTwIL2wG6ifI/gSXsuhbsg+NT1gPVIJd
+					1Efc9qWvujkQ7Y3uOfO0Qakbv9o= )
+d27.example.com.	86400	IN DNAME d28.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					G4dzVFvM+hAc7F/m11AnrNjcRp/7gOa/MV1S
+					EXdf+geKzDOlNMSuDQYHebZ1yjyO1zSFc/TS
+					jA6InaXNXRf1IiLXll0Sc7bXqQZAlUDshpp1
+					tQU4az4Z0mzdRdOsLFysd/9j83lL755+g6TY
+					nVn/3KHbX6gRaPcyEOFqe6gR3ts= )
+			3600	NSEC	test.non-terminal.d27.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ariwMYWZb8te6M9WnpRi8mLaNGPmiRfy3sY/
+					eEwwohC4eSueB5/OAO2Fa5EzNpCY8OiYc22e
+					sNou+IYICFTDn6smP35QV1Ltbwsk+M2VE2yz
+					RKWuXPz45qykVFudloHild3qcNz2RI+3Suak
+					rZ+OxgaqtD16nXZnxjsDY8bUB/c= )
+d31.example.com.	86400	IN DNAME d32.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Ibfxt0RX9+Euc0P9EWzoazqm2pNZYCdL2cwg
+					GnH6Y/oVk/KhjQi5UziXTQob5ihX82vLgRaP
+					8MeUaPdACmy7CsuDandsRSVgc+ZkwOaaiFOo
+					4xguJqmWgqD2FBSeI5qgtrlL/wjW6V+CsF0C
+					hvWmGhYMkaOOKRPE3xuqoOO5ye4= )
+			3600	NSEC	test.non-terminal.d31.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					RmoQsqaU9WHhcfkWUbJa0+yZQFE6OwWUi2oG
+					meLhay1FZ6YubZDR1/o343M0UzenV94+Drmo
+					GjDARWjHrN/fFHbrhf0paTwDxd2hCHKfRK1o
+					mGVGJzmmGYlTju9FzUsDhFVY07Ea5k2L9+VR
+					ZUklKZ1gmEVT4t5/uSrS8pT69LI= )
+test.non-terminal.d31.example.com. 86400 IN DNAME d32.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HY+yqh3Ssj66gyTGxAHPW7IoZvYNeu7pauFn
+					0WgRSwcd6y2CzyDrqCPRBoY6uZIQxbqw6DOa
+					T7QpAGzk+gaeBfZELmpvfyLTsbdd0+KzTaer
+					oNlveT9pIoUYyvF36jOtkq28Qh8YwCCC2GtY
+					5sxQYDX9njTriEljlVtzeQdRnbA= )
+			3600	NSEC	d32.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					u8NHxb8uh5qwmJq3JoYOF0056NNalcvUN6eQ
+					ZsAt+84JPgUkjR+IA2BODjgZYF696VdS7FCU
+					n6jU+5UO0ouMjWBArILglX0AttVC3SmmKyfs
+					UIBmBK5caCEtEayaxJs9cKJC9Dp6bpivzvbn
+					iMHE/Dw1GLkl6AV8g8aDYs6WUo8= )
+d32.example.com.	86400	IN DNAME d33.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					AS5nd7zJuGcT/P9QDrE+JwPMLCWhK/scvd0K
+					JbgZvmbf7dJyDXjNwOx9I8X0JFH3udhL+6J0
+					jT8vaZYTkgCeMIJc4dC5W1rouAHlvKyQgM0S
+					IeY4bmc4UzUYbmgWoTlPzO4GsK2j5owkJFlt
+					UbGmbpoYuY2uFuoM+oqk/lkO4XI= )
+			3600	NSEC	test.non-terminal.d32.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					0EsOsK7NuVQjp5RGvix7beXoTYLvBVDfyFlC
+					xuaMDE2kcdi0UcW+fiq8/WzToZKd8n5qsSkh
+					XvewdNoRsfaVykgj8+DjpfZ8etohf3auQVwT
+					p/qyBZ+dZApLhoqqcxhKbgfdyq6FmQCwX+xN
+					csb28Hsqz8U1xZcEf8dx9N1FdoA= )
+test.non-terminal.d32.example.com. 86400 IN DNAME d33.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					H33EqQS6p4UdDRfCP+bVqKAAOTSKR7ZAbwJM
+					kebVHincfNSPp7yl4HrOQd8i+ywEAVjoFtqq
+					X7KdvUSv1Reskw5kt2Yx5msbJMGJdIljg3F/
+					gm8afdHNLVo3ilf1r04JCJgEq4jpck0NDFv6
+					KW3sJ+B2q8SsAgZ/NsqKVkByn8Q= )
+			3600	NSEC	d33.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					QSmQHU9L3+67wx5YgwUNt9C55W+sfJKojkBi
+					BFkRTqUDb5+nm9aF8Y7Fc0evCBzRr0lvAjNi
+					m9z4MjQse27KWqpk+7cIDZGSPaRevbNO3Q8r
+					15d0HXxuqdzWz68byabI2NuNbCVBFVCU7urM
+					v7y9OghP6sdY1Eju1OestuZ9VRU= )
+d33.example.com.	86400	IN DNAME d34.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					rOYGG79dKzxEZ5Ywazxq8942tWOeI/RMGrRS
+					Xe0fb1svHYV2UTX9ohX6LclTonzPQwVlOi+N
+					0VjBECDZsH9GXlIw43yifybcSDV/VM9fahku
+					tStuDkhNy3RpjQ5PSWr+aXbuHM/AqNuCJXh4
+					K4F+AhnPBDE7Xucd2oT4gYEpUzA= )
+			3600	NSEC	test.non-terminal.d33.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					TzGtSlbvxKvpEQWVpOR7TmxqnGZVwvqXGgw7
+					bYT1EgPqtVVh5la+0MvszHKf5xOq2+S5UZjA
+					bgMh1gQ9rKw4IFelQ9OPBZvCwd0zWOj6T1+y
+					cdRtvRK3ZvBM5eJ1CAhNyuSVkvHOk6+wGasK
+					mG6KM8GMqNN2XhYt6Dfvt9klNKA= )
+test.non-terminal.d33.example.com. 86400 IN DNAME d34.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					zveTqBCx5lN9/4aqk2f/MYW56/fmhL+Il3Ll
+					8Tx6RYnhn6qQZoeqy85dyLvWI69uwPOlKVS4
+					MxiALMn+c3rYyPw2zpW1jMKawMAQnt5OAcE6
+					UtpQcpmYuizbEvSKU8o1jPjFU+Kn4iCaz8Q3
+					EETXBpEGDSVDkiYHxWsJVTSevEM= )
+			3600	NSEC	d34.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					OtKiiybJm9EwaRKR5yZ+EL644M7Sd/ImxFL4
+					rUsoFenyBIoMOiLpnXuBsGihBLIyvg/ELMZQ
+					Y2lSZBSIYuP+w75nPZw88R1spi01+gx7QrPg
+					xiPM8Y6OEEVzHzv3PiLwkwbyGSu3Di1yv+jm
+					NKW4X6tnslpjFozJ3bhXT68vanQ= )
+d34.example.com.	86400	IN DNAME d35.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Hl6mLcNObM99IzWPf9uBCBJbDqF4qMeMzIIn
+					MtTqk8+Z6jVKoJ/bJm+VXX0Dy4OBuwfrB3z2
+					MOaIUl/1RIkDClFpFPYVWSbuUkELw0T8UqTS
+					TDReleobOtDuV5ckzQENxzng3BXUzQFI7yQq
+					H72kUTUhG3HP5EmuaIObw/DeEak= )
+			3600	NSEC	test.non-terminal.d34.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iJEzg06kV32IjiWQU1Dz6fnEyt3hMviPuRiY
+					WKvrwZex8JNN1zO8MNcdvOQQPnZwmrgarVRG
+					ncl+U4A1jO5/5uCsEBXMzwtVqtbHjXuKUPsp
+					L/7pqHUeg3pRR1aRropTb7klYmHL5AHxGu+2
+					S26IrGdvxM8R+03D4ks2I5YDHVk= )
+d30.example.com.	86400	IN DNAME d31.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					iz66peI7dI1+8Bo4F0HEtmQ911g8wD1ILT7T
+					2BwdixlyrEy3pCOYMs5qyhjUTX4GMCOT597A
+					osCt3souLPsDCShBSYIaf1WbTUGM9zEeoG4x
+					dDTgpzA0kmKcY+mJzQKriIJ9t+J3Zogjh3R2
+					5RtDTefYyk5FR1drppbln7bnWhI= )
+			3600	NSEC	test.non-terminal.d30.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					CUzjs/O6TQRAivsAxd3zoc052NeN9k0NlpFR
+					KLWzOFl3yQaX2b3zFpXJhcC8WgIg4I2cMaED
+					sOs/98jqIOTv538WGRablidhEZAjkguo3YnU
+					Yi8foZ079frfWbeL5stzUn+bXiAFX6SIaF4O
+					6D7qcScSFFrImBr5lUU5C7mdVwc= )
+test.non-terminal.d30.example.com. 86400 IN DNAME d31.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					miSX5BLAnSn80bdr+wNmdSM7iJ0yiBnvNFWu
+					aNKgv3nT4Ae3HSpEmNQObKOpRlA7Dfkw1XKB
+					qlJZOEjSE4UNTBG/8Le1G0u+qUuHeqHHAxUC
+					S7KoR1tAcwSkyk9vSSai8t9zcGzmZ5x+wpGx
+					xk1htlq/xigbGHAXoOk4axF96QQ= )
+			3600	NSEC	d31.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					UBDdtVUEkXxnz4jmt3NRE3uodD5UxczcOV69
+					buELznNVoO6IShDY+s2sWpGzIpQVdN32CMoe
+					uAzWI1PqQgu2xGMPLCynsiPrYVDkY2QK6FCX
+					GCSAncLinwYgF4mJ8rnwnx4O1bZtOxBPA6e4
+					3YRDR9IxlOrWojTn3+0eg+tuiL4= )
+test.non-terminal.d35.example.com. 86400 IN DNAME d36.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					mUffclGpyz7Hf7LJVgwMBm8xIp/2YQ1HIHU6
+					5in/8qj4Lt/KbiMkKUoylsEOk1EZCORgbdUr
+					c+sD7OL1IbtNRHi5zezIY/J0/Opj9rNvqDx5
+					LdqQLUZATVknm8w7P0zKAKR53dJsfBorodV/
+					3ojk4cOJ7KQOmOpz4VZ51aX4P0s= )
+			3600	NSEC	d36.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					j/oECHOEQmCSuYZY+7ihr6kXkAU5HGBVRe2E
+					1cvSu48vm4u0kpez5lNcgIYidXUGkkLgbzRZ
+					g8qerNrUolUGW5Ou6eH9vRyOKxFx7CN+r0VK
+					s4SmaA7Z9QKoDhMhTL+6L5MD3SuPmTfHeMSb
+					YyYEwfVZ/BQbUivC3f73uImgqa4= )
+d36.example.com.	86400	IN DNAME d37.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EEdpNIRLMORdKGKHVrueW2QjjdTi9L832k2O
+					ZP3mH8b3VFKNehdpo35k6Jc1zHFB2/0TiNkX
+					OqjkgiBi/spmXHDop3T9o08R9egVmBkfxpHz
+					Hos7tfjjPlPExmYnLJto6XDJHEg3dhVQk8bc
+					1hkPCXCoQUo8yF6T2KEix9H6GAs= )
+			3600	NSEC	test.non-terminal.d36.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Mksb5Hs5S3teHznWOMMqESYJhjr5FHikFxkn
+					uDgzRNbHUa1AQeMn9LBsO2hGA0xsZQ+urmJk
+					x6GaGTlQfL6jfqe9CeEybqnCAWWqBw9GtW/d
+					LsO2pqYPwmHe8tChw2FukH1F/zzn5dX4NJvS
+					hzkeZgM7IDJ57mcoOoTvbtK0FqA= )
+test.non-terminal.d36.example.com. 86400 IN DNAME d37.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					DXzD95y216T2+S/ZqH95hGzcN2yohQ/JEgCz
+					4shcLhfyhBCF8UMQzuAyE7EK46nglb/9p9rB
+					r4bEYGOTbzj+Fucct6TLkToLPtFmYw35Bl+d
+					6XAGhllLeEJI6tLHD7IEGkM6vpwqiJFZyXsg
+					E21gaNSNX6pxp9RCQyArBAxgg7I= )
+			3600	NSEC	d37.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EEpCIFxHTpKCYFf+dKgCzqlj453laGc/PTA5
+					6+jqWd6iGPTBGBOpyHm5QhgDfVVlpsu0G6xW
+					aBLRyN7zhW1gsCm5pGnymBSdrQkifHE4RnzS
+					DridL6bOrSGteU2Xgu2AnH9GLTttfs+CixcM
+					rh46Efjw1Iq9N4NYi+mzgitZnaY= )
+d37.example.com.	86400	IN DNAME d38.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wNK3wDPNSo4TIM5spFthBdQRvL5ksyo4pbgb
+					rChnKVgaN7WlGUKUbh7ILq6L8Gx3Dgx+Gysn
+					1IntGBz+5LJRwbFJ/mkBB+u/BpotekSNb/nS
+					f1AloGCtSTjRTp1aPE2P73+Lzqh8QQwx8SKF
+					zKLtZ/s3sxGqwA7q7qxbUJDVito= )
+			3600	NSEC	test.non-terminal.d37.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AvLP/8seBWJHTYbBh9UahXM4N5vzeyDpKVKn
+					Y1lBfkMmiLb2db1P+Tvkvzo6YxRuETkZFUgA
+					QOFRAyYhqNgII4TlnMkg26VcyojGLZO+k8ky
+					WAnK3Py0jSOZlri9J4FgjqU9xn0Wuru9XZSD
+					kpn3fzUAKhU2KuUcKuXIWQUvGuA= )
+test.non-terminal.d37.example.com. 86400 IN DNAME d38.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					mzyChHLbPJW9yGrX73k7fLCDdavZBDJOtTxD
+					xixFNsfDLTX1LZTP4QtQw4sp+gGEOGQZbZrD
+					9VLGnKTPSl9PmSKHEDpNsHt1LgJQqyPu8wF8
+					jl8muCjcw8wB4idoVRqoQ1tuQNdKazHmGE1/
+					zMNrEzQbDafDWucznGK9o4ngDqc= )
+			3600	NSEC	d38.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oNwmaTIxrKdUB3LTHPeKtBHOPA0CAaNRYuxL
+					e8XY1Ex7SyARjaYD323Ch9nFIXezWXmQ3Y6X
+					xbAhLLJ4s3+osk50TGOpSUsmuCJ7oDYdKlwY
+					QDkigNBMUvHf8m2fnFJtfIjWTYZbAFktKABj
+					RIVqNpPAEQG1EcXHXbcy6MoWCvU= )
+d38.example.com.	86400	IN DNAME d39.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hGzgFbxjCnZCM0FfXpyncpMaYDIul1IIHqzf
+					rd/c4vtU4mrJ53Ix5KI/0xTpu68CjJB1mIg0
+					J+1qbhuFYlDO8nftcuafCFXZMaTGoCtyL3Jc
+					pnzsD9mkhHrhhkMh7770ZXi+MECucoHx/siB
+					9h1qsqll4wma+zcU99sfEsckRGU= )
+			3600	NSEC	test.non-terminal.d38.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					gss886rBEatmhX/pYGp2ycafXr09n51+q6L5
+					YWYrAD9IR29qUXsT9LOnh3gkmIawSiG/u/7g
+					ufRi1LRNyWuDRfLrBBmTmQfkyKTfPKUYWQwu
+					40Wy9cZ7juNnW8lB6CZ/OWIFI5dS/+QDd0Fs
+					0gD5G3EJsCPI/6hJWg+25cSMS9I= )
+test.non-terminal.d38.example.com. 86400 IN DNAME d39.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vLHrl7gZRn11fvjVGVJp3sEtJyPWjE3usU1f
+					ozehBRzA0xuigXcRyuJ9OQHgA6Tmjxs6dsTG
+					ZOlT6kCWeVsFsa24Iiuy6G7ei+wPeYqbyZUS
+					x9lpAJTDjmi6T8eeHGNazC3mNSjtbU6XdEui
+					i21Ob89nF2XsKBA3fDv48w26whc= )
+			3600	NSEC	d39.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					T5iOV3jE0Gm5wcijUk5Mow6Lrzps6FvxQ9lI
+					N9675nomxuo/BD5Y/p8MkHKaQUhJ0cSQhNgF
+					8dsaDzc0M2zJAHJlT99WHGhScJakBTo72x94
+					LONS4EQCnKoE/wYdfPClvWutp5spV+7WPb6D
+					+n6CFEjx1hPNdPsRdgnhb02OBjM= )
+d39.example.com.	86400	IN DNAME d40.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NDIEHtFYWSI5P+8qBQj3ZLvWOOXwCNOtLDwh
+					76QtFxqu7S+kHY7b+w9RZi+WR7cNCimBD/pM
+					341M3ymgfKx6Za9CzbvCR/fHwEfdm0OTJfw+
+					UUdMdXk2gHOw9SrP8T237XUuWIz5QV/ZekMr
+					LgtGGmZ419qpiBVcUgj6o9P3Nbc= )
+			3600	NSEC	test.non-terminal.d39.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SB7LxD9BBhASAyMoFI0BfVUIQbV669zfGa9P
+					E/VM3el3yuBYDUPpKQaw+ovjujeDGvIbbz9N
+					JiVG3g5eXiQMHony7Laasb1Y1VkrnomH6G0S
+					Kx/wPJ/gSkJq94uVM8vMwTEBYsUzTTFiwc0U
+					r+9qAndCue2ggO8VoFjY6OQRnZI= )
+test.non-terminal.d34.example.com. 86400 IN DNAME d35.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vPUvcC15rTnoBEejvJe/7n8aivkRzA0PL078
+					QfkS3CNxrVk62Ba6MI1NY9+kQBOed0aY4bhA
+					t7ZEFwaiZtVA5owcRCWymiDZ65gX2gcmNppL
+					40DBp2B5xEGFDM+337w21Gakj+f9US/AWllk
+					BY8xlgOTxLHTRkHds2PEeooUz4E= )
+			3600	NSEC	d35.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					hk8Napz3hJKVPlbN/5vNiE/1U6BnOGKdxj1e
+					yx4U509Ik4oc2XL3BeXPO40xPEAJKL0WMtUa
+					xOO7SwTNgLy/B2/1KZwqk0QTzteyr0XtMX9i
+					K7bPvVH3M4gZ64zDXE0OKngHs6Aewg0H+DH0
+					ofslIkrEmzGor8L4jJcO8W11YIs= )
+d35.example.com.	86400	IN DNAME d36.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Ep2CPSeWtSOdFuFenSMD1iShq9SzYF784nVJ
+					rOMpUHXeJ8qUV76Sb8OFinmh/nEZAP9KZIxX
+					krkV141Pvph2EuASLuv6+Y7DV846dztz4spW
+					xXLLbX7Eg9QjzHPPAosExomSGa7+y14PpaDc
+					JfFJu50nx7OQTkr4HuGCW7EMNp0= )
+			3600	NSEC	test.non-terminal.d35.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					fm5PRS8J58nYSs/52NPOREfn0+cQNcy4RLGB
+					us/hXZ5ahbRWlpaK1NgeDbYqCfriFpCSWJCl
+					oLMVKJE7NiawaspAe5VyiFY19vK7gpyIRjox
+					C5U/4GqVmQ9gSPykfsH9J/XFYfOjryvGFgZ9
+					p7lLopuYxhpvZVTCYBjlIgSCAD4= )
+test.non-terminal.d4.example.com. 86400	IN DNAME d5.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					W8QnYa1Uyb1jOYWIOB73ad+E8xj0UaadmzYH
+					eSCKl0YZ26L9d4VXjzFOrLIQMcxBk1pwY+Ll
+					iTrnQfoQC+MO42ZRNBWaJefh92VnBgZYnL/o
+					6N782Jo6RTCTuzhODfZGMrvZdGOaagqk8BiP
+					YPob0BCP/4A8woduHq4LBIm572E= )
+			3600	NSEC	www.d40.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oDZcLuL4ICNIwh1eswzWap3ZQMRcbgnc6Ofr
+					Db2N/qMtQ5LNQJxRgdiFA64WBEOq3AibOMV3
+					L1MlIDHZPOjnHOnm92V3deEQH2a+d3xntH71
+					z3XzvLE1Qn0T1ehvmiPz5WVxUbfD82mKNE2u
+					bqIhES7ghFGPsZwMisWbYnnbSaM= )
+www.d40.example.com.	86400	IN CNAME www.d41.example.com.
+			86400	RRSIG	CNAME 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					o56J8UlTilwtXGyMxQzx7RG7ZI9qQaEvjkj5
+					afY/GDbhDnjCWt38VEmxiOYT32qf4X+7rBsz
+					spZJkWYhJOkgBD0zuqWcIv3dRmCJyK9sqvaK
+					VD4PKpsx0n1E7n3Wt+SIaoxyB75WYcLXrIcb
+					Pe82mi//bc2UNDb7KO5P3MtxxXU= )
+			3600	NSEC	test.non-terminal.www.d40.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					q6XtW5CF5STV+ssIwjCzO3+WGF9wk+RGKhSJ
+					8Swr0N3FIG8eVM1DFCLtntBTsWLVUa8GxtIg
+					TqNCo/QN/akRk5XAWdEPOaH8VH3j9TIiphJA
+					MEtmiBAau4FsNxwhMyzNoRU6K4eXrmthi5Qp
+					T00cwCDBU+L0+TgHG74aQWsXaro= )
+test.non-terminal.www.d40.example.com. 86400 IN	CNAME www.d41.example.com.
+			86400	RRSIG	CNAME 5 6 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xs27GJvBFwz6E8giGiO4mfvvG5YfJRGB/hco
+					dGvJSExS09qpZRj/Pv79utnj/e/SZT7KVByT
+					smzRNRp2zCmXhzdd5ymOBKSzz2J0yjCAxyJE
+					ezXZ5BOeyMD39s3wHNRla/At8xWntVtZ7sTV
+					C0ZcVhBwjTBdEqzEqo4ZWVvjHCQ= )
+			3600	NSEC	d41.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 6 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Y+ShsKZVeXkOQeu2aSlFw3sRb2hZTf7D2Kh1
+					synhkjSbfGud0RM87gtlLisHx6GRp/kM20G/
+					LXim42S5qRA6PZXez6SEVPHKsCHW2IjxkO0h
+					QScT7R44dre9oY88hX+QcMFsZ3c3qphJJPOo
+					VpawlU14Y9x5K2eFhmZRqwXpltA= )
+d41.example.com.	86400	IN DNAME d42.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HALKMA0yTqwQOizKYXQ7jTFiq582MkO6yvI5
+					TKZLd9MzuIjuFLw/EKSPcvhKCIreS9Gqeqxf
+					icDqiTd+mqVfI9OVYFivI4KR4+cXxTDTlOhT
+					SxHfUFT+KWHFKP/yEQzlYkburU8Ku+S+HMu+
+					FjupYSTIwyJTOaEYcVKDQGJzTtc= )
+			3600	NSEC	test.non-terminal.d41.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AHx4C0Bie3OyC1B7vaAGl4iMfv0I4y6cCLng
+					7N+BLafBgondhrJvwwZiIugG2A10ogeilLm5
+					JfVb/LfVk/m/6hOM3o+HYj0G4HnrjLj221Cr
+					jNnp8Efs6Ey0Za/6NfMtdMIfBnpuQo0b7976
+					tH6KMUhHgJ0OjtLxKJ55p06Z/wM= )
+test.non-terminal.d41.example.com. 86400 IN DNAME d42.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bLG7GY0x1i7OGxX1wvPG6PwgZnvm90kaKnnA
+					KE+HgbcwEnZMD7fmWNFG/+ASyh83waBVz+RX
+					D16XHdncxufxn0/P0Vm2x9JjWq8PTfSgmMK4
+					mh3up4ojOCzO/BVmBuLgjodF5CzELWALIPC/
+					gw7eW0INNu1AEQuR5+puB7+dlAM= )
+			3600	NSEC	d42.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ky6mcrxja84cjouSZ2ptv5/6GhnUSS4iDBqh
+					8xuSovtOMAi80i/0e9xaXLpQaZtw1tz/uATT
+					nJVGJdtz9efTahahKDUgRK4PoPh4fcJHhXi9
+					bvS5oh2RnfVJpGCWIQW6jIo5LWvi4cZRKPt0
+					V2X4pEkOSAMKmHjUr0kg0+srGxQ= )
+d42.example.com.	86400	IN DNAME d43.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					v9BTtT4w23lhSGF3/sdWPT4nGIE1Gk4uCXRo
+					fgNTQvgGDZXzkR/HsWBvLBlOr75yKxJLYAKX
+					yVoMGIECluCTiMD5raK/YwRrBzMqDIie9a/v
+					rGljVXiLz7+evSAhVS2Dsh/Op8P489F00h5a
+					t6c0F6bLEwNTBuHwrlcPQx/r6GE= )
+			3600	NSEC	test.non-terminal.d42.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					GEy2Wj8dgY4Pi4K9ZrAcvVNq6t/g+RWJ2Vi7
+					5gUNkwuZl3XaIC8PNgSgAX1jbT2BD+R7IzTp
+					UDCsTyLJ7j8TnV5vIQIS4cPhQmLSYPKrrWtF
+					TbmSkewgiwMcSjBBn71KXvglYeq8EK9o6X1o
+					VrMIF0kHnZljfhzpLNO5PaURhaE= )
+test.non-terminal.d42.example.com. 86400 IN DNAME d43.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MRSJ050jY2e0PLYWyaqz4dO8Q/iwP6ba8pMI
+					bAhM8Uk1JNOrUTcDVU1wLsO/kpImRJ6Xzs/v
+					zmiFM5DocAN682b3U1tT4AHOLcerYTEGlpkW
+					SLjp1pAF385dXIAnCv+rtXCMfyPC+YgpxMzB
+					SXTisFNd8F5e3u6aUqPedbwQmyY= )
+			3600	NSEC	d43.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					rmP0fij7DUJPiaMF6ZkItdAGUNa1FtVp4vyk
+					MpRXS+MttP7RZXZ45lGMEs+ymukukQOB7mV/
+					ZEja7C2Z+fo/QGHwskxI8aASMRySE6vjfYvV
+					YdSoXVEWBXMkemw71UOn0Oys8xl2iVEnqovq
+					ml7/XVe9Bs71nDzIHnucqU1/57U= )
+d43.example.com.	86400	IN DNAME d44.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CD2maM1SqIdNxtcGjc9kToOkRq72ixZQcjJC
+					Ru/+Q8eo13KM6Lm6+kDFQ8HysPxht3eqrA2J
+					G/JW/Xn5g1y4DBlGcae29NQ8D4iH+noSarbm
+					N9ISn08BaNLPv5OeehUKaOg7Nr84iJiZRQ+I
+					wk94NH9WdZ4/Nruj0iyebJlPr6w= )
+			3600	NSEC	test.non-terminal.d43.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iXuTUyGAg/HMX1oxcTKlABI7bzNg3/t/LMHE
+					z3eK9K9f2CgOIijVVrvtLxARAzTMT/XGK/Pn
+					dluny/mOBft371a/PdTybtLOkcE7/WpQrMmY
+					GhR1a8soX4LPNV5G0+jfI45P1067+5578Jgf
+					jXG5hxRCzs2jB0bd3fhCTR0peK4= )
+test.non-terminal.d39.example.com. 86400 IN DNAME d40.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					LipatlHHUbS8rIX8ebq9YxSTmjzkMcMuy8VQ
+					uzCsZJqJAMJErVmu5Dg/ru705ZDyuzpd4tq1
+					UaES2xEhyK1eLrPv2uCNNlRFjikCQVBHrpI9
+					cgMuycS9F0nDwVTchmonKkj+kPoQ34CbDFnq
+					6DDUjm/2SPm5bF+qjCkV5IbO800= )
+			3600	NSEC	d4.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					bzj705cPqlP13E8HzF9sXJAfFS4lFL4D0+Nh
+					DRHFt0BrTHYD6bIqtJmHs0CmMOr2FprPKdX2
+					bY7p/Cv8qiVQnItaunfHXh67Fx4GTzYg+ejC
+					CY/wx3tFtKmTI0ia/cNYAZ3NT0NHWziPYGxQ
+					4i3geIjS6z61D8o3iCp7N3qKSQk= )
+d4.example.com.		86400	IN DNAME d5.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					LZHOm4LZy2va6O3JRX/BtA8JQWk4G4qta1kF
+					SgY4dXycWGor7o9GYL+GKN7NCFvdLn1cpQ1X
+					RlAerWa6biCX8cwpBssCRqrwupQRoekv1hbw
+					LC3j/knlyqO0BkvQN2PExdQRJ5QS2V4maAGU
+					kDIPFy79GAJQ93QlDT/zifUxbvQ= )
+			3600	NSEC	test.non-terminal.d4.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					s1b5b/MYKL4vxdg5RUvf5/jWottjvPclybpS
+					zpin/ipti7UZuh8d1NNyQZ8J9jlcVxtsrBZh
+					LxUWNdOmEXVbYIdMy9OT7Ifve/HCHGZUIR/b
+					xLT5edj5gWbo1FBWsOQP5o8iMGcvxYXxEytB
+					DG9xU+8hxwY3rFi9E/fnTCTpCXM= )
+test.non-terminal.d44.example.com. 86400 IN DNAME d45.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					cNiTpXMKvquXDgxXLi5jat7z7ZBCipMRx5Wg
+					BOv30kuPnhi5410N8oe9yafxdp9ad5SJaaUs
+					3Sja0LNr3DdP5OnZJwjRieNLSrOnnfW9IlVn
+					AEXV534mK0uWd8tVKkPfqGhYm5E9+VEMBJmS
+					P+mxUV9qN4Nfi5uKxsvsGP/X2QI= )
+			3600	NSEC	d45.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Z6B+6qoJby9830kXX0Ipb2YG0x/DPh5cT4iW
+					SkrW5HfQblP3EyC9jz+hfbb6ykU1hG2Uwebe
+					Rnh8s5KgQy1/QxjGMEQ/6X02whf2Av+U5LCy
+					7M+zSKkh7hZOdOznIjz1mku+BI/rX9yC01Ub
+					PMZNNWxR8BOrASwp+6N9tnZHRYQ= )
+d45.example.com.	86400	IN DNAME d46.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					jHb09ju0HWTRdI9jAAiL7UOlQYO0svjOysGy
+					P8qHc/XStyVhstIi2tSMUUPZpeFlgJ61iiC9
+					c90OQNMveAgtSkbKaQ1r4cMaY7gVeHJuPIw7
+					mVxpF+n2B7xAWvvANt59rW5BTN/bV6UatVko
+					mdPFYuDvTlWhf6IvcYDqfsUSfPk= )
+			3600	NSEC	test.non-terminal.d45.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ihkftxAsQSjHaDWKofsXfZ1vZl/oPixqUTTx
+					KJST/31O/47trPvgx6G2LSOpEgsy2JbEmC34
+					yy8hfQef4JylZ2b6mcyov/AhNC6PI8WGvAMI
+					9z/GI+4x1uXu+Rgs7cjoAdaUnFOocvUj5W9X
+					i9VwC3mHSNmy6ClEZP9/79Z/eXU= )
+test.non-terminal.d45.example.com. 86400 IN DNAME d46.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xUxK0dYE031R1BCgI6228gsDBNPstInJX8NW
+					MaAtbTGAvvf+D0XMFIWu4r5NVp3BvEnHeLzN
+					fGzFFqcQiQRBe+GF7mVVjqARRe1gWM0ROcqK
+					GGZFa/05+Bes1sSXnxbMYm4qX5KjaedbQL6z
+					CtAM7U3ToR8g4bue3G+VHPvlSgo= )
+			3600	NSEC	d46.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SjJK8JkHuqV/a9lehj6bgogqLcBu50PqW3+X
+					2F0TvvJOsEo9pWPMuyqaAiqHQpXUPsBm6fAZ
+					EMQWBN7T+tmImuaRgF7IXraUyGAst6TmO+L+
+					Vb+KwlYI+FujaQ/oFAk6yp6HnVYKMqV4ShOq
+					2r/UB8WuN82ul5rNNz/h/pCUD2c= )
+d46.example.com.	86400	IN DNAME d47.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					XoBrzFfsxIpgxA1nOaNxYIOySa3spCUJ5H17
+					1utUO0op9BgzdYEvehRIkBJjplv4oFHVcsJs
+					jCboFbv3tMCkj9A/Higx55xfNbHRNcmJbeJu
+					oi4ziXjUfSEqy9o3ldjgyUKY/BJIPzWo3O6r
+					p5Gfp9eMOnU3Q3hzsEV23Ifx94E= )
+			3600	NSEC	test.non-terminal.d46.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ZVeXqVWde/EPyuz1Z2SAbPOr1ZltIlH066p9
+					4PpYMzpTOzRqOstifzv3+LFMXCFKVLV7qHTv
+					jhs6F60VlvNUepcyRRuqkqXnyrP8Zh2Y6k6p
+					qG347nHdxWpg8PKEV7RhMFItBeMph2mj8b/k
+					CH37VhfjjRuXT4sxGY/gCa2G3es= )
+test.non-terminal.d46.example.com. 86400 IN DNAME d47.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					V6C/pyQIUWDpqI6+MidAIFN29TLDte8VgvHL
+					NKWYiDO/rxL+GFwOo+or5LgMQcQCJ3/Ld69v
+					9yAgzZ4VXjFR1M9/AwBo/GdEgrEvDoP4/+s2
+					F42+JychSrlnBT4Pakb/1zXyEVIKjrvMo+bo
+					Pgc4cCLG023N+gUB2MDehLYTFWs= )
+			3600	NSEC	d47.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					IvZpHSWiTu5qRMoqnRxOQahb8v8HJ0VQVxu7
+					moqeOaVHI5LMpuH9nUo/rjLhAj/7NdTsXhJN
+					3qAoB8NMilH8bYENG4F/RmptFzOgNaNk77X2
+					N4C3YTDiRfE5k/6atFX46cl2kR6gIqE+F1jk
+					8x4xihPr8bOl6oYfPF1nmVRI19o= )
+d47.example.com.	86400	IN DNAME d48.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xixHWa5CeM1lQa4R03whZvcZgoNZcwby2wuq
+					ACK754tpdnMbqjWqe4ZFASLZFmSVgWxfNhUJ
+					od0mOng+z9WFLY4DtHcNNV6BQ7NlxStEVTut
+					laA20fOiHd3iks4JZ43VeH3I2fi80sPN54NU
+					1MVkEkaYZ1HJxLC4KVR+fWpBics= )
+			3600	NSEC	test.non-terminal.d47.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iqG00wlMWWmZ5tov00IuECsekiI1EQjPV1PX
+					/wrwXdUseDKRLPH5kIXi+OvyMzXX1X9AcCpX
+					VV18vEHJWWcrZu4Kfir3w1oen9KIMdZW7X6V
+					7Mwj+7Vlh0DCBQRxg8diQFjpvrY9imgaou6b
+					aVEM4+Q1MBFcD2423lYPoVZlNLw= )
+test.non-terminal.d43.example.com. 86400 IN DNAME d44.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					I0oUhQ4wgHV7a2epnQBs06nXHcqiUz6G5NIX
+					wSlT6PN9ThHEn0HFqT7V/LQMGx8JIN8/1Yw2
+					Q5u3ZE3p2xrKjv81ruqCzNZLENsBCH43+DqY
+					0SYIQbtmugmLfmTgSXU/MMP4ztY8VGW+qo2h
+					pgHxz39cq46HcsbGj++mAVip0kQ= )
+			3600	NSEC	d44.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					rIa5atSObcXoXVmVYyuklbJK+IOU8GftEjrt
+					dbTPjk4T9DxIWuPRbKpKT/XHDLNbzo8aFRLU
+					hXGDaFmzngPZwv3Wud1zkZq/ns4ZQTlfrbUI
+					dwapcU16HWHAwGWMtpIruqu8xPh0LMcGadl1
+					yEjA+q0axbLcv0RyfnmDlw/XIYI= )
+d44.example.com.	86400	IN DNAME d45.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					yqPQHJ9Yr663aXtjK85RGBwHcGNnHH9lenLV
+					GmBF3ZoRLqJrJ0A49z5GUyCg3qYeHKxq+66E
+					Z2pTrojdrlagHLJlDBb71glOLVcm3a+37/Hk
+					6kn83JYYb92f7zyqZpPfIn7iYJ+qIHiJtksM
+					QIc+R8jLNGxBl2E1nMnbo2wgP1Y= )
+			3600	NSEC	test.non-terminal.d44.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EGZreUf5MT0iZ0CNg7TCp3Y/pIbKuhh9qxol
+					tgid9AZjULjbVpAXE0BZ/jcE1AcafnloqtuK
+					acDy2knb+cgnEzMh2cnX1EdQzEHcK3l0t8gQ
+					e7OiNNoPqC8PxAPB7b6lkABdZ4+7S3so6mbB
+					UyqVmU1SjSV6VEr8FqbXBGNbNEw= )
+test.non-terminal.d48.example.com. 86400 IN DNAME d49.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FDdsMgd3r/K0KejqZiwPG1VpaXsL7oQ19AH6
+					X0KACB0eTD5LBjnsxsZXmEXfhn12aTSAUmks
+					cQWlUfhgSURi465V65PaQUjJ7K6bT2pKw/xC
+					LXLEN51ayOVpMCb7mOXclqK8x0384d7Ydoj1
+					Tznde21GMw3KfAQLxU/u8IdGDC0= )
+			3600	NSEC	d49.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PPToUHTj59/4gaW/e75WdBnu2eTEsmjlAhwF
+					qYSAp/8KtxHgWi2pT2ieCnP/cmTjf+DwznUp
+					Wtjwbas7em70yRghkVlBxc0hOvwnY83JWkCY
+					xtQqHFyi1zjLv7xNFwklQVMuuOXXNZewgXhi
+					NfGj6OI6hSXYrN67ha+oZp9Svfw= )
+d49.example.com.	86400	IN DNAME d50.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					NGeU91ToYc/kcz30H1EyQPxUvGGIEqTMdbQN
+					ke8xZkcQFrN83pU1ticZb4kGIsM7FtD5jIIT
+					dL4mNIccp1n2ZHWj6f+8v/rUY3UoZHUEElQj
+					j2WJjWyiQ/RCeniXPouJhTBUJJSobS7Yv1B3
+					rdMJCS+xD1y9EUm7TqjfQ/gTvRs= )
+			3600	NSEC	test.non-terminal.d49.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					qVvvc33dbxJckhXaK8iS2wR0jyxenN0v+HQ0
+					JuM0abF2jO9PC+ii/as+nlJqx5i2JpbEfcpo
+					qbHaVIjk2fmJ0bpXzInqy8FIYx5Ecj0gvvOL
+					udoaw1uQyjbDuld5YS6Gp+6A0zjJEv1rM2T9
+					llhJqDNM2B4q0YUrlXT0Iq4885o= )
+test.non-terminal.d49.example.com. 86400 IN DNAME d50.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					zFySwAcqUfxAT8EjN/zyvX4MLYegRedzOEmD
+					PJ3WLeS7+Cf1adj+pnVngtU3b2O+n6qD1idx
+					Jk9/2hhs6QfdXh41M5+CmSHWmBOB4ZolJZaH
+					7LbGboddB7Pgg5ii7aI5PestuIlxti0bDni4
+					CT9y5NuSDkh0ZLANu87nPgyvFHk= )
+			3600	NSEC	d5.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					HrjH1Sls23W70YGVTC+oArCIolJJnkdXwmpd
+					mFIvA5DcxxXHL1Ts4VrN4basf+V2JO9Z+qJK
+					OwxzyqZNQ6RaAKfdMyi5r1KtXOiwXv2CT4OC
+					zkiwJ0LIPM/LfY1XYWfuscfwxTf9P0Ykno+f
+					/k6KRafBrVwW1FfsbvIXWk0KbFQ= )
+d5.example.com.		86400	IN CNAME d4.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					P27Ws10dDQwqUBOvgj35x+oiTRbeb66Bpm8h
+					nh0EX2ggiAThkXRivtUpq0YGoalowF6JeFbh
+					kwTlnLUkap7Si2fLl8oEWfXtjnn3nKfiwaT5
+					dsgtBr5SRnW11r9KmSPG8L0epZLrx1JErpKf
+					2GeJ7DBRCV898dMBYZ0SzP7Hm3I= )
+			3600	NSEC	test.non-terminal.d5.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					yOkGOgkwjs2N+CjTu/wXW4UfEReQrlljcGFQ
+					IwzPykpswEIcRwNTzDEon2pVNjkPVWR9KrYS
+					3pDMAC/mJ1AMRdpeYBa+V3gXYLHr4gRbn/+Z
+					g5YlPvOapiJzQ6fpSaH23wRzJUlQ3YBjCCE4
+					yLfBfoFWa/XFkqPJRxZn9oTv6fw= )
+test.non-terminal.d5.example.com. 86400	IN CNAME d4.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					IKorGneADWlr8jw1na29kWTMKsLt5DEHkLV8
+					rKr/uJQyOL95NFjpK+TAdcMq9Hpz5GGdyyOP
+					LT1fgGkwQCwWI+PS3+0LGBbqhHU8KQ5FAhOP
+					62Dmnw/ZUkdGuyZAM0PgkPH7VSnChS2asa//
+					qiEM6+mkIAvRLo9PAqDTJoG2Z4Q= )
+			3600	NSEC	www.d5.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					fsiK64ApthpuFVaGIDfA+IZB+B7W6hESuNgv
+					lOybm0u1ErUP3GjbdbzGy02P82/pHbyRgDr9
+					8lguywf+/otpRqiXvryZ1zl+dJG6SY/oIAEu
+					vssgVAwaYg27k8URhth1t++7H2O2cPQFdLj9
+					LT8wGBqCiMM/zju2tlvfsvL88pM= )
+www.d5.example.com.	86400	IN A	192.168.1.6
+			86400	RRSIG	A 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					vULD1Jbi59Qxhz03ulRXo80nB0txjAqC271K
+					5wD/Rz8/6o3OtnM0F+ur7IIKJJQexl12HddX
+					sl+b55HZhfuLwerz9ogoSTIqaLZhWr/6kiDD
+					W64amx9Q8LModApfqhJtIwXIafAbYB9PvJiQ
+					vzG3On291i6e6vKFZlboEJrgh9s= )
+			3600	NSEC	test.non-terminal.www.d5.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pecgp2ophbepdqcJs9nBnFBPh8Tkatu9SPq4
+					9HAIC67BLvbWA5PvL6fWa8gWhc38pw3pcIYP
+					Xyy4UIkfQ5VB9X111xCx4IKPbLu2a5oAcM9/
+					DbhPEvica24qm3oPQ9BOK/kgtgIlHKxzxkCR
+					/X98KIc+AEtBmOgrVxZaxmoTKbU= )
+test.non-terminal.www.d5.example.com. 86400 IN A 192.168.1.6
+			86400	RRSIG	A 5 6 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pgSJ/3TEinAqRRnYar7+7t3Hka00MnAEHTlO
+					GH9Wei52rUwMfvWJ8CG1kDKIEJXNm5ySMkYO
+					3m0MAhfXgFzJB1e+SxDMDh7cM4ZWQH0QEL9o
+					HxvaWRo6w5hDuNhHvvX3F5Wcv69w+yCZmEiK
+					gZH/DXwsvPdhBKvCVUhV2Enkr/A= )
+			3600	NSEC	d50.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 6 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					L1V09ZExCtlcPEZ6Udz1Md/T2liWu0BH2cCO
+					SJCcV4hjsQx4gZ0487lDp1L2+AB7SVImpU0N
+					5uqf0mG/j7fSdtYOfcTuYxasTHN0SY8icv9v
+					nZzz+IZc/RHLWVopF87yqD3JeWpdyOABHfVe
+					0Or8sNWsEBwO0R6E0xZOckKZhYc= )
+test.non-terminal.d47.example.com. 86400 IN DNAME d48.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					APHibTalIK/3/jQ4N3rw2P65yx/8lPb8V5zo
+					CAQCj5W/dHiuZ6Pu1SQ8Z2qEoEsw37rEzJ1s
+					EHWNxua2aGh0pxaeLcT7Zjta8ZYkGMuKUniq
+					4l54AaYYH4bBvdeKVTMTdMk+GML1sMx8YlWX
+					53a9qrohmSLw2O5gs+5JsYr9JwI= )
+			3600	NSEC	d48.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					eTUXVw920hwLFlxNJfzIZxbSG28/LRZ/tSm/
+					4F+PLW0CthEqxV1INI472E4+FL2C/zc5hhLi
+					oSK8ZNlXK9r57oCYNAWzba9GdtNWERAtQl9f
+					OdvvdRfn0rN2QXh4Up8CXvfeEWV5AMjCcXLl
+					0IM7mpva55YbY0bAIKr2OOOFsXg= )
+d48.example.com.	86400	IN DNAME d49.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					graqGvlYjOAhU6i6T1nds4DyOiJAmbW0G2kh
+					oXE1f8rGZd5BoiVED27aIdqP5351Tb0PvAj9
+					IW7BhFVySiwHs9GZ5OAAj6vjW6DFYTlmdc4Y
+					GMTsEOlyKLGFCGTh/XepTLuWmIi4+LBuQeUK
+					c2kr0Ed/qKv1OJoCGnh0VUH6aho= )
+			3600	NSEC	test.non-terminal.d48.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PxepWNMME35o1ChOQhQDt89YLWwLak8F3rq4
+					iRWnbIgmN/N/SRf8rksQdkCiV5w++OLqTtl0
+					yjK5Isv87r79WFwxInxCA0lKJagbO2udW05p
+					K61l3TE5Qtxtt+ByfZv5vBezFR0CKUBVGBfs
+					FV7K1R8LfAhzS0CbyfNwmEiuQlo= )
+d51.example.com.	86400	IN DNAME d52.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ob7SvAUXVsIZER3zbqaWDr+3cvglyQrshVTJ
+					e/zpf+qkxLrQ/xuspUrN4u69AIGBh8V8EQub
+					q1BwSIP8fSYweIdE5Vr8NZ2T4pT0H1qkZWgZ
+					ulB1N9eGlBw/93GZQ4ol7s3AINgVcWTo2UR/
+					zA0G/GgSJDn9W5DmS+JWM6+Mki4= )
+			3600	NSEC	test.non-terminal.d51.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					ukD2EC5ZSNIjqi+K27LKR5O3JFGK7Q192TxH
+					8wQpCN8mBs5WbBdUcYoCbww3cF8MYEqF71/i
+					XKlAfZ90v0epp637aYIyCP3h4jo0cAUB3WSo
+					RlWpEEDoQKELaC54a7Igg9Fl5ppsK7JuA9KN
+					dgpolGwcDI8SGScSlBjKnEa9c+Q= )
+test.non-terminal.d51.example.com. 86400 IN DNAME d52.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OHeLvB8FdcnIGHv10dwFvOygb/h950MtdpIZ
+					Qzd6UNAnuyhYfhcL430ve0B0NqDYUlyE+J8l
+					PFEcRbaXOHS9phNud49FqL2z2kxiRUzljH3L
+					YWYKKRCuIyiIVLcD/7N68dbhIh2w/DxoLDlT
+					Gl9Bt4sIqibKqLZvWCVlPhVUmkk= )
+			3600	NSEC	d52.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					l7KlwFlFAHjkfRS1xknFqZyFS5rQvZUfsAP6
+					8SY6yHJ7uf8ObMwn5vnFNZmlU9lKuMoqrO3D
+					u6Rj+gTkYixs9h8+yWCuxa05CzpF4dBBqMQ5
+					acNoEPXdKjX9VNXNwQY1BQ6hj68nbTtB4sxm
+					nLuXPDhYJt1hRto4b5oNjEp8LTo= )
+d52.example.com.	86400	IN DNAME d53.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pwTKX029yQ2Ds3kewJVumKJepAvBDCPg16In
+					xYY0c39EMn9M7KfnWcKwRIyi/6jwFH33ngRw
+					MldxPtyC0BrTxMU/3g8fbQwa4+td1RzXoqyh
+					P/TRyMYuZqg7pRvd3ZvFNE+BmLIK6Nl1tTu+
+					/5U55WiMTIFMLNBk4rszGI/yDek= )
+			3600	NSEC	test.non-terminal.d52.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					R3PUeC7YLueyfxokG213cfGUdOxH1GYv0Xtc
+					grLW9vGWWZPqbk+ihl2iFL4FnCGkxz844O9x
+					9p40HblMFbP5m/ZMvfXkT7fRvO8I8JAlV8v1
+					xsE4pQZdfPm2qFjHBIweFekZ7xgcfGWK8m4s
+					qICF2jGxzTS60b9hVxl9hn2h+LY= )
+test.non-terminal.d52.example.com. 86400 IN DNAME d53.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FKwgRwy3//wjuTOO38IJQzVX4QA7TKc7soDV
+					aGhLAzV/iJgvOqDR3aUWp2FkvXBZmFKz/uYr
+					0ktN1L254Ld0yON8fGpb22nxiTjTjZ6VUn6f
+					OdPGHWQXWD0JkyVzopHbHZHvFFpn91ZiSb/9
+					3OKrzWhd9amcnmYg4qAMtTbV7E8= )
+			3600	NSEC	d53.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					JtQfr/5qedGto/KadEIT956iI1MX6ThkTjMF
+					e09HJj/DDJx+N7oLUhdtpq+pDOobldHBGpvv
+					aiOmkQZrUt1eruLfhmbN1LnqerBXT+SzOKt8
+					6SdXdyQv2FCRu6dzRxSgXbkdoxObWeZXrVMf
+					4/jC6IiQF9V7EVQL0XoMULHOlYk= )
+d53.example.com.	86400	IN DNAME d54.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wxWrxE4uGjPL1/qXJCoAf2Ya2ovHw0gDjEHZ
+					BnLwQ4FmCK0aa1OCg9WWLkWTaFHJWgo7+YeV
+					ksPSFfwJ14Lv9UG75mxgRyEs7HKYtsyfn5+x
+					8Kl3F3/w7lTkr8kyh2iuPPPBIEjH0CdzcNV/
+					B/pyyJS/Tw9Ep9CrCJeXIJU3hLc= )
+			3600	NSEC	test.non-terminal.d53.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tulemDQTMeBxeNlTmhl+iQ5277c+lmqlt1UA
+					HfvP0FYE/JIyDQ0EeYMZm6G4MiYAFipJkiSb
+					d1aE3nUqVqB5DyxAboUSVavr876HPaSaHmH1
+					tbHayHu+EOIlAoNp/TRysbtA088x9oEBNMzl
+					CMcFSwTqeIM/+sHYYFv20NIDrP8= )
+test.non-terminal.d53.example.com. 86400 IN DNAME d54.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Av/rhbzcoT5NMBy+W5gC42TGQACIfID+v2zR
+					2AS34F0YctsV8nRqUweDc29neHertB5QavCR
+					cYOcjoq8FRU2Fv0nA2dq2sV29FOlbemSuIjk
+					mRurIyLQvYsM10X0XyIbspiE0WGUd/whY89R
+					xq5tV4d63bgScmPMThWkh2zrKT0= )
+			3600	NSEC	d54.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					jMjBoTAENoFkGGVC4ZYIwCB/B17yiFI/PGkP
+					PlAc6FqXAuJv5s4ANZ1ivmRC2S7xfoFhWcRa
+					Wi+rYsFA4HCXtd4XojYeF51mvwf1MJM3QKir
+					JIPxJmDriQzMlIPrA792GXbxy/eHm31JKOff
+					4Lg6xBRrarbjGbLn52Wv6Qx9Upw= )
+d54.example.com.	86400	IN DNAME d55.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					tLcB809dF0SzNNkTDxQi2yUUvGKLLx80cylQ
+					2Q+LQE0thrKWEtzoUhp7dojgyTLuZom0ZGOL
+					st91bI18DujPydi4UZuXI0n0z81uXrP9Jr6T
+					ks0MwWJWnavrZxqxMootxjB/2YMi8vCunKTe
+					YRotKTTfVh35OQATrmD/ixjfrzY= )
+			3600	NSEC	test.non-terminal.d54.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					R37llTMvvIym9/JyvIyndMruAaY7tYiAIADP
+					dx3xLb8tOd716299yCNWvjXb/1DROrRt9GD7
+					ZW23R7wVzsd+MIhmtM65z0JvhZaqSDwigW3V
+					r2MQmgwrw04PKpabMANu6eNoi6cv/lYbCyTh
+					FrLSwXkqcB1ITuC9r2cX1ab+yEY= )
+test.non-terminal.d54.example.com. 86400 IN DNAME d55.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pJmpKXUwGwF9NVXTj7p0VCFgLBgPy4pFG7+R
+					Az7HiuVWRRhU3GOjE/WlP/4yYrDIHVkKUqIE
+					KqZcB6/H9INvWDDCl5QdFtNn0U+eR1POPLbL
+					QIzGYEBWMnBQyfbAPolXv5vXS+Y4lkpxgq3R
+					6TvxrkY715Y+/XL/JbozYbTuTIE= )
+			3600	NSEC	d55.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					IlnT22tG+kP9KOvuD5BmA9340tK9Dg0SzS7u
+					5hNa0OwkgHmlRkl8QQP+fszXqcV2w5iJXs2a
+					uPXgNYeUa1KPJVLMhjGuxhcQE7QO4htnZj/L
+					YGUvM+TcWSKvsxJJW+pWK8op2/Wryq4ZhxK9
+					rwrzpOpxWsrrM5qdbp3nSBojMKY= )
+d50.example.com.	86400	IN DNAME d51.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					K38j/kWSLO6dlsaj6zjwzAlTyzh+i/vBy9FF
+					6piwjv5C/zTVMD1FJfib8lt59+3XXtHQLY4I
+					k75phzMefkNltxceDjajWizW23J/07pMfYFn
+					tkqaiMAPRAQ9n2IS9YGiE1pXGqUgDyNgguPo
+					u8W8FNXnDeLt4li38LFvA2iXJEg= )
+			3600	NSEC	test.non-terminal.d50.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PPCtzDBJWAfEY8bjbhFkmMFdrPMcOdY5MIgq
+					xKd3inR1G8Dd51NiEAcjHp+Q7mMAyEUMf7n+
+					4l8QjLnbRcBF73PPtOMr7TIX7jzYRYHRXHFT
+					/TJPhy92NmXqc6t2SrWWRB27vyDm91KDxACa
+					hdZFGjRPuHeWCE2OXVZ0F1ylBU0= )
+test.non-terminal.d50.example.com. 86400 IN DNAME d51.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					iBHaBt2XClcxB0nB4zKOinsruncTbD34bWTU
+					lXbKWRzY2muNaht8QrbkOcGp01GviPxexQar
+					oMpYD8ranSChSRDeBBBu6KcUSuAeWT36iRDV
+					8trQAnMkf/pAg+Yto9eDsY1+Xae6Ji2sMWhJ
+					BjjmVKBLmNQVfRqpPABsmKmpnOA= )
+			3600	NSEC	d51.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					cVuYXx64JJdqXvauOdvMUuJqV3mKej/SSmIk
+					LZf1GRFEeRkcfTgsrNMJyJPYAaqSRLg9dX6I
+					rRrV0J47CcAMLmoknYmNYRqLLbDlV2rqfkre
+					msB9xYw1ip/r1kk3Aa7+7+oqcDyFh+UdkvsG
+					8To9CaLe+Z4W/8XT5Ipef2FJP0o= )
+d56.example.com.	86400	IN DNAME d57.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					A5FrHt38MZ7HRVeOk65HFsY1//PGz+OAk17Z
+					g/LGytFcTEF04VHK/V6UthcWmgBr/bTfwwLz
+					MHPQThKv/a9BH1gi+xh0Z78s/Bqz5wYoyvwv
+					xKM4hP1ybXX5+ymVVwQ0mVKHml0KYMZKmSIq
+					o708k4fKUS8R8Da8gOAz3wNiLI8= )
+			3600	NSEC	test.non-terminal.d56.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Z/iyqtyhOATyFDbRwK/2vzwVG/s8wqT/XRC9
+					QPodJbFfR4veh+SNkJJH9vgl1plMpUPFrhr5
+					YZQZIltnh/XB4lknhH2hBbItDZzjntkv4RsZ
+					1QDqveNMgCsJUgO+wcRggALI9evUzHT/6m/w
+					9PyywulEFdV442oTHYRwU+GIabU= )
+test.non-terminal.d56.example.com. 86400 IN DNAME d57.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FzVD7OlhI3F0ucWJpsiNcHSdjgESqsFDOIQl
+					fxMDdAx8dZwAjptkWMd0UFomLViP6XxnN5VR
+					zOa9kFm8tLsuGnThDWX/MJXEhCL3ZUIkQ4Qz
+					OI7rq/S7eJwCRsekvtNLz9t9o+Bdegp4aqAt
+					8IS4j5pHN7UPFJGnWU3+izZ7tis= )
+			3600	NSEC	d57.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					KEtvHe8ziDkahA14gafEjTg3sunGX8ZiwSYy
+					ZzerUSPz5j1yYBhGNN3icENQlPSs8WVeGA7K
+					wDlA8uG0WsqxBeTzIwk+SWrnW7qrOek2zYr7
+					NGIVsnONs86+DarU4i+k2b4WTt356F9YHShN
+					31QGI8dGYnuaSwQ3nvUWfHHCa98= )
+d57.example.com.	86400	IN DNAME d58.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aepXpMXVir5N39tnsWWqa+TBIOL2O3wUGwxM
+					Gf0BKdCLffME8dSsjHDzePx2xqFRXmaO0Fqu
+					02hHcUUS6gr/0QHvwdM3fag9c2JLZD4Ot2sD
+					g3dz2WlkeLDYIiJP7CX+WmtjBRGPIbDM/mMt
+					Gu435xsdUzey6hqAIeCnPRIbV4A= )
+			3600	NSEC	test.non-terminal.d57.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XzgpBHxvhafDE3zHcgI5Lkm8gDmxqWk0IKGt
+					uiewi2Cd1CdflbCBKn+YW6KjWjCcGYc2LNva
+					lzOpL5XNc+2Dx2gp4jlb3VmNXh0oEetvqSRb
+					hjlo5REnuQAHiEQH9a2iQL5HCk4Er/PCIRs3
+					uoqpIU13gCCLdXONdEoxoQ8aQHQ= )
+test.non-terminal.d57.example.com. 86400 IN DNAME d58.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wTn554M8BJc2A9xvTs0/f03p7Zi0wjetuFyN
+					Krlr1eqHxhaKP5xcBKxFBkO/DG2tDK1jlYOI
+					/hY4lxQnT0ucuYl8xkaXKOfitK8dN9iOxGpS
+					qA+EyXZpNQJVvyMYvVwOJoUKKlJRb0V8FcBY
+					oRiZXriPAVqx0+pmRHn7mWcAciA= )
+			3600	NSEC	d58.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AZyh+Ul3lfZQS2sZZtd6QQZWYEPhyfm5ZKpw
+					iXpYww6dgGLsFfxo0NlXM9Ci1WZ5dOtNJN7T
+					F8ZwrDgMESlJ06f2wtfOWSK3CiK4TlTAvEYm
+					dbbvkjCxLOSPQa6NW/x3tHdKqX3oKxm6mQVz
+					CkcBIoXL+O7sWFYgoR5cHO4vAto= )
+d58.example.com.	86400	IN DNAME d59.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					g4KCW7ISDwBggwNDFTV1dQjGd6l2CMBOAMnD
+					B116Aa4VN6en5MO88tDH5KnaUehE40C5Fh5w
+					7s3zrMSnDsIAEKS7Q5WVQzJYW7rCvH+l9uWN
+					ffG++8WK5AF8oS1jmx9Ai9B2r2TKkidaKOfF
+					WQohh582K3klHK8fVkeXfAO4XJA= )
+			3600	NSEC	test.non-terminal.d58.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Hzb6pV53Lgs3UeNl9PQSuK4vXH9Usif+AE3v
+					JUEXMot9sf/Yqj0YQ7bp2fi24CHtHkyJTBqL
+					xr0OWwghDiY1mzzc9f886O1UPRMaVw0yMhix
+					tGPtUrQAmlhxbCEkT+HL1FqS6X5VenRRStgr
+					hhejEInXnKcJvz/mu8X5iAybVyU= )
+test.non-terminal.d58.example.com. 86400 IN DNAME d59.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					RKs5QfnSUcAXKCRJ8cQwmzJGZQ4Fww9vwngJ
+					6h4B1xDJ/XIchmupkI9ZyxOCcPNNwvI76Xmw
+					9zJCiDzRc3vvleWmZ+WMntDzwn1LFGRgoS1z
+					qrol5HuJbnmLXFLHzDIi6xKdHhA9OH8pmMDf
+					VURAjLRl2vHd0uA+mG9VGWU192o= )
+			3600	NSEC	d59.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pYVsbpS4N+m3AM2IjGVnEhaCyeW9PJKysg+g
+					CAar16agqOBZAFEQ9imO9u3zLYL68aS+X5B8
+					cjibKkux4jynHN979m0lZZKFXlxmuGRd2Hlk
+					EkbWW9a7nay8Rw9enNTk38vTX3MNcaNtufdc
+					FTHqnDIFzRm+DUvU74kfT7SC2y4= )
+d59.example.com.	86400	IN DNAME d60.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HV77cJwpdWFAisXOgbIkS5iTQ/j0QFspwE8K
+					mpVT/VVgXFVJHcD4WQLnshNUFPtVE+TTEdWG
+					jj5iNZtNH7nnZMH8GxhXIAGdZLRIilTSlxuF
+					mQVoE2arlQ0MVjUKTWkJPTmlQtPAIPJMydJz
+					2h4cW+gv8qbKjG8xe90lpN3ijVs= )
+			3600	NSEC	test.non-terminal.d59.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wFxN38pgrGqoslSEI+p3oPvdMbP38YKekQSX
+					YCazFjuxyYQDpA+Q0EA1vZBvGEHy0VmlO0AS
+					IwHlN+DzuAWLqDi2sfIY/9vJkBHmRhs5KDV6
+					yQUELyH09q/0Nn3IHdz4PKLLN9NWKdwVdnvR
+					3ZC/7OVPVyqMJk8ZxIVrUH9YSfE= )
+d55.example.com.	86400	IN DNAME d56.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					IiWLmG2Qz+QqrPwbd+PEXQcaupEmJSVE+AaI
+					sQFDdbAj9X6oQoKVwRMj7DFhWr2AlVotAfo+
+					UmQAH1hvTjqFS2gDi2Y3iKVQyQJ/2y8Htvze
+					xmvhdL6j5PjuZPEHQpJ2lZs7BDhuJj77Ydcw
+					oKPedUcHfIbX7LQY372oGiPpYZU= )
+			3600	NSEC	test.non-terminal.d55.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xyV3SO1yg1FpRzB0l+tCOOlQo7JjJOIOFFyl
+					Ee1JIox27pDz7zRFjDg3/YWQ2KeKJx9noxOy
+					xaBdcpKrj4OUnmUFKU6NfH+fd6Kbq389+Xa+
+					fyPdGZRwjv7bVuP/neO5phkGUWwJ/kWHM7dx
+					XnkqZtKiMQNfWFRWiq6E2Jn+Iyc= )
+test.non-terminal.d55.example.com. 86400 IN DNAME d56.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wTyWA8Zw2epn77Z/T/Oien5kGWld9yj4GnQX
+					uHDC5BbE6nwl/iOQIThVSfX44eUDQ6ZaFtP/
+					jdzQfAmjj00CZ9MNkMVO0OTvytIJn9m8n+Lz
+					Hllr3trcuRR5fXkLi/76f2bOW60Xa5vmBp4+
+					Y+G8r09NHh+8lsVrTlcodMyAF5I= )
+			3600	NSEC	d56.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					qlY1jFfkXadSPnSaFVGWH65YrjE2WkrVpt4u
+					taX76HBaJLXiZ6NZd1srPss7LI8m9nRW3gKS
+					s8BFjZfJ7tqYLXW2vLekYHBlKWd4A6VLTW/h
+					uxN1Pni8hPrSQPi88VVEymbsE+NqE2g4E6pi
+					euwOTylhs+oDvqMbNMNTjGpUtDI= )
+test.non-terminal.d70.example.com. 86400 IN DNAME dicarl.cnnic.cn.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					sJOusae4Tsw5x4toPAZaqoWO0l3LxNJUIoQc
+					cYeLVCdVNvqLMOzu0HpuV9H3RLHvp8vjBJBD
+					vB39ujHG5YBLRzV7Bllzy+2l69OrmmNhAo9g
+					sdz/7PhPCUkc/tedDrpCDUqmvA4LOE6OmF4i
+					zWUyC3701nIgp/8bDg5bQqCZSls= )
+			3600	NSEC	d72.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					HzbLK6MfElgWNL1klvwyL5Rezwx1JmKNfkBJ
+					tGT4xFwV/l1hNzx3MmcOgdI9vc8vw84RXPYq
+					vlCvfLt8HCtZmpULDxrTcK4+hzc9Rwd6sk2x
+					2ZF7Z9oZFfND0o04qfBQummdTaU34YH/gzlS
+					xWiAFiy2LLe7YiSPEDLuBcHtjas= )
+d72.example.com.	86400	IN DNAME sub01.d72.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oQsloDjou9E1NRfVb49eHUuKtsehFiUu/Uxw
+					AUoojfDtVWf1JgRpZv+Uh0EQyjky7U0+MmGK
+					Jio+9ws9Ek3oCJIdDVScdfg4EUHANcCt99Uu
+					ggRqr7VwBXiYz/vnAL2/7qJ9H+IajKwFZxUm
+					k3TUE8rItUT67+GbgjSvgacQTbs= )
+			3600	NSEC	test.non-terminal.d72.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					BzbybR57RmDRyn4oie1kfGuyX/AWGhCVqKLJ
+					iI09oGeR8qxaah1wnEt8J53nqTDA9u1nG2R5
+					XNEa8k9GPjuqHsVl7uI4+/2bAc4rSaU7KA54
+					EmeWw/5J/BZy2JBH3Fbao4eO6k70r+3DcxCV
+					5Gg5Z4CSuEEnB0G+hHpYgiBojX8= )
+test.non-terminal.d72.example.com. 86400 IN DNAME sub01.d72.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					mTtEj+B0PvJH4o3sUvL9pWMXo7n5Kq1nTB99
+					0trN+F1So91BjrGDznv/dZ7nkv+8QovFuyyL
+					QgKtl4hQFqaNaC73SpkChlAdKQO78JPE/N/s
+					vabju8PLRd2fYRk8C9qBGqF6bfxhvQgwtMa+
+					RpFDWytdzzbYeftcLK1O9Jfg8C0= )
+			3600	NSEC	NS2.demo.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					JUrLP2PHy3QHGcOTajs1lES2bVh1674iREdS
+					lWUPV77GIFycVPQnCrh69aEf3W/7Z3ih30sd
+					mAxRaKQRSVpofa9mOY8m6hIN8lF+fLFj+RNK
+					EKc2rn/jlYZAIIA0W0T5x2mKsNFMsCjxjwHJ
+					udsQ11DSbfrKhEiZZsd/fdAQHPU= )
+NS2.demo.example.com.	86400	IN A	218.241.108.15
+			86400	RRSIG	A 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					gEBkB1vm7CjYdB866+lGSyIRuwxiErInV4k4
+					Kpa7iJvyK4aJ2K9vqoG1wiralDK9HoeksKI7
+					6/80+p1QSkqbeCz2ehrj5qxDvh+afQnWzh1p
+					Ah6/nZipnGT7ZZcxlYKXCVosStpwT+yvX90x
+					Qp1uKeXBGQIS3doSO5Lxnhc8I9E= )
+			3600	NSEC	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					yhhP5MbObZRTlDKhvX85VX/1ca88R7yPUaJk
+					6aiugigneW/uMi1ZjjVm/aoLufHhQYbcEJ+1
+					IeQW3xGDNl01dFfwZETizQoqOzpsQ/PtNYbE
+					Y3BaMYvGtUi2+JxPDkbTicRX1Xz1P++u3dQh
+					rPvHd0uHQtWMM1/cOAkd32/BxTM= )
+NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com. 86400 IN NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com.
+			3600	NSEC	N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com. NS RRSIG NSEC
+			3600	RRSIG	NSEC 5 7 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					efX0JgQvcHgH7Fh76nqS04/6f7i5Grz1p7lH
+					6YeEyZyjl+v2r7ym7kdyp+kUg9Dbbv6RO2pl
+					juSFb3x2WNt4k4poUH3zveDY005N5teX93KT
+					Cklu2bw0fkJ8imo8hpNNvClp4TDXcCCDR/jP
+					2hSBXnzA+AC1l8bkuMdyGsGnksM= )
+ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com. 86400 IN	A 192.168.2.2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com. 86400 IN DNAME sub3.cnnic.cn.
+			86400	RRSIG	DNAME 5 7 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Pkj+vbKUhB3wDl/k2vnC63u3RCtPymJuy8PV
+					JLaNEQjf6svjS393FKrH4xvJjP78RnWeVYsd
+					um+wC5iOgYQEvyguZd3LwbzjkED8se2Sr29J
+					tGnHiKu6iNKCnjQBSz+G2IoL33vofuzAK9Dx
+					KXAIU7kDjcdpA7rOO/qouzG+Rtg= )
+			3600	NSEC	NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 7 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xU36WQo+z1lj4DeMxU/kkzlVNvTEO56NiCrT
+					wI/eBiDTa/scpXsAgLjkDK98eR3sPDSbYJor
+					22efGHKL3r7HE0JXgXg3QqaTtHYRx4aHVMvB
+					ui3BEgB7M6/fzq7M5a7NNsqm9bTzQ4kFkFWA
+					alN9kSbWRqZeTVY+WnH1cWHhKsk= )
+ns1.N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com. 86400 IN	A 192.168.2.3
+N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com. 86400 IN NS ns1.N.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.G.H.I.J.K.L.M.example.com.
+			3600	NSEC	mail.example.com. NS RRSIG NSEC
+			3600	RRSIG	NSEC 5 121 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Cvi2ndHGWcwRYdPZTCehM7WmYht+7+ZRyFs6
+					qr51uwvfaSwaepBghslFUx6OaNPlFCx2SH3h
+					Dc3WGKG5L4Vf+diFCbbyQJd9T/ZJ9XLyamJx
+					s70tGx6HCtn5WLSuK8t+ER7mkazaW4wkhyT5
+					5eec49Q+PrVErHs0sTh7QmR3bo0= )
+mail.example.com.	86400	IN A	10.4.0.1
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					E3BIWNPrCMlws0hchvEmK08cxmnk/Sthe6Ha
+					KMTkqSW1GvYqopHNkT306tpznyRPCquz/5Xg
+					fr4h0ME4Ii+Sgdc3cQ3y57FckehktyOSCUv4
+					/eq+4ZNCIU8CEpM3GPif/+6Jw6YJNdo10psi
+					P5BFduWTcf4D2wkArfyeKFX8zf0= )
+			3600	NSEC	test.non-terminal.mail.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ex1fByxHWTiEUvk+SvIHtClMf1tpaLZbBkU0
+					Uvvb6cscstzgBviip+LxNQwvP75DkXIIUu5A
+					YWFIYcFZATQQiUPhXeQxjh50pTRhhyA16Krz
+					urrNuK5asKiAaZqJ9FZ1CfYfgfhAfsUr00SF
+					CV+oaAFLTuzycM56Bs6hhpbQEfg= )
+test.non-terminal.d59.example.com. 86400 IN DNAME d60.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					k2ouJMhtyyV4zQdY5tPxavUC4O/5bhzABxmd
+					2HRsU5rAh9fwQ5dP3pSegTVXnUDaEOAWO3Rz
+					D2OfUsQcJcBwqJk4aM8vjimqFOKuIGy5A6SL
+					ByNjum882LA8c85utl7+dE/F8cdMcIS+mW4U
+					kRJ1M9N54GoYTNFVhNpn+O3lXkg= )
+			3600	NSEC	d70.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					WXa6gm/fCfzC+cCJ4FHLyuph6UmvtBoikli2
+					xDRHwcr7sfIHEPMBsWkSiwSh0ooibDcnxc9b
+					1Q9KMiU63eyVwnYrWa08ZBiNfeGU5MFICoR6
+					t3flIl+7PDQw78pbYm7piiO4gxS2AC7fBn5Y
+					KftJNCWiBVnroQFC+aBZ6lVZQbE= )
+d70.example.com.	86400	IN DNAME dicarl.cnnic.cn.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MEfjKN9rAmiv6FWIBmFRwpyUhlgej/s74oZE
+					nLuniJl5qdiOHLsCM7C7Koo8tYaUlU9k9wsX
+					ARFReBoUQ/E+u9eWUKMzkg2je1bR5mieNVYp
+					3l/xGO79gcLK8sp3fsHxWMeVAw7ec6svCsjm
+					g1ysEcuNN1A8GbAjzyaTeKE1MYI= )
+			3600	NSEC	test.non-terminal.d70.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vzGn9aTaLqQfvuZRf3NP2Q+2lROavGKDkeuc
+					Gzm4/2oGOtv537VRyNh1W5VMA3hooxFMoxf4
+					OCeTaxU0TowduMT33qpxEW5amPZ0H2KpWi94
+					Sks5qX+p17352SlXrUmn1PpUtlw4SiAcTykd
+					IGyk9SyB3EDkoxL19QKB9PwzlVw= )
+test.non-terminal.mail1.example.com. 86400 IN A	10.4.1.1
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					WgbJfoitNOZcm06k+IK+DiJEaSC5G3SYR+k5
+					kyWsovzaB9AKqqzTz4BZHNmEK8MuzBv7fo14
+					6dB4LuR38KdiZsrM1rpE+CaeS/qc3JxihFwT
+					I0MkQTNaYzXaJlVwacFMOFix20e0X4tIe8as
+					iSEui2GAfwLt5zoEsC5Ul9J63Qs= )
+			3600	NSEC	mail10.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					vE0IY559z+QzSelb3Bj7d/jreDH6RpGzM0Yy
+					zJJrvc7apgzCRP7VDya8liZQEpsjRmAsarEm
+					GdZSv0uKrLz0HHBsykDdR7cp3bBg8v9QDtHB
+					RQG4ed2Rpi5B7ycdx6HXEa0n2ZLhZk90D6oZ
+					ytyx77Z+jG7Z/me3RI5TymxAH+E= )
+mail10.example.com.	86400	IN A	10.4.1.10
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					wv7NomK60P/RCdDsS1eUBrtI00kEsu/NJyhJ
+					VJM4HFVrYXOcKjEfl5lXM/fJBv4LlAMhuzFD
+					2MziNeRr4crbzVt6vAYzQq/2CWBZDniiJIKd
+					EakNNliNu1BDVr64lm1gDDs3+a/2hWL2E7XK
+					XeZXphgYquug2L1dtTRbW27G1ZU= )
+			3600	NSEC	test.non-terminal.mail10.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Yc1N7vRqNUhxvcPwS0GnjofDzyGa1h+gHTZz
+					TkG/RYSeDeUz13jXtsVB1/ZhpA94cEn5DR5x
+					3Pi31mr61Zsb1zKI4q3NsbM7vTor32gbzbj8
+					CZHVwMjkpd7AOiPAk14q9iREPjPYCC2+mMD0
+					OcNs6HssNzvC/DrhwRWPwz4nfGw= )
+test.non-terminal.mail10.example.com. 86400 IN A 10.4.1.10
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oBEDA9mWjn4OiB0u1eSerGPp7A5g31dX7bod
+					ieAtEu4C3Lnnrpkcem6iS6XZN2d9D2M7TTO4
+					kYho5fytEHFu5kTfmtWuBirf1DoAV3rcpqY5
+					Sbc8NZE03uJ4jKuTHbNOdLuk8Gr78apm1sB4
+					MC1thf7n62h033OrfcYwwobwBRQ= )
+			3600	NSEC	mail11.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Um60SGEk2RxUQK5GNZ09duBxDi0iTuIslKXa
+					Wi55L5/oHvXR/MM7VqNWnyGmJNBPz7Oqe7V8
+					i7GA+Z/sbkj/Gs7Nnzimf712UlxxpF/rTv23
+					3VZw6/MLw40eIXVFkymOLIeYzt9zb5+53RVh
+					bpPsYviQ1mOCmw2gQ25VNJ9rPHg= )
+mail11.example.com.	86400	IN A	10.4.1.11
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					XaQmxG9oM6lGDSbNNOG73U8NeV/3kdRHHsvF
+					9Ja+sl6phtEY6M8ErMTsxzmWkqxfJ9GvjWdr
+					ivfv8/SjtWiLMZJQhigpruMU916sfK1X06LY
+					NVbUhtVJm5HNhQ2CVKyZFRWbidfXnm7SJFNL
+					1hFGKNWTF/DRlPK0bsEDqG2DhnQ= )
+			3600	NSEC	test.non-terminal.mail11.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					repU5qTAzTYlOJwTesJkEzZrQ1qc4mWVqHf0
+					lNcjzKIoN7aGplQ6SW/MCuJMRfAWWK2HLFse
+					2jXwU8tEDfvr7tuv2CZioN7WuDE7PpjNJzwn
+					sxdaiEBZSWDL9kSacQwyNVwOjL1WMxHSuuRm
+					DzNkWMhC4xNLCFHKrdoEPWk3gj8= )
+test.non-terminal.mail11.example.com. 86400 IN A 10.4.1.11
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					RM30OrGcHqGperkip7zqX/3bGYfdwRIkzgsG
+					Yn3ewcaG1eVmu8peZg86Z+9jljSy26oy8kan
+					9//kn67W9tyBfglj223vVhU4QHlRl7AQxMc5
+					7VDUQj9pHfXh0x3hLo07lwta4H8ednxLFHnN
+					l3GR6bJyPbE/AzXfhIFLiT+SKpI= )
+			3600	NSEC	mail12.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					BbVJnGuGXOC9hc7wIhcOGFz4eH2sfqK4fFhc
+					m4fEt6H6Gn8X1iXA+4czMkNqQv+Y4w744SSn
+					idOj9W7xj19zAp5uzmviFZUyUeQ08JOSxaE9
+					w1immavwVVInaqoDzBUF3k/EQO6ZlPRklZlc
+					stMHTIU1GmdqRcLUedHTUDGs+HI= )
+mail12.example.com.	86400	IN A	10.4.1.12
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ULkNZR9GJ3jNYk6tMgA4pL9mzqw8fuRSNUYd
+					bdRFNvbbosxxz/7A5k4Eyf9t3daJXQ2BOoI7
+					ior+ioy8HtsbkUhkhTwYJ/LYUmUif2J7jWMx
+					67I1IFXDbWXEqv+iV10nnknKL8nJk8a1c7xt
+					3285LqsQXhifGD4nvbXOIwTYNZE= )
+			3600	NSEC	test.non-terminal.mail12.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					kViShVqq51fKGo+KUhc460FRF1PmfDaXtSZo
+					JEe0ds7jP1jdoIMs6rt/M0NH1lg0gcmbhlsE
+					DEnClu8HEqCsp6lbz1TgNeqYNgkQDqmyZggk
+					mXyjEDtQ4xql8XfzbkX00dX5u9ACPZIkmvKV
+					4iQS3bLGiCQg1w5WlPGfOZTl7KY= )
+test.non-terminal.mail12.example.com. 86400 IN A 10.4.1.12
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lYsqWwKz6k0JDzTw8T95/MAnXbaODOB/Ab5M
+					zkmjC3jWKDgOnlvQrMlYf8BqE0HJb63vX0px
+					vAX2TKPGvQ+wEB1fed22nqw7DYjzfuNzOaOt
+					0ELyEzlNAwQ7NDSkT85ng1l1qEzPKYIzlgc0
+					L97wHcnPv7Urj/igApMX/8NkQ74= )
+			3600	NSEC	mail13.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					PU/IhwdYZcKTwIIwSxlcuen+TWvG2gRp42QF
+					B/Fldaec83BSWKmq9GbXuccIFoHNKMTArnfX
+					9uuIP4xLqkXkDUYD00iaNhpRw1Jffbeoh3Fy
+					JSH9aY0xW4Y3osobMQr08iavv987OhbNKiYy
+					v/fPjuz0iYm9/1HoJLupZUsfeZs= )
+test.non-terminal.mail.example.com. 86400 IN A 10.4.0.1
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					DnPjHjEhdqCWkgzAPRifXUGDx3g9V6yJt5j+
+					EdYQRCt++GDbEF2Ynl71Vd/zpTacCUWYps+K
+					WabrsUhsjMHIPoipa2xjobIfjrsqfo8pqrMx
+					RZtCt8fZyxK7NLczKU/Ie+apcoOYnDMW1AbN
+					lSL+h8c3HiZ1DHQdFPq8D2BA3LY= )
+			3600	NSEC	mail1.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					qNtQsc3FtsLw2H+d8zCCslSYohsV2ofLlmyK
+					9dBVxWmMkVcPBpfx+4b1fjV8SL/+SHUtVPA0
+					2Yx8S1BIRcOMBuM2ENJNKKExfCAHLf0dqOvd
+					mZZe7z1TTgMkeBCAG5lOZhsZDg5F2jAPYOeC
+					b/YHwPsRrPWh7p6Ai96af4BmuAQ= )
+mail1.example.com.	86400	IN A	10.4.1.1
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					eFsMrAmwRL0R5sbyaZrkr4vfQi9RvbkYObM6
+					rqNpfDjw6eOwvxLm8oZFr12oCGI3xBw6mgHT
+					pF1l7y24pZoCnGpg4Q1ag+TBVgvZuFfEcJAk
+					KALe8a9BhF20Uvs0Ec+BiKcu7ed7irAic71x
+					C7qanobK/CJ0P4PX+hiW9skHGV4= )
+			3600	NSEC	test.non-terminal.mail1.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					mRwBgE7mSYb9F5TixnzooW/4dvwLq8zEn1/C
+					HIGSimObo2B94n/Ef5NQ1kf1gqvfyn+ZP1HW
+					8hvDLeo1paMJd8xmqknIjOcV+hcjntTid38T
+					BgHAurPSRjiy4MQARJGWc2EuHnxt0QqAjs+H
+					MhDoIi1II4LAxJZyWTSyWthL1YY= )
+mail14.example.com.	86400	IN A	10.4.1.14
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					H14+atsKW8ZWNd8JZ36TkuBFZhXdkJUThLzW
+					c8gqBsErgeeZMxcUC5ygm3//cI++yJVMD1Bx
+					HTu3b7fksTbJGvX3UdhVTzGdR9YvJYi9D2Xn
+					cafKBE+9ETotMM62piNdmCY/lVEURI00/yvk
+					6mXZYH76sDNi6i/deK6SmMpHWv4= )
+			3600	NSEC	test.non-terminal.mail14.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					WxINgY9cqH55Isi0HHR23e9i4eKjvdw2lv4t
+					QYXV2NUS1sFTrEIpCGaBMKYwKh8xkSM8fuL7
+					bpMzvG3emC4Rg0n9tizYCNjsfTCQNoFNvpqj
+					2fKuWxUqV6gjzTb6KjlKOSfx5SW9L5Sg0Tc2
+					GV5b2QHiW0e847ABx2dql++GF6E= )
+test.non-terminal.mail14.example.com. 86400 IN A 10.4.1.14
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					J//po6XMFoHBXbqh6v2zbK3aUovMyDggAYj/
+					o7eDkEihai8nWowXtpMbxys/1dm/l0WWyBCF
+					GaO7vLLxkRt6F7phAKbcAV2yJF4U64nnvIrV
+					aHFWF3fkdEN78t8CHtl+aYi37878in4t9Yvw
+					ALGkXfLx+UG2+0TxpzQ3mGfto74= )
+			3600	NSEC	mail15.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					coWx1XV3F2ZUu50ZiDU+5msSuqZwpZxvBBys
+					TSj8+jo/sPDSA/ilZSss+WxGOHrhppalbpcX
+					TnLxEhmPHPGUf6NLfB5+N0v0Pf1HyhXq8Z7g
+					ULFqYCVK16MQkSGuYxX7maN8/XtosxX+ZrF1
+					7SeJqpHzWFTPIiO+gTrAAXSJHak= )
+mail15.example.com.	86400	IN A	10.4.1.15
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YP2OUilH+GET+E3E5YWCCslWg0rCQi4xIIGi
+					FnagBLB+XNA4L6ciizUxKgFdZ/Z0C7Op7X4/
+					cLEMSsOtCGgYaNX0EqdT4oXk652+mL0yKs5y
+					T24PzldUd5Zh/iUCCZ6uhjoO1xTMSsKqZnyz
+					6DIHk6OPqbjV4I3tEIaWgQ5qaAQ= )
+			3600	NSEC	test.non-terminal.mail15.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tZ6C9X+QdFelME6sS9gz/aIUBM3qst73Km1f
+					0qkA3/P09OA0hlFzFSebDDwq6mpFyVbi9eNZ
+					PtCdYo/yU8Ijn9Hnb3aazkcPUQk4CI6wkAzE
+					mQNpj7rwzvMdBmQbRAdwUGbdVoJTRbvjcZ8S
+					7VYEHp2V78IC6+yDrxT93dKgXTA= )
+test.non-terminal.mail15.example.com. 86400 IN A 10.4.1.15
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					nWQkiRRvlHtXeb//24mAa2yBryERD0bvWw1l
+					7oL39AemUF+MVHmHc9xAYqahzizK1SAmd9ax
+					Q26D2ipGfDDAvcLkZ7w80QiPWELBCC09O+2R
+					lUXr1n1XopyT0m7DTFYg4BH1c2xwrqMrAqyi
+					frjEhuKvdnPucunHpOzhJaLd6+c= )
+			3600	NSEC	mail16.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					czIMj3JdbgqmUC0i7Q5qxCO7YlYwjag6dPN8
+					eT3mQnWoM5njhxVh4WTonM3Lh29BhZdYMdkM
+					u3Ba8xG4JFASCO21EqArHjrOsEr8h0RVNT0g
+					BXY5NEUXH5IjCnqePI0DTrgFf374HoAAK5ve
+					cwAtWtWQl20AeRBrFB1auzqme/Q= )
+mail16.example.com.	86400	IN A	10.4.1.16
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					QKYCaMEqGKQmVHWNriSBcVRwuqtHkxGIfaC9
+					WQdNL/Mbt5zGxS/6v1W8MQtRpWHWrWOZBvNn
+					RjfNta+GNjI88yY3qe/Q1S9RQsWdLA3I4XKT
+					+Y50ekCI/+qtxi6yhhHFKTSQK4DvPskkX+9D
+					UkhYhnzrqlp7zUQl1RxV9aQJDrM= )
+			3600	NSEC	test.non-terminal.mail16.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					az7+23AJg24nymox8k5AB5VlGa0Zvplh9K9i
+					qkAYdvVR4qQK4Ugd7B9gUxVeWiPy4sN8S8IW
+					YgBnuskgy/Ly99DAQ1wqmkJdFpIzW0oC7P+Q
+					qFEViacIEwtmfGHczJvNtkeXQBHS2dgglxHj
+					7Ih37xOkph2NdStunkIxNfReV78= )
+test.non-terminal.mail16.example.com. 86400 IN A 10.4.1.16
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					TJGi0Oa4+d7VIPH3n/oFToOXxLKISZaByKjA
+					s8gqdx8iw6D6ce6ces97fWQWY4QysYFmxKsU
+					zxefahGr2NW3NwOqN5kCyP5hzbN5bvzPia0Q
+					wPvZowOcotDzd8E2igxRdna3hAa5UxV6BaEt
+					G/qsalYLs5Sd5n63gaMk7zD26hw= )
+			3600	NSEC	mail17.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					V4WYG/l1Peo34Q5hfm69QwRtUszRoZ2JjYdq
+					d1wQqZBoXO79SXU3TssrH77iL4hTZNxug9AC
+					MVWbr14KIok8kVgOTiHcuoD8MEvXOYldVT2n
+					PHur9u98YWUl67tIHxFJaEDllUr+F/MSphIj
+					xDE+JoILqyqQxiBplivpYQpKd54= )
+mail17.example.com.	86400	IN A	10.4.1.17
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					tP5Kusdk8U8sk73CRE5h4OzGQA5xX867rStw
+					vnmLO7QxUwnUt86iHTA0WLZ9tUSU48e1QgA3
+					sXdfsE2s9lL3RkBCOeZBbtVaEoJra4lrsQqE
+					33/lJ2dEXinmUp8V8ndMrDZjoM2akMWqil8B
+					retyu8+6sDBRDq7DwOo6DnhXZpU= )
+			3600	NSEC	test.non-terminal.mail17.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					rLomo4w8U3IUOk3Z/VM0cq8Wf/O2w7/ZWvVx
+					a6b9nWBEfkDPkhLNHMN+bb99SMepeWKZEbNB
+					aM73aSqbebSFwdc2LLBAqQ0tN8H3ay08FEK0
+					RkZUncMkUWuAwdWePDPyy/OWllJCuMJCOP1w
+					9fVbQTm+N8pIQGE+8VbwKb6CR1Y= )
+mail13.example.com.	86400	IN A	10.4.1.13
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ekti6VPO+1/EmlifNgbhfoQK76lcypNefc6J
+					F2TLJvWqiVAObvbLGamIu2gXtyZjY3SZtkL0
+					DN4gkao68jLi57kmqQq8QB9TYUjV3Sk9q1KF
+					T6IVYs3hMXtVftUf5F48fvY8MiciDX2ef9hI
+					DDAzlju7Xm+28VThG+4HdLGOABw= )
+			3600	NSEC	test.non-terminal.mail13.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ofh4YmlpGvaFnSfgxt40TCB2tXJj1ni4qE/i
+					ZKO58Yk6Yhewoh9PnFu+zY1iqqiOFdkwm1p8
+					0ZnBv8zEnBgyWlaDGlyXYaekbopPR2RCNVCz
+					zBDfTUkV/ZH/9jHW52vxuCTEXJbfyDtoMpSH
+					bpywxlsz4qUl2LsTwUXln7XWj0M= )
+test.non-terminal.mail13.example.com. 86400 IN A 10.4.1.13
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					RF1mMLuNWPr/PlRrXFMfOa5OpOzrkmpPwACm
+					K5Q31EJxO0ypnWSR09YzAkltDVutHLM6tEvF
+					2r4kPeAPMoNe6dh30QMQp51knE6Ltcqp/2AJ
+					g4g7w2V9I0cwRnVzIvpSvZESJKKWEpjFB1qe
+					T/QwCOMDUKEKyVeQmk3/qaJbS4c= )
+			3600	NSEC	mail14.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					DTP8SAm5AK+j54fkHzEuAkWdlJ9+y3nioDsU
+					Gc+UlH0iDZJ0sw5xRbzFK/p3eO2aYbOQqyCX
+					2J15B3KMCcUNRRe22nkHS3zEeQqY7vfo3xW9
+					U5CBg7PY2EmuZ/nwj7oP8RE21SQj7NaIC5nn
+					pej4vBhEFWqPC1fsebCp4vxil1I= )
+test.non-terminal.mail18.example.com. 86400 IN A 10.4.1.18
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					cDlI0qI//7Wy1+EE5Cd0Xvbj/mtk55jC1ZIy
+					0m9TwV8M7vMKv7Z88w35YzpkOlZAbvZrOk4Q
+					dTXjaT1KVVW4s3zn0ZGSHjMyiZu3XeDmFJGg
+					CM8FxsrzwemZmVrWgLRkvo/iM8h+rkMM0c6F
+					xSMHyQS+cETpPCiLe6XoBtrWEpU= )
+			3600	NSEC	mail19.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SXveX1Oea1X38bLeIwQ8XqKyeCPhiJ7VMhnm
+					sj8VCrIVAl3opZt4TeV4HhbEO8OTHORb30o0
+					ruRxRgTiIPkjiPsyJ29jSklyL6BiN32HTJGz
+					dUzNOQLaa1BVQn4Z1/vafMfABamOv1nkpdwz
+					D2xC96J2A3dfgtYcOw6Z9uH471Q= )
+mail19.example.com.	86400	IN A	10.4.1.19
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PsTOjwnxY1kNxu7MfaFZ68LjNqq5DzFBtU6/
+					6L6VshN9VKaP9XmlvSbj2TxWNitcK7159y1w
+					Bo8O3E1xr710wOvjeEoEt7zRBxaZKhHO+WfO
+					xpsP2d24rwaQXt61hP2rREow5DjCT0lHXUm7
+					/stCotu0+AisTQSf4UrJSQcos/U= )
+			3600	NSEC	test.non-terminal.mail19.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lnY1TXd46C+A9ScdyYn3AZNg0h5xUk3DvKUS
+					OG5uDVgM4Ox/i2aIlAcnrtb+YlYKDTi4dZQi
+					CIoCSsvahVnB3rtkyqmNYps/wD+31FukUN4w
+					KJY1IJSSBOd9TpuOyOMVOZk4a8ewJCReJLQ7
+					fdQdaxc8wz+VIWX5m6E8I47I76Q= )
+test.non-terminal.mail19.example.com. 86400 IN A 10.4.1.19
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					rhR31JvAxtmNDYbh+BEc/7r409c4+c+54nnm
+					tUlHy8mAT6m2N55avXOvjHXCifhlChCDoToC
+					fzehwMH/PaV5BqarR4f+IESsCeXWbpgreQGp
+					pDAvFKoQSMSG6tHb/oURZz5D9Nj27hi0yW7Q
+					+0Js3qKbkzAVPi4qCAg2qCA83Fs= )
+			3600	NSEC	mail2.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					SGOyr7LJYoaqqRT44xDjqwJ7l8+3SkVZylDG
+					b1Uk4D66k2QoEb0382hXIou8OylOYFu6tKha
+					CsSL9CjDq4gP7XVar9sCwqHnRiO84cEO4TKQ
+					rWKK7aofN+N7bGJojEPMIcfMjAQyVEj0DijZ
+					Bz+vfbMr/3sGHpjwYyDfi5QOXwY= )
+mail2.example.com.	86400	IN A	10.4.1.2
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lxfw+OaPPVMAePmo+8Tj/037dN3b9bwL7Vrq
+					eUfzJQDfXX5lcxxfUvKWZWaBYu3+SGQcA/iv
+					MfX7dU85urSeHfDrtzmL70v/ltJVv2vShg8a
+					D/WbPtACA0i7AQloTV0iRUQElwP9H+VtaI/h
+					F169y8UouYvhrxVJpkIfGsKy5bE= )
+			3600	NSEC	test.non-terminal.mail2.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					yRRrHYIrXUzNO48M6ol/YKQDsDscuCXD/ZTc
+					qhd4SjVCRYwmPa4bFWSgrZUlOLEOIBZ1EvZm
+					HYh52Hq50xhzGZp6sH9oew7jp+obrEqFgE6P
+					pcZb4pSiM0r+Jtqzs8PeNjuoC/nKXvpbN6yK
+					AMjbhKymox3kOBqGd7Bd5nKR+SY= )
+test.non-terminal.mail2.example.com. 86400 IN A	10.4.1.2
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					M98D8qNyCROc7XGZZK0wXCaU61Gvgn19ABeX
+					8OKXt9N27a0P5khTQ2I/ANqixKdjMPTXAEtn
+					RbCLhE9m/Ffrcslb+6q7gmIquehlrSeHgovM
+					3Z/KdPtCmn12CASmXTV+SglLjPi3zpqSGXeU
+					NVEo+1BK4/VjaA7vwFJOEGNRvjM= )
+			3600	NSEC	mail20.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					UqXAJQ0qmNqF7Pi9ugPXdlAzYEextshmHi+0
+					d8Ex7jXeMis2X62F191k7f0h6OY/sAxjbugy
+					utGhqDS37xObZIf1pIYYQrI6q2DJtU0tLLBK
+					v9V8lOEcaAya2btbevjSFYk/p0R8lsY7kjLd
+					FtqLs/ca8d/R635/bh1kuaTXZO4= )
+mail20.example.com.	86400	IN A	10.4.1.20
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					k33/p4b8hiJjrapigEjN5y19hANXjA2jOZWM
+					QLJDh15G6kTxiPIWmj0sS9+77fF01LYEO+wX
+					KFr5+EHDvYiNMqr99sjpxkKymkDem996xKSZ
+					pbH6YDRvTppF7rkL/wmG7hmO1RDwGyginyJr
+					V549ykQ6+1As5qcM1aUFwGqUWHA= )
+			3600	NSEC	test.non-terminal.mail20.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					bNuO49PAGLOyE8ACYFdaYW6QJMfP2MbCd5ct
+					M+gBo4LzsSiSkni+T+hMro142fHJiJAmYA+L
+					3rv2+nT+DZWXplwY+AMz9KW7vATRSFlRlFfF
+					PZ1fc/TNmsauPIHARZnMxc5g3P/c09wN8n0r
+					IKp1unynOUpKKtZBGsvK2zJMwms= )
+test.non-terminal.mail20.example.com. 86400 IN A 10.4.1.20
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					AduBecIyU6OkPrmM2rpdxLm0FKPDJzw90w4z
+					70qUdGH/hJPHg3b0kmD0WVnlbI2FNWD6juZS
+					Zd+bAriXFxxg3jIOoWthGcX7ndWqJQ4MUk1W
+					5PeKOgyA+o+DtUBymKKS1C2G1DQmOcitWOD1
+					pOo1jawNJ8PrL7r8psS6PEv9VSA= )
+			3600	NSEC	mail3.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					NFPdkaP+u974qr1A28LJKjF1kOTF/bN1pM+W
+					J8uSC2ZuRFGrJtKYC/IgbkiaZA4wG0OiQzbv
+					9UWu87hETfGszTPfvHhSsgQPbw0D3SVFx2MR
+					xqX2Jejet+eS/IBitiTntqUJUKTkBIcVZ57b
+					N72RUhhR6LIzd2l6HCnZWKdtISY= )
+test.non-terminal.mail17.example.com. 86400 IN A 10.4.1.17
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					T8gcprOnmnCYj+oa2agvk5UxQ1SIN46p8GvE
+					PV2+d+oLaruxIRf50Q1aCVaa3qtXa5cKZglc
+					6OPTDykCNYPZ8Qkaqbauq9XFWEu0jEg+Ko1F
+					FWpPHKesHQjRQu9/XsJq3198aDp1JF+Od4CP
+					/3c4EF4a76jD2WHltHU+2tYPDAw= )
+			3600	NSEC	mail18.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					xSnml2cHIp7DLeiODjrm4CckTM+eGhUketW4
+					qzlptyPht+BcBY6r7QGSsD2XMd71gLLC5zFX
+					3Ih5suA24CsXJRRf1McMaAlsLj3W/043SIE6
+					QT1l1WVRkaAYZAwlK/ZVwWvWXCzAFaMAwl0l
+					NGg4GKljzo1VKej7mxQEepfkIKU= )
+mail18.example.com.	86400	IN A	10.4.1.18
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pgMM8YR5BN5sS2FZqHQkJTUrXI5fwIDP1K6S
+					p30INrhtV7ZzuJftLPhU9iA0+pgR4uCLKYT8
+					bzVoQOg+ISgxWkMUr1pkmEA8fQIJqakIJAp3
+					laU2Jz5Egd0ILQk/ZwhVTBDsnHC91BWaFCTd
+					u0sw5DTlEC4Jw4rd53lrROJgtSI= )
+			3600	NSEC	test.non-terminal.mail18.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					OvjZKUeOwOhFF29tGvHGlad1j7tnED8t2EFX
+					uwKw2u5e8ALW6/gI6qD5/cXlHxV/fV3Mmydo
+					Do9XZRpbRzj/+GSc01nda3hS89X/c1vdxEqh
+					KOqzmukIahWcb6OdSxabzQBxUMX3Zn6xpNeH
+					7ZF0cuPuBbyg1+D6V12h72xtIoU= )
+mail4.example.com.	86400	IN A	10.4.1.4
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					PiMqiEaBWJ+5AX50Vx/Nt+8ZW8aX9qJ/2yTo
+					TFUWr/x+UBN4JuTIdslKRCMFUaaKRsRE6zx3
+					pN/oAwGUU4tavBiPoL4oPK7gX/DotyELK219
+					PCG2coShjUsrjEXoWs0G0Tcczf/zH1SnRkL1
+					/s3HvjZqmgPkmqGx2kjpnp4QMcY= )
+			3600	NSEC	test.non-terminal.mail4.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					zcsX93LwEFg9doHsO0wAS5EWhvQ+FoFiFRju
+					dNmipFXcoZ337K+5Q13gSW0XR8xBCMtZhNjI
+					WVxem1NbB87UOTwynp8ybHv3FqwtCzhOaCXy
+					qpVWZnrxJCyFsmWjmL654YAvO5yc/hm9NVTo
+					mLQRJmkeGXHYHdtoILaN8ZYpn44= )
+test.non-terminal.mail4.example.com. 86400 IN A	10.4.1.4
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					qI6qajPmldqEI8dtJ2aylv/j5PoTb+UD/xsw
+					lpcYvpBbk1ZJQXraWTAKvytlTf1tOswha+c+
+					+uQcUzsGKdlIO7pFIoNTbf2UciUkYzlw87bj
+					0IqdLws0Orq7beDMRD57bxYAcocqsg7JcK+b
+					QOkx7ThU+vzO3PlqhpCPrIm+XV0= )
+			3600	NSEC	mail5.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					hyyqXEMBD0wr1EiuayMANDLRjWuWqOCJi2uD
+					s+NNfwvPzCArxkjhVG1n8Gxv7ByDiCsGj3k7
+					q0Y8cSX3XItqdmF2ltKkvpjMLmBN5OB71ahs
+					rM3nFS/hp6Kq3NQpiy3qnl+TYxKVflqHroIb
+					yMeD7xDseHZg1WelNYq5SKIOlkY= )
+mail5.example.com.	86400	IN A	10.4.1.5
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					BwjGy/pQq8wwq2oWeo8IjkZWnXmxU9F4Aiui
+					V7enbF3/e5Ls0/aNFFH1/C+BiX6ehulxCLkF
+					8Npgg98+UMVgHEkuqcph7zHivTuArO94M4XN
+					zC0ANphLEac93//GtrZcI/QC1mIxQrC9+Kuw
+					RK5swzlI8jEWvn4Gncw0KVVsZMw= )
+			3600	NSEC	test.non-terminal.mail5.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					kFxxuuQI4s4rutL6doGHWWzh3xa56l6Q8b3n
+					OMMeh6QcAkc2POP1iK2/GAgWyymgaF5J16+f
+					qptFjboQl7XeusiFt539Xxjqd7kyE2H2m5dZ
+					WZqeoYI6jeQy4RYEaQkji+wm4w/kJ5tT2jil
+					5pwyqkQx10xnvnx+wT52xv2Hifw= )
+test.non-terminal.mail5.example.com. 86400 IN A	10.4.1.5
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					nQ1Rf5Lhe1y+CE91nOrgW9KqRf5k5wZmp2jk
+					DuvgTJ+p3BPRXOhyVVxGwi90N4grlutXkIu3
+					I/FgibSaUSmoPQvZrmsxfwB+tckPXCYp+AP1
+					U9iLrA36lJ6vpkniV2aGfxxkxyFt8xGVWy6z
+					xlMN3OrofQ4417d0wyCMyJIsi94= )
+			3600	NSEC	mail6.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					XWNdpdSMLhscZuHwpjTOQly+5b+EeQLGkxU4
+					kB2+UmdB8t+bk0kPCC0Fn/iUDu+iVxasow2i
+					F5GDBJTtqCdfXZI4uAb0Difwsf2O8q5H2ljc
+					jSQpv56iYt36XxobLWiVe02dgixVEIoTZGQR
+					qr/nSkPSGkQZV3t92CO7bXvFtZ0= )
+mail6.example.com.	86400	IN A	10.4.1.6
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					U311WSJmd9YNtNw9VMXSApDFH2VnzY0fc09B
+					NAiQYo7Gj0NCvIAK/0bL74pZjBEg1oqSoNG2
+					QcaHA+1HY+8jvkEii1kRVAxP03BZvW2U0RoP
+					eExCk/WyNhyPf+E6rujFEjkM7BiD+43dNeX9
+					Uuw9enf9Lge1jO7oqE3c6Uc0cGw= )
+			3600	NSEC	test.non-terminal.mail6.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					oFMJmWpaSlpIZrkmW5PKp/ZEsmVtDrNYSAbr
+					gGHDUUt0+ZmVfHAX0tqTDdFg+kaKQ5J3BN1j
+					8yAIBtMocPzefaRvI+vU628lXQvve6wezZMd
+					0gQPURodkeSf/s85hMFhkxVx8jkapiHisxPe
+					veVdhCswAvCDhWcLToLTQyDVKoo= )
+test.non-terminal.mail6.example.com. 86400 IN A	10.4.1.6
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hlxRsoZQnLv7Vd84GLMWWbvpeXI+WmNU/vGM
+					k7vMqloFdK5VbNiV1UU55RAszL+mfxFQiLLH
+					/bxRSxqpwaQ9n2HdnB7EfpmSk7CthVhjOMv9
+					5C5zB4V1Zq8t3EUkoEgrXULoMRCJ5kjkHbUv
+					BuwCwvcwO8dzhy/kkfR6CU9E2OA= )
+			3600	NSEC	mail7.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iTb4Nb6g7r6GgAMmgr7+b5eYscku9X4mhjIz
+					XjEj69qxTYjk3hDtX/eEC3SFGP7MDqqwbFH5
+					rNEO1Z4dE9o4P0D8CcYHi1hjCnQcBaYKpy8k
+					d82DaVXkxeuKPSTHBNApBL6IItcfsR5F7IYV
+					3MIZd1DqdNNbWroZD0r9S0UZ5xI= )
+mail7.example.com.	86400	IN A	10.4.1.7
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xq5d9fK4T5Byh0DDoU9ng3S3ODGKagJFHuGk
+					AZ7F4gaHRuu65To0mqLR7EYcpIMHT1N0qIfw
+					pig2GWtcfG8hnhM2Sg4Ecec1Spq8MnRcfEVP
+					/taJWtTc+uFPz26Ib9PBZcFEusQO0uObH1rz
+					Y/+3sI9150q2hVo/9VYQdG7Dw4M= )
+			3600	NSEC	test.non-terminal.mail7.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					eVx1EXYO0mkWdvbBM0bsPC7cyA3XmDzMSR9j
+					c+ljmJjE2tGyPJlJHoyqSrxPe+ZCLPKxMvMe
+					svILL090OysHffdCnNUHbJv5P36XrDMtP2AY
+					RhLFmQfY4z3bu1WWIEZmt9gNSwSDD0wJlS/P
+					gx9IyKwYzbYgI8RMq3A78iCnzd0= )
+test.non-terminal.mail7.example.com. 86400 IN A	10.4.1.7
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					IJUdllCwxGAuk5DFWKXf2UeJyoSU4UezntSQ
+					bKFHK2MCx6DgvfQMGkHVsQpobQGiThyW+Up5
+					UZULM85mtYzNaW2FcZ5inBgNk07+ulhBRYSV
+					yfoJMh22hvL2B9kUrq9ahdxQEXwAi2EXsx9Z
+					IqY3x1GT6sTiRr075QFGKsm533E= )
+			3600	NSEC	mail8.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					H9QW8lTHfPL9+68q1K2UDhxB+GBfvf3OHSVT
+					XGrc/ZeLRozSTdv0kgEw+fMtZEnNKjQ6FkSK
+					IT4KRjpzfgPPerFDSdPnpRLB92oexIqW+4HL
+					VyUqvndhJHQhtuI+6oUds5kKP7wtx0SJNtlM
+					FFApNNKJbNXqGSgdcMH0VX6X3xw= )
+mail3.example.com.	86400	IN A	10.4.1.3
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					HY2Bj1RiTEJ50RwIVeFIHtltIqSe0Ag8+hRV
+					2nkT0XJyfyYJgUzmyhQZXyifwmVbA9GB+ikr
+					48W8YExB0tz/0LKQ/7ZnAJIVeIqZNxTHH+8E
+					lTtdY0BgVb1jbGwVjMPPP2PMtHIV6js3SOKf
+					etKGzHGtwPKLJ5zJQ9JIqGLAcb0= )
+			3600	NSEC	test.non-terminal.mail3.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					dDmzEDtwj1sY+OIx45+eR//i/eXqgDTK0BvV
+					wXTGD7twq/4wJm98L0zwVf9nBWvPBVuPxbes
+					RRkYQMUDsrzbRe6nwlMOzBq8A+vkgjPg0jPf
+					XGXjf+VuBhLkfthA/zGtIbydaZD6+9GQZcuT
+					Z2PmsUcE7tLSUETrGUfzWLUx+N0= )
+test.non-terminal.mail3.example.com. 86400 IN A	10.4.1.3
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					WK8oxOqRtx+WvmlPwLqzk9cg4i/edlo9Q18m
+					c3WSKOcl8k9PIsGLdmR15S/0FwPE8RAwZj5V
+					ivNvD1jZPji4FUd5uqDOIIEf8I7h/oJXtICt
+					fuHXBta451J9hHax2CQsbdRAmgOPePKumLjE
+					DjWcuIDlwd5fUUWlSNJXGgaGqB4= )
+			3600	NSEC	mail4.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					JlLVYj66GZBi5EzNOj+dNuNbhAzNfETJEM+v
+					HEKoxHIMQycdQIE+qIRnslLTOiS+mGcNqvuM
+					QwDh/pX0T/aJfv2iNavo6Kteo1mFqjC6WdlA
+					dwKHgGQUaFpITdhlLdoloBljJ+s8qf0XQu51
+					prk95kMz7J+P5HDfISD1NUiM2CQ= )
+mail9.example.com.	86400	IN A	10.4.1.9
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ilueEhVsd566HjAQ9OKBjKllUmR34IIsUt+d
+					gDJHfac3bkLpoFTaONpUWHFzzGdMk+1qJz1h
+					1JUlaJhUBZaAVS1YmTtnVhtEe0ir8RlJWDti
+					Jps6xnL0NnWUJn9OHVHyi+4bpewBuCRCL1oN
+					G53y0Ie2BtaQ0gKfxOv81i7PZoA= )
+			3600	NSEC	test.non-terminal.mail9.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lOFQtp7jpHPGoWz9OzviTsXFBHUQs244Gvh4
+					p4DTipDsg0RaQiyK9klKigNabJh2j5hrt+lx
+					q/bvlur6lfUijW593HWEAgCck8wQrHPgg3HE
+					vxwBrxIbueuxuxOT6QOYH6lBzzG4HDf6LSFM
+					+zCoYsYXXtbEI7rxqcd/WieiFqM= )
+test.non-terminal.mail9.example.com. 86400 IN A	10.4.1.9
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FVGEqnhagAxIPSX0Nim/AR7ePP5GwBEnvCsu
+					oRpgnIgpCcBKJrKPqlF/aOF4/dFtysXvbQCW
+					Tt0MSFEfQsDFcVOj6bQ/jZq4oAvZW/TBG7na
+					z0J4pTckegIPzuzVso+PtLHbONxu5Ts+IyyO
+					Ble0Jz86L58IamZKXRHlYkV4LOk= )
+			3600	NSEC	minittl.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Tj6rYC12mMnPrPa2wDOp09e9cuByqjvO+y1i
+					riH51BzIMDEUEeaDYCQfPWnJtReNPOoxjeA1
+					4RQbyLtv40A8Wylwq5U3lHrHO5iB4hWTm/Qe
+					vhbzdmrxPYKWhZUgamb22UMY/mPk5O9iMeQA
+					adOVtlQr+vxZHLfP9st/M5FD464= )
+minittl.example.com.	100	IN A	10.10.1.1
+			100	RRSIG	A 5 3 100 20110408061651 (
+					20110309061651 27366 example.com.
+					Mf8cekGVYrEFZW3FXsta3pbcxONMxlfpxveF
+					yvKxd4RmEa3a+LW7AANsVSCLXdret4r1hFcE
+					+Cz6XSw+HcIcF+3tvcQRqpHbtu+ZBZVafIHc
+					jlvCpw8vaGr9TL9+KiFSPxZvh7f65vd7oUlR
+					0IJfkPLsRiKLq0TFwooxXX48w0s= )
+			3600	NSEC	test.non-terminal.minittl.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					sbqJlXF9wG3NiLwQFhKu+LCEx5E/S567MXwU
+					l4845BDvl2xUr+UK35xIVrAzbKk8baYtc6Ad
+					YFEx7CAE6wc++U8WdON4ZZtMaFt9v4ckBAAm
+					/El1zvZ6LhzhkzQTtt8fx++g7iUfNRfJeuBw
+					iVe00wSg1cRchlP4B0QtaNw37nI= )
+test.non-terminal.minittl.example.com. 100 IN A	10.10.1.1
+			100	RRSIG	A 5 5 100 20110408061651 (
+					20110309061651 27366 example.com.
+					LwMLnZZyz34kJ8AstokH/TxMvAGtaOO04D3J
+					2k5HauNrJCtluPYbDELm+b7ngEc/wOsHhu5c
+					PPdWRWrmhUCz/sEcw0W0MD6lgEVd57GTEAim
+					W7gEDp6EcQt9f2g9LUxuGS4g9YoeHucENI+n
+					swfDBEypCOzz22ajeqic37jgiqA= )
+			3600	NSEC	multiple-type-a-record.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Fy9D+zHXn4q5C3Ypa+oYjOwAD/SyI7PW/AWC
+					WlbPBIYIeDMWfToE2FNahRpV448K+D9QGsyK
+					rpQCGqyZoK4VGw+SMvmwIowQ0kP3vfS9kjLM
+					bGtd2ZZo894qa1AwHMjfC6HJKSfg117l+Rfb
+					rQR1g2B9dSq8vTRMHPBFhEMqZRE= )
+multiple-type-a-record.example.com. 86400 IN A 192.168.2.1
+			86400	IN A	192.168.2.2
+			86400	IN A	192.168.2.3
+			86400	IN A	192.168.2.4
+			86400	IN A	192.168.2.5
+			86400	IN A	192.168.2.6
+			86400	IN A	192.168.2.7
+			86400	IN A	192.168.2.8
+			86400	IN A	192.168.2.9
+			86400	IN A	192.168.2.10
+			86400	IN A	192.168.2.11
+			86400	IN A	192.168.2.12
+			86400	IN A	192.168.2.13
+			86400	IN A	192.168.2.14
+			86400	IN A	192.168.2.15
+			86400	IN A	192.168.2.16
+			86400	IN A	192.168.2.17
+			86400	IN A	192.168.2.18
+			86400	IN A	192.168.2.19
+			86400	IN A	192.168.2.20
+			86400	IN A	192.168.2.21
+			86400	IN A	192.168.2.22
+			86400	IN A	192.168.2.23
+			86400	IN A	192.168.2.24
+			86400	IN A	192.168.2.25
+			86400	IN A	192.168.2.26
+			86400	IN A	192.168.2.27
+			86400	IN A	192.168.2.28
+			86400	IN A	192.168.2.29
+			86400	IN A	192.168.2.30
+			86400	IN A	192.168.2.31
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					YT07B2OmuwkPtDW5FUPj4iy7ucdoTKahQKWT
+					8KGn9vGwdbVLZXQ0L0rtvv7SO6SiDsYbDmEX
+					MxCp5Ecs58A0FCpIPhP9yKhPOLHA2UKMAch3
+					FfdujPf7SK0P/TxE2l1zQ2wF7pD/dUuV3DLf
+					uCuIetcVYC7AYJy8xQKi951ubYg= )
+			3600	NSEC	test.non-terminal.multiple-type-a-record.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					d6wmda+yHwrLO6zvpOxegvusUWmIwW/QqPwi
+					dLc6+IcunjlFPd6/fiHa9SThJv+Dh9rssiFQ
+					iLpi7tO7sPZlDdmJoXJMXlV0zapSs9ACxdiY
+					vWDbZfFcGdCeN2/FqjqCQ6WnCnFf+R4ahGTx
+					KJkcsKfPVAYSbDuDItUZ13yxPq4= )
+test.non-terminal.multiple-type-a-record.example.com. 86400 IN A 192.168.2.1
+			86400	IN A	192.168.2.2
+			86400	IN A	192.168.2.3
+			86400	IN A	192.168.2.4
+			86400	IN A	192.168.2.5
+			86400	IN A	192.168.2.6
+			86400	IN A	192.168.2.7
+			86400	IN A	192.168.2.8
+			86400	IN A	192.168.2.9
+			86400	IN A	192.168.2.10
+			86400	IN A	192.168.2.11
+			86400	IN A	192.168.2.12
+			86400	IN A	192.168.2.13
+			86400	IN A	192.168.2.14
+			86400	IN A	192.168.2.15
+			86400	IN A	192.168.2.16
+			86400	IN A	192.168.2.17
+			86400	IN A	192.168.2.18
+			86400	IN A	192.168.2.19
+			86400	IN A	192.168.2.20
+			86400	IN A	192.168.2.21
+			86400	IN A	192.168.2.22
+			86400	IN A	192.168.2.23
+			86400	IN A	192.168.2.24
+			86400	IN A	192.168.2.25
+			86400	IN A	192.168.2.26
+			86400	IN A	192.168.2.27
+			86400	IN A	192.168.2.28
+			86400	IN A	192.168.2.29
+			86400	IN A	192.168.2.30
+			86400	IN A	192.168.2.31
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					iYwlsJGf+LDo9qHyfQbjh6+fEqliq7qTyiFB
+					aUdSRT/RHoJ2dWXxrkxxJ2uo5xMnVyKxlfHT
+					mXXwUSrUU1Swfi3ROh7n4+9P+T8Z9wvmTLSp
+					VBDIyn98uKqacA4Oyj5TOLUuu1hHRfqJ5lfM
+					O1Aml9wQ/MMtPr9XjiK99+dHnPg= )
+			3600	NSEC	multiple-type-aaaa-record.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					a6PDPkS1fCfOwM5+GDtEdRK9MfR9bgd4NMj0
+					Hnb5ZdIX+aRUrEykFGvhdKHmoae4nvagOLfC
+					rd0fMCZJqia4JLOh6b4Z52qf/yDyraceadFF
+					A7bcrLFCdKcumJqUZMs1XEkBuIdThtcHG/S9
+					VtRbtoeVIGCrHj1cA2seUFM1RZ0= )
+multiple-type-aaaa-record.example.com. 86400 IN	AAAA aaaa::1
+			86400	IN AAAA	aaaa::2
+			86400	IN AAAA	aaaa::3
+			86400	IN AAAA	aaaa::4
+			86400	IN AAAA	aaaa::5
+			86400	IN AAAA	aaaa::6
+			86400	IN AAAA	aaaa::7
+			86400	IN AAAA	aaaa::8
+			86400	IN AAAA	aaaa::9
+			86400	IN AAAA	aaaa::10
+			86400	IN AAAA	aaaa::11
+			86400	IN AAAA	aaaa::12
+			86400	IN AAAA	aaaa::13
+			86400	IN AAAA	aaaa::14
+			86400	IN AAAA	aaaa::15
+			86400	IN AAAA	aaaa::16
+			86400	IN AAAA	aaaa::17
+			86400	IN AAAA	aaaa::18
+			86400	IN AAAA	aaaa::19
+			86400	IN AAAA	aaaa::20
+			86400	IN AAAA	aaaa::21
+			86400	IN AAAA	aaaa::22
+			86400	IN AAAA	aaaa::23
+			86400	IN AAAA	aaaa::24
+			86400	IN AAAA	aaaa::25
+			86400	IN AAAA	aaaa::26
+			86400	IN AAAA	aaaa::27
+			86400	IN AAAA	aaaa::28
+			86400	IN AAAA	aaaa::29
+			86400	IN AAAA	aaaa::30
+			86400	IN AAAA	aaaa::31
+			86400	RRSIG	AAAA 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					x8x8CvwAHG+JZBh9u2x/0DaiiP94QpQZGhXM
+					jTbtwBMphbStQ7nic1hj6PbAf9lD+aS5hYuo
+					vUc4Ef1wCUdvQ7bzzgFPChzWJ1cMQf+qD8OX
+					pUYUbMklFReEIOA6M/0qeD4XaWuq4NedHTVF
+					Kks4D2u5QBHksqAFguW+k23I8uE= )
+			3600	NSEC	test.non-terminal.multiple-type-aaaa-record.example.com. AAAA RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					hnQieVeyJETv0V8rau8a8CXJuALihgviFDAj
+					EctzT7D+97HFGkmQJuwoTIIZMl65AlV4p/tP
+					dDoT0FnjahNeA/+ifEGqpSb5nM4J46SipBEl
+					yc7gXwYvF3VzthY1JtXFIwz6/EhIj9Ypoh3H
+					dtRVcSwNe9Ts1LQen4MJGXojlis= )
+test.non-terminal.multiple-type-aaaa-record.example.com. 86400 IN AAAA aaaa::1
+			86400	IN AAAA	aaaa::2
+			86400	IN AAAA	aaaa::3
+			86400	IN AAAA	aaaa::4
+			86400	IN AAAA	aaaa::5
+			86400	IN AAAA	aaaa::6
+			86400	IN AAAA	aaaa::7
+			86400	IN AAAA	aaaa::8
+			86400	IN AAAA	aaaa::9
+			86400	IN AAAA	aaaa::10
+			86400	IN AAAA	aaaa::11
+			86400	IN AAAA	aaaa::12
+			86400	IN AAAA	aaaa::13
+			86400	IN AAAA	aaaa::14
+			86400	IN AAAA	aaaa::15
+			86400	IN AAAA	aaaa::16
+			86400	IN AAAA	aaaa::17
+			86400	IN AAAA	aaaa::18
+			86400	IN AAAA	aaaa::19
+			86400	IN AAAA	aaaa::20
+			86400	IN AAAA	aaaa::21
+			86400	IN AAAA	aaaa::22
+			86400	IN AAAA	aaaa::23
+			86400	IN AAAA	aaaa::24
+			86400	IN AAAA	aaaa::25
+			86400	IN AAAA	aaaa::26
+			86400	IN AAAA	aaaa::27
+			86400	IN AAAA	aaaa::28
+			86400	IN AAAA	aaaa::29
+			86400	IN AAAA	aaaa::30
+			86400	IN AAAA	aaaa::31
+			86400	RRSIG	AAAA 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					szXkzygL5I0RgjQ9CEDYm0yeFS0bpwk1EgO7
+					cYnf2i9PxX5npLk9WRZVLsFLsHmj2eRgXvsb
+					AADYxOzSwdEIZeqBgsy7Eoee8qYntoSpXOM0
+					QqyVKp/4pVP3JAW9a+j6SyjboR2dXJFY/9XG
+					Ox8BkwtrlAsW5/2tLT8mD9jfjYk= )
+			3600	NSEC	multiple-type-apl-record.example.com. AAAA RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					DjrQLbKKPBy1hB8LWgIO8BlFonO2LktUIigM
+					wTmzaWMgAgiKaw3BHZwYsbKzP0BqAb5FcS92
+					9R6rx7yvd1x3ykx0AjctR1Teno8yqenlErNr
+					eY/0aU1PLgnnnqGMJEc/Kv0vuQfqWrzJDXDH
+					Vz0SIfn56DArnR/+k/BD/OfD3yg= )
+mail8.example.com.	86400	IN A	10.4.1.8
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					oOjuOj5G4jOjwHN2NRy7j+jpbsDF+bw5sVjn
+					UKSi+WENwlhZODEtJENVVoRB1ri7B47w3JV4
+					GagwVUWVeYmbalk38hRtKD1Ak9C2o1cAyv+p
+					BR3YazWd7mYqxhdvu/n2E4D7IB5+MUSZ2LUT
+					YPnrsCta+BfEobMTA8kUplMj6XA= )
+			3600	NSEC	test.non-terminal.mail8.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					yCUwmQfvAQblEsFsNiPxnhCVKhjjZTeBFLPN
+					cES2e3gA6cy23sHmujvkSsUhl04ZceNmqZE8
+					UzZL5YFNemGy+GHAOnvY03L+4d52pAIsH/33
+					OC8KmOAPXySnMvAkIF4nv32gJIuCjB5Qn1LU
+					IlxyAMSe7ZOaxfcc9d5AvkA0xKA= )
+test.non-terminal.mail8.example.com. 86400 IN A	10.4.1.8
+			86400	RRSIG	A 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					MuQ87eA65dY5dqnUVkoau0U0AMOYEPDciAmm
+					oULk/zlvcHpPuxEcHh0oIB3jvzYIc4BqXDyJ
+					fc7JKXhwWJnVI9A4AkUNebdfPA+WkR/LtOpE
+					8lmu2gPxRWdkWuDflmE/e6xuPoK5oTz0see4
+					vGgzEEYtuK2PNJo2WoJQL4jVfps= )
+			3600	NSEC	mail9.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					z0uNfSHz4i4TJhgEkY8QWkDu+Nqa/ngzQ3rZ
+					7SWCVhMQxROnFSF6l9U67oxzariVRobR0Bt4
+					sv/ufpa3j68bm28B1JjbZEUkIVteAtu2mSgN
+					s9jfb2c/NVdacVX/qtr8d/9boq426im3OvEq
+					bEsv4DbQTyzTjQIBFJmfztZ7AIE= )
+multiple-type-cert-record.example.com. 86400 IN	CERT 65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65533 65534 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65532 65533 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65531 65532 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65530 65531 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xQoPoH5wwAOIiZspU1WKMKdO4QoVyW0BolZX
+					5Tdi7VW/tD/HYBJsJ6qm+YsfMEs4gMFjkUTy
+					oxIMi14lDk4CvKV7g6jpn1XReRJQHM4sFrcN
+					/Rnr7xLWQicNi3jCIdHwQiGAon/ld9+dhQwi
+					P/DffsAYU8XHCnrB+vBUF1bGSlA= )
+			3600	NSEC	test.non-terminal.multiple-type-cert-record.example.com. CERT RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Q6w8eQLJK6pucvBPhxcDis2mEmPfH0cvzFvy
+					Rq37BEk3qPqE9VzvnMlWOfcR0D/f1zychP0y
+					PwSxRSX56+IiBnAUczMMI1ESiy0CMpWFI8Cw
+					kuJeVcDlBbqzgK6T6aRs08dwfos9V2WcQczt
+					um4kDs1iP6hu95xoIXOD5AaF23c= )
+test.non-terminal.multiple-type-cert-record.example.com. 86400 IN CERT 65534 65535 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65533 65534 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65532 65533 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65531 65532 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	IN CERT	65530 65531 PRIVATEOID (
+					MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45Ik
+					skceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVf
+					SCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY= )
+			86400	RRSIG	CERT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OZzzum87ApOeJSFbd7wDbmr4iY/3iAKbh8RQ
+					UNJDBPwHj8KbJlttJ9gmjToSyk3P7SrbS7U7
+					Pk/2i38keOWZVW9ivcksmt0ghx2x3I1FP63g
+					aH8ch+7Xhuh5Jchg0Kce1+5mXpVu+j22qfPQ
+					1cPyG/Ret1LaUhrSkXMzsPAMbCc= )
+			3600	NSEC	multiple-type-dhcid-record.example.com. CERT RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					WopCB1qLP8JM8dH0Rg7ahT5KpZ1PrkjfzQTd
+					okVyD/OeeIuA0AtUZ92DqMvUu3HfHHp/Dt52
+					ROAavolZh7nXqULc770QeysyeHvBOjY+H0F5
+					yZCjUKFm8GH0+1LPQsYnZTE8yrCNWflb6qTk
+					saBhkD1SnfAaLkY9fjCQRcXvZ3g= )
+multiple-type-dhcid-record.example.com.	3600 IN	NSEC test.non-terminal.multiple-type-dhcid-record.example.com. RRSIG NSEC DHCID
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					IrzmyShLB6KgAaQAz5AOWMBW8Ww74oWgoWry
+					DP89FY0GOn8RdXfeBGTNVCLuZO46l6JBdcYz
+					0YRoSp2EsfUzcEP7ykNpKdUiIt8cu3bO//w6
+					jViWdm7O5yWvGVgk03o6xJMqsSsqqXXx07PC
+					s8oICZkWDc/ivWe9EZm+N/nCoxo= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( BBIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( CCIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( DDIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( EEIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( FFIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( GGIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( HHIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( IIIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( JJIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( KKIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48755 116 32
+			86400	RRSIG	DHCID 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					zFbrcp3DpDdFEj6IWGhneuND7eyaKu+2Sx15
+					ol0dEX8HlFqmojg95PruZxCO/iUlT0azgfEc
+					zAmztRiVU/YSCW6JjMb/7t8BU9XvISyMQvqB
+					IQjKKtmkHBz4QkZOp+KhDG2u1lCXNsx6SNNd
+					TI0MBFI2uOs6r8SvwVVyaKT+9Yc= )
+test.non-terminal.multiple-type-dhcid-record.example.com. 3600 IN NSEC multiple-type-hinfo-record.example.com. RRSIG NSEC DHCID
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					D2ft8CG25E0aXD1OQUvZAyQwEUwrgQwubVc2
+					745OhUK74XrisajtydaXeo1lcY63/YugBhMn
+					fbOO7dAdmsA5PcUmEUN6YPF64F9fci4SBmoh
+					I2VMWpQl5wDGMJJlCTh//UsYMgVxitsf2ilr
+					/d4c5zpd4KWZiCMx7va4MgAUyoo= )
+			86400	DHCID	( AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( BBIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( CCIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( DDIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( EEIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( FFIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( GGIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( HHIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( IIIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( JJIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 35 0 32
+			86400	DHCID	( KKIBY2/AuCccgoJbsaxcQc9TUapptP69lOjx
+					fNuVAA2kjEA= ) ; 48712 84 32
+			86400	RRSIG	DHCID 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					lY/VinZHODSBjAKVarQgP6t/W6ELmy8nrFN5
+					MmAxDY7hEniet6b9Pj2ZfJwXuxCLCaBjK533
+					CflXFrMUhRQ2ou0cROzx5SYFaHvXjkTYBNjx
+					1Wyq9/oymCoR7wvWC8oVnQ19C+xn6bQaJqMK
+					ALeaYlArNpnRFCba8Y6rXBLWFOw= )
+multiple-type-hinfo-record.example.com.	86400 IN HINFO "DG MV-4000" "1990"
+			86400	IN HINFO "DG MV-4001" "1990"
+			86400	IN HINFO "DG MV-4002" "1990"
+			86400	IN HINFO "DG MV-4003" "1990"
+			86400	IN HINFO "DG MV-4004" "1990"
+			86400	IN HINFO "DG MV-4005" "1990"
+			86400	IN HINFO "DG MV-4006" "1990"
+			86400	IN HINFO "DG MV-4007" "1990"
+			86400	IN HINFO "DG MV-4008" "1990"
+			86400	IN HINFO "DG MV-4009" "1990"
+			86400	IN HINFO "DG MV-4010" "1990"
+			86400	IN HINFO "DG MV-4011" "1990"
+			86400	IN HINFO "DG MV-4012" "1990"
+			86400	IN HINFO "DG MV-4013" "1990"
+			86400	IN HINFO "DG MV-4014" "1990"
+			86400	IN HINFO "DG MV-4015" "1990"
+			86400	IN HINFO "DG MV-4016" "1990"
+			86400	RRSIG	HINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					UwdNrH/kb403kMqM5iogfB1a0VrA77U/kqEc
+					kyUgUuOmX4rDM7n4de2ZF8/llmqqM0bGBoiS
+					CjqpxIiflbq56pLEgWC4GmzoSIKtWZOKepZJ
+					QYS9zjAEr8r65S64XtrBSCC9bSEHrPVVl0GD
+					lHJLWBBs/8bPkOFevrbIHOjrmAg= )
+			3600	NSEC	test.non-terminal.multiple-type-hinfo-record.example.com. HINFO RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wxkUhmJ2GrC/KbBuuaLO2AcSm7dprDcbbBmJ
+					BmxuJ4QDjp1PCWbhzo3GlAcQ83zDbi2JQMWS
+					XFq3/6SJCJ0U0K5F6mSVd0MKJgcbHBvMUdIj
+					46FxLCRjDjN3+Ej2A6egcmVcVxbmolVcbwS7
+					jLm/xMZHUHFs8sIuCJGDyZLFBns= )
+test.non-terminal.multiple-type-hinfo-record.example.com. 86400	IN HINFO "DG MV-4000" "1990"
+			86400	IN HINFO "DG MV-4001" "1990"
+			86400	IN HINFO "DG MV-4002" "1990"
+			86400	IN HINFO "DG MV-4003" "1990"
+			86400	IN HINFO "DG MV-4004" "1990"
+			86400	IN HINFO "DG MV-4005" "1990"
+			86400	IN HINFO "DG MV-4006" "1990"
+			86400	IN HINFO "DG MV-4007" "1990"
+			86400	IN HINFO "DG MV-4008" "1990"
+			86400	IN HINFO "DG MV-4009" "1990"
+			86400	IN HINFO "DG MV-4010" "1990"
+			86400	IN HINFO "DG MV-4011" "1990"
+			86400	IN HINFO "DG MV-4012" "1990"
+			86400	IN HINFO "DG MV-4013" "1990"
+			86400	IN HINFO "DG MV-4014" "1990"
+			86400	IN HINFO "DG MV-4015" "1990"
+			86400	IN HINFO "DG MV-4016" "1990"
+			86400	RRSIG	HINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					gkoYkqVsjRqPFQx8a5B42+kidExzFOoEup9r
+					9q/V/xtxx+z8T84u/qXxwLwKgLoYGBafVH2+
+					0XJLQ/Gg7pJK2CeWAoDElKmeLSl7VB3epvxe
+					KfFIWl9kOjakoDkaEPc6XE3Yo/JouelyGj3Z
+					LqHYXHA7xozZYw+K5cLqsMTNqjU= )
+			3600	NSEC	multiple-type-ipseckey-record.example.com. HINFO RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					z+pbp+klFIu5h22skrEjRFJV3P9c8cmUx2aX
+					fLRUl4XMUf6hYrQl+4zuMp2OwS3UnMY+mGQC
+					G/PnbvoFbc7kemyaYtJXbs4CpE1mk3FlSzbW
+					Rowb7K7gy9S+P88b/SLgJvV5V0cZLbp1UqV7
+					mewGUQFsc7JSXZZzko8QyDsW8D4= )
+multiple-type-apl-record.example.com. 86400 IN APL 1:192.168.32.15/14 !1:192.168.38.0/28
+			86400	IN APL	1:192.168.33.15/15 !1:192.168.39.0/28
+			86400	IN APL	1:192.168.34.15/16 !1:192.168.40.0/28
+			86400	IN APL	1:192.168.35.15/17 !1:192.168.41.0/28
+			86400	IN APL	1:192.168.36.15/18 !1:192.168.42.0/28
+			86400	IN APL	1:192.168.37.15/19 !1:192.168.43.0/28
+			86400	IN APL	1:192.168.38.15/20 !1:192.168.44.0/28
+			86400	IN APL	1:192.168.39.15/21 !1:192.168.45.0/28
+			86400	IN APL	1:192.168.40.15/22 !1:192.168.46.0/28
+			86400	IN APL	1:192.168.41.15/23 !1:192.168.47.0/28
+			86400	IN APL	1:192.168.42.15/24 !1:192.168.48.0/28
+			86400	IN APL	1:192.168.43.15/25 !1:192.168.49.0/28
+			86400	IN APL	1:192.168.44.15/26 !1:192.168.50.0/28
+			86400	IN APL	1:192.168.45.15/27 !1:192.168.51.0/28
+			86400	IN APL	1:192.168.46.15/28 !1:192.168.52.0/28
+			86400	IN APL	1:192.168.47.15/29 !1:192.168.53.0/28
+			86400	IN APL	1:192.168.48.15/20 !1:192.168.54.0/28
+			86400	IN APL	1:224.0.0.0/4 2:ff00::aaaa:cccc:bbbb:9999:5555/48
+			86400	IN APL	1:224.0.0.5/8 2:ff00::/8
+			86400	IN APL	1:224.0.0.9/12 2:ff00::888f:0/24
+			86400	IN APL	1:224.0.0.13/16 2:ff00::7777/72
+			86400	RRSIG	APL 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aehwZTTprSc6w/FDMjLqB574zGk5TMjPpKw9
+					XPUJ2oH2BvAffjSolgd96+3DdrcRnn/8WxUB
+					NxJGGfRldaWrpz1/2Kyh+H1/b/neo30pAHn7
+					yM6Ikl9INciVjk7iubLA0jC42szWDywaGPRm
+					GxaxZrcdNU1m+76HG+X5z7/qtyw= )
+			3600	NSEC	test.non-terminal.multiple-type-apl-record.example.com. APL RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					BLMYiCErePflhN13zVr9H4ixeq1EC/m1/Igd
+					c3cthuQ3YRbYylhmJ1Y/3FBJyjnExM3JVPlg
+					0v+kgG34F1i9QzItAKk03VNWwSSxuW3wLRhD
+					7m0KlyactIGcn4PzzQUbcLNuvApiphJb5EDT
+					Wd9TAvhZchgdsbcB2SJTEypHPYM= )
+test.non-terminal.multiple-type-apl-record.example.com.	86400 IN APL 1:192.168.32.15/14 !1:192.168.38.0/28
+			86400	IN APL	1:192.168.33.15/15 !1:192.168.39.0/28
+			86400	IN APL	1:192.168.34.15/16 !1:192.168.40.0/28
+			86400	IN APL	1:192.168.35.15/17 !1:192.168.41.0/28
+			86400	IN APL	1:192.168.36.15/18 !1:192.168.42.0/28
+			86400	IN APL	1:192.168.37.15/19 !1:192.168.43.0/28
+			86400	IN APL	1:192.168.38.15/20 !1:192.168.44.0/28
+			86400	IN APL	1:192.168.39.15/21 !1:192.168.45.0/28
+			86400	IN APL	1:192.168.40.15/22 !1:192.168.46.0/28
+			86400	IN APL	1:192.168.41.15/23 !1:192.168.47.0/28
+			86400	IN APL	1:192.168.42.15/24 !1:192.168.48.0/28
+			86400	IN APL	1:192.168.43.15/25 !1:192.168.49.0/28
+			86400	IN APL	1:192.168.44.15/26 !1:192.168.50.0/28
+			86400	IN APL	1:192.168.45.15/27 !1:192.168.51.0/28
+			86400	IN APL	1:192.168.46.15/28 !1:192.168.52.0/28
+			86400	IN APL	1:192.168.47.15/29 !1:192.168.53.0/28
+			86400	IN APL	1:192.168.48.15/20 !1:192.168.54.0/28
+			86400	IN APL	1:224.0.0.0/4 2:ff00::aaaa:cccc:bbbb:9999:5555/48
+			86400	IN APL	1:224.0.0.5/8 2:ff00::/8
+			86400	IN APL	1:224.0.0.9/12 2:ff00::888f:0/24
+			86400	IN APL	1:224.0.0.13/16 2:ff00::7777/72
+			86400	RRSIG	APL 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					FDKSvC1Hlgc+duM5wdWPDAjmqdJgxv22pHhI
+					xxHh6Y75VPi1zockKHZ/L9vMVm6kTtp697/h
+					UjnY2zzD104gUX1NPJPfuUJg8bdhd+r56zpc
+					uRPeBZI9EXvSXkmdmnIHtCv9Pq0wR5mOZSp1
+					zUeyUnR8GJUH+cKraS45IW7mwJ0= )
+			3600	NSEC	multiple-type-cert-record.example.com. APL RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wlrUQ2kurNfp9VNdmGudUuLx0GbQAgEHyh9V
+					ABZDLzzEZy6ioJ71evrUa3ra3XoCb5/dg/MP
+					aOpGeD++ohZ6XOTmDEygH6ZxQflVLAuevBGN
+					XfmrZxpEAX4Ff9EecEnW8Esw3a1bUs7Pt8e4
+					DPUEN++I9FnGZ/6AETeoQJbqKns= )
+test.non-terminal.multiple-type-kx-record.example.com. 86400 IN	KX 0 kaku0.google.com.
+			86400	IN KX	10 kaku1.google.com.
+			86400	IN KX	20 kaku2.google.com.
+			86400	IN KX	30 kaku3.google.com.
+			86400	IN KX	40 kaku4.google.com.
+			86400	IN KX	50 kaku5.google.com.
+			86400	IN KX	60 kaku6.google.com.
+			86400	IN KX	70 kaku7.google.com.
+			86400	IN KX	80 kaku8.google.com.
+			86400	IN KX	90 kaku9.google.com.
+			86400	IN KX	100 kaku10.google.com.
+			86400	IN KX	110 kaku11.google.com.
+			86400	IN KX	120 kaku12.google.com.
+			86400	IN KX	130 kaku13.google.com.
+			86400	RRSIG	KX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					K4xlhr1K6jZ/6wNo4FFN/gKSMRWeC5UD1J3T
+					inMvzeTwWLHM7u4HvNB/uqqM6d6w/clp2bx4
+					YG51yG8w9yZSMWLeqdbgMrvi3PojR4GQRGAM
+					y+27D8ocGPuZfd0tGIJ6rKHxoFlwTKJ/0lKQ
+					Hy+mN8DszNIexzJGGD9j5VYgGAM= )
+			3600	NSEC	multiple-type-loc-record.example.com. KX RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					nGn1/sPftbUJ8K4cmAW4yzVfjphyNDt9rQWT
+					B4Ut+I0llInvc+4qShem8orJzmTbH6gi4mJj
+					Kn96n5X9yvbrFby5ptwHcOVokn/rzlYpV+0m
+					4G2wlMVAfzFts0gJ54nKUmUmIzYETLduYPX+
+					Aq0HzuZbMIRCMOLK6wBI+f9QTWQ= )
+multiple-type-loc-record.example.com. 86400 IN LOC 32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	IN LOC	33 7 19.000 S 117 2 25.000 E 11.00m 1m 10000m 10m
+			86400	IN LOC	34 7 19.000 S 118 2 25.000 E 12.00m 1m 10000m 10m
+			86400	IN LOC	35 7 19.000 S 119 2 25.000 E 13.00m 1m 10000m 10m
+			86400	IN LOC	36 7 19.000 S 120 2 25.000 E 14.00m 1m 10000m 10m
+			86400	IN LOC	37 7 19.000 S 121 2 25.000 E 15.00m 1m 10000m 10m
+			86400	IN LOC	38 7 19.000 S 122 2 25.000 E 16.00m 1m 10000m 10m
+			86400	IN LOC	39 7 19.000 S 123 2 25.000 E 17.00m 1m 10000m 10m
+			86400	IN LOC	40 7 19.000 S 124 2 25.000 E 18.00m 1m 10000m 10m
+			86400	IN LOC	41 7 19.000 S 125 2 25.000 E 19.00m 1m 10000m 10m
+			86400	IN LOC	42 7 19.000 S 126 2 25.000 E 20.00m 1m 10000m 10m
+			86400	IN LOC	43 7 19.000 S 127 2 25.000 E 21.00m 1m 10000m 10m
+			86400	IN LOC	44 7 19.000 S 128 2 25.000 E 22.00m 1m 10000m 10m
+			86400	IN LOC	45 7 19.000 S 129 2 25.000 E 23.00m 1m 10000m 10m
+			86400	IN LOC	46 7 19.000 S 130 2 25.000 E 24.00m 1m 10000m 10m
+			86400	IN LOC	47 7 19.000 S 131 2 25.000 E 25.00m 1m 10000m 10m
+			86400	IN LOC	89 59 59.999 S 179 59 59.999 E 1000000.00m 1000m 1000m 10m
+			86400	IN LOC	90 0 0.000 S 180 0 0.000 E 0.01m 0.01m 0.01m 10m
+			86400	RRSIG	LOC 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ulzhF8Ko+Sr8OHUBwmFjaJv55/L91bpQvg5e
+					24Wm5wtvHh/HKDJpokvbj9DHhCpqK1E/9AW8
+					kc3qZjSnzt4FoLM3RqXrUVyWF2T1AnQgOCmu
+					kPaH3oxyrPSg8H8XYSFNckLA8OXicG1xTNeh
+					FdDhgNMEDr4PnBvgmUby7u3cQqo= )
+			3600	NSEC	test.non-terminal.multiple-type-loc-record.example.com. LOC RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					mwez/8p0PQ3c/jv4785yYIeWJmj1UCE40Sbn
+					rBGW/cPQDluXBSrKkcHiakmwm2Ox6VTNZPG9
+					m7sh0w8bxemoH0ELEePVXmbmICJxRC92n91f
+					laQKNMB3x0BWLviyWWzP3CIftWMRf4VBUIcQ
+					VhZHkXOcNfFF8gBeeOm4msZdX0M= )
+test.non-terminal.multiple-type-loc-record.example.com.	86400 IN LOC 32 7 19.000 S 116 2 25.000 E 10.00m 1m 10000m 10m
+			86400	IN LOC	33 7 19.000 S 117 2 25.000 E 11.00m 1m 10000m 10m
+			86400	IN LOC	34 7 19.000 S 118 2 25.000 E 12.00m 1m 10000m 10m
+			86400	IN LOC	35 7 19.000 S 119 2 25.000 E 13.00m 1m 10000m 10m
+			86400	IN LOC	36 7 19.000 S 120 2 25.000 E 14.00m 1m 10000m 10m
+			86400	IN LOC	37 7 19.000 S 121 2 25.000 E 15.00m 1m 10000m 10m
+			86400	IN LOC	38 7 19.000 S 122 2 25.000 E 16.00m 1m 10000m 10m
+			86400	IN LOC	39 7 19.000 S 123 2 25.000 E 17.00m 1m 10000m 10m
+			86400	IN LOC	40 7 19.000 S 124 2 25.000 E 18.00m 1m 10000m 10m
+			86400	IN LOC	41 7 19.000 S 125 2 25.000 E 19.00m 1m 10000m 10m
+			86400	IN LOC	42 7 19.000 S 126 2 25.000 E 20.00m 1m 10000m 10m
+			86400	IN LOC	43 7 19.000 S 127 2 25.000 E 21.00m 1m 10000m 10m
+			86400	IN LOC	44 7 19.000 S 128 2 25.000 E 22.00m 1m 10000m 10m
+			86400	IN LOC	45 7 19.000 S 129 2 25.000 E 23.00m 1m 10000m 10m
+			86400	IN LOC	46 7 19.000 S 130 2 25.000 E 24.00m 1m 10000m 10m
+			86400	IN LOC	47 7 19.000 S 131 2 25.000 E 25.00m 1m 10000m 10m
+			86400	IN LOC	89 59 59.999 S 179 59 59.999 E 1000000.00m 1000m 1000m 10m
+			86400	IN LOC	90 0 0.000 S 180 0 0.000 E 0.01m 0.01m 0.01m 10m
+			86400	RRSIG	LOC 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Hhg2/gJ4NSn/PBU6SaFXqd35wqDXOKJ84O5Y
+					Z0SfMJjZQ+S/jmGfPEDADp0p0d7J7N9ttari
+					yw9HMZ5AGOjl44aKfwVLivXcjITsar5RKyIT
+					E5Q22bb/SrDJUb9orcGJZmhFPlJXP7VGBbO8
+					frk9fsvG2g1wsO3Wh45M9us3jLI= )
+			3600	NSEC	multiple-type-minfo-record.example.com. LOC RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					y84udhTt/XPPoB6q1IjRXiC3DCBklB1h8rHY
+					fmjpmoqGc6eFViSWr3K3gx6XnuaOhIsXRjFe
+					knQlkYIRGy42YHvY7IZ1BiLDtM3k3twqsasP
+					9sUVavv3Km+IdvOfvTtbU5UYcaLiTIr8M7/p
+					vIPoqkTWeXntb0KR8rYYylVGPZA= )
+multiple-type-minfo-record.example.com.	86400 IN MINFO sun00.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun01.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun02.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun03.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.dn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.en. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.fn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.gn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	RRSIG	MINFO 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZI7hm5Zn9qwBl7HVkMLFLOrv5E4ggMSNsJ4w
+					MRJCIv+69fdhS43NYA/W2hQfUzOXa/JhFk/i
+					z+guQ6N6XhllidIaT53W6AIHZu/19QKpL2VS
+					VMQ4pDrtJYzQNsemeTcvfGzZdBmbPc/5QryR
+					zbswkajykzSDL9Au08M8TncCB3c= )
+			3600	NSEC	test.non-terminal.multiple-type-minfo-record.example.com. MINFO RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					fUwTo84k6vpmBltSZR1MZNtTDdZSGQ1/+ICZ
+					ummg0tYmImI6Ml3VBSgZepkIDT+7fa4JDWPT
+					EpYp7GK19OPgv8ijQhmPU3OVNAeqhvMpjK3g
+					w9IoR+OEQRYhgezsA0hyKIhd5OJ9bW/FBJTf
+					04Q8bo9tHqfUSpM2yK9c9xoaL70= )
+test.non-terminal.multiple-type-minfo-record.example.com. 86400	IN MINFO sun00.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun01.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun02.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun03.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.cn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.dn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.en. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.fn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	IN MINFO sun04.abc.foo.bar.liu.zhang.han.cnnic.gn. pipo.fifo.lilo.tito.gigo.bibo.riro.siso.vivo.cico.cn.
+			86400	RRSIG	MINFO 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					eUJ2HVgSxrFxBXmoEMHybIZ4CScum7nVIjJB
+					TRXwAZBoqTFWAxZ8v3tt2e0aIDk5lu3H/lLa
+					Z2ThcXpFYmibcBid4eWhwhsUoj+/vsProK6Q
+					spXz2+GPg9C/1aVmblO3JfUUQ/XHbDGLSOyJ
+					TtWC0MqUDbKu86jDlKOTTo5tyiw= )
+			3600	NSEC	multiple-type-mx-record.example.com. MINFO RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					YK9blDNd/KdWiDYEFQi3wPAiY3r7+kk44aRl
+					IV0E/Mwpg6Uy/n6h8fS8Jxv35lWusKFjR76F
+					6ekvGjn+a9aXZ1INxR2F2aLMxI/pM9qnntty
+					PdBx+X8OQlrT3ZU4Egt+Edl+TYZEmLYVCCaV
+					nvQw5+tXChTPlgjxCs0MsJe+LSo= )
+multiple-type-mx-record.example.com. 86400 IN MX 10 mail1.example.com.
+			86400	IN MX	10 mail2.example.com.
+			86400	IN MX	10 mail3.example.com.
+			86400	IN MX	10 mail4.example.com.
+			86400	IN MX	10 mail5.example.com.
+			86400	IN MX	10 mail6.example.com.
+			86400	IN MX	10 mail7.example.com.
+			86400	IN MX	10 mail8.example.com.
+			86400	IN MX	10 mail9.example.com.
+			86400	IN MX	10 mail10.example.com.
+			86400	IN MX	10 mail11.example.com.
+			86400	IN MX	10 mail12.example.com.
+			86400	IN MX	20 mail13.example.com.
+			86400	IN MX	30 mail14.example.com.
+			86400	IN MX	40 mail15.example.com.
+			86400	IN MX	50 mail16.example.com.
+			86400	IN MX	60 mail17.example.com.
+			86400	IN MX	70 mail18.example.com.
+			86400	IN MX	80 mail19.example.com.
+			86400	IN MX	90 mail20.example.com.
+			86400	RRSIG	MX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					n1a9V6z3XbAXFUwAtE0eqS1Cq5wJhIG8AZkF
+					rABGfxtLR7zatMeRwIjx4aUoUI5vLWN0E+di
+					1xOAEDiFOjw+jFYklcR6dqREdrEbJFYAOPwY
+					MCCKeOPay3VcJxW/Z5yjLSBPnq7jq9ERawcB
+					MJnOnKS49WaibS3VYiWuXOXfn2s= )
+			3600	NSEC	test.non-terminal.multiple-type-mx-record.example.com. MX RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					U1f48jBPDKboX/uyoNm8/bRKVV9ro2iNx28C
+					0QAyRv/Wm3oc+u9dJQZF0lobbf12XiYOP+G1
+					UTSBTx8TKPNqkeQWYE/jjpiB7DOF24Ua6Mh+
+					d+bofYik7Eissuyqm6jJbkfJjSjNluAixbKc
+					iRmt1BNYGIMfXj4FsJHYESRMW1M= )
+test.non-terminal.multiple-type-mx-record.example.com. 86400 IN	MX 10 mail1.example.com.
+			86400	IN MX	10 mail2.example.com.
+			86400	IN MX	10 mail3.example.com.
+			86400	IN MX	10 mail4.example.com.
+			86400	IN MX	10 mail5.example.com.
+			86400	IN MX	10 mail6.example.com.
+			86400	IN MX	10 mail7.example.com.
+			86400	IN MX	10 mail8.example.com.
+			86400	IN MX	10 mail9.example.com.
+			86400	IN MX	10 mail10.example.com.
+			86400	IN MX	10 mail11.example.com.
+			86400	IN MX	10 mail12.example.com.
+			86400	IN MX	20 mail13.example.com.
+			86400	IN MX	30 mail14.example.com.
+			86400	IN MX	40 mail15.example.com.
+			86400	IN MX	50 mail16.example.com.
+			86400	IN MX	60 mail17.example.com.
+			86400	IN MX	70 mail18.example.com.
+			86400	IN MX	80 mail19.example.com.
+			86400	IN MX	90 mail20.example.com.
+			86400	RRSIG	MX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					BTXMAaDMhKrLa9vsctT6XkutEC4KRzmyFej5
+					PbCv/n+q81Nyevyp5VZjH2/u30JNA2BDjhcA
+					EvMUncGljMiz9hKvqW04R295Z+aSq0xINM8H
+					wE0S+Ef1KQDNJv4z9jHwnvtJx8BXT+RXeXMK
+					t9+uv7X/ejrWFrgLGEVnrP9MexE= )
+			3600	NSEC	multiple-type-ns-record.example.com. MX RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AFH7WPdHrW3IhPeWuE7kBvgLWqa/Qd7zm+69
+					RzH0tC7ZEB/LH7noLvHr3a4L0gYR0CD7p6Oh
+					q6e7KNGcA/bUoS8YXxlQiyl/ByGQxSe5jUVi
+					zbAk/6p7QlRg/6q3HlphjK0r+C23FlUsElcu
+					kV0WEzGZ8rONYzxbduUVluTW0Co= )
+dns1.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.1
+test.non-terminal.dns1.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.1
+dns10.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.10
+test.non-terminal.dns10.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.10
+dns11.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.11
+test.non-terminal.dns11.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.11
+dns12.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.12
+test.non-terminal.dns12.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.12
+dns13.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.13
+test.non-terminal.dns13.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.13
+dns14.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.14
+test.non-terminal.dns14.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.14
+dns15.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.15
+test.non-terminal.dns15.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.15
+dns16.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.16
+test.non-terminal.dns16.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.16
+dns17.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.17
+test.non-terminal.dns17.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.17
+dns18.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.18
+test.non-terminal.dns18.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.18
+dns19.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.19
+test.non-terminal.dns19.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.19
+dns2.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.2
+test.non-terminal.dns2.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.2
+dns20.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.20
+test.non-terminal.dns20.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.20
+dns21.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.21
+test.non-terminal.dns21.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.21
+dns22.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.22
+test.non-terminal.dns22.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.22
+dns23.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.23
+test.non-terminal.dns23.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.23
+dns24.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.24
+test.non-terminal.dns24.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.24
+dns25.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.25
+test.non-terminal.dns25.multiple-type-ns-record.example.com. 86400 IN A	192.168.4.25
+dns3.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.3
+test.non-terminal.dns3.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.3
+dns4.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.4
+test.non-terminal.dns4.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.4
+dns5.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.5
+test.non-terminal.dns5.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.5
+dns6.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.6
+test.non-terminal.dns6.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.6
+dns7.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.7
+test.non-terminal.dns7.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.7
+dns8.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.8
+test.non-terminal.dns8.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.8
+dns9.multiple-type-ns-record.example.com. 86400	IN A 192.168.4.9
+test.non-terminal.dns9.multiple-type-ns-record.example.com. 86400 IN A 192.168.4.9
+test.non-terminal.multiple-type-ns-record.example.com. 86400 IN	NS dns1.multiple-type-ns-record.example.com.
+			86400	IN NS	dns2.multiple-type-ns-record.example.com.
+			86400	IN NS	dns3.multiple-type-ns-record.example.com.
+			86400	IN NS	dns4.multiple-type-ns-record.example.com.
+			86400	IN NS	dns5.multiple-type-ns-record.example.com.
+			86400	IN NS	dns6.multiple-type-ns-record.example.com.
+			86400	IN NS	dns7.multiple-type-ns-record.example.com.
+			86400	IN NS	dns8.multiple-type-ns-record.example.com.
+			86400	IN NS	dns9.multiple-type-ns-record.example.com.
+			86400	IN NS	dns10.multiple-type-ns-record.example.com.
+			86400	IN NS	dns11.multiple-type-ns-record.example.com.
+			86400	IN NS	dns12.multiple-type-ns-record.example.com.
+			86400	IN NS	dns13.multiple-type-ns-record.example.com.
+			86400	IN NS	dns14.multiple-type-ns-record.example.com.
+			86400	IN NS	dns15.multiple-type-ns-record.example.com.
+			86400	IN NS	dns16.multiple-type-ns-record.example.com.
+			86400	IN NS	dns17.multiple-type-ns-record.example.com.
+			86400	IN NS	dns18.multiple-type-ns-record.example.com.
+			86400	IN NS	dns19.multiple-type-ns-record.example.com.
+			86400	IN NS	dns20.multiple-type-ns-record.example.com.
+			86400	IN NS	dns21.multiple-type-ns-record.example.com.
+			86400	IN NS	dns22.multiple-type-ns-record.example.com.
+			86400	IN NS	dns23.multiple-type-ns-record.example.com.
+			86400	IN NS	dns24.multiple-type-ns-record.example.com.
+multiple-type-ipseckey-record.example.com. 86400 IN IPSECKEY ( 10 1 2 192.0.2.3
+					AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.4
+					BQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.5
+					CQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.6
+					DQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.7
+					EQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.8
+					FQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.9
+					GQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.10
+					HQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	IN IPSECKEY ( 10 1 2 192.0.2.11
+					IQNRU3mG7TVTO2BkR47usntb102uFJtugbo6
+					BSGvgqt4AQ== )
+			86400	RRSIG	IPSECKEY 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					S6gFr+bJMrovfOsEzphLuH/peRKpC1e9CIw1
+					MxMQNN4YRW0XtJ0P6R4crYkRIE6hOtMsAHlD
+					PTAOZmnInmM/8Nhv0f7917NFJLrXpmpcqFLu
+					lolxyYPgTvDEaD4hE6ufCbHoxcQVPvDoNNUW
+					MA6sat8kv+I+6/uR2yTNUuDn5xk= )
+			3600	NSEC	multiple-type-kx-record.example.com. IPSECKEY RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					bSTvLRt+Gky6rF00U36bSN5SkSqtMQYlYvvP
+					GpulB8CBePWtgvyfgoqqldDTxfrqNzNMJ9ty
+					VZuHP96F9g15C/hOcuatoYri+HxTaNnUnk6c
+					bKGx7EKkkw7DCwO/WeD+DxAYiGVv1ugJ1hVz
+					MV4zSmYKajwf1TicojyQsxedD5o= )
+multiple-type-ns-record.example.com. 86400 IN NS dns1.multiple-type-ns-record.example.com.
+			86400	IN NS	dns2.multiple-type-ns-record.example.com.
+			86400	IN NS	dns3.multiple-type-ns-record.example.com.
+			86400	IN NS	dns4.multiple-type-ns-record.example.com.
+			86400	IN NS	dns5.multiple-type-ns-record.example.com.
+			86400	IN NS	dns6.multiple-type-ns-record.example.com.
+			86400	IN NS	dns7.multiple-type-ns-record.example.com.
+			86400	IN NS	dns8.multiple-type-ns-record.example.com.
+			86400	IN NS	dns9.multiple-type-ns-record.example.com.
+			86400	IN NS	dns10.multiple-type-ns-record.example.com.
+			86400	IN NS	dns11.multiple-type-ns-record.example.com.
+			86400	IN NS	dns12.multiple-type-ns-record.example.com.
+			86400	IN NS	dns13.multiple-type-ns-record.example.com.
+			86400	IN NS	dns14.multiple-type-ns-record.example.com.
+			86400	IN NS	dns15.multiple-type-ns-record.example.com.
+			86400	IN NS	dns16.multiple-type-ns-record.example.com.
+			86400	IN NS	dns17.multiple-type-ns-record.example.com.
+			86400	IN NS	dns18.multiple-type-ns-record.example.com.
+			86400	IN NS	dns19.multiple-type-ns-record.example.com.
+			86400	IN NS	dns20.multiple-type-ns-record.example.com.
+			86400	IN NS	dns21.multiple-type-ns-record.example.com.
+			86400	IN NS	dns22.multiple-type-ns-record.example.com.
+			86400	IN NS	dns23.multiple-type-ns-record.example.com.
+			86400	IN NS	dns24.multiple-type-ns-record.example.com.
+			3600	NSEC	multiple-type-nsap-record.example.com. NS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					hGy291VFD0/csxNnK9OwnL52ufIRnZpta7MK
+					1KQ2XboDyUTxJEKbKFiQpD33eUDDkNgcbueF
+					57BBm2A+O1Kmn5I58ri22hQOZGVEqXlFJsFe
+					tQ76bHy0LUUt1fy2vXdjeC2Z1KonDbxJiRpa
+					772s419tSBNU500199iHoH368yc= )
+multiple-type-kx-record.example.com. 86400 IN KX 0 kaku0.google.com.
+			86400	IN KX	10 kaku1.google.com.
+			86400	IN KX	20 kaku2.google.com.
+			86400	IN KX	30 kaku3.google.com.
+			86400	IN KX	40 kaku4.google.com.
+			86400	IN KX	50 kaku5.google.com.
+			86400	IN KX	60 kaku6.google.com.
+			86400	IN KX	70 kaku7.google.com.
+			86400	IN KX	80 kaku8.google.com.
+			86400	IN KX	90 kaku9.google.com.
+			86400	IN KX	100 kaku10.google.com.
+			86400	IN KX	110 kaku11.google.com.
+			86400	IN KX	120 kaku12.google.com.
+			86400	IN KX	130 kaku13.google.com.
+			86400	RRSIG	KX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					tdUveI5DwuJTkM1NOfp+IGWO5bYyLjb4ujTo
+					1IlGJoVzyzA4NxGQGhX7zHVMx3uI0Mj85eQ0
+					pLsUi9SLP/gXNcvz7KHnEc7UnBFraochDS0n
+					Uop0Y1Kh7PjL8/jrTjgnDsz0Tg9yAJPNrIMa
+					JHQWasZjphbO9iRFrlJ4XTKHx6A= )
+			3600	NSEC	test.non-terminal.multiple-type-kx-record.example.com. KX RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					TuV2ESpHYIOFm2VZ10JCEPLLmoIRg36FVY5O
+					qj6vfg/6vzIxLviMtBlq+SYoiADw+w+EeQaq
+					cYhuv44V6G5LlfViSLNFWPXntBnEkIUQlLVc
+					B9vbD2bYb7pPBW40qn8m22d5xDaz+VFi7/hV
+					JeRNhEjb0nl1De7Vw4yrYXguF9E= )
+multiple-type-nsap-record.example.com. 86400 IN	NSAP 0x47000580ffff0000003210999911112222333345
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333346
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333347
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333348
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333349
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334a
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334b
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334c
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334d
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334e
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334f
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333350
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333351
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333352
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333353
+			86400	RRSIG	NSAP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					VjjJ7wbuhaC7NRGHCYvLvMcfIq4NfrqsKPUT
+					R3MGYS2BDQV4zRH2+O3ZZvJPowMYjRLtirZb
+					zCufgAeMSffttz0NYaeFc3aPt3P99Svdyj8A
+					8a/A31rCsT2pX3JKpjqsbWvZ71ezJtlysizF
+					chSvSB+zfVzrZkYUIaAxj4GQOmw= )
+			3600	NSEC	test.non-terminal.multiple-type-nsap-record.example.com. NSAP RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Wtp2ageuXKacRJvnPgqHi7DFetvEH2Sti3Y3
+					ofcZlCu0k9vH60DHGPQVZZDXMsJqNbm6rEP/
+					8gl/FULxmdbYt54xrXzhTVj5LLQ/zIwHfYcC
+					ybz6EnBR5ECIm7AYDssaGYS30q378ILGaIJp
+					pE9ekJ7BMuvlnfcY16cpIrTla2I= )
+multiple-type-ptr-record.example.com. 86400 IN PTR 192.168.2.1.example.com.
+			86400	IN PTR	192.168.2.2.example.com.
+			86400	IN PTR	192.168.2.3.example.com.
+			86400	IN PTR	192.168.2.4.example.com.
+			86400	IN PTR	192.168.2.5.example.com.
+			86400	IN PTR	192.168.2.6.example.com.
+			86400	IN PTR	192.168.2.7.example.com.
+			86400	IN PTR	192.168.2.8.example.com.
+			86400	IN PTR	192.168.2.9.example.com.
+			86400	IN PTR	192.168.2.10.example.com.
+			86400	IN PTR	192.168.2.11.example.com.
+			86400	IN PTR	192.168.2.12.example.com.
+			86400	IN PTR	192.168.2.13.example.com.
+			86400	IN PTR	192.168.2.14.example.com.
+			86400	IN PTR	192.168.2.15.example.com.
+			86400	IN PTR	192.168.2.16.example.com.
+			86400	IN PTR	192.168.2.17.example.com.
+			86400	IN PTR	192.168.2.18.example.com.
+			86400	RRSIG	PTR 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xMr0GjsJdcM49li65zthlitnHMAn9TnOvwZG
+					BCq3Z6tfwLqMjQ+OE5GJL4LxRwbzeD4He5F/
+					E0jgt53h5UBXIDGQW5JVn37eymOpq85AZXXj
+					DPwzSE52wPSiglYdE8yD1YCiuMsUzwuxIuB4
+					vmsQ6Uhk290QA1B+HSF2lOozQ6M= )
+			3600	NSEC	test.non-terminal.multiple-type-ptr-record.example.com. PTR RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					Ycs286OBLxSiSUj//nyrgzM4A/RjGADr3q5B
+					zyX8lCk2DyBIOVzJi6s17uy/FhuPiIHDXUMG
+					TN/30+tlo0PNaK+sA7wSY01djNVdcGuWv5id
+					LNaeHi5poNlOw2LwulKvDH7jbctBTDd7yaPu
+					S00drnPpXu0BhF5+QrBnRS7G3pw= )
+test.non-terminal.multiple-type-ptr-record.example.com.	86400 IN PTR 192.168.2.1.example.com.
+			86400	IN PTR	192.168.2.2.example.com.
+			86400	IN PTR	192.168.2.3.example.com.
+			86400	IN PTR	192.168.2.4.example.com.
+			86400	IN PTR	192.168.2.5.example.com.
+			86400	IN PTR	192.168.2.6.example.com.
+			86400	IN PTR	192.168.2.7.example.com.
+			86400	IN PTR	192.168.2.8.example.com.
+			86400	IN PTR	192.168.2.9.example.com.
+			86400	IN PTR	192.168.2.10.example.com.
+			86400	IN PTR	192.168.2.11.example.com.
+			86400	IN PTR	192.168.2.12.example.com.
+			86400	IN PTR	192.168.2.13.example.com.
+			86400	IN PTR	192.168.2.14.example.com.
+			86400	IN PTR	192.168.2.15.example.com.
+			86400	IN PTR	192.168.2.16.example.com.
+			86400	IN PTR	192.168.2.17.example.com.
+			86400	IN PTR	192.168.2.18.example.com.
+			86400	RRSIG	PTR 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					cU6aFz/ZFM8Sn/3faM0jdOxmQ7l3H4yBNIkz
+					dDK/NhisaScsEVifPDSkDOye3Z0mCB22eJSt
+					Z5OKiLEfG7LIskHVFckYcjtX1/z9Atiimqfk
+					EKyqefWHDmYgcN79Ik212BR77qrAaFc9VbE3
+					pt0fImdLIoavysX2H6ja+LddfWg= )
+			3600	NSEC	multiple-type-px-record.example.com. PTR RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					iW85YGRBWXGMMKOCwy9jObygUotQ+qtYXvGV
+					DhlNSa92e9fr3lkJXmkTobs8yM8Y6y26sgMO
+					N7Pu7ecOoj8lrGqnhvh0qDQ6XHi0yZndTsAy
+					nx6oe2MjTmn5Qfo+a1JLCf6DPTPvq8WJTdPl
+					WOuYYdxULuYWZxwhMfpO6udbeWI= )
+multiple-type-px-record.example.com. 86400 IN PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	11 ab.net3.it. 1-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	12 ab.net4.it. 2-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	13 ab.net5.it. 3-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	14 ab.net6.it. 4-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	15 ab.net7.it. 5-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	16 ab.net8.it. 6-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net9.it. 7-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net2.it. 8-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net2.it. 9-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					L4Ei+7bRt5fC/yz5QKoLdjDQHf4tFRfueF0H
+					RXKm5ytymaaNfbA+MWVB1YAo/4volienHpz8
+					6xwW2UEdBmSlAN+F2ITp9vy3Rbt4WRrvW1f+
+					EHfZUAW9b9wNfjY2gYNiBkD+/Ilw4le/gG3M
+					4bD2RDndIcDrS0ibgPhfJV9yBnM= )
+			3600	NSEC	test.non-terminal.multiple-type-px-record.example.com. PX RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					n8tYwZFxp04RsaevVGSgiJYIUB4yQ8PUH13r
+					CtOMhyZ9pOKRapoZo+oSCP7XKPrjpAu/IoJw
+					Z0ZIEgDEGvMmrd7eJF5kvx/Ac7Ev11M3LsfP
+					Vqo5yyMbTEzdeQjx8Jy+4PXs8Q7L4t2p1Qal
+					Yju8Lbn5PW0trhw2mQd9lr3UIXQ= )
+test.non-terminal.multiple-type-px-record.example.com. 86400 IN	PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	11 ab.net3.it. 1-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	12 ab.net4.it. 2-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	13 ab.net5.it. 3-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	14 ab.net6.it. 4-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	15 ab.net7.it. 5-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	16 ab.net8.it. 6-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net9.it. 7-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net2.it. 8-ab.PRMD-net2.ADMDb.C-it.
+			86400	IN PX	10 ab.net2.it. 9-ab.PRMD-net2.ADMDb.C-it.
+			86400	RRSIG	PX 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					T5eoO8YYxMN4gJ7wbonQn2qt+QuMXk9OqErP
+					HhqWbrCGhdgj+n4KvbqzAgutcBWcNDEM72F1
+					J5kcNJyw7KB5Cgc5LPOYFLr0e0GLdKMDKR8D
+					2HictxvGwxNa044z54ArZB57K8dj0ZvVKD4x
+					gBddOCAdo6xjA0yDPSqThASjEPA= )
+			3600	NSEC	multiple-type-spf-record.example.com. PX RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					W7UWZhx9H+WRE4rWvaqN6WNA+sjnAwOJ9qvr
+					oacCBklJMCu/8Dq8OyK4TbJ/jQdcZHWPA7Ck
+					Sm1A3dw3WjD6xrNXFdk53UzHBV4hpIgFMMaU
+					cPRnGoH2oYMeysqHxxG8kaP/snz3FFM795E+
+					7p7SutdJRwxtAgYEJ0lTMbnYYQY= )
+multiple-type-spf-record.example.com. 3600 IN NSEC test.non-terminal.multiple-type-spf-record.example.com. RRSIG NSEC SPF
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					fYl7qQa5MF35eatIE/SXaNuHSStpVPruc2nJ
+					TP6A6uwDz3mG52EJg55ppiy4geSS6PO/LHU9
+					hnf0PP7uL8tgyDcxlLEvtCkaSaZ9H6yrsCn2
+					28j916U/OTEzOxtz6jvHZL2dXr4jizTJIaAp
+					hCrRq/7pzZfzcubwzwfqpZW/TbY= )
+			86400	SPF	"'asdfghjkl"
+			86400	SPF	"'sina"
+			86400	SPF	"'cnnic"
+			86400	SPF	"'jkl"
+			86400	SPF	"'c=sina.com.'"
+			86400	SPF	"'fw=fff.com.cn.'"
+			86400	SPF	"'ibm"
+			86400	SPF	"'dell"
+			86400	SPF	"'google" "-" "microsoft"
+			86400	SPF	"'leibusi"
+			86400	SPF	"v=spf1"
+			86400	SPF	"v=spf1 -all"
+			86400	SPF	"v=spf1 ip4:192.168.0.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.1.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.2.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.3.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.4.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.5.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.6.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.7.1/16 -all "
+			86400	RRSIG	SPF 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					nIzHN3gjvwLEZxKGRIX8ip+LLb6F4zPkkV7P
+					zgNkeUwrT9/1kTxn6dM7JLUs4B2e3TTOVVau
+					/8keis6ERbW51w0dR6glneGUqvWOk+GH1Qdo
+					nJLOkpPnXqUKr50pcLxS8YCf0bqYXZOy3uWh
+					4eEKEKlgnYGys/+oZdiB8ulPR2E= )
+test.non-terminal.multiple-type-spf-record.example.com.	3600 IN	NSEC multiple-type-srv-record.example.com. RRSIG NSEC SPF
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					uCohn+WaZg8LrCFrvjz0xRgKR2FTGMh2Vmw1
+					HrHnzdFj4RhAKIlcD+CMsaWlNYetu4AvK0Xw
+					uB+Q1GjkOjMhm843RxjNSXacCzvIoixYrt8w
+					XR8fLeRzv6fZbYocyKjgXuOmiIlBQp47yOW3
+					ptItmoFKrcxoZ5KW3dIvAYLNISM= )
+			86400	SPF	"'asdfghjkl"
+			86400	SPF	"'sina"
+			86400	SPF	"'cnnic"
+			86400	SPF	"'jkl"
+			86400	SPF	"'c=sina.com.'"
+			86400	SPF	"'fw=fff.com.cn.'"
+			86400	SPF	"'ibm"
+			86400	SPF	"'dell"
+			86400	SPF	"'google" "-" "microsoft"
+			86400	SPF	"'leibusi"
+			86400	SPF	"v=spf1"
+			86400	SPF	"v=spf1 -all"
+			86400	SPF	"v=spf1 ip4:192.168.0.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.1.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.2.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.3.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.4.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.5.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.6.1/16 -all "
+			86400	SPF	"v=spf1 ip4:192.168.7.1/16 -all "
+			86400	RRSIG	SPF 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					CjyonA4FOC7BYfeSGe7dJNO3sn/8SkVAH3+m
+					P1pxkJzMRzemMu65sFI6vlnRtbCvh6Q5wPRH
+					s2YDpiO0+QXDn6+75vS2Fzgmn5nOppt2SSsA
+					oRBM+uDaAmsBreYFJkXtx4PdpbaL/pGE3hx5
+					qmOAHRxS6snoZtewleyWvCnr6GY= )
+test.non-terminal.multiple-type-nsap-record.example.com. 86400 IN NSAP 0x47000580ffff0000003210999911112222333345
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333346
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333347
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333348
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333349
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334a
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334b
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334c
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334d
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334e
+			86400	IN NSAP	0x47000580ffff000000321099991111222233334f
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333350
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333351
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333352
+			86400	IN NSAP	0x47000580ffff0000003210999911112222333353
+			86400	RRSIG	NSAP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					xefH7sd6NOTwJzREvnIXvOnh6bokfP6rjCJ6
+					Nwdl/Sgh6bDsbrrJTVIPIgZOXsjU7/OKakFG
+					ICOdpVWYmYnLnYcLyu/VP1zgXDnRydEFyYVp
+					WT/67H1dsCcYWM7KHq6eVdhMZe2pKturt1cD
+					W20lTJ0jdg7AK3Cg8v7K74Fpqzs= )
+			3600	NSEC	multiple-type-ptr-record.example.com. NSAP RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					w51cGk1/OFOq2wQoOUaswnmf7SAQkj3hc1xI
+					9SRdhrG+FwVn+4wxP43/kBdvWI/auSUgWqtT
+					OGGg4vBCq3AXw3ujRIZlVmfJjUtIOSZQp9mC
+					8pwU9tRhQJxMNBp3YpI2wlDZH4oUvZ//OAqI
+					1zHHt8nwM49xbnZN/RVZwsITVKI= )
+multiple-type-sshfp-record.example.com.	86400 IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7891 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7892 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7893 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7894 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7895 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7896 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7897 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7898 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7899 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789A )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789B )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789C )
+			86400	RRSIG	SSHFP 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					diDyrgPWHOROwzvA4uiTMlMt7TecCExaW4Di
+					lAcbaKw0L9FFm7Y/NFzbMnbTHil7oQXsj7YL
+					ACSfB2VEYOcbz+634MAP6OhWAbYi2tH4NtCo
+					NN7s0FO+X1OY4loW+YUzqv07GQx3rGU1Rp8H
+					ZN9SBxByLYX6/iv70IOoiOzwGIo= )
+			3600	NSEC	test.non-terminal.multiple-type-sshfp-record.example.com. SSHFP RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					jdMPQ4Z+FZBsMN8U8avHc2rz+YgCM9QzMK+J
+					DSP23aELopJTeocG1unpLkEjw5btJqPW1Hxj
+					bA2G/rojgP8hUOi4qLis1AiA6rjHILnW/sD+
+					6H7DAxB7/tvD0SSJn55D3vmqU5WMrti9ofuA
+					n2LYz/MooVo2OMZATdrHvHGvuz4= )
+test.non-terminal.multiple-type-sshfp-record.example.com. 86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7890 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7891 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7892 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7893 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7894 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7895 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7896 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7897 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7898 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					7899 )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789A )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789B )
+			86400	IN SSHFP 2 1 (
+					123456789ABCDEF67890123456789ABCDEF6
+					789C )
+			86400	RRSIG	SSHFP 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					AZgsDXFCkg8QK/kb+myeB2S7Rt2/UoDtLZbi
+					iNmCi+ichEtXHsrYFW+cwnRC1ooUGGmR8RWq
+					IY+i/K1DdifcNu1eR7Fw8jvSGSwdP5PjcmZv
+					D7qsy9a1z6S4w8DV76yPSscc87feqJeFteDT
+					DDOY5qfTjDlU8NK0BeYyhIuAvIM= )
+			3600	NSEC	multiple-type-txt-record.example.com. SSHFP RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					gD4t70ymAKs3OGFjmOapjt4j7Sj4jxZoqtHP
+					/appQRN8b+sfq7I8bPuldmjGY/3dqoOuqXI5
+					i13PMeixxs6tWkfNAIc34/5V2jCnXH0ew+4f
+					NYP5Jf3En5XgXL/tMrMbduQvQL/WSqRj/eDX
+					JMX4Q7kAzPeey5dRrOhugnnVU5Y= )
+test.non-terminal.multiple-type-srv-record.example.com.	86400 IN SRV 0 2 80 www.movie0.edu.
+			86400	IN SRV	1 3 80 www.movie1.edu.
+			86400	IN SRV	2 4 80 www.movie2.edu.
+			86400	IN SRV	3 5 80 www.movie3.edu.
+			86400	IN SRV	4 6 80 www.movie4.edu.
+			86400	IN SRV	5 7 80 www.movie5.edu.
+			86400	IN SRV	6 8 80 www.movie6.edu.
+			86400	IN SRV	7 9 80 www.movie7.edu.
+			86400	IN SRV	8 10 80 www.movie8.edu.
+			86400	IN SRV	9 11 80 www.movie9.edu.
+			86400	IN SRV	10 12 80 www.movie10.edu.
+			86400	IN SRV	11 13 80 www.movie11.edu.
+			86400	IN SRV	12 14 80 www.movie12.edu.
+			86400	RRSIG	SRV 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ogZhDnKwKdVkMzz5tdzNb4g6Ob/eLvTYKDrl
+					V+lI1twfv79u2wRrrDGMPopIoqt2R0L8TCFd
+					6R9ZRGuqaXnH7RJO7dcMrPtfqaOXrfHobxI3
+					/869BlqTZTHh5KXAnxc2ecLPMz5ZKRvbu0Z3
+					a3+Ltis8XxQbA06VsgpPhxsEWc8= )
+			3600	NSEC	multiple-type-sshfp-record.example.com. SRV RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					lMSeqTve8vhMIrgCXFvFTvmV2oGxXtTTowxB
+					WK7WSwXBc3HI/sXPLlH4WkM9lYG0A7W/RtnI
+					Q1rmeiTCGr/Jnedn6fDfi3drLPxN1PktZyiT
+					aqguYMh5O8o7Bn3WDF7jsHoTCO2RBWVu/C5P
+					mOCIbM/bI0+Pz+Fr+bQXufBk/wU= )
+test.non-terminal.multiple-type-txt-record.example.com.	86400 IN TXT "txt::1"
+			86400	IN TXT	"txt::2"
+			86400	IN TXT	"txt::3"
+			86400	IN TXT	"txt::4"
+			86400	IN TXT	"txt::5"
+			86400	IN TXT	"txt::6"
+			86400	IN TXT	"txt::7"
+			86400	IN TXT	"txt::8"
+			86400	IN TXT	"txt::9"
+			86400	IN TXT	"txt::10"
+			86400	IN TXT	"txt::11"
+			86400	IN TXT	"txt::12"
+			86400	IN TXT	"txt::13"
+			86400	IN TXT	"txt::14"
+			86400	IN TXT	"txt::15"
+			86400	IN TXT	"txt::16"
+			86400	IN TXT	"txt::17"
+			86400	IN TXT	"txt::18"
+			86400	IN TXT	"txt::19"
+			86400	IN TXT	"txt::20"
+			86400	IN TXT	"txt::21"
+			86400	IN TXT	"txt::22"
+			86400	IN TXT	"txt::23"
+			86400	IN TXT	"txt::24"
+			86400	IN TXT	"txt::25"
+			86400	IN TXT	"txt::26"
+			86400	IN TXT	"txt::27"
+			86400	IN TXT	"txt::28"
+			86400	IN TXT	"txt::29"
+			86400	IN TXT	"txt::30"
+			86400	IN TXT	"txt::31"
+			86400	RRSIG	TXT 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					EI+oudyovCkHhDkHJO5B8KWQkKBowxFVXgPE
+					Aglas+tpdVlsyJ0DrOc3z1vOoJXnKW85SUH0
+					6DkPd+0PAmSraPNKHZmiL1onBgWjZgoXl4vD
+					NTTnBpnRrHTmxXF50x/j0tBwnSrIwqWW/exk
+					kkjthFL9jS/fJfSve2PHGqrZhtY= )
+			3600	NSEC	multiple-type-wks-record.example.com. TXT RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					jSP0eD1wN/KI8yAI4a3JqUXdN2a3zZVxdYgg
+					XaheCG4ftdh5RLMfZzZygx4OAFM3i9xKH2ul
+					sS8fyDcNx2yC8K5apt9CvQERQK6DgzvOMLv0
+					w/SJ9r7VsPwGQYGFkgL5lM/8j+OT8yWfqHKV
+					UqRVp2N9llMBgsZvONbcOAgk5y0= )
+multiple-type-wks-record.example.com. 86400 IN WKS 218.241.109.1 6 23 25 53
+			86400	IN WKS	218.241.109.2 6 23 25 53
+			86400	IN WKS	218.241.109.3 6 23 25 53
+			86400	IN WKS	218.241.109.4 6 23 25 53
+			86400	IN WKS	218.241.109.5 6 23 25 53
+			86400	IN WKS	218.241.109.6 6 23 25 53 6000
+			86400	IN WKS	218.241.109.7 6 23 25 53
+			86400	IN WKS	218.241.109.8 6 23 25 53
+			86400	IN WKS	218.241.109.9 6 23 25 53
+			86400	IN WKS	218.241.109.10 6 23 25 53
+			86400	IN WKS	218.241.109.11 6 22 23 25 53
+			86400	IN WKS	218.241.109.12 6 22 23 25 53
+			86400	IN WKS	218.241.109.13 6 22 23 25 53
+			86400	IN WKS	218.241.109.14 6 22 25 53 80
+			86400	IN WKS	218.241.109.15 6 22 25 53 80
+			86400	IN WKS	218.241.109.16 6 22 25 80 6000
+			86400	RRSIG	WKS 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Ay1hCHvEA0uCa7qBEi0ABZrf3qsAswLbfBoA
+					ep+6yXF1e0Yv7nQPVlc9qJT1yoDLgVdNzpO4
+					O7DyZ/sWVjoXxFu5pAiKY+X4rgr4XT48NuBm
+					0uzE2u9fNS/fi8lZoozhpWgGCLvP9+96pjGk
+					T9WMZOh9qPCLs8O0f3VFK+KLlzE= )
+			3600	NSEC	test.non-terminal.multiple-type-wks-record.example.com. WKS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					pzOvjfjiGC9VJvwetU61b5K90963EiKAeTou
+					zgBFZslR6OYGDUeoYNuYi9CDJPyOctb8NAsq
+					6EZXU8WBAGAPJbXp3+VtWYVX8Cu7nI1fMdbA
+					KUA5GCiUBlNp/w75unen6fQ9imtblyjg+/XC
+					kIlek+vR08q1TBM3WUbKVYUinGU= )
+test.non-terminal.multiple-type-wks-record.example.com.	86400 IN WKS 218.241.109.1 6 23 25 53
+			86400	IN WKS	218.241.109.2 6 23 25 53
+			86400	IN WKS	218.241.109.3 6 23 25 53
+			86400	IN WKS	218.241.109.4 6 23 25 53
+			86400	IN WKS	218.241.109.5 6 23 25 53
+			86400	IN WKS	218.241.109.6 6 23 25 53 6000
+			86400	IN WKS	218.241.109.7 6 23 25 53
+			86400	IN WKS	218.241.109.8 6 23 25 53
+			86400	IN WKS	218.241.109.9 6 23 25 53
+			86400	IN WKS	218.241.109.10 6 23 25 53
+			86400	IN WKS	218.241.109.11 6 22 23 25 53
+			86400	IN WKS	218.241.109.12 6 22 23 25 53
+			86400	IN WKS	218.241.109.13 6 22 23 25 53
+			86400	IN WKS	218.241.109.14 6 22 25 53 80
+			86400	IN WKS	218.241.109.15 6 22 25 53 80
+			86400	IN WKS	218.241.109.16 6 22 25 80 6000
+			86400	RRSIG	WKS 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					bh+t72rURTD/AUNkK7tSgUNR1MfoksE2IlYg
+					bVwdLtmoIZdG6bH1ZjGI+EqxFL+jDGLiCHC/
+					HvZ8zc2QEjDYCvIvWU1NdaeVFAxqLNSDuz8g
+					d4l47H99JPTQgzRTGynfuJndDzFo76QEwSph
+					PhPQMgp2LQekn9IJ09ld+afY+4Q= )
+			3600	NSEC	NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. WKS RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					O50OPaNiLok8UClIxTBPo9b/yE/3Ouyp2u4j
+					6WPPzEMBqYb2fZ5YTlF89hJBcR9COabqc6Zz
+					yJnU0cyKBWu8r7kIcuIDCb0BrPN3/50b18CQ
+					qp1oarmS8E1SU+yPkPLbJzQcDiZpSb89Uqpe
+					pNDtVGe8SkYkcgzHI0jOnRCrSSQ= )
+test.non-terminal.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN	NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com.
+ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN A 192.168.2.1
+test.non-terminal.ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN A 192.168.2.1
+NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com. 86400 IN NS ns1.NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.example.com.
+			3600	NSEC	testa.no-type.example.com. NS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AeXmrYa9++hgSgWI8qLyDG/6HnVUFGjv/Jh3
+					Sbcbz/Wkt35RywxgixoMPizs3rxlEmy/jBCC
+					C3p4cBQIhSZ2vOsExbEpadNbbCNaI0Qilwx3
+					LSOScfgBKeUdpDjaUnJPEgd8EbMDjBGDhySf
+					KOki0VRaVnqP6EFLtlFyf1wQXto= )
+multiple-type-txt-record.example.com. 86400 IN TXT "txt::1"
+			86400	IN TXT	"txt::2"
+			86400	IN TXT	"txt::3"
+			86400	IN TXT	"txt::4"
+			86400	IN TXT	"txt::5"
+			86400	IN TXT	"txt::6"
+			86400	IN TXT	"txt::7"
+			86400	IN TXT	"txt::8"
+			86400	IN TXT	"txt::9"
+			86400	IN TXT	"txt::10"
+			86400	IN TXT	"txt::11"
+			86400	IN TXT	"txt::12"
+			86400	IN TXT	"txt::13"
+			86400	IN TXT	"txt::14"
+			86400	IN TXT	"txt::15"
+			86400	IN TXT	"txt::16"
+			86400	IN TXT	"txt::17"
+			86400	IN TXT	"txt::18"
+			86400	IN TXT	"txt::19"
+			86400	IN TXT	"txt::20"
+			86400	IN TXT	"txt::21"
+			86400	IN TXT	"txt::22"
+			86400	IN TXT	"txt::23"
+			86400	IN TXT	"txt::24"
+			86400	IN TXT	"txt::25"
+			86400	IN TXT	"txt::26"
+			86400	IN TXT	"txt::27"
+			86400	IN TXT	"txt::28"
+			86400	IN TXT	"txt::29"
+			86400	IN TXT	"txt::30"
+			86400	IN TXT	"txt::31"
+			86400	RRSIG	TXT 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					e7Y+piYf7OeKFSgsjUABzPA8Io5ZRNv+euzl
+					4LY8VvzcVsORAITUUVGhBM21MK7qGOvJ3uIZ
+					9rh6Ojv4XAx8fzBLMaGLJLTUeZjC2CASD1t2
+					Sahbxvmmv1/Ikj7lSe8hsLjp85yuZ4KWKryl
+					a6kK+QW2/3IvVHF0P5T35EiZ158= )
+			3600	NSEC	test.non-terminal.multiple-type-txt-record.example.com. TXT RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					nN89y/xJwgkmhrr6HsGqcKubezzlYDVQJI2J
+					7vXUFik+AVZwsJfoVmfnX87osJX+wrYzVG1w
+					RtUN0L57zc7O+SYfvb00OjeQjIwYfEQprhm+
+					orrbmStdGehT+qSeGoDitupTJYgY0rUpVb9o
+					ap0qcZWH7QBNdTQrqdwTXj0oaQ4= )
+multiple-type-srv-record.example.com. 86400 IN SRV 0 2 80 www.movie0.edu.
+			86400	IN SRV	1 3 80 www.movie1.edu.
+			86400	IN SRV	2 4 80 www.movie2.edu.
+			86400	IN SRV	3 5 80 www.movie3.edu.
+			86400	IN SRV	4 6 80 www.movie4.edu.
+			86400	IN SRV	5 7 80 www.movie5.edu.
+			86400	IN SRV	6 8 80 www.movie6.edu.
+			86400	IN SRV	7 9 80 www.movie7.edu.
+			86400	IN SRV	8 10 80 www.movie8.edu.
+			86400	IN SRV	9 11 80 www.movie9.edu.
+			86400	IN SRV	10 12 80 www.movie10.edu.
+			86400	IN SRV	11 13 80 www.movie11.edu.
+			86400	IN SRV	12 14 80 www.movie12.edu.
+			86400	RRSIG	SRV 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					LYlM0amkBW4UvNWm/dJEqk4BDDNndLZ11kdF
+					03qFuHTgXsRqmwWFuZo5y4pQ3r7Zvt1T9EgS
+					1JtftwnqmtdD1017G8Te8nOtNIWZZfEL6Jbr
+					FFbPoNY6o5ATSCZ+qMVsyPAcPZy4LUZlbnQc
+					In0YPMUnSuIqmawOwkHuhwN4okI= )
+			3600	NSEC	test.non-terminal.multiple-type-srv-record.example.com. SRV RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					tcZ7KwV1sX6P/tBKrok6DTp5AqJDHvXioeO5
+					RIXmfQyPQLWsc2i3EokkABiFz80PGARx2BEd
+					RxZUxkHXhCaoVXkQHDih+90uOVEOJIBMmd6e
+					KLfF2k0cmaUwP2ZrUcXV1i6hz04ouyWj3ZS8
+					9+vibTjaKHRQfFHd8pj2+KbMuE8= )
+NS1.example.com.	86400	IN A	218.241.111.236
+			86400	RRSIG	A 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					rqS35MJl9mPPZiLU3qRIxBLxO7vGn2lDoh3f
+					4YXB8t0bKCxvldlINNermQ+3filYHqxst4DF
+					2baZCXU8bTpBEr2gtrhRp5/kDan85kTicZzj
+					tnJgdtDEdK7QBIcxtC6W/UoZAskINhfHEAvp
+					VrfeGxq9FB/ZM7mA4RAJbd9nTIw= )
+			3600	NSEC	sub.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					kvH+Drx2kDQXzhuXyscBF12sQ4BXeuUwPb4t
+					oj6rddztnktJV8Y6w3JLBDwIIUxw/ciqrRt0
+					M5AO14ujKlGgeG90Q8By9em2T7X16zYfLKIt
+					Dvi1VWmggPHVec1TeX9IqNs6ub/bK2MZ4T+x
+					+ehCHwojKTP8Y/b4nvx/kvskhBM= )
+test.non-terminal.sub.example.com. 86400 IN NS ns.sub.example.com.
+ns.sub.example.com.	86400	IN A	218.241.111.236
+test.non-terminal.ns.sub.example.com. 86400 IN A 218.241.111.236
+sub.example.com.	86400	IN NS	ns.sub.example.com.
+			86400	DS	49822 5 1 (
+					6E7920E917F926300EDFB5F61B57588CF2B5
+					2ADF )
+			86400	DS	49822 5 2 (
+					3EBE7AF8D46657F51149714AC5FF2FB23F5A
+					D8258A2229764475C86C9B5B1A59 )
+			86400	RRSIG	DS 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					ZAl7uANYIwncfhAV+AGiunvt4BflavkEnJGV
+					KXPgcLdpPCsBTLCXPbyAqxiu0ywgXQ5JuIHm
+					AF0AKzeE+abEiPipP816jCi3rQiSljI/zwHI
+					t4fcB5zvM0yBE0HkAVP+ftNbda2RvF8cjXH4
+					aPieL89lCcC3zuVwEo1NZIommKo= )
+			3600	NSEC	sub-cname.example.com. NS DS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					nesi4ehQeGU8evobfldaepUGLmgw57nf2Wg/
+					F/A6TkmbgnVoWWPkT4KBSMgTmuym2TfFq7AT
+					b6hIsVh+OYToioFZha6UwrIgtiqxcplgCKwY
+					WB/tLtprKcTMlcaPWTtgzA18m/j0p7enlL13
+					kAJxjJIbKD4YKIRC0yWzlgk/Grc= )
+sub-cname.example.com.	86400	IN CNAME www.sub.example.com.
+			86400	RRSIG	CNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aWW0K9aKL99ZOTnljdoWQxANkr5aZ0velC9D
+					WOob680cmhJ+8OlQVMNbcMZyPU7Zr8nHKAXe
+					0On+72WLqsiGEQfZvBvMbm70R5jrEbtfFlL2
+					8UdkIzkMPJf+IJlg+qFdZk7w1i6xlRxDOOKB
+					vZgZQwD3eTO2971kyypBYK+/4aU= )
+			3600	NSEC	test.non-terminal.sub-cname.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					AtfbnSLONvl0EB0k7oNBEqQCL3WIrsCmf+sn
+					CB5AOLE7/lWzsLm0vCN8lbrOXhqzg6iswPVO
+					vEvxkqpuA9I0iObyiqwYNfo7Dr1DWKSTjq+b
+					WdjKHw3LZ9s1BbrJX6Z5qtAU0I/22Tia4OMi
+					UFn0sPWOka7LNW8imGdsjV6K9cI= )
+test.non-terminal.sub-cname.example.com. 86400 IN CNAME	www.sub.example.com.
+			86400	RRSIG	CNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					cvcWxilQsUeAl698HIsB+hfZO4jeYJHTSGCC
+					Y1eX8QEPox2LLmzkuB+j4VnBq9p0bOyg5S1r
+					FS4I8piCKJNt0xmCnXsVgaeEZ1uwBmkXN5nH
+					C9ba32o3aYUwEyAX/TJyNnKjc5Hl1Z8ePFOX
+					05KRjn0Q9DjYsICA7F7ZMVYIWhE= )
+			3600	NSEC	sub-dname.example.com. CNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					M4TFyUkhvxkTPg+VD6v04O3DN5W15itA7iXI
+					2JbePRx0MSK1nMx+tgKpYu/6hmsMMTcKpwph
+					TtZf+ieQTD04YoCk8hOm/QgHHVbt1HM47wMZ
+					AjdMosBvTAzv3Os1I1tENctPLPSCEdWUbmuI
+					JvmKiUG8Zn/9dvadT8rWu58kBOE= )
+sub-dname.example.com.	86400	IN DNAME sub.example.com.
+			86400	RRSIG	DNAME 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					pI27ntzYV8TIzdk9ObcvyV5VTdiMjCb0IPFi
+					gt/R2MXT9p5c/am6PyO6npjbxFIvibIyUvZg
+					YTtcN1vkE/d4RpgIZtaT0Zc7SNobXz1xVWXM
+					kOA7sK4cdI+7hv7bcQbrowXyF2TJnxO8FK8d
+					JWngaQS23xT4dSujJ5Q+gHP6kGQ= )
+			3600	NSEC	test.non-terminal.sub-dname.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					z67GTr+8vik0Gc+xI2efUrBZD4xw/4bb9dzP
+					AmnqEtIcuUdZnpBybe4KlwvbtYpalkF0lil2
+					P7zFNhMHc8Afb5aPLTUBQQFGo5XRZABzo83g
+					EnCmK+wCnGT50EZMJq5DZBRleCsynVd+ltKV
+					ZD+dVp/NwpQXJC7GRiotTK1oh8U= )
+test.non-terminal.sub-dname.example.com. 86400 IN DNAME	sub.example.com.
+			86400	RRSIG	DNAME 5 5 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					hn45X0G/jwq6aqv1b6R9gS+la+mJUE8tpnQa
+					Sn1dk4Bcrf6tkI5GHvL/CeQTVAMfaKlnbnNE
+					wduF99rru4LzAz0kI4I70Oo0R2TfqzHjCD7P
+					BgtOg5rym8Z0gVA8DYlXQ6fwZvxzsoY9nuGR
+					P2yDYo4nY1kTTttzi41KIoYI0+Q= )
+			3600	NSEC	www.a.b.sub2.example.com. DNAME RRSIG NSEC
+			3600	RRSIG	NSEC 5 5 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					RejBSjNeUjtNBFw0N7tnaDXlDddCiAQIBlKS
+					swczhQxS72crD1vnPh4lg2TAxSytTlXUeF60
+					VRKmD5C+7zXMcKhukzTipWjLFaaQr83VfAUa
+					htA2UN1fNu2AGBWdZKJvKc18AtDNsgdwbxKY
+					6zGg9r8lDdDv8yrt1EhVlETC9eo= )
+www.a.b.sub2.example.com. 86400	IN A	192.168.1.1
+			86400	RRSIG	A 5 6 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					OI3kSrtJbMMv+qbScv46yi9qfSupzUvD7R28
+					T5KBKUe1lIBM/nP3w4W/WUoYnG+ao5XNdSN3
+					BuxYOd1gDOMr3ZSSbzAMOvoOviVSxbW1X3Lm
+					P0/nEHkQF9L0UygDn4qnZg56Tmt5VGHDWk7U
+					HZdJ3Sa6jMX+aPKPbchyaG5wiqA= )
+			3600	NSEC	test.non-terminal.www.a.b.sub2.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 6 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					wTJX72cgdq0aNwh5MpKg5N3lpMxdI7oaEqjQ
+					7LFdlNhge9pKGFdq4qpvKrqqt8H8evlW5CMB
+					ZtDV58SY8mLuNoJZt/ZEkc5BAe6SEF/Jshzs
+					AcZenhh2LhXRC9yTbIc2uUCFOf/t7w5DZRSF
+					qgLA4tfw0I8tlndjbZsd7owPixI= )
+subdn.example.com.	86400	IN NS	ns.subdn.cn.
+			3600	NSEC	subdomain.example.com. NS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					nCfBP/IRCUZJEG8TyfP13MrhQZOXPsEPZWdd
+					qLQkrXgywK4whngLQBC7RvmHJrmjZFhfNIGM
+					ATfsP6Ii5BgqQDrjxqvftMNta81rTxnXZEOb
+					I6wgo+F4OlFZ0esMgdNTtsVawXV5rxMCL3hA
+					a0HXZrxSp+ZOrn11rOYGKZ3XvXs= )
+test.non-terminal.subdn.example.com. 86400 IN NS ns.subdn.cn.
+testa.no-type.example.com. 86400 IN A	10.1.1.1
+			86400	RRSIG	A 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					aKBQAJSupqxsqeTrD/UTweU75M2V2wv8bLlw
+					yqp3FnzpLUeakTS4a6Y0qtvzumUohe1gmHj0
+					DQTtLMRaxNQcIleU02fCUI+d9BUh4xLhYevD
+					vP/t2k/zKoLWuVttDkQBarpifVq8axpguPEl
+					TT/kRyzk+VCpCzQSK4rik59OXA4= )
+			3600	NSEC	testaaaa.no-type.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					mSGRBg1l+w1qsFWrIt3tFNT2S4OOHteoiaJH
+					K+T2Smsy7o3OdJ9mL3F1Hh35QXDy4HDTjib3
+					3odGn+4dot3ZY3aaafUW9y5Hdqprf+T0u8Ir
+					m3THIDMQB23pviwXZq9yhykzTKFFVPUL1Gat
+					sLleGYbv4X3R+cZ8aafVs1bGxaE= )
+test.non-terminal.subdomain.example.com. 86400 IN NS ns1.mysub.com.
+			86400	IN NS	ns2.mysub.com.
+test.non-terminal.www.a.b.sub2.example.com. 86400 IN A 192.168.1.1
+			86400	RRSIG	A 5 8 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					d//X2Ycwf5qOjOPnuGu3VHqIwDgnrTFqVMBq
+					jZn3CtYDE0hOTjwZNYyisTV+XJjUQZWko6XG
+					Usu3xKvyoxjLYQygY9nhzBMZG9lYvobJAHLw
+					2Cd7QmfgwSzLKDVPh3ONyZy/BbZmnMubaWwO
+					k9EO1hGarRPIfvSi14bTa+VfEqM= )
+			3600	NSEC	subdn.example.com. A RRSIG NSEC
+			3600	RRSIG	NSEC 5 8 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					CTVkFc2+9gdljg6aNEN7dhDqqtZJXz8juhOt
+					lM4iNhwMWUy2kTEfGC3koSp8aVG/h+NIMH5m
+					lPDX+4BYM2XtLC23SWyyc/s/nnUDqTPw7PAL
+					R0/+0Rcv8YGk0N35G5jX+LBN2tXGNNMuvThM
+					p7jCSbFwO8Y7H8rlMf5i6Ygunu4= )
+testaaaa.no-type.example.com. 86400 IN AAAA ::1
+			86400	RRSIG	AAAA 5 4 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					eWUKLr3s4Flt/t8FjM5q7cRykBc/FNFXwTN9
+					pq2ucDrkuiLfe5ej4MNe6aNO6EOncRWVH6Qa
+					uJ0nisOuUZg2OVFIEHqLP1YF58O/xlhK3dDb
+					1kAIr1+cM3CEkN0l3AJ6yd92j6P0611Yu26s
+					7JlF3ZuX52VZpve9N+uk5uEsW/o= )
+			3600	NSEC	NS1.example.com. AAAA RRSIG NSEC
+			3600	RRSIG	NSEC 5 4 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					FcHjt3C/q4MU3ZV2q7FoF4zsop0qJDf9sR7y
+					Bx5pqk6AvXKcrpqUMIHlGlRxE5MJHi4bGBTi
+					Hyr3tZ6eXBVPqM+PBm3iT4HqnHGkwJm1dFWj
+					bayBY/7q4LTyQhReP3PaZjApkhqv3ehIlG1J
+					zuIHw5Axvw3bTzexBUlNgmDvrNQ= )
+subdomain.example.com.	86400	IN NS	ns1.mysub.com.
+			86400	IN NS	ns2.mysub.com.
+			86400	DS	6613 5 1 (
+					39A2A64CA73B103E983EE77305E8DAEE9DBB
+					B0FA )
+			86400	DS	6613 5 2 (
+					8D24DBE7FEA6E40A27382B45EE189FBF30B0
+					0FB38734BA5415A7695B11FE5CE7 )
+			86400	RRSIG	DS 5 3 86400 20110408061651 (
+					20110309061651 27366 example.com.
+					Hsr5Z2S0t6NrbGYI69ynQyZYZfujoq4ANuCs
+					NqRkWa4fVQQ8uJr04pCAe2Dzm3R1dWyAHOAM
+					kUtt7GwYYH/hjjs4K3E0h63cqAkbxmyOdss/
+					lelPaVAGt66D5QSE1SRXKGKnQUD+sJM0plkz
+					1KrMV/PNibJ1R3U8hYYtwh+gAyE= )
+			3600	NSEC	example.com. NS DS RRSIG NSEC
+			3600	RRSIG	NSEC 5 3 3600 20110408061651 (
+					20110309061651 27366 example.com.
+					EWh5yFAxcePS0iGoif8JFj4ZvWuPtXSguzrB
+					OEl8BNMY4KeMVmwBLoGRpECKpybqqTXB/His
+					7mejU9HzP47cNrD0eV73UvbHe0qc2DlgfL5Q
+					hXVMdQJZ0GJO4r6HNwoyMxOPZMXnDSijjVkG
+					UikyHQsGCfF7um8cw2KBmp73xqI= )




More information about the bind10-changes mailing list