BIND 10 trac2225_xfrout, updated. 13e8c165b1fddbcb34868c1ed4731fb199b233e7 [2225_xfrout] Merge branch 'master' of git://git.bind10.isc.org/bind10 into trac2225_xfrout

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Feb 26 02:31:40 UTC 2013


The branch, trac2225_xfrout has been updated
       via  13e8c165b1fddbcb34868c1ed4731fb199b233e7 (commit)
       via  e606d8d0e66a4522640c3bf6ae53b787a7419c45 (commit)
       via  4c9255afa0727284de95283783d5e40dc7341606 (commit)
       via  2642fcae535a72ea8a5a3e97fcc7f20391fe9306 (commit)
       via  1f7444c72818dd7940251f9c8a077cdf7ec0e7fa (commit)
       via  a1eced2feb4cb3025ef27c436d219985cbf3b3d2 (commit)
       via  d6e34fc0d99e325ccd5f253abdbb1abd27b21935 (commit)
       via  6ffab5a7aa42d2f1210d3036658dcf4398c6ff99 (commit)
       via  3fa16c71cbffab13bcdeb311a1e81a29f107d647 (commit)
       via  808dcdccc72caa04645c15af4493a76bacbd838f (commit)
       via  4df19b60af5ade5f1705fbb76a90fbca0e6b7fba (commit)
       via  ba2982025bc36dbf61f1268a6c0c884b2a669127 (commit)
       via  563843956a6102cc3da274eb79413dc6b0d411c4 (commit)
       via  1c1d2c888dbadc9cf707b8f49ced2403e864cd8c (commit)
       via  7a34e78976f20bec3f0e8287cb44a4ed7e351924 (commit)
       via  9afaf171e6bd58b74e4ae89b394b51f5e8bc6fb4 (commit)
       via  77d49bfce9ba4ef3bcd39529b1cd0148381044cf (commit)
       via  6dc0f0ecc269c2b59f78bc0dbd9176214b3266a3 (commit)
       via  e653adac032f871cbd66cd500c37407a56d14589 (commit)
       via  54e52000440917a5d9e3dfb0862262e2748c07e0 (commit)
       via  5adf1f39d4b8060cd5cc7ab764f94ec6faaf5193 (commit)
       via  2c66b4437daf5d4ee493cb328d02eba49d1bbc70 (commit)
       via  6f119e40e88a7fc07e1b3bd1a3e26c3e46b9dfab (commit)
       via  0735f72f09fc04cb01aa4df9912ecd265b4f8a05 (commit)
       via  5958767f0f9b18aa1d0fa7336ca2bcf12daf1bb2 (commit)
       via  e4aaeac97a46220f8f333ae8e1e5b39611995786 (commit)
       via  75862a73a3498055dc8333ab25edb7130a5d492d (commit)
       via  8131da32a67a248150d55280f94c01ce0c377272 (commit)
       via  0f795237b2b0384cde3a60bb49df75cd529e31bc (commit)
       via  f8e0a4f7e6fde7d1fe2c63a0bebfe00a2e2e7164 (commit)
       via  c8aea8a73e16028bb07d51caafe5bf8188d0ee14 (commit)
       via  107f0d258ab020c6ef131a0c6d682c1894fb85a3 (commit)
       via  484cc29669ae8eaf5270802cc66cbe0daaf24b1d (commit)
       via  5ba7df48ebcf5759d87e4e487aca9deb35799b1b (commit)
       via  521c12d55ea5df2b98ef0543bc78e8d2e40c8a4b (commit)
       via  30aa2837a02a8926103dd73668a2572d70555658 (commit)
       via  3ddbe715a140ddcd4d6c2cdea1401ec0e28ea89d (commit)
       via  f0ecf9503468cce0ddcf776adf143b46c821994c (commit)
       via  3bec0f1f82f1bbc2a296cb40999047421abcba94 (commit)
       via  e4688c06e8217659cf1c1c72adacba12ef9e8974 (commit)
       via  2d286d766980909cda293cd10fe80c8acc7cfe46 (commit)
       via  7da8c5f511ba519a582e5c9828b74de03651f701 (commit)
       via  10cbf4c33a915a6287bc8b32b5b3f521b4ced50b (commit)
       via  59651a74809b06c0228d2b39202335fffaee048e (commit)
       via  4d5d7d6e423cb6e46a9f4acfde4e8ebf434951d2 (commit)
       via  cee365b41dfe5e24b62d02d21a2f52749bb19688 (commit)
       via  f5ba7aa63517eaada091025d8ec61a34b797a743 (commit)
       via  2e5d462ccc30e3c63f82ced6aa9a3c4732562188 (commit)
       via  1b746a6a6ab6eaa92aa9ba913b690dad4c930378 (commit)
       via  773d25dc86682595c2af983b7c349deea9abb0b6 (commit)
       via  f29f0653f27ce5e551039d544b07acefd6e1275e (commit)
       via  b459be530b5b159af7de708fe653f5b500a9745f (commit)
       via  3d8d88cb37a6423b9f1b969e8ab3342e8116cf83 (commit)
       via  12027383143fceba912caded72cdef8451a37021 (commit)
       via  ab159f505de08729862904b1412d9dede8138013 (commit)
       via  17242d96b692893b0fe127c0f4883d30a765e58e (commit)
       via  146d0e9b8a417220a9a9eeb9adb4c2ccb66db178 (commit)
       via  26a7d162b701bb210d4394348d35fa8090da2733 (commit)
       via  de4ecfcd4827e8e0002c426e11e5ad36e7e14da3 (commit)
       via  24503d327ec68c528cfc19e3228223718f1487c9 (commit)
       via  462f0ff4fbef6bdf657f4833c2d8f0e2cce1cd41 (commit)
       via  c8870e86d867789bf2e8dedf6f5e960dc47faaee (commit)
       via  cd2d3c39ebcba3fb50822fba492c41c6a4bfce25 (commit)
       via  09af4e2b9e9b2840dd475ef112d485e3476badd1 (commit)
       via  9d00b71c14e4e1eb7e390c78b40e015f960595af (commit)
       via  2b0ef32a8eb90122efa930c31147ca6e56df5716 (commit)
       via  227ca9fd94365eebd3d21447c821ca7ec76971f6 (commit)
       via  a5db81cca25ff24aebb7c1855ecd2ee40e2f129f (commit)
       via  434528966996239ed0f7fbe639b914d85478a515 (commit)
       via  104a04b32d7705a95d5e9492dce82469aff21a0e (commit)
       via  c2999ba2c107046eace915fab85202846b6095af (commit)
       via  6699e12852ba1f4bdd6971c7d3f1b973bfd93964 (commit)
       via  6714481ecee6046a62fc351158f8c5c7d9e0bf30 (commit)
       via  a3a6e386382332790b88db561ce7bac20d3dbcd8 (commit)
       via  4b5aa826a6b741ca9e49e3efef3440c06863ebe8 (commit)
       via  82d462fc39ea567a142decf52bf2ff2a9971cac4 (commit)
       via  d1acb02130ae1a8a4f9af1263fa552499a99f377 (commit)
       via  ff2215ffb7e7149c50764841e00d8d9186a81294 (commit)
       via  4ac27e8d2435fad4be79a75ef830e1d0b20a896a (commit)
       via  bc2a0da61893dc52ab49851360c23c5fbe18dfe6 (commit)
       via  6667c5c3485db2ec1da350d4b90896b871e07bad (commit)
       via  dd0f73adac540774a6cb2c99faece4d6c4b90353 (commit)
       via  488d42f3ae5c7f97ef144370036b5c9b7736a9d1 (commit)
       via  4b678e1d42ea66fae49f2248b4c4cfeb32fe0a09 (commit)
       via  ce03b1032e086e7f2cb038068dfbbdb5eac61645 (commit)
       via  50bea9582f85b0684aa17a7cea7fb9d2405896c0 (commit)
       via  d6f24ba6266d3ed630a3fbbe2b4b8ef2cf501343 (commit)
       via  7725df2d751443bf37be18f1640c5c86a8a9df79 (commit)
       via  39a8fecdf3bbeb905f6716c3b42ae250e9215542 (commit)
       via  e87bf04b2fb276c3926b01d34fed2503764b574b (commit)
       via  79b6c09920b67a9301398bbf7a9e94c1650a323c (commit)
       via  bbad6f7eef1c652a915b278005d09f4b371883e6 (commit)
       via  1217ce4ef8f48a661d101d7e4b30894289a27150 (commit)
       via  d8da851da8c3b403493ce0df832946d93c94e8cb (commit)
       via  54e8f4061f92c2f9e5b8564240937515efa6d934 (commit)
       via  271cb4cfda71897f041e709b07a86694350f9f90 (commit)
       via  3f85c6420a49c56d7e74b38634162760849f9e66 (commit)
       via  2c05b09207ff79b66217e941e884c0b91fb7f309 (commit)
       via  d1af010b641ff25dda7aa76ec6beba1ba551467d (commit)
       via  762ee6bc10e8f2dbaefc1f1351bcadff72b59eae (commit)
       via  919a87f1210c64263f3b06ca93e3bf6b771d23b2 (commit)
       via  c5feeae4a31750b774f96f94af5ba71699161fab (commit)
       via  be08a607985750a0ab0815916c810cf4ff11a82c (commit)
       via  6bd562f85c775f7662d586bdee3671a9ba8baa2a (commit)
       via  946c4e8afa9647ee9a3e4481e66760512ce556e0 (commit)
       via  ddca3c089d371b29e69960049770aaf4f0e22fea (commit)
       via  9a3a2236442d10d2b7a93f7ad3be4b5e52d80ff1 (commit)
       via  6409bf0fb2fcb3d60c664009be730f1a71fdac54 (commit)
       via  67940bdbff79a551466de411f4ed3126a254888e (commit)
       via  e5e511b58b6ad59b3d79f19c2f7d18b0a6843273 (commit)
       via  0147b8cb625f27bf57438b9e1af25bbd9f597f01 (commit)
       via  bd35b30808c5093ee41aea3f8289f691befb8219 (commit)
       via  3a3c7f52a1da822814cbd742a565ac4ed9c801d9 (commit)
       via  24b3e0cb75ea0a1f6b22fc91d679313ed7a6468f (commit)
       via  abe78fae4ba3aca5eb01806dd4e05607b1241745 (commit)
       via  06ab4db18f6a852f81d5253686d7f9006e6bc27f (commit)
       via  b4b8c1e5392a8aeee4402bc97f776cfc889f43c6 (commit)
       via  24c235cb1b379c6472772d340e21577c3460b742 (commit)
       via  70632300d70401c696161dff39ad126ff98663df (commit)
       via  7788547667e769783edb16a83a89895522e2f332 (commit)
       via  894e0ca1da8ca1a1f572a0e0d0a4f91102827d67 (commit)
       via  3132b8b19495470bbfd0f2ba0fe7da443926034b (commit)
       via  4982a87469884b80b077ec4ad9dc5445aeea6dc3 (commit)
       via  1cbacf19a28bdae50bb9bd3767bca0147fde37ed (commit)
       via  88b964a46c18be801102503b45d8256f26d3a3d0 (commit)
       via  1197c10bcfc5b9a47054a7dc98cb797c14175053 (commit)
       via  529fdf6dc7f6148c7e28a29ab45a4575b3783d2e (commit)
       via  22eaf88024420eb44ccfca5659ab1136871ce252 (commit)
       via  97371cff7f91db7556294ce559aed170a718dc4c (commit)
       via  b57fc0894581ef07334a8f6c5bd0a6129d5289a1 (commit)
       via  54bbed5fcbe237c5a49b515ae4c55148723406ce (commit)
       via  aff7100abe378e77ed36e6239a82ca483bcd2288 (commit)
       via  87ce14cdb121b37afb5b1931af51bed7f6323dd6 (commit)
       via  cf0ce4bad603660b8f0d98e76414fd5b3572e2c8 (commit)
       via  227f2b1dab3ee9739e1c8671ca242313ad4eb796 (commit)
       via  b8d6b949eb7f4705e32fbdfd7694ca2e6a6a5cdc (commit)
       via  5f9c4eec3c69bb08684969ea118a1eb00cf8dd1b (commit)
       via  8e33f9e96aa79b1f99828c063cab84328ce3f248 (commit)
       via  d404649f95abf23268f91c31b30d52b06e5a3df3 (commit)
       via  cfd00e940391d98c71f3cb026558d66f291a59e0 (commit)
       via  d7f14ea88e8cc0f3e7f08b4ee6c4647ff2908279 (commit)
       via  ea110815f2864c353ac69ba54dd837987890d496 (commit)
       via  12071a88b91b30fada5848868fc3ecd173785b37 (commit)
       via  e090b84bd5e2d79d7730563beda5e95140c5d03d (commit)
       via  e6f86f2f5eec8e6003c13d36804a767a840d96d6 (commit)
       via  8d1f4d45b8998de8ca478a1bb600b8cbb88e4a31 (commit)
       via  3f272be09aadc78d27333ddeba66ba7e9de25f1f (commit)
       via  52f22bb0132d78d07145fec0f1fde03069f7e5fa (commit)
       via  3e367ff100f7d1b76ec8743385917ba747b9ad34 (commit)
       via  72106475f625075e3e49bdba04e6f9f26b105294 (commit)
       via  5aa5b4e403893b1de767cea00b4a3f9d9a17422e (commit)
       via  5950991881a51d5b88ec6234d310adda43e11e8a (commit)
       via  dd2dbeb5a4507ba50ce1547972ab4ea1b56b4655 (commit)
       via  daf2abe68ce9c111334a15c14e440730f3a085e2 (commit)
       via  1eef52e751a97720ba679256b24b2c90ed98b5fd (commit)
       via  6eb4e61e5886a972750136b425404e17dbd476ea (commit)
       via  050472189e8f79ce65d165241d19ccbf333eab20 (commit)
       via  1aa0a1179c5948cc63bee18a2a19106d6ed1243d (commit)
       via  beebff23a438a65506ea2af860686ed0272da31f (commit)
       via  7782afcefe47162534a377769d9eda2c0fa960ff (commit)
       via  660a0d164feaf055677f375977f7ed327ead893e (commit)
       via  e540ba5b43c265fff937245932c06ed501859574 (commit)
       via  50e61198ea74d395b0bc9015c9f01ff29e357e48 (commit)
       via  aa5b7e1214e00019776d7bab0cf49df604d2a7e9 (commit)
       via  be156ccbf943ec27f2174e4cfe11f2f67e9b2975 (commit)
       via  d14e31cb67c834948664d5d958984bdc3aa2cf8b (commit)
       via  52b0979f34d6def45fe8a618d4cc79f724d514d7 (commit)
       via  9a9b17823a2c57e3013f4f6da055f2a7cc48c289 (commit)
       via  9d5e1f515860689e1d7723cd113c6a5fa2a8866a (commit)
       via  4a2220ee8ef3586b5b1b21f58111cc585f069d98 (commit)
       via  9b16b116c909bedfc1353147f3948ba19f42fb5a (commit)
       via  1d0c2004865d1bf322bf78d13630d992e39179fd (commit)
       via  dd447189c8e307c305415a34894c48972cea5a2c (commit)
       via  b4de3233542a0c98c04c0cf730bd8222efe897b7 (commit)
       via  6a06b311fb9efe408fa6bf6dc2fe37a5ffcf2154 (commit)
       via  c51846715ab031b8de7a988f779cc41ccbcf6ff0 (commit)
       via  57c90f7a929c38440118c0e10e4dd19827fd371c (commit)
       via  89c595272222aa858ddbb6559dc3ec5aff63f2a5 (commit)
       via  266bf8571b08bed62aa5c65f525826d1fb625bbc (commit)
       via  3a07d07e04c693056cc4c50a1ac3b79d5696f05b (commit)
       via  6c5b161b7b67dab51d46984ce94bddd7a3c3c30b (commit)
       via  c45a2112f2ecec8f96e7810f4f5dfd7d46043e4a (commit)
       via  e15ccdfa19349060a082add1541e553e4b9d1d4b (commit)
       via  2832cc07032db112749999848d8506febdb44e78 (commit)
       via  3a8141cf7bff5642a70edac8b9dec1e458e552a9 (commit)
       via  dc4af29ccb665d56b5262cd3db947ef5852c6ff9 (commit)
       via  3e06e05268d8316d275a5a9987a3d8ed5af4f993 (commit)
       via  16930b0baef10c65efa010f09464b55bd208f0b2 (commit)
       via  1a80b1dd71902c7942e11316b53c6cba4a16565d (commit)
       via  4694c98d55d5fc5c26c540ce81c0c73e597578a4 (commit)
       via  11633f6c60336ff1ba648e09b51db064252e034c (commit)
       via  4f5d524dd601a838dc0647b15e99cac00b9ce7dd (commit)
       via  eb018c9d3c3a60989492dda959a9c932e7cf2e71 (commit)
       via  b2ac76a62e2d18ec16251c57a4b3d8d5776d1bcb (commit)
       via  59c744cf4838c919abe8763501208e02aff9526d (commit)
       via  e931cdc9d86861eb9ca96a4bdd3bdf407f2e897f (commit)
       via  2c51eb144dfdf9a63a982df1e8a20bc3665d82a1 (commit)
       via  b13d755de9ad00a27e63d863ac977aa6a18fb8c7 (commit)
       via  7f8ec08cfd2eb7c92041fece5a4e67d48fb822f8 (commit)
       via  b5e2be95d21ed750ad7cf5e15de2058aa8bc45f4 (commit)
       via  1d6a2e3fb2715b445ce835847d7d353886495fea (commit)
       via  899432b47a8460c65ae0211b0bee1f9296bfa433 (commit)
       via  c30f889cf94e021413599a1bd2f193b887824ba3 (commit)
       via  3a9d8e2406929a87eaefc22953dde380c4a9ebc8 (commit)
       via  964547642571d9146219cf2f9d6e08fa03970a81 (commit)
       via  8a17ce75a1d3287785c9d0234f3e4c82232a39ea (commit)
       via  880db2ba394a9dbe0133f5e4730ae4b99f6bd20b (commit)
       via  60b36bdabd4c052e5afaebc1a0d2ddd8eab637c2 (commit)
       via  d437aee8f3a3370d76cbc25d2c49d903eb995b7c (commit)
       via  fbaab5fd3c4fc983889b194a96310a0239b040d5 (commit)
       via  f866170c9af2ddb0eb4ca0dc3f060ee62d2f92f7 (commit)
       via  60a9f3a768ebd546c8aeff70d84b769dc95836ca (commit)
       via  a12aed4bde955f0edb68717ee23895bbc78baccf (commit)
       via  ac75b8db7bb9c0b104672d0987d98ec8055c698c (commit)
       via  3fa52fbaed9589ecad689ccf105bbf7365d26d62 (commit)
       via  55f8f410621028a556a3b0af8d2d41bc0f60b08e (commit)
       via  4d6818eb58a726d0abd92a171a0f18334a9eb3b7 (commit)
       via  b20cc153bcbe3914a610ea5c9a03663ba788555f (commit)
       via  4792e513f5dc087a6dc5e51f72acf0efd0cc4f37 (commit)
       via  79f65e1240e0104f6d425ce63821e1297b78a3ce (commit)
       via  905792e57908a04539e76abdd32e67289ca9d4c6 (commit)
       via  b68752a7e48f86bdc07c9a6e34929a9202d0e039 (commit)
       via  b4546edb4138647efa2e2129f5461d80d4486630 (commit)
       via  530f569e47b06f49402611bda07e1956cdf04a24 (commit)
       via  da67c0642c9403f08e278e2424bc7bfde74e034a (commit)
       via  6f83737a9b9deaacd5ce0799cbda9e18fdb81c4b (commit)
       via  4c439a4cca7768510b4549c73e0f43120d4c9739 (commit)
       via  fbf11f41c327130fbdb39fcf64daa16f278eb197 (commit)
       via  733d42fa3d0b0b0f426a4817dcd022c764158d0d (commit)
       via  e5005185351cf73d4a611407c2cfcd163f80e428 (commit)
       via  bfefbfda28cb512b12643555790149b7c64414f3 (commit)
       via  4d074c3e7048f8dde151e078bee4967949d3b32e (commit)
       via  f7a26a8f9ee4adf64d754e6c2a6c07977854c40c (commit)
       via  2a723e7e4bfe970673f1ea0a61262d1ba0a475d9 (commit)
       via  89fbc1a1f41da33150176d8d0ba83ae8e88a03da (commit)
       via  6e489c0c04f6682402b594b222095ef50477614e (commit)
       via  73709cdf8042f63328f41c8f0498ecaf57f11dd4 (commit)
       via  f29a543f5e4d5f44473c5e957c5ec90bd413aa6c (commit)
       via  070dcf030b13bc1b3e356e4f2313e1f6bbfda0e0 (commit)
       via  3b03a16056601b26d27db3a4cd0baced7e4ba756 (commit)
       via  564f4b8990e4759f57033f4fc9de2359e3baf829 (commit)
       via  005cba1c8d62e2f44ad05b512ac9b7be639da725 (commit)
       via  d85b2e22c5c45050d3191ee73c508bbd3cd1251f (commit)
       via  5a6d38e1f78650477176b1cd8424227382621c7a (commit)
       via  db77f1f08e569fc378c1e63361503773f9b9e85e (commit)
       via  2284240947b4871b246d6d3a4be073dcb560325d (commit)
       via  aeda8e4862687e5ecd870a520616b734fa910b39 (commit)
       via  64fb39c963cd9e6494f71dfe14d9dabdf869fdc8 (commit)
       via  3a185f59245200be3c6b2e86340ac1c2ae464efb (commit)
       via  b43c93c8cb4e0256677c01d5f649093fc27c998a (commit)
       via  ffd4a283b18f8eaa453712e1e615e2440b12aa0d (commit)
       via  0749f9e194505698031990eb7c544e8ec076fe10 (commit)
       via  39c1d353784c56ac2f1c42836348393b7d80303e (commit)
       via  2a1d32f1610c1b99a2b6bcfdf350fcf123c51e19 (commit)
       via  d76159997442d71928d459041d46d89a01fbdefc (commit)
       via  ebeb7923963456d7f62721327290b75572ab4279 (commit)
       via  aa4dcd59d930af330b7f082c40a395d0bc424d97 (commit)
       via  8df1853f98c6fdfbdc186062426904d047259d53 (commit)
       via  1ec905f87eaebf01ae956b1ec5ac05afbfae9836 (commit)
       via  936279ca980c2c2b5b711f147703665f722ffd9c (commit)
       via  6dae0d1f016190f74098fc92cc5200bdc9ea165f (commit)
       via  37743e4ec13cbb7e4b2864ce54e3d9732a1e8101 (commit)
       via  8b2f7c325534431cb4f6cca82c5d314583e03248 (commit)
       via  06fa3ca48f34c5bb6c235a1fbda2cf00be69c2c8 (commit)
       via  2baf0ceb67f23351cd20ac77978b29366f7c5638 (commit)
       via  6ded04bbd0fb963754e4123cee99cb07de07a618 (commit)
       via  bae3798603affdb276f370c1ac6b33b011a5ed4f (commit)
       via  6dc113cc0e20a4781ad0f991871966d244371440 (commit)
       via  28c7d972110b86833c31631d563b07a2824efbab (commit)
       via  3c200a3decdd5bbc30bbdb9c81f9f206eda98ad9 (commit)
       via  3a8e933c07b9493fd5deb97d86433532c68cce8e (commit)
       via  b9be907e65b56003803b87a8886d37196c53741b (commit)
       via  87da92a958f4eb914c981d0b3ddab3cf68d41803 (commit)
       via  f7a77b8a0b46d3a01fc3a31a303e029da1c5f6b3 (commit)
       via  ee5c66336b0baf8424d5be04670dd5b96344e07e (commit)
       via  6eb06132ab8aa9e1e4c6b73a233952b4bf23baff (commit)
       via  6b09c6be32b221b73a05f98de7814c650597883a (commit)
       via  d1ae5b15754d5d359c52fd6f58e23e0e0907d4f3 (commit)
       via  3188ee1246e7e1b52b334cfa6edb04d2123ea759 (commit)
       via  076dad2aada1624b0b632e4eee3e6a1907c51a16 (commit)
       via  cb95ae3f178ce497a8dce0aad4173a8586dc9ca2 (commit)
       via  f07dbb59715b26afeef7ff682bba887187ad169b (commit)
       via  b1f09a967614c9668bedc3d877bb12f1622222f1 (commit)
       via  db90d30b97219e365c3643fd6c79878eaf1ac518 (commit)
       via  9a7c7bf6690bf3a6d85b5f3dc802d819825b3955 (commit)
       via  8b84c4beb47bf82e9c8302c39b2144a4717f7d1b (commit)
       via  2dffde2cef71ec693097f59f81fe40ada8035975 (commit)
       via  7377c385cd5b4f37024dd55919873adde82a2da8 (commit)
       via  8adef6491ebef3e81833f3d23b334c5b4fc1f72c (commit)
       via  f88b4851913521da4d54becbd90dfdcace073396 (commit)
       via  8a33e4abf487623ef3367e5ea85c49b7e9086c94 (commit)
       via  efb422b40e2d7068e17866fcefe557e54deee572 (commit)
       via  6f514c3a7c3c727c8c0a8f690f4f3f18abe49032 (commit)
       via  6dab65b159cc406f375c2bc504a3622b628e6879 (commit)
       via  a8f2c7a54ea5061e3b4d5ee48fb2e2fd2455c75d (commit)
       via  8ea6b0f1c24282a98d7134d8f6e2eb0c181f9ffb (commit)
       via  19a4de9fd0738a4332169f432035fd4734311f53 (commit)
       via  8404133f0a362cede4819322da6506b83968e79b (commit)
       via  10d63236169056c2c14cf4807d05017599c0a3bd (commit)
       via  a6a1bf6c90da7fc59eaf094762eb1410f14b8658 (commit)
       via  2af2991a8d5e0a5f6debff5f9105fd215803b6db (commit)
       via  1c470ce95278e5a67b3babfb4e7adec849053e6b (commit)
       via  f95627b501f5bf720e74de1d2cdb17219c826f02 (commit)
       via  93b27668a1fc63da7fd0527a04691dcd00c9e310 (commit)
       via  5b479207c875b0c09d3e2fc92e05ccf0e46a8773 (commit)
       via  2eeab2ebf0b7e9de2a7c73e553572dbc313d06a7 (commit)
       via  9430b068ddc62ed1a31ec72b3012aa87d8a743f4 (commit)
       via  f6959cc20c195647f061b13d2aeafb6e8cdb11de (commit)
       via  cddeabfcf7ae30d053f82952310377186b91d2e4 (commit)
       via  ba2d4df266cd44d44175260cf16bf2d22a4e1f12 (commit)
       via  dfee1cf2eaeca6f2b5729027f3bd51e640ab482b (commit)
       via  8eb3dbe543fa39f7702a48422777df9752dd8afb (commit)
       via  74110729288f3014cfde862c943bb68bc1fceb69 (commit)
       via  4c56f4c81c03d04a1d2b8be3250ef1bea9979ef4 (commit)
       via  ddfbc7fa1ca5fc712e16801f5f24807f90d8e88b (commit)
       via  fbb78097f3aca9bd8fbf4cce1f1c7169719d04e5 (commit)
       via  a85aff6a94f4f8e08bf3beaaf4da6e282b28e253 (commit)
       via  476b3eff5488d89b03d7ac34830ad52973e9b0bd (commit)
       via  94df9fad7ddbe91fff09b601cfaf07fcfd346659 (commit)
       via  5a0d055137287f81e23fbeedd35236fee274596d (commit)
       via  a01569277cda3f78b1171bbf79f15ecf502e81e2 (commit)
       via  6aa1c3cc7dbb55d32304ada9b88037346ba929b0 (commit)
       via  bd93846c0d74b780b2e6a6547686c9bc2db6fe23 (commit)
       via  78b66fd894cd71185baeef5f4eddce6c9572278e (commit)
       via  a272beeb913cd0adaf04080b0f4284e1510085a6 (commit)
       via  0b249de43aad4472b98dfb147a7f3ac1c15c1d3c (commit)
       via  00116a66e0d365563789ff4ed56cb3a08cb95156 (commit)
       via  971ac6698f44e468f072fab7baaea5eb6f6b77a3 (commit)
       via  7d086e721bf8e5b081aeed8a95d9cf517f3cf7d8 (commit)
       via  acd8358522b4ac20a75684b6ec616269bcc705f2 (commit)
       via  23610f5bf4d613f503793bf7c8526c67f95df223 (commit)
       via  1c50c5a6ee7e9675e3ab154f2c7f975ef519fca2 (commit)
       via  7f69bab21e2bfc6656a1926348f2ea4920301b61 (commit)
       via  b6b57fb469c8a0483c1050ec64dc46b6dfb1b40e (commit)
       via  709b6c520e3e86c880655ded5cbe375d29f80aa9 (commit)
       via  677e990f61d47065da92899bd3c82115cd977c8c (commit)
       via  878c361337c79e35816bb7df20595b8a5faa3491 (commit)
       via  a08b7575e7d42740c3f659087420472753bbee16 (commit)
       via  0a6fc5a8a77ac5f0e579dbb57da5ea5eb1923c39 (commit)
       via  c274bccc9c7ab201ac00f09896b2511791556278 (commit)
       via  95b8519b040545420529f7dee5944826f6cc1224 (commit)
       via  826ac1b1e637a6aa8b5763c4b810755ac0551446 (commit)
       via  cfa26ab8df9b533d32b8dd5aa405bf237bb58f12 (commit)
       via  e62a5e2f0da16fd93c019450b7072e56d90c1359 (commit)
       via  7919cceebc8fbeb56e7808133880aeba14b79217 (commit)
       via  e220a4ed9277845220c8550f24e87c16422d9dee (commit)
       via  dc6a6a9ef65b75bdb4cc79a67a83c04645657055 (commit)
       via  9e8e9cb336031bf88a5f458d9c96afb0549f3042 (commit)
       via  20f13469624c75aa090ad74f5ce2518adf826f01 (commit)
       via  98928031fc761eec73838139b2e3e5e9502eedf1 (commit)
       via  266bfcd67adafe326c13c6d835f5875628972d9f (commit)
       via  666395baa9b73aca0312787b683a7d3a96e7ca86 (commit)
       via  8431fb8b25cde01d16bfdefdc52b2eb2b07cb756 (commit)
       via  ac23914ba629242fa651b4d68b61e9e5380c0643 (commit)
       via  2a1e4152da4fb42c78e57ada20de7e6a4d64da51 (commit)
       via  4df79169011293abac9c08a1cc47e4f16f5e1750 (commit)
       via  73ca6b06d15e426c0d57c41a0e126d7433acc598 (commit)
       via  271e37c6b0befddbf9291577460868f0c67ea428 (commit)
       via  f59c311cfd135589af52c6f8a9afa45c03f84318 (commit)
       via  814eb8ad33d8f85621d3daacd4c64c4d7e3dc43d (commit)
       via  11f5ae7cddca20ae003331cd69b817be4aea790c (commit)
       via  fe0db0adf0796432ace4794c157efc2bfb79e008 (commit)
       via  269cd1867284c4ebf44ebabacadc99c6413bcacb (commit)
       via  ed8243603f26e46d8ae48f0fb4bac7545c5ff4c9 (commit)
       via  583de5551d162a5feb89bf5759e573b32d80f142 (commit)
       via  53dec20f027b589c2202f182a01d8e33ef15c2a9 (commit)
       via  937c982cf30ed26570ca8853c45f8afe1a32e3e7 (commit)
       via  bc42c4b3d31ed960581808d76e7150e0fc3eb1d9 (commit)
       via  c9ba856c4cc0f98b33cbeb030fedec3b29ee0e0c (commit)
       via  10166e33f1d08985830a8bf5804af40c00328b86 (commit)
       via  4f49376c5dee81bcc140f1445e762f62ee92e29f (commit)
       via  e6348b6115a2525de18a2d70c4b15fece46a9c90 (commit)
       via  794f240b5c6d6da7907f6efab5824658edf26fa6 (commit)
       via  3e94ba20d52e2c62243af504f95f5b3134efd0f7 (commit)
       via  7d28f0a9b596bd3a4580372c93408904d8f2d8a5 (commit)
       via  fb2a1a9621d321c1db03bd3c4184d14e77f9d276 (commit)
       via  2755265bad7544bdaacfeed81e71ae590f043866 (commit)
       via  722fbab9dc7891a6d4270d9e8fac453791fb0c51 (commit)
       via  1954d8d1d6b4b57c3f66443585cbe6aff51b4342 (commit)
       via  810a54ae8ffc10a282796b9ba64594c629010580 (commit)
       via  20255f329b3db92930f8914c3a10f06de26d8fa5 (commit)
       via  bfad7cb107492b6459df53f79875c3225096e67e (commit)
       via  5351989c3736c027df8f164ee257feb6d51f9b72 (commit)
       via  c1b8e63ca9cf15d022805691970e3ecc0dd0e096 (commit)
       via  f3710cc1ce7bdd800176c5b70f22710bda652ddc (commit)
       via  10833250f2751b41b6d9e9b86be5396ec3b4e062 (commit)
       via  59d2798eeb72f4b81dd0c7ee380794da67b96424 (commit)
       via  691f87a3076fba4d5ce60a0960c1c07a35055e05 (commit)
       via  a1705370803388f15833e588db710fe520fda751 (commit)
       via  10a2897883c51ec83247ddcfe137a19807f41a69 (commit)
       via  57f3e532a4cb9ef57484b638cfb53296dc403e95 (commit)
       via  31707f9fd9a78add4895394d0168d5664184b18f (commit)
       via  5cfbdc70c17f139c6c0d7d74afba76240ecd0474 (commit)
       via  76f20bfafceeca8bceefda457fe64904d4d21c59 (commit)
       via  44699b4b18162581cd1dd39be5fb76ca536012e6 (commit)
       via  8ed7d3706940a9a822503426fe4c09f3bf995610 (commit)
       via  5d31621e52c2f2be062284f71a589218ab9a4d0a (commit)
       via  819407f4b51521da995e893f022c06853a6f40cd (commit)
       via  d8c50d0baef0ad3a1339b1c03bd0d37a32719d86 (commit)
       via  7e110b499a751ca43a473a94eb4448bdbe78a32a (commit)
       via  2db190194445d191e1d1eb75f0fc1936d0a791df (commit)
       via  17a9c25450a3129fa5787a5deb70d371a602f311 (commit)
       via  c5efaec3f9196e4b4cabccde691f30ad9de380ba (commit)
       via  ae25fcc7abecb79eb3d4b9df1e0b463c27f77258 (commit)
       via  58ccf7aa110fe656c52060cbc7b2cc26b4a9ae9d (commit)
       via  0aafc9b4325734e8d8d16805ad459f8dde153fdb (commit)
       via  af2672cf1515f459dfc5db30919c407abcb8273b (commit)
       via  e4cd5386850b79a824320a63bfed69f03358574f (commit)
       via  7ddf561d6304d62ce755344b0e28ab9b025b9f27 (commit)
       via  e6603386c50335787bca7443a9716414cf68c7bc (commit)
       via  5d1563f963952af222030a404b21a0bc8171e2ac (commit)
       via  859b69891fe1fc3be67bbd293397fbe7b989eb26 (commit)
       via  f91f95678f03873d47480a9589dae1936423cff7 (commit)
       via  3ca5de640a863aa8b84e5d34b241a26a63992e11 (commit)
       via  ff930eca8ab894a76eb0a695ebde98a7bf117d45 (commit)
       via  3d35bcb14cbe4eba0cf2a2605bad4ede5ae6c338 (commit)
       via  e8c5250c5b3924c34159c92b2e3a23b8878572e6 (commit)
       via  b8e8e7ed5ff301eb18db71ff83c46479984f5fde (commit)
       via  9c42816e5f405de02ef30728d82fcb045cf6a803 (commit)
       via  f18d297fd5b1651ebf61d5d72ca0d64b92fece30 (commit)
       via  a5a7f330f48cf6a63e7f67d690ea3487c11c2cce (commit)
       via  e1ed220b645ea62b01d9a467f8724be4fd59a696 (commit)
       via  adb9e821ff8fa75c3ecc1ecc853ff3e90d1edfd7 (commit)
       via  463700b34d94d933cc4244480e46f975c798d777 (commit)
       via  f575d8fc0316d69b2ea54788b43948488dface2e (commit)
       via  0479cb528e77e29f67b3a05ed79a83c2ef483455 (commit)
       via  d985d0dde44a6c4b090cf211c295ab10a65924e1 (commit)
       via  4f0716782cba2f94c577e80cc23e4759b2440907 (commit)
       via  56e9d0e542d1396e9d0f373bb8cc1fd5d0a945fe (commit)
       via  3f74193c572fefc2e718ca0952962494a9680ddb (commit)
       via  ba7573eb62566aece58b514dfcb3b5a322adfed1 (commit)
       via  717d619224d93b6dc6da0cf6267deffc31e130ad (commit)
       via  10fece1ac6ec02b033f00689fc31ac4f93570dda (commit)
       via  9a7784d748031b97dbb5a55fed84dcca254096d5 (commit)
       via  2ca96761f12b10e51faa6e394617baffbb68afdd (commit)
       via  b122fa56ec0caf72e351f973c9ef337b2b3122c1 (commit)
       via  ed2adc060ea123c5a6fec274950fdc68cde48059 (commit)
       via  86a88ca3f958089b8d586d77f0e501f2792320d3 (commit)
       via  85b7b8462a2bab6084aa724a9fe85208d2c80f84 (commit)
       via  6d9b521367bc30b39209551ccbea6c8e20e140d8 (commit)
       via  079a6684785bb75f1ae2c2c2ebfc1838831e783d (commit)
       via  4c4e2711beeb2eed8104055cf66dd4e8151c4fd1 (commit)
       via  93716b025a4755a8a2cbf250a9e4187741dbc9bb (commit)
       via  3476033eb79b246bbf0904085f4cab3805d5eddd (commit)
       via  d792272541407b25dcda463321416d61315d785f (commit)
       via  21a9a30e94cfa668daef86935894d6b5257179f0 (commit)
       via  f1b061b42a6ea0257f09d45de0243d064497609b (commit)
       via  f7c0e1bf2a90711cd6df426b17465eedafaade00 (commit)
       via  4dd6c4cc1c15974d1009c489f2e26e987479ea77 (commit)
       via  ed014f274ce18bcbdb8c79c3ea856a88af23f8e2 (commit)
       via  f94444fe1c05288c12f6255bb3552a8c8166745a (commit)
       via  daccf2d63231865ce3c5498a4bde4e895f047cd7 (commit)
       via  dbf019c34b50e415fae366e062bdaa353d873412 (commit)
       via  d94641e52198629abdd3ffe82751b0b6ce11ff28 (commit)
       via  d8c2ea58e026b76c516f7ff6e3d6199af1b5ecc7 (commit)
       via  d4032a6703f672811b92811c10998d8eb718eec6 (commit)
       via  9aaf0f9883c7a67ff2acd8be43afd91e235f7164 (commit)
       via  83b06fb184c17f70a28ab307347e9eb075ee048d (commit)
       via  ce5cf26e3637a7faf5901debecaf542cdacf69cc (commit)
       via  c0fa34d5aa68b4d189cfb606373856e6fceb1388 (commit)
       via  ab9c7fa4343ba35decbf47b765d81ffa785c7638 (commit)
       via  702c844a645dd91379d0e6b6896566863291d96f (commit)
       via  a2cb2c80637696d1268f87660508c6aa8e0e14ec (commit)
       via  825e49f101bf3a00de47d0c6e388f00e265f5658 (commit)
       via  9cbc650016910ad14ded2b0a4a7fb18f8275085a (commit)
       via  6873aeabcd152ef491fa66b1292192e1c16e1215 (commit)
       via  ddde1f3034cb004bde11a8c1ba41944a2ce58fff (commit)
       via  12807b1d6e3a0846198bcc062978c077ac101b91 (commit)
       via  b22bc32b2776aa8904ee4fae2e9f6b075eace0f4 (commit)
       via  df5cb12f60fc4f22b24218a54bf428f403cabe22 (commit)
       via  72383e89593fdc91a83b0ffe875a4fdb5114fbfc (commit)
       via  79b78d6538b85a97e1a84aec63928a6bd0251218 (commit)
       via  2352105cc77dd16a583c8f4fdcaf9d680e450344 (commit)
       via  3d4f3cd903294e03bafbf37963051fdcf2233cae (commit)
       via  ea780724240cfb2e065d3cfac7a32ba16e931dc3 (commit)
       via  443be4318110331b2761b8d945dab4f05d765a1a (commit)
       via  8a33bc3ac5aa1fd9e9532b08d9622530c2b5998b (commit)
       via  8f2bbf55feb66a26d6b2c416fd902f488f9848ac (commit)
       via  4a7f643283ece35b839644bc5aeadbdce6766c2d (commit)
       via  ac808e9e265fdafa0182e15da1f5acd1e94d797b (commit)
       via  9b3c959af13111af1fa248c5010aa33ee7e307ee (commit)
       via  1ec1ffb481e68fdd06d04fa38aaf6b4348669649 (commit)
       via  6ad900eeff1c9e2c704dd5259565c28b8846aa37 (commit)
       via  62bb1c4ddcb01d285edfdb04016d710597c708e7 (commit)
       via  2a742e19fb8c128456c90b9ae679d2a4806313d3 (commit)
       via  89fd37be8d063c6fce0fa731ab7f3ac9c45667ef (commit)
       via  4760fba1fcc4d0fdb762b69cd6090002b9190be1 (commit)
       via  5e9d101a16146d2bb60f128cba65083b72e04086 (commit)
       via  ad274a49ad5f36231b8997240272c89b4edf0c2f (commit)
       via  6ff25a392e3d15ae5a9aa1ca11a4badeb95bf39d (commit)
       via  0a85e0e55c24798e91bdbbd39bd1fbe97d72f3f8 (commit)
       via  bc5a59ac90aa09fc1d32212ab1b80428b46f9543 (commit)
       via  c6afb4411dea5f77e3f1ce923271f124583fa59e (commit)
       via  f969ebef7a0d51d33c9c2eb3f034ad25bda2f4f3 (commit)
       via  552cbb67476914a81d0cdf226fc2806b1edf935e (commit)
       via  385f6f102749b237bdab4854d7a30f38203a46cf (commit)
       via  4921791213303bf926778b79873a30fdb334d033 (commit)
       via  ee17e979fcde48b59d91c74ac368244169065f3b (commit)
       via  09b1a2f927483b407d70e98f5982f424cc872149 (commit)
       via  0c19f89ff4a9838e93ed647ed34af6ffad3f420e (commit)
       via  cc9e3303451d440894ce918ae5f1e0d55b30f650 (commit)
       via  dcd93a56893257541fbe19fcd112f7fdda5cb7bb (commit)
       via  1a235092e9050f116b87a1edc5b2b6095aacc9e8 (commit)
       via  79a33db9ed37ba4715b35d1d9c74dcc550a50788 (commit)
       via  44fe82eeedff8f69053c6f455134a256daab3340 (commit)
       via  97953d08e3259263743138dcc81ef4332e585e39 (commit)
       via  9859c1d73774b09bab6aee9dc8082428097aeae9 (commit)
       via  521189be3a1dc89fc9010dfa9fa13a31ee233a38 (commit)
       via  cd2c2c8ec6cf8a335897176339c8150228be4a36 (commit)
       via  779d9312bf84dcf7ce26bd1b1d6276179e026ad2 (commit)
       via  e283a05caf9dd0aefc7cd08a405dbc47510fbd43 (commit)
       via  848cc407b16d4874dc5abec493248cd64db018c6 (commit)
       via  5106746a3bcc359ba14fb569d6921b9cdf5b244a (commit)
       via  6d750aafaabefdec3e2d3bb75343bc520b8ef6b5 (commit)
       via  750c848d04cca9137a34383c6b44bb203e3d2a94 (commit)
       via  9dbce1aa52c7342dc4fe4292983d33b826fc4217 (commit)
       via  40bbfbc8f6fcfa08154b0c76ddbb41c2725f24f7 (commit)
       via  0a94c9b7778c06dcadd0cf77ccf785afe53dc0b7 (commit)
       via  0bd3e904e235bf19714dd6c39de6fd7810541d31 (commit)
       via  555bf4c3d7d588de640091b4bf677c130d34d94d (commit)
       via  e4e606091def44d790b193fbcfe74623dd31ef43 (commit)
       via  7491dd625f34f755d9764cf9e116cd8374be1d88 (commit)
       via  cabbe83773e3b4bc88f80f81cb4d370b0ef7a2f6 (commit)
       via  1e2111996aa44a583fcdf0997a6aa170542f3ea2 (commit)
       via  fc03d665a777c47920a85bae41f3e359c61fa42e (commit)
       via  2a9656fb9ac69e87273f14f4a6807986ee9739a8 (commit)
       via  a333e6c631fd02410295adfac58d8681c635f782 (commit)
       via  3c7af17b0022c2404e22618bb46682991c7e6a3c (commit)
       via  64dd4df0a88c7007cdc22249118fbc0d3d59cd70 (commit)
       via  3d1ea31fe2461f28b7337c78623834eb987c73a5 (commit)
       via  1f6f8905d7319519c6f2ebd5864eeb4d6d700d03 (commit)
       via  388c202a9b3c95f3d8d1aa0c76803b1f398974f3 (commit)
       via  09c24690d48f8b8b7239668216b8fed9bac179e0 (commit)
       via  4d6c30931eee834bb63b11fabec9d84390a9f6b7 (commit)
       via  368ceac8bfb49a0bd4c0a0c98fe624d623de9c6d (commit)
       via  701cf211bb322f46cd0188b8adc2f8e9ad8ac8e6 (commit)
       via  eb1b9e524157d9c378ba0350fe3217d56dbc0665 (commit)
       via  aeec2dc1b9c511d17971ac63138576c37e7c5164 (commit)
       via  a50fe182f38a02d9cea3256e5908cfa1e1658e00 (commit)
       via  e5faeb5fa84b7218fde486347359504cf692510e (commit)
       via  7bed043f816679ee3ee3c6d75202d47b1531b37f (commit)
       via  ffa68930da0e9e19f697f1345807108dca356386 (commit)
       via  8b05639cdcea9e7fd65a50c1e62fb449a4526916 (commit)
       via  91aa998226f1f91a232f2be59a53c9568c4ece77 (commit)
       via  bc66f6d0df259657efc39b87f33e68dd08062202 (commit)
       via  e99a3dd0a0c6e698a5b3108af017c76fa6d115ec (commit)
       via  6317823834dced610691841ee7c082249fa1f8fe (commit)
       via  c99567a4b1d2f5cfe345239c74b981efc8a4d585 (commit)
       via  1da05510732e259e76ef280d7b879fd237b746f3 (commit)
       via  ba3695664abb8b686c8fee6d25bd356b68cd5c7c (commit)
       via  07414de00e7bbbafcb73166eb969ce1fd38105ee (commit)
       via  c00795e0f9d07c7f0d47f04098addd3144dce7d4 (commit)
       via  4f3158323950fd4c5bbccfdfcb33b5bb48e01dbc (commit)
       via  e34d32533ce85b2ae710f6ab45ebd187cb3520b7 (commit)
       via  d72eca9cdec9acb880e136c1b908fb136c7e1957 (commit)
       via  388434f8a4c3693e76b95dba9cb9d6ae183a6407 (commit)
       via  a3cd0126b46392c4c150d9e865ff82811e24006f (commit)
       via  27e6119093723a1e46a239ec245a8b4b10677635 (commit)
       via  79acb1197b7046a21034d5a1dadeb6b2efbf030a (commit)
       via  de49cb6406849be06c5452ca532bb1007fe5c509 (commit)
       via  5b8a824054313bdecb8988b46e55cb2e94cb2d6c (commit)
       via  e0ffe686d622e43dfbf3e286252044d1fd20a6ed (commit)
       via  cf78a006585e1918376e7e5847102c4dc435be19 (commit)
       via  217087aad01f35b863da3b69012d4b3904b35a7c (commit)
       via  4b7b2f9a808352bb4ef1a71de3a46cdd79076050 (commit)
       via  9bb9dbe6234769cbe525c24887eefe16ef1d7cee (commit)
       via  f6882b13b9264d0d64345a341a73c75ae6d9c535 (commit)
       via  0d69610ffffd701cd3a6fb2645f9ff24b69cb3b7 (commit)
       via  e382b73b40ea40386202d1c91dfe57c8a4efc11f (commit)
       via  8765402aa09dbbf42b7cf3e8449a633a850221c4 (commit)
       via  f0ad7b6307f49bb7bc4a45311e6f1b33b42dd885 (commit)
       via  4890e1207ce2c4fd0875c321e14c8931c6313e6b (commit)
       via  8ea9fa7608fbb63b0effbef970535ab96ef4edee (commit)
       via  5d3f0570a21d753d681d170622df02ef39ebb70d (commit)
       via  b5b877d1ec728e2dd0d8992a825dd2145c1277a9 (commit)
       via  f485d39ab6e394bc034b990f872572c3700d0312 (commit)
       via  a55716a04087917db71ff5b224b922d05ec6d6c6 (commit)
       via  769bbb5edb0fe537e497ebe1a9fc3dfc130a5866 (commit)
       via  2cbabde53f226cb4fa4883b9578268719f28732b (commit)
       via  6c6f405188cc02d2358e114c33daff58edabd52a (commit)
       via  5237d9415f6fb14c932695d59d1d2721b185bfe3 (commit)
       via  d117d8720025b9e57fd1cd2eae7792c0700cdfff (commit)
       via  7e31b4ded3983b1271fec3799798b52c105b140e (commit)
       via  525333e187cc4bbbbde288105c9582c1024caa4a (commit)
       via  2023dc6ee89d9e43dccbf85e55505ef54e4e8895 (commit)
       via  ca962cbac01e4c3c79050b57ca07165c3b7662ae (commit)
       via  016925ef2437e0396127e135c937d3a55539d224 (commit)
       via  0be5967e2ff6364d8d38ad297be99925dfe20cc4 (commit)
       via  c4df99eac2910af079f19b0bdacc95d7cd88192f (commit)
       via  99a6e8470907e678cd8c208eeef2810b4bd0bacb (commit)
       via  6167f31e01864656cf1a26a0d6bea75f08783a01 (commit)
       via  d9421d93e3a65e6025281ece92706f7c2003ae77 (commit)
       via  32973fceb52e1da15903df796fc1fa55dc3486e4 (commit)
       via  e273dedf8a3875ddb241b796c19144d14819f5d8 (commit)
       via  fae9e0052b6f71b38e003bda562cc49ab4d4b9c7 (commit)
       via  1bbf2ae947fdfb85b57fcd41a5c3f386bbadd221 (commit)
       via  aa76df71dcd756e7b233af47a6c936263813d90b (commit)
       via  c4a5a733f2e6729f4d91bc7c1117f4ff0fa70e1c (commit)
       via  f4a107a8f8775523e32d8ba0bc3e28e2f26eff3a (commit)
       via  631366a33bb06d01547c0789edfadde7a17228bd (commit)
       via  e05c0b3ebb376233dd9648732fb5c992bb72e242 (commit)
       via  a60ee6bbefe447f7ce863641dd88cdb1d3f0766b (commit)
       via  d27b4c92e0aa23a8d39338377d705a75f78d1f3e (commit)
       via  a4bbade712c4a082d8ae95c9389021d27b74b382 (commit)
       via  aad83b6edde86e70a460cdf887b985841c161016 (commit)
       via  83c28cb3836d45e3e1abdc5a53c0d994148d1af2 (commit)
       via  39a3150a0fe822b177c53379b2c93ad6f24585b9 (commit)
       via  610f3ecc55290ff4c2d3453f0f90c222b00a6f38 (commit)
       via  ea6e8ea2e28a3c7b22ca2390f3509d791522959b (commit)
       via  c80274000aed9ab258b3e0b46ddb2c3212a7b877 (commit)
       via  55b05119c73ef4858995efd2377c16e17f8a0f06 (commit)
       via  d7fd34a4bf69c07812461671ac8d8f0dde0ee440 (commit)
       via  1bb3b6b661cc500b2a7cad2447347a23b7b1fadc (commit)
       via  d5a2bb8d02bb017405ac6f79e2eeffcb7fd23052 (commit)
       via  9de5d287390383e072dbb2c4cbf9d60253893e41 (commit)
       via  2887502a9e0084cb16c79aba684a65f9d4fda69a (commit)
       via  88d25efcbc3e7b6a8fe7dea5c78e40115be1b1f4 (commit)
       via  0f4eb55137c6c0d2da2f14270a3c843fae14d187 (commit)
       via  c0b406791e7d3be3fb7962d52f6b6a320b4a7736 (commit)
       via  dc2aa27ea58ec3be03e742f2f4dd123a2c044200 (commit)
       via  6fcb36d000e1da11d66baeb4b97278dd974d6a01 (commit)
       via  bca4daf3e3ea6538b6796e570daaeedb516b2dcb (commit)
       via  b7221c64cd88051434a3d254a0ec6a1fe07ddf6b (commit)
       via  003f49d97927cc4dd85c4a631611152e7e10bd1c (commit)
       via  fd29a774079b86f2b62c857d13ef450f0da29a00 (commit)
       via  e149d57f779c6597a6ed1d497c40a9641ac6651c (commit)
       via  ce19e77d9f6b9715502b5636511421dc09148f86 (commit)
       via  88ff44432d5fed287aa8a91d620692f4a715ae1c (commit)
       via  9f03e9dd3f34b0a502b0d69ec7f08b582011dcf6 (commit)
       via  d31f5bd476744ced094fc2aecb557b945586b056 (commit)
       via  bb6afeceea763fdfd012b8a2b6e9e4247f2d623d (commit)
       via  fa342a994de5dbefe32996be7eebe58f6304cff7 (commit)
       via  931a65b517fd80cf03afbd8ff3c5c70a121f66e5 (commit)
       via  671b6ae757f8a4f22bec449afa9b743c4ec2d719 (commit)
       via  4d44f0bf193dac303be3a15258fe8faaf857c6f9 (commit)
       via  58c958d4503a9a45be0267dc833c6e3be178dc14 (commit)
       via  45466d27ef5c4f095c7d3bf23b4d0a4ad30a8bcb (commit)
       via  54d482bf70ce2878423df57efd6bbb8138805914 (commit)
       via  002b5ff189dde721ac10f21d83aadb0b9e641295 (commit)
       via  4c38d52144ef9a80ee8edb705d98ce6baaf4c378 (commit)
       via  738540ce3a7b5d06707d5b298a6223629ab66050 (commit)
       via  3b37e9c152b05606bb5401c16c5b9f6d37155539 (commit)
       via  81ed5b0185f7b37aafada49c52880ba87b03785f (commit)
       via  37a8e164d7e3267b42ad438f49ae2505bd5b952b (commit)
       via  e3bde86b2e51188e37fab58965709fe2f22f9610 (commit)
       via  a4aa18ebf42a9f94818519a5805e7caf7bff61c7 (commit)
       via  1ea439fadbf39dc980cff8c8848994bdbeeb1e9a (commit)
       via  d4d5c0ee659e6ecfb3e3384f2462a58559464f80 (commit)
       via  2db3158111a1e1ae660fdb515f0d461e6798e27b (commit)
       via  933430e40bb35135d741df5b9c8b944c5bf9be83 (commit)
       via  e3fb3a101e6874ca1c93e46916ab53f278c55642 (commit)
       via  826d0c45b072ba36bbd60dc71fe3097cd604de74 (commit)
       via  a0ac798d243153455ce1332a8ef3e1363b33273c (commit)
       via  2443a6fc801159c879f4051f17c79b2e776b34bf (commit)
       via  79f0d62ef03b3774a0b0c6237eff78af821bdbc4 (commit)
       via  3886d1174c6552cc99c3d5fa2c727c3ee0bcc281 (commit)
       via  fdbba41a48cffe7efc185b8eb59fd3471aeb78d5 (commit)
       via  3f1577b50df4375e51d94be2650ab2ae5e4d6698 (commit)
       via  30276d77d28c951226859d2f1f452abfabdcf6f4 (commit)
       via  2cecfb45e98d30493019d4664fc7ca320e377a2e (commit)
       via  f56d5006adee1ae27e38960d26e46b5fe488c965 (commit)
       via  fc075a50ee9a1d31c4851afc1f6df64c67951547 (commit)
       via  6a2437122d5dddfc0ddfd923c5036331ca23fb12 (commit)
       via  f16d079d34dc61a5cea082328c3eb38beeea3d7c (commit)
       via  45b03507d6ec3868648713f86e7789b15f78a367 (commit)
       via  656b5d1cb045b35499ced064fae6bc1962f91ad6 (commit)
       via  77c9f2b09e47184c42f56658dcd93c4eee36587a (commit)
       via  2b81c6b347116512da7c653b0ca542a04b82015a (commit)
       via  32a5e02895ad3faf098172a08c11ce4df535521e (commit)
       via  695d9fc3bc135de080369b0b7213aca3c264216c (commit)
       via  5f6ae1f6c5c0f484c1e2f3073d713784cf3c5373 (commit)
       via  4c2bed018107dea2091ac26f51e81d2f14f33582 (commit)
       via  f65147ed98354cb39e52568a6ff1f7f98ad885ff (commit)
       via  1c59e1ee00a8d1ebabfabb592ee910b22c72f1d9 (commit)
       via  63c3bee3545216695dacb5b06c52c90ab82f31ec (commit)
       via  6b6cbde6a1ac6ad0f3f11923ee6633ced00d529b (commit)
       via  c61ae0fbbba155063ada04a08ec44f3dc27ab6bc (commit)
       via  808decc6c1639304e030a84d2bb2a04bd1b27db8 (commit)
       via  f4e272c729e2a77f720b06a22819013f6695f06b (commit)
       via  89cc0b54c0de3bac967e2ae8135aad6d654edfe1 (commit)
       via  acc630c2e40165f605aad3dde959bc2f3871ea6b (commit)
       via  c7c532323f9f5f9d98050c0728a87e04800d7144 (commit)
       via  ff5861d1c7d7a689d775b251086d12032fcabd54 (commit)
       via  aae75525fe351f4df368402e7e05aa0e52b234b1 (commit)
       via  5267d959d14763af2a7c938a136267655722cd77 (commit)
       via  6a47ad417ae15c4cc9bad53347ae06088a642ec3 (commit)
       via  1ba7dea264623db66cbf62fed95db34cde362cf5 (commit)
       via  b927f6e09523bcadf613b4e409a0039e5bfbb03c (commit)
       via  0cce212fefe299518426d10812c74ce14d547782 (commit)
       via  878a31b83ab5df9441804a67a2f9a16ad615ae84 (commit)
       via  c846c5417c22b4a3b02122860ce9a6977a6ffa44 (commit)
       via  ae4e532f39b85f619ff99d8feb91898d8ee741a9 (commit)
       via  ba27028c44e71d0fa19077209b412538be635c81 (commit)
       via  9a7261d103fb09bf87b1f827a733aca3cb87d46c (commit)
       via  ff502308eef747bad13e1e4c763ca7fc2d820a99 (commit)
       via  0e9831ebbe7ff8c719605c36f3c3292db31d28c8 (commit)
       via  d33133715b3f211459678061e0f2d3c40738c07f (commit)
       via  a6e58431e3582cc73e5c3e2aa20ee09c5da199a4 (commit)
       via  f2fa03f0b6156c8a64376d1524fe822e3a74cb16 (commit)
       via  869ad53a069b3fe4836d818fe820160e914a017c (commit)
       via  e601cb8dbb5dae21aa90061d2dbf0e23223186c0 (commit)
       via  76b963dc31b5df73631b3689868b991759414ba9 (commit)
       via  5fa3d0e12c20cd9d07fc83c98dbd32c64eadca3e (commit)
       via  cd894167c8d367f7367b790d60c3dd23f740ffdf (commit)
       via  add399ede802585b4606e6b07d60fe831aa8ec7a (commit)
       via  7773035d231a2a55664dbe04baa4744da4ada7a7 (commit)
       via  8d160f47d4cd2b6bf265580331215fa9d48a9571 (commit)
       via  f0779391ff33e44afac4fc7911400d9b3f345446 (commit)
       via  a2e1d3f2d9f4bd9680932a46cf2b00c1cd2a1a64 (commit)
       via  09a0594ddec459ff3d7bf1e0f0814847d5904883 (commit)
       via  a25a5fca02c5aca0a29113ca293581b1b48bcfdd (commit)
       via  8e118d8e64ff03678c4dd4bdbc6e8e8c64737ac6 (commit)
       via  13b8d3383b390dfb30ba39d9f7c69d1c0a7fd572 (commit)
       via  7eaf1f34a92aef6e6e82b59e1a8200c858820b77 (commit)
       via  45b538d01cc68a759ed8eb1d9e069def986e2ae9 (commit)
       via  7f75e58b7f26fc36c457b74770f8bdc0043a1618 (commit)
       via  3d3d75ab559780b95a325c9890364e2c80c480a1 (commit)
       via  b3804a1036a254bf6ba00bae3182cc0486ddf7ff (commit)
       via  ba18b3b37595da5364dd82adfb880d3cb5d916d2 (commit)
       via  bd6e48f80ca1eb587ef1895b1614554865b85fa5 (commit)
       via  98fd407e255aadf68b0e1ba7c89b0f65619373ad (commit)
       via  644541309f301c6f86495db3982eb5ba69b40529 (commit)
       via  76759ae07db6edb36cc063ef1f89e247d910275a (commit)
       via  cb24062bb3a9d55e5a22098f526172f130a50d60 (commit)
       via  370c09f6e3b2d4141ed573bfbab6e39302d670b7 (commit)
       via  7eb39cf5f50a31ccd80d6373074301f5caeb088c (commit)
       via  566a0c71ebbdeee3981152aa0d98e53a4eba102a (commit)
       via  9d1691533c1bbce4518ddbe617b6e2b24ff532ea (commit)
       via  3eb8564cd9f9dc2b05b25da7d837a742acb7a860 (commit)
       via  c7de383107b3644fb0fb941341b369f8693e9382 (commit)
       via  d4e61c261d0af6db6da47bba2b1cac1ecf4ce002 (commit)
       via  56e8f3e3e99557bacd0f4d4a2694f42b2c2f63ef (commit)
       via  9371828a3aae06b6a5de33743864bcf3e20162f4 (commit)
       via  c74f64796e9901c453ab7d4e509d736d037884fd (commit)
       via  72e963ce027a56e814d5404feee00aa0b4a45b15 (commit)
       via  0f4c8ad79bcdf9810013fa667dd04bf0e67c21b5 (commit)
       via  90f9161b787dfe68158c12bd07d2e362f2db8cc6 (commit)
       via  99d1141934d6bb027bfd402110b5706aa114adaf (commit)
       via  261d1e5735e818cbf12cd6d004faf0ccc86bdaf4 (commit)
       via  cbc4276308e412d456a20e5eaf816af86ecac82a (commit)
       via  b0b2c34b61603f6a2676f139d5ad328ac1f3cdc5 (commit)
       via  6f2e770cfbec4ffed1f314bed4e1b8b480c32c16 (commit)
       via  acd0cdbbc9e3e261cfc0e0f8589bff184a2f2e8b (commit)
       via  40f93b0c0d8957a55fb668c12a20f90d4ac9b9d3 (commit)
       via  47378a9cbd7221316b4c760e63d04076e30c73e3 (commit)
       via  3c564a11e1f20def92a19c61b7af3451eb5401f7 (commit)
       via  988a0f092329316e2b371a28f2a1d23424bf9faf (commit)
       via  494784a813b1abdaa08e0bb3826ba72d0da5d15e (commit)
       via  8cdb5d8c29af3be627e3c7bd5898d08392da4b35 (commit)
       via  f04b2ebeb31bc3ff1b8866be4b426bfbbb423803 (commit)
       via  dd62fb425882a361673e52f264b24d2455d9b335 (commit)
       via  c2165222deb85cb2ff99a7146b28c659624edc24 (commit)
       via  2afe3383ec01875950b489b7702b2ec2c3281d64 (commit)
       via  9e0f9e4df2927c9ae7173053b2efc57ec8dd82ee (commit)
       via  e930663b459bf75063193ed08cb3d455adaaccae (commit)
       via  36f21c21868230dc6dbf60b898607cca53fceaf4 (commit)
       via  9284859b4ab4af8670ecf1cd6de999a04cd4285b (commit)
       via  1e68893cbfb6d4742e1d9def9ca2960935c7e2b9 (commit)
       via  74a034d57525026cb30591f3e89c49be2f2787ec (commit)
       via  12ca269d63653d1db9280920717554f3d06f885f (commit)
       via  b65007a6a4dbc4b192f78dece6ba84eb32e0b3bc (commit)
       via  8de2a109e5827ed6bac158e8a12c453d90a23f26 (commit)
       via  f3e3dc930b7de63dd8842b61a7ec042ac99c235c (commit)
       via  bb6e5acc09639be9a9009f3d266435aee2b0fce2 (commit)
       via  2ac23d0d571713a390d154263040c1f1290bba89 (commit)
       via  bce2a3f58dd9c95985a53c6235835aa9fb4c719d (commit)
       via  4c3dc79c413854edcf660874f8bd58d626b808c8 (commit)
       via  9b47527a3fd00d3504dbdecc5e6b073834825c66 (commit)
       via  db2a410da1fb7553909b47ddbc7ce34456081f47 (commit)
       via  efbe16c46b234712eaa7629ffda12b1a906542af (commit)
       via  4d9785cd658ba91b5f01c90c1855d239596c5f53 (commit)
       via  7d02b9cc8837e089433be66f7973ba578e72ee39 (commit)
       via  91a81c3b9a1ed47103c00e50fe3d141a2e9929b9 (commit)
       via  ab7f77f9ea18ce289ccc7484c4a40dc73548bca0 (commit)
       via  cb5a5f6e3c043b2f94884f5cb9101b661a084fc6 (commit)
       via  d5d8fa746c2cb23166e93f76423ae7ca645ef6a3 (commit)
       via  3e2516ee09187b5c9af57e0cd6552bb298ebf02d (commit)
       via  8c169e9a6032d69dd852f49d567eda1ecd7de706 (commit)
       via  a1107af9f039334d628220553229476beb41143f (commit)
       via  a0f35ebd59dee9b3f9b87c6b16d9185766f1d1be (commit)
       via  6f61065e702d8ccd5b3b2da2c5e07803270ed120 (commit)
       via  a44025da797abe06f2d1b1a7de98f68b37e0c5d4 (commit)
       via  34dd2565e959d9307cd17a1664d514ba76b68e24 (commit)
       via  50c6b204fe5c51af7bed0f5538b8d6817b654a24 (commit)
       via  5abc52b3f407f042b7fd189aa42a6a23228c0be7 (commit)
       via  92cf23f15e80e32f2983eb69d7c5ca13c336ebc4 (commit)
       via  7a821cf7fe79d72a294053865a65fe52b29394ee (commit)
       via  24cecc6e6249e1805160c7c6d1ed121ae57a451f (commit)
       via  0e784ad2b33879f2cfcb40921a891fb73714be68 (commit)
       via  c30ebf9ecc8b18a7b2e6ae57f6e8db582acb00c7 (commit)
       via  7dd1d39f9711ec039988a527eff33dc5912b4721 (commit)
       via  0382951b17dfa9647f4f1b4c55d021f51138aa1e (commit)
       via  d24fcdc5998f904c5b81de311066935906566ff2 (commit)
       via  01cec039d9326d4d29e501109aa3bf5b28896786 (commit)
       via  16a7ef79d27c65f25a72908244b088fd8488c729 (commit)
       via  7791af176bda3e99caffe8ca2aa2fc69d92a95dc (commit)
       via  1603af4c983f4fbebc4731177680c8c9549b4c60 (commit)
       via  fb246fec83de75f41171b48f48c314b985a985de (commit)
       via  081f73d83d9afee393283514afc4398b8515f6a3 (commit)
       via  5b92e04d29ae21a217b8ce01fe3487ccd4ca180b (commit)
       via  eeb6dd5d64907846387b886cd2aa20e018e4234e (commit)
       via  52598eb44e5c7fca9f1902be4c1e54e786b13d3b (commit)
       via  b9b6e36c4e5201c5ffb5f405ee7c4e18ee787d1d (commit)
       via  ea7ef4dac89ff14aaa752ca10ad0a1ec965ea0f4 (commit)
       via  b08a456d702942de353ae57529bdbe2d1ba22d07 (commit)
       via  f9b1652469debfcc2974149219b4098019458649 (commit)
       via  425b14dc49047c29338e415f6360a15c81b4f48c (commit)
       via  b2d762a14ce55201967f0d38e2216289b98955fd (commit)
       via  401f99d8ce662e361c4aa067e758e03b8c0a78e0 (commit)
       via  fc44d8a5b5084a60cf7d7cddf7cfe537191d14af (commit)
       via  82896b534152bc5c29d8db5939965c073e283dd4 (commit)
       via  72c2349d91de8ab45839a701b6befe30f04d542b (commit)
       via  859bfb0777fc4ef95de9dcc396b8ca5e98d91760 (commit)
       via  131b376fc16fbe7bee9dc8753daba0dc04171cff (commit)
       via  4f7957ecd5a7995dac7662569c2e4dd7d86c7d77 (commit)
       via  1bd6030873ee6e27cddcbb6437ef15ca84ee9cfa (commit)
       via  9aea53afbe639d939b04df9307bdb48e2952148b (commit)
       via  c8c8c8358a7602094b6177b5336d39b9de172b87 (commit)
       via  5d108ef3a0b5b5d9fe322ceb478c36077deedfd4 (commit)
       via  bc6378d402e5977beac587dc87b73351609f01a5 (commit)
       via  2edfabb40d94f795923f8dbbd135e20c9c19f8ad (commit)
       via  05d4686ef8b343fc4ca4ea0bfd6c62fe4b73ef84 (commit)
       via  d597f938295cdfaf4670308558f692523d0857f0 (commit)
       via  68f0ecce4c8ec9f5b2fb16fd56fdc0dd89dd2101 (commit)
       via  577a426b8734d7f77e4dceae80fe0c344ab15330 (commit)
       via  415e9b6a2c8544882c71e3cb91d47bb768e41a9f (commit)
       via  1b616670c801a181c8ba5718710bdeb6573e3e4b (commit)
       via  2f912a5d91267471e059ad8bc3e9f0377de2f487 (commit)
      from  ab52e5a00f2bd30d6f2d5e38329f3955c9c23cbc (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 13e8c165b1fddbcb34868c1ed4731fb199b233e7
Merge: ab52e5a e606d8d
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Feb 26 11:11:48 2013 +0900

    [2225_xfrout] Merge branch 'master' of git://git.bind10.isc.org/bind10 into trac2225_xfrout
    
    Conflicts:
    	src/bin/xfrout/tests/xfrout_test.py.in
    	src/bin/xfrout/xfrout.py.in

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

Summary of changes:
 ChangeLog                                          |  249 +-
 README                                             |   15 +-
 configure.ac                                       |   58 +-
 doc/Makefile.am                                    |    2 +-
 doc/differences.txt                                |   12 +
 doc/guide/bind10-guide.xml                         | 1800 +++++++---
 examples/configure.ac                              |    5 +-
 examples/m4/ax_isc_rpath.m4                        |   62 +-
 src/bin/auth/.gitignore                            |    5 +
 src/bin/auth/Makefile.am                           |   28 +-
 src/bin/auth/auth.spec.pre.in                      |  218 +-
 src/bin/auth/auth_config.cc                        |    4 +-
 src/bin/auth/auth_messages.mes                     |    9 +-
 src/bin/auth/auth_srv.cc                           |  181 +-
 src/bin/auth/auth_srv.h                            |    5 +-
 src/bin/auth/{b10-auth.xml => b10-auth.xml.pre}    |   71 +-
 src/bin/auth/gen-statisticsitems.py.pre.in         |  385 +++
 src/bin/auth/main.cc                               |   34 +-
 src/bin/auth/query.cc                              |   33 +-
 src/bin/auth/statistics.cc                         |  284 --
 src/bin/auth/statistics.cc.pre                     |  277 ++
 src/bin/auth/statistics.h                          |  365 ++-
 src/bin/auth/statistics_items.h                    |  609 ----
 src/bin/auth/statistics_items.h.pre                |   53 +
 src/bin/auth/statistics_msg_items.def              |   48 +
 src/bin/auth/tests/.gitignore                      |    1 +
 src/bin/auth/tests/Makefile.am                     |   11 +-
 src/bin/auth/tests/auth_srv_unittest.cc            |  477 ++-
 src/bin/auth/tests/command_unittest.cc             |    2 -
 src/bin/auth/tests/config_unittest.cc              |    3 +-
 .../auth/tests/datasrc_clients_builder_unittest.cc |    3 +-
 src/bin/auth/tests/gen-statisticsitems_test.py     |   90 +
 src/bin/auth/tests/query_unittest.cc               |  270 +-
 src/bin/auth/tests/statistics_unittest.cc          |  123 -
 src/bin/auth/tests/statistics_unittest.cc.pre      |  714 ++++
 src/bin/auth/tests/statistics_util.cc              |   75 +
 .../auth/tests/statistics_util.h}                  |   24 +-
 src/bin/auth/tests/testdata/Makefile.am            |    1 -
 src/bin/auth/tests/testdata/example-base-inc.zone  |   19 +-
 src/bin/auth/tests/testdata/example-nsec3-inc.zone |    2 +-
 src/bin/bind10/.gitignore                          |    6 +-
 src/bin/bind10/Makefile.am                         |   32 +-
 src/bin/bind10/README                              |    5 +-
 src/bin/bind10/{bind10.xml => b10-init.xml}        |   80 +-
 src/bin/bind10/bind10.in                           |   11 +
 src/bin/bind10/bind10.xml                          |  461 +--
 src/bin/bind10/creatorapi.txt                      |   28 +-
 src/bin/bind10/{bind10_src.py.in => init.py.in}    |   97 +-
 src/bin/bind10/{bob.spec => init.spec}             |    6 +-
 .../{bind10_messages.mes => init_messages.mes}     |  110 +-
 src/bin/bind10/run_bind10.sh.in                    |    4 +-
 src/bin/bind10/tests/.gitignore                    |    2 +-
 src/bin/bind10/tests/Makefile.am                   |    2 +-
 src/bin/bind10/tests/args_test.py                  |  115 +-
 .../tests/{bind10_test.py.in => init_test.py.in}   | 1078 +++---
 src/bin/bindctl/bindcmd.py                         |  177 +-
 src/bin/bindctl/bindctl.xml                        |    7 +-
 src/bin/bindctl/bindctl_main.py.in                 |    2 +-
 src/bin/bindctl/command_sets.py                    |   24 +-
 src/bin/bindctl/mycollections.py                   |   15 +
 src/bin/bindctl/run_bindctl.sh.in                  |    2 +-
 src/bin/bindctl/tests/bindctl_test.py              |  125 +-
 src/bin/cfgmgr/b10-cfgmgr.py.in                    |    2 +-
 src/bin/cfgmgr/b10-cfgmgr.xml                      |   10 +-
 src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in         |    8 +-
 src/bin/cmdctl/Makefile.am                         |   17 +-
 src/bin/cmdctl/b10-certgen.xml                     |    3 +
 src/bin/cmdctl/b10-cmdctl.xml                      |    7 +-
 src/bin/cmdctl/cmdctl.py.in                        |   64 +-
 src/bin/cmdctl/cmdctl_messages.mes                 |   10 +
 src/bin/cmdctl/run_b10-cmdctl.sh.in                |    2 +-
 src/bin/cmdctl/tests/Makefile.am                   |    2 +-
 src/bin/cmdctl/tests/cmdctl_test.py                |  160 +-
 src/bin/dbutil/b10-dbutil.xml                      |    2 +-
 src/bin/dbutil/dbutil.py.in                        |    8 +-
 src/bin/dbutil/run_dbutil.sh.in                    |    5 +-
 src/bin/dbutil/tests/dbutil_test.sh.in             |  102 +-
 src/bin/dbutil/tests/testdata/Makefile.am          |    1 +
 .../tests/testdata/{v2_1.sqlite3 => v2_2.sqlite3}  |  Bin 15360 -> 16384 bytes
 src/bin/ddns/b10-ddns.xml                          |   11 +-
 src/bin/ddns/ddns.py.in                            |   69 +-
 src/bin/ddns/ddns_messages.mes                     |   48 +-
 src/bin/ddns/tests/ddns_test.py                    |   39 +-
 src/bin/dhcp4/Makefile.am                          |   10 +-
 src/bin/dhcp4/b10-dhcp4.xml                        |    3 +
 src/bin/dhcp4/config_parser.cc                     |  186 +-
 src/bin/dhcp4/ctrl_dhcp4_srv.cc                    |   70 +-
 src/bin/dhcp4/ctrl_dhcp4_srv.h                     |   23 +-
 src/bin/dhcp4/dhcp4.dox                            |   14 +
 src/bin/dhcp4/dhcp4.spec                           |   52 +-
 src/bin/dhcp4/dhcp4_messages.mes                   |   77 +-
 src/bin/dhcp4/dhcp4_srv.cc                         |  359 +-
 src/bin/dhcp4/dhcp4_srv.h                          |   45 +-
 src/bin/dhcp4/tests/Makefile.am                    |   10 +-
 src/bin/dhcp4/tests/config_parser_unittest.cc      |  494 ++-
 src/bin/dhcp4/tests/dhcp4_srv_unittest.cc          |  242 +-
 src/bin/dhcp4/tests/dhcp4_test.py                  |    2 +-
 src/bin/dhcp6/Makefile.am                          |   10 +-
 src/bin/dhcp6/b10-dhcp6.xml                        |    3 +
 src/bin/dhcp6/config_parser.cc                     |  180 +-
 src/bin/dhcp6/ctrl_dhcp6_srv.cc                    |   86 +-
 src/bin/dhcp6/ctrl_dhcp6_srv.h                     |   29 +-
 src/bin/dhcp6/dhcp6.dox                            |   14 +
 src/bin/dhcp6/dhcp6.spec                           |   52 +-
 src/bin/dhcp6/dhcp6_messages.mes                   |  178 +-
 src/bin/dhcp6/dhcp6_srv.cc                         |  260 +-
 src/bin/dhcp6/dhcp6_srv.h                          |   41 +-
 src/bin/dhcp6/main.cc                              |   15 +-
 src/bin/dhcp6/tests/Makefile.am                    |   10 +-
 src/bin/dhcp6/tests/config_parser_unittest.cc      |  537 ++-
 src/bin/dhcp6/tests/dhcp6_srv_unittest.cc          |   61 +-
 src/bin/dhcp6/tests/dhcp6_test.py                  |    4 +-
 src/bin/loadzone/loadzone.py.in                    |   57 +-
 src/bin/loadzone/loadzone_messages.mes             |   11 +-
 src/bin/loadzone/run_loadzone.sh.in                |    2 +-
 src/bin/loadzone/tests/correct/correct_test.sh.in  |    3 -
 src/bin/loadzone/tests/correct/example.db          |   14 +-
 src/bin/loadzone/tests/correct/include.db          |    4 +-
 src/bin/loadzone/tests/correct/mix1.db             |    4 +-
 src/bin/loadzone/tests/correct/mix2.db             |    4 +-
 src/bin/loadzone/tests/correct/ttl1.db             |    4 +-
 src/bin/loadzone/tests/correct/ttl2.db             |    4 +-
 src/bin/loadzone/tests/correct/ttlext.db           |    4 +-
 src/bin/loadzone/tests/loadzone_test.py            |   47 +-
 src/bin/msgq/msgq.py.in                            |  238 +-
 src/bin/msgq/msgq.xml                              |    5 +-
 src/bin/msgq/msgq_messages.mes                     |   74 +-
 src/bin/msgq/run_msgq.sh.in                        |    2 +-
 src/bin/msgq/tests/msgq_test.py                    |  388 ++-
 src/bin/resolver/b10-resolver.xml                  |   13 +-
 src/bin/resolver/resolver.cc                       |   13 +-
 src/bin/resolver/resolver_messages.mes             |   13 +-
 src/bin/sockcreator/b10-sockcreator.xml            |    5 +-
 src/bin/sockcreator/tests/sockcreator_tests.cc     |    9 +-
 src/bin/stats/b10-stats-httpd.xml                  |   15 +-
 src/bin/stats/b10-stats.xml                        |   16 +-
 src/bin/stats/stats.py.in                          |  206 +-
 src/bin/stats/stats.spec                           |    2 +-
 src/bin/stats/stats_httpd.py.in                    |   86 +-
 src/bin/stats/stats_httpd_messages.mes             |   45 +-
 src/bin/stats/stats_messages.mes                   |    3 +
 src/bin/stats/tests/b10-stats-httpd_test.py        |   31 +-
 src/bin/stats/tests/b10-stats_test.py              |  480 ++-
 src/bin/stats/tests/test_utils.py                  |  205 +-
 src/bin/stats/tests/testdata/b10-config.db         |    2 +-
 src/bin/sysinfo/run_sysinfo.sh.in                  |   13 +-
 src/bin/tests/process_rename_test.py.in            |    2 +-
 src/bin/xfrin/b10-xfrin.xml                        |   11 +-
 src/bin/xfrin/tests/xfrin_test.py                  |  383 ++-
 src/bin/xfrin/xfrin.py.in                          |  158 +-
 src/bin/xfrin/xfrin_messages.mes                   |   30 +-
 src/bin/xfrout/b10-xfrout.xml                      |    9 +-
 src/bin/xfrout/tests/xfrout_test.py.in             |  124 +-
 src/bin/xfrout/xfrout.py.in                        |   71 +-
 src/bin/xfrout/xfrout_messages.mes                 |    5 +-
 src/bin/zonemgr/b10-zonemgr.xml                    |   11 +-
 src/bin/zonemgr/tests/zonemgr_test.py              |   24 +-
 src/bin/zonemgr/zonemgr.py.in                      |   23 +-
 src/bin/zonemgr/zonemgr_messages.mes               |    4 +-
 src/lib/asiodns/sync_udp_server.cc                 |    2 +-
 src/lib/asiodns/sync_udp_server.h                  |    2 -
 src/lib/asiodns/tcp_server.cc                      |    1 -
 src/lib/asiodns/tcp_server.h                       |    1 -
 src/lib/asiodns/udp_server.cc                      |    7 +-
 src/lib/asiolink/tests/tcp_socket_unittest.cc      |    7 +-
 src/lib/cache/local_zone_data.h                    |    9 +-
 src/lib/cc/.gitignore                              |    1 +
 src/lib/cc/Makefile.am                             |   10 +-
 src/lib/cc/cc_messages.mes                         |    4 +
 src/lib/cc/data.cc                                 |  129 +-
 src/lib/cc/proto_defs.cc                           |   45 +
 src/lib/cc/session.cc                              |   40 +-
 src/lib/cc/session.h                               |   46 +-
 src/lib/cc/tests/data_unittests.cc                 |    4 +
 src/lib/cc/tests/session_unittests.cc              |  145 +-
 src/lib/config/ccsession.cc                        |    4 +-
 src/lib/config/tests/ccsession_unittests.cc        |    2 +
 src/lib/config/tests/fake_session.cc               |    2 +-
 src/lib/config/tests/fake_session.h                |    3 +-
 src/lib/datasrc/Makefile.am                        |   20 +-
 src/lib/datasrc/client.h                           |    3 +-
 src/lib/datasrc/database.cc                        |   21 +-
 src/lib/datasrc/datasrc_messages.mes               |  187 +-
 src/lib/datasrc/factory.cc                         |    1 -
 src/lib/datasrc/memory/Makefile.am                 |    1 +
 src/lib/datasrc/memory/memory_client.h             |    2 +-
 src/lib/datasrc/memory/memory_messages.mes         |   91 +
 src/lib/datasrc/memory/rrset_collection.cc         |   57 +
 src/lib/datasrc/memory/rrset_collection.h          |   85 +
 src/lib/datasrc/memory/treenode_rrset.cc           |    7 +-
 src/lib/datasrc/memory/treenode_rrset.h            |   29 +-
 src/lib/datasrc/memory/zone_data.cc                |   30 +
 src/lib/datasrc/memory/zone_data.h                 |   57 +-
 src/lib/datasrc/memory/zone_data_loader.cc         |   32 +-
 src/lib/datasrc/memory/zone_data_loader.h          |   10 +-
 src/lib/datasrc/memory/zone_data_updater.cc        |   11 +
 src/lib/datasrc/memory/zone_finder.cc              |  124 +-
 src/lib/datasrc/memory/zone_finder.h               |   16 +-
 src/lib/datasrc/memory_datasrc.cc                  | 2043 ------------
 src/lib/datasrc/memory_datasrc.h                   |  366 ---
 src/lib/datasrc/memory_datasrc_link.cc             |  277 --
 src/lib/datasrc/rbnode_rrset.h                     |  230 --
 src/lib/datasrc/rbtree.h                           | 1993 -----------
 src/lib/datasrc/rrset_collection_base.cc           |    1 +
 src/lib/datasrc/rrset_collection_base.h            |   54 +-
 src/lib/datasrc/sqlite3_accessor.cc                |    8 +-
 src/lib/datasrc/sqlite3_accessor_link.cc           |    8 +-
 src/lib/datasrc/static_datasrc.h                   |   50 +
 src/lib/datasrc/static_datasrc_link.cc             |   22 +-
 src/lib/datasrc/tests/Makefile.am                  |    8 +-
 src/lib/datasrc/tests/client_list_unittest.cc      |   72 +-
 src/lib/datasrc/tests/database_sqlite3_unittest.cc |   68 +
 src/lib/datasrc/tests/database_unittest.cc         | 3461 ++++++++++----------
 src/lib/datasrc/tests/database_unittest.h          |  278 ++
 src/lib/datasrc/tests/factory_unittest.cc          |   81 +-
 src/lib/datasrc/tests/faked_nsec3.h                |    2 +-
 .../datasrc/tests/master_loader_callbacks_test.cc  |    2 +-
 src/lib/datasrc/tests/memory/Makefile.am           |    1 +
 .../datasrc/tests/memory/memory_client_unittest.cc |   43 +-
 .../tests/memory/rdata_serialization_unittest.cc   |    8 +-
 .../tests/memory/rrset_collection_unittest.cc      |   88 +
 src/lib/datasrc/tests/memory/testdata/Makefile.am  |    1 +
 .../testdata/example.org-duplicate-type.zone       |    3 +-
 .../tests/memory/testdata/example.org-empty.zone   |    3 +-
 .../memory/testdata/example.org-multiple.zone      |    3 +-
 .../example.org-rrsig-follows-nothing.zone         |    3 +-
 .../tests/memory/testdata/example.org-rrsigs.zone  |    3 +-
 .../tests/memory/testdata/rrset-collection.zone    |    4 +
 .../tests/memory/treenode_rrset_unittest.cc        |   51 +-
 .../tests/memory/zone_data_loader_unittest.cc      |   19 +-
 src/lib/datasrc/tests/memory/zone_data_unittest.cc |   28 +-
 .../tests/memory/zone_data_updater_unittest.cc     |   19 +-
 .../datasrc/tests/memory/zone_finder_unittest.cc   |  357 +-
 src/lib/datasrc/tests/memory_datasrc_unittest.cc   | 2246 -------------
 src/lib/datasrc/tests/rbnode_rrset_unittest.cc     |  276 --
 src/lib/datasrc/tests/rbtree_unittest.cc           | 1074 ------
 src/lib/datasrc/tests/testdata/static-bad.zone     |    3 +
 src/lib/datasrc/tests/testdata/static.zone         |    3 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |    2 +-
 src/lib/datasrc/tests/zone_loader_unittest.cc      |  155 +-
 src/lib/datasrc/tests/zonetable_unittest.cc        |  128 -
 src/lib/datasrc/zone.h                             |  781 +----
 src/lib/datasrc/zone_finder.cc                     |   95 +-
 src/lib/datasrc/{zone.h => zone_finder.h}          |  424 +--
 src/lib/datasrc/zone_finder_context.cc             |    2 +-
 src/lib/datasrc/{iterator.h => zone_iterator.h}    |    0
 src/lib/datasrc/zone_loader.cc                     |    5 +-
 src/lib/datasrc/zonetable.cc                       |  160 -
 src/lib/datasrc/zonetable.h                        |  160 -
 src/lib/dhcp/Makefile.am                           |    1 +
 src/lib/dhcp/libdhcp++.cc                          |   75 +-
 src/lib/dhcp/libdhcp++.dox                         |   16 +-
 src/lib/dhcp/libdhcp++.h                           |   10 -
 src/lib/dhcp/option.cc                             |   62 +-
 src/lib/dhcp/option.h                              |   24 +-
 src/lib/dhcp/option4_addrlst.cc                    |    2 +-
 src/lib/dhcp/option4_addrlst.h                     |   10 +-
 src/lib/dhcp/option_custom.cc                      |   25 +-
 src/lib/dhcp/option_custom.h                       |   22 +-
 src/lib/dhcp/option_definition.cc                  |   53 +-
 src/lib/dhcp/option_definition.h                   |   66 +-
 src/lib/dhcp/option_int_array.h                    |   24 +
 src/lib/{dhcpsrv => dhcp}/option_space.cc          |    2 +-
 src/lib/{dhcpsrv => dhcp}/option_space.h           |    0
 src/lib/dhcp/pkt4.cc                               |   11 +-
 src/lib/dhcp/pkt6.cc                               |    6 +-
 src/lib/dhcp/std_option_defs.h                     |  244 +-
 src/lib/dhcp/tests/Makefile.am                     |    1 +
 src/lib/dhcp/tests/libdhcp++_unittest.cc           |   36 +-
 src/lib/dhcp/tests/option4_addrlst_unittest.cc     |    4 +-
 src/lib/dhcp/tests/option_definition_unittest.cc   |   51 +-
 src/lib/dhcp/tests/option_int_array_unittest.cc    |  169 +-
 .../tests/option_space_unittest.cc                 |    2 +-
 src/lib/dhcp/tests/option_unittest.cc              |   14 +-
 src/lib/dhcpsrv/.gitignore                         |    2 +
 src/lib/dhcpsrv/Makefile.am                        |    4 +-
 src/lib/dhcpsrv/alloc_engine.cc                    |  358 +-
 src/lib/dhcpsrv/alloc_engine.h                     |    4 +-
 src/lib/dhcpsrv/cfgmgr.cc                          |   11 +-
 src/lib/dhcpsrv/cfgmgr.h                           |   12 +-
 src/lib/dhcpsrv/database_backends.dox              |   14 +
 src/lib/dhcpsrv/dbaccess_parser.cc                 |  116 +
 src/lib/dhcpsrv/dbaccess_parser.h                  |  133 +
 src/lib/dhcpsrv/dhcp_config_parser.h               |    3 +
 src/lib/dhcpsrv/dhcpdb_create.mysql                |   14 +-
 src/lib/dhcpsrv/dhcpsrv_messages.mes               |   76 +-
 src/lib/dhcpsrv/lease_mgr.cc                       |   13 +-
 src/lib/dhcpsrv/lease_mgr.h                        |   14 +-
 src/lib/dhcpsrv/lease_mgr_factory.cc               |   14 +-
 src/lib/dhcpsrv/libdhcpsrv.dox                     |   16 +-
 src/lib/dhcpsrv/memfile_lease_mgr.cc               |    5 +-
 src/lib/dhcpsrv/mysql_lease_mgr.cc                 |   25 +-
 src/lib/dhcpsrv/option_space_container.h           |    2 +-
 src/lib/dhcpsrv/pool.cc                            |    5 +-
 src/lib/dhcpsrv/subnet.cc                          |   13 +-
 src/lib/dhcpsrv/subnet.h                           |    4 +-
 src/lib/dhcpsrv/tests/Makefile.am                  |    4 +-
 src/lib/dhcpsrv/tests/alloc_engine_unittest.cc     |   11 +-
 src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc  |  434 +++
 src/lib/dns/Makefile.am                            |    4 +
 src/lib/dns/gen-rdatacode.py.in                    |  124 +-
 src/lib/dns/master_loader.cc                       |    1 +
 src/lib/dns/name.cc                                |    1 -
 src/lib/dns/python/.gitignore                      |    2 +
 src/lib/dns/python/message_python_inc.cc           |   14 +
 src/lib/dns/python/nsec3hash_python_inc.cc         |   14 +
 src/lib/dns/python/opcode_python.cc                |  140 -
 src/lib/dns/python/pydnspp.cc                      |  230 +-
 src/lib/dns/python/rcode_python.cc                 |  146 -
 src/lib/dns/python/rrclass_python.cc               |   43 -
 src/lib/dns/python/rrset_collection_python.cc      |   73 +-
 src/lib/dns/python/rrset_collection_python.h       |   10 +-
 src/lib/dns/python/rrset_collection_python_inc.cc  |   51 +-
 src/lib/dns/python/rrtype_python.cc                |  144 -
 src/lib/dns/python/tests/edns_python_test.py       |    6 +-
 src/lib/dns/python/tests/message_python_test.py    |   34 +-
 .../python/tests/messagerenderer_python_test.py    |    8 +-
 src/lib/dns/python/tests/nsec3hash_python_test.py  |   46 +-
 src/lib/dns/python/tests/opcode_python_test.py     |   82 +-
 src/lib/dns/python/tests/rcode_python_test.py      |   60 +-
 src/lib/dns/python/tests/rrclass_python_test.py    |   20 +-
 .../python/tests/rrset_collection_python_test.py   |   46 +-
 src/lib/dns/python/tests/rrset_python_test.py      |    8 +-
 src/lib/dns/python/tests/rrtype_python_test.py     |   44 +-
 src/lib/dns/python/tests/tsig_python_test.py       |   36 +-
 src/lib/dns/python/tests/tsigerror_python_test.py  |   26 +-
 .../dns/python/tests/zone_checker_python_test.py   |   61 +-
 src/lib/dns/python/tsigerror_python_inc.cc         |   14 +
 src/lib/dns/rdata/generic/cname_5.cc               |   59 +-
 src/lib/dns/rdata/generic/dname_39.cc              |   59 +-
 src/lib/dns/rdata/generic/mx_15.cc                 |   82 +-
 src/lib/dns/rdata/generic/ns_2.cc                  |   59 +-
 src/lib/dns/rdata/generic/ptr_12.cc                |   59 +-
 src/lib/dns/rdata/in_1/srv_33.cc                   |  129 +-
 src/lib/dns/rdata/template.h                       |    4 +
 src/lib/dns/rrclass-placeholder.h                  |   14 -
 src/lib/dns/rrset_collection_base.h                |   40 +-
 src/lib/dns/rrtype-placeholder.h                   |   30 -
 src/lib/dns/tests/rdata_cname_unittest.cc          |   36 +-
 src/lib/dns/tests/rdata_dname_unittest.cc          |   36 +-
 src/lib/dns/tests/rdata_mx_unittest.cc             |   35 +-
 src/lib/dns/tests/rdata_ns_unittest.cc             |   42 +-
 src/lib/dns/tests/rdata_ptr_unittest.cc            |   40 +-
 src/lib/dns/tests/rdata_srv_unittest.cc            |   45 +-
 src/lib/dns/tests/rrclass_unittest.cc              |   25 +
 src/lib/dns/tests/rrset_unittest.cc                |    4 +-
 src/lib/dns/tests/rrtype_unittest.cc               |   53 +
 src/lib/dns/tests/zone_checker_unittest.cc         |   20 +-
 .../tests/nameserver_address_store_unittest.cc     |    2 +-
 src/lib/nsas/tests/nsas_test.h                     |    4 +-
 src/lib/python/bind10_config.py.in                 |    6 +-
 src/lib/python/isc/Makefile.am                     |    2 +-
 src/lib/python/isc/__init__.py                     |   10 +-
 src/lib/python/isc/acl/acl_inc.cc                  |   14 +
 src/lib/python/isc/acl/dns_requestacl_inc.cc       |   14 +
 src/lib/python/isc/acl/dns_requestcontext_inc.cc   |   14 +
 src/lib/python/isc/acl/dns_requestloader_inc.cc    |   14 +
 src/lib/python/isc/acl/dnsacl_inc.cc               |   14 +
 src/lib/python/isc/bind10/Makefile.am              |    5 +
 src/lib/python/isc/bind10/component.py             |   57 +-
 src/lib/python/isc/bind10/sockcreator.py           |    6 +-
 src/lib/python/isc/bind10/socket_cache.py          |   17 +-
 src/lib/python/isc/bind10/special_component.py     |   52 +-
 src/lib/python/isc/bind10/tests/component_test.py  |   39 +-
 src/lib/python/isc/cc/Makefile.am                  |   17 +-
 src/lib/python/isc/cc/cc_generated/.gitignore      |    2 +
 src/lib/python/isc/cc/cc_generated/Makefile.am     |   31 +
 src/lib/python/isc/{server_common => cc}/logger.py |   12 +-
 src/lib/python/isc/cc/proto_defs.py                |    2 +
 .../lib/python/isc/cc/pycc_messages.mes            |   20 +-
 src/lib/python/isc/cc/session.py                   |   46 +-
 src/lib/python/isc/cc/tests/message_test.py        |   15 +-
 src/lib/python/isc/cc/tests/sendcmd.py             |   16 +
 src/lib/python/isc/cc/tests/session_test.py        |  144 +-
 src/lib/python/isc/cc/tests/test_session.py        |   15 +
 src/lib/python/isc/config/ccsession.py             |   69 +-
 src/lib/python/isc/config/cfgmgr.py                |   83 +-
 src/lib/python/isc/config/cfgmgr_messages.mes      |   13 +
 src/lib/python/isc/config/config_data.py           |    2 +-
 src/lib/python/isc/config/tests/ccsession_test.py  |   61 +
 src/lib/python/isc/config/tests/cfgmgr_test.py     |  122 +-
 .../python/isc/config/tests/config_data_test.py    |   27 +-
 .../python/isc/config/tests/module_spec_test.py    |    2 +-
 .../isc/config/tests/unittest_fakesession.py       |   10 +-
 src/lib/python/isc/datasrc/client_inc.cc           |   14 +
 src/lib/python/isc/datasrc/client_python.cc        |    2 +-
 src/lib/python/isc/datasrc/datasrc.cc              |   17 -
 src/lib/python/isc/datasrc/finder_inc.cc           |   14 +
 src/lib/python/isc/datasrc/finder_python.cc        |    2 +-
 src/lib/python/isc/datasrc/iterator_inc.cc         |   14 +
 src/lib/python/isc/datasrc/iterator_python.cc      |    2 +-
 src/lib/python/isc/datasrc/journal_reader_inc.cc   |   14 +
 src/lib/python/isc/datasrc/sqlite3_ds.py           |    4 +-
 src/lib/python/isc/datasrc/tests/Makefile.am       |    1 +
 .../python/isc/datasrc/tests/clientlist_test.py    |   10 +-
 src/lib/python/isc/datasrc/tests/datasrc_test.py   |  185 +-
 .../python/isc/datasrc/tests/testdata/static.zone  |    3 +
 .../python/isc/datasrc/tests/zone_loader_test.py   |   19 +-
 src/lib/python/isc/datasrc/updater_inc.cc          |   85 +
 src/lib/python/isc/datasrc/updater_python.cc       |  154 +
 src/lib/python/isc/datasrc/updater_python.h        |    2 +-
 src/lib/python/isc/datasrc/zone_loader_inc.cc      |   14 +
 src/lib/python/isc/ddns/libddns_messages.mes       |   18 +-
 src/lib/python/isc/ddns/session.py                 |  118 +-
 src/lib/python/isc/ddns/tests/session_tests.py     |  619 ++--
 src/lib/python/isc/ddns/tests/zone_config_tests.py |   14 +-
 src/lib/python/isc/log_messages/Makefile.am        |    6 +-
 src/lib/python/isc/log_messages/bind10_messages.py |    1 -
 src/lib/python/isc/log_messages/gen-forwarder.sh   |   15 +
 src/lib/python/isc/log_messages/init_messages.py   |    1 +
 src/lib/python/isc/log_messages/pycc_messages.py   |    1 +
 src/lib/python/isc/notify/notify_out.py            |   18 +-
 src/lib/python/isc/notify/tests/notify_out_test.py |   18 +-
 src/lib/python/isc/server_common/auth_command.py   |   14 +-
 src/lib/python/isc/server_common/dns_tcp.py        |    2 +-
 .../isc/server_common/server_common_messages.mes   |    2 +-
 src/lib/python/isc/statistics/counters.py          |    4 +-
 .../python/isc/statistics/tests/counters_test.py   |   23 +-
 src/lib/python/isc/sysinfo/sysinfo.py              |   15 +-
 src/lib/python/isc/testutils/rrset_utils.py        |   28 +-
 src/lib/python/isc/util/cio/socketsession_inc.cc   |   14 +
 .../isc/util/cio/socketsessionforwarder_inc.cc     |   14 +
 .../isc/util/cio/socketsessionreceiver_inc.cc      |   14 +
 src/lib/python/isc/xfrin/diff.py                   |   23 +-
 src/lib/python/isc/xfrin/tests/diff_tests.py       |  105 +-
 src/lib/resolve/recursive_query.cc                 |    2 +-
 src/lib/resolve/resolve_messages.mes               |    2 +-
 .../resolve/tests/response_classifier_unittest.cc  |    4 +-
 src/lib/server_common/portconfig.cc                |    2 +-
 src/lib/server_common/portconfig.h                 |    7 +-
 src/lib/server_common/socket_request.cc            |   36 +-
 src/lib/server_common/tests/portconfig_unittest.cc |    4 +-
 .../server_common/tests/socket_requestor_test.cc   |  147 +-
 src/lib/statistics/counter.h                       |   21 +-
 src/lib/statistics/counter_dict.h                  |   87 +-
 src/lib/testutils/mockups.h                        |    2 +-
 src/lib/testutils/testdata/example.com             |    8 +
 src/lib/testutils/testdata/example.sqlite3         |  Bin 15360 -> 15360 bytes
 src/lib/util/Makefile.am                           |    1 -
 src/lib/util/io/socketsession.cc                   |    4 +-
 src/lib/util/python/Makefile.am                    |    4 +-
 src/lib/util/python/const2hdr.py                   |   65 +
 src/lib/util/python/pythonize_constants.py         |   57 +
 src/lib/util/tests/fd_share_tests.cc               |   78 +-
 src/lib/util/tests/fd_tests.cc                     |   34 +-
 .../util/tests/interprocess_sync_file_unittest.cc  |  145 +-
 src/lib/util/threads/tests/condvar_unittest.cc     |   29 +-
 src/lib/util/threads/tests/lock_unittest.cc        |   56 +-
 src/lib/util/threads/tests/thread_unittest.cc      |   49 +-
 src/lib/util/unittests/check_valgrind.h            |    5 +
 src/lib/util/unittests/fork.cc                     |   12 +-
 src/lib/util/unittests/fork.h                      |    4 +-
 .../configurations/auth/auth_badzone.config.orig   |    4 +-
 .../configurations/auth/auth_basic.config.orig     |    4 +-
 .../configurations/bindctl/bindctl.config.orig     |    4 +-
 .../configurations/bindctl_commands.config.orig    |    4 +-
 tests/lettuce/configurations/ddns/ddns.config.orig |    4 +-
 .../lettuce/configurations/ddns/noddns.config.orig |    4 +-
 tests/lettuce/configurations/default.config        |    2 +-
 .../lettuce/configurations/example.org.config.orig |    4 +-
 .../configurations/example.org.inmem.config        |    8 +-
 tests/lettuce/configurations/example2.org.config   |    4 +-
 .../inmemory_over_sqlite3/secondary.conf           |    4 +-
 .../configurations/ixfr-out/testset1-config.db     |    4 +-
 .../multi_instance/multi_auth.config.orig          |    4 +-
 tests/lettuce/configurations/no_db_file.config     |    4 +-
 .../lettuce/configurations/nsec3/nsec3_auth.config |    4 +-
 .../resolver/resolver_basic.config.orig            |   32 +-
 .../lettuce/configurations/xfrin/inmem_slave.conf  |    4 +-
 .../xfrin/retransfer_master.conf.orig              |    4 +-
 ....conf.orig => retransfer_master_nons.conf.orig} |    8 +-
 .../xfrin/retransfer_slave.conf.orig               |    4 +-
 .../xfrin/retransfer_slave_notify.conf             |    4 +-
 tests/lettuce/data/commands/bad_command            |    6 +-
 ...xample.org.sqlite3 => example.org-nons.sqlite3} |  Bin 15360 -> 15360 bytes
 tests/lettuce/features/bindctl_commands.feature    |   24 +-
 tests/lettuce/features/ddns_system.feature         |    4 +-
 tests/lettuce/features/default.feature             |    2 +-
 tests/lettuce/features/multi_instance.feature      |   10 +-
 tests/lettuce/features/queries.feature             |  192 +-
 tests/lettuce/features/stats_httpd.feature         |   16 +
 tests/lettuce/features/terrain/bind10_control.py   |   84 +-
 tests/lettuce/features/terrain/http.py             |   41 +
 tests/lettuce/features/terrain/steps.py            |    2 +-
 tests/lettuce/features/terrain/terrain.py          |    8 +-
 tests/lettuce/features/xfrin_bind10.feature        |   62 +-
 .../lettuce/features/xfrin_notify_handling.feature |    2 +-
 tests/lettuce/setup_intree_bind10.sh.in            |    2 +-
 tests/system/Makefile.am                           |    2 +-
 tests/system/bindctl/tests.sh                      |  125 +-
 tests/system/glue/nsx1/b10-config.db.in            |    2 +-
 tests/system/ifconfig.sh                           |    4 +-
 tests/system/ixfr/b10-config.db.in                 |    2 +-
 tests/tools/Makefile.am                            |    4 -
 tests/tools/perfdhcp/command_options.cc            |   18 +-
 tests/tools/perfdhcp/command_options.h             |    8 +-
 tests/tools/perfdhcp/main.cc                       |    8 +-
 tests/tools/perfdhcp/test_control.cc               |   23 +-
 tools/query_cmp/src/lib/handledns.py               |    2 +-
 tools/system_messages.py                           |    7 +-
 500 files changed, 20086 insertions(+), 20725 deletions(-)
 create mode 100644 doc/differences.txt
 rename src/bin/auth/{b10-auth.xml => b10-auth.xml.pre} (86%)
 create mode 100755 src/bin/auth/gen-statisticsitems.py.pre.in
 delete mode 100644 src/bin/auth/statistics.cc
 create mode 100644 src/bin/auth/statistics.cc.pre
 delete mode 100644 src/bin/auth/statistics_items.h
 create mode 100644 src/bin/auth/statistics_items.h.pre
 create mode 100644 src/bin/auth/statistics_msg_items.def
 create mode 100644 src/bin/auth/tests/gen-statisticsitems_test.py
 delete mode 100644 src/bin/auth/tests/statistics_unittest.cc
 create mode 100644 src/bin/auth/tests/statistics_unittest.cc.pre
 create mode 100644 src/bin/auth/tests/statistics_util.cc
 copy src/{lib/python/isc/datasrc/zone_loader_python.h => bin/auth/tests/statistics_util.h} (65%)
 copy src/bin/bind10/{bind10.xml => b10-init.xml} (86%)
 create mode 100755 src/bin/bind10/bind10.in
 rename src/bin/bind10/{bind10_src.py.in => init.py.in} (95%)
 rename src/bin/bind10/{bob.spec => init.spec} (94%)
 rename src/bin/bind10/{bind10_messages.mes => init_messages.mes} (78%)
 rename src/bin/bind10/tests/{bind10_test.py.in => init_test.py.in} (70%)
 copy src/bin/dbutil/tests/testdata/{v2_1.sqlite3 => v2_2.sqlite3} (91%)
 mode change 100644 => 100755 src/bin/stats/stats_httpd.py.in
 create mode 100644 src/lib/cc/proto_defs.cc
 create mode 100644 src/lib/datasrc/memory/rrset_collection.cc
 create mode 100644 src/lib/datasrc/memory/rrset_collection.h
 delete mode 100644 src/lib/datasrc/memory_datasrc.cc
 delete mode 100644 src/lib/datasrc/memory_datasrc.h
 delete mode 100644 src/lib/datasrc/memory_datasrc_link.cc
 delete mode 100644 src/lib/datasrc/rbnode_rrset.h
 delete mode 100644 src/lib/datasrc/rbtree.h
 create mode 100644 src/lib/datasrc/static_datasrc.h
 create mode 100644 src/lib/datasrc/tests/database_sqlite3_unittest.cc
 create mode 100644 src/lib/datasrc/tests/database_unittest.h
 create mode 100644 src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
 create mode 100644 src/lib/datasrc/tests/memory/testdata/rrset-collection.zone
 delete mode 100644 src/lib/datasrc/tests/memory_datasrc_unittest.cc
 delete mode 100644 src/lib/datasrc/tests/rbnode_rrset_unittest.cc
 delete mode 100644 src/lib/datasrc/tests/rbtree_unittest.cc
 create mode 100644 src/lib/datasrc/tests/testdata/static-bad.zone
 delete mode 100644 src/lib/datasrc/tests/zonetable_unittest.cc
 copy src/lib/datasrc/{zone.h => zone_finder.h} (66%)
 rename src/lib/datasrc/{iterator.h => zone_iterator.h} (100%)
 delete mode 100644 src/lib/datasrc/zonetable.cc
 delete mode 100644 src/lib/datasrc/zonetable.h
 rename src/lib/{dhcpsrv => dhcp}/option_space.cc (98%)
 rename src/lib/{dhcpsrv => dhcp}/option_space.h (100%)
 rename src/lib/{dhcpsrv => dhcp}/tests/option_space_unittest.cc (99%)
 create mode 100644 src/lib/dhcpsrv/.gitignore
 create mode 100644 src/lib/dhcpsrv/dbaccess_parser.cc
 create mode 100644 src/lib/dhcpsrv/dbaccess_parser.h
 create mode 100644 src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc
 create mode 100644 src/lib/dns/python/.gitignore
 create mode 100644 src/lib/python/isc/cc/cc_generated/.gitignore
 create mode 100644 src/lib/python/isc/cc/cc_generated/Makefile.am
 copy src/lib/python/isc/{server_common => cc}/logger.py (69%)
 create mode 100644 src/lib/python/isc/cc/proto_defs.py
 copy tests/system/ixfr/clean_ns.sh => src/lib/python/isc/cc/pycc_messages.mes (66%)
 create mode 100644 src/lib/python/isc/datasrc/tests/testdata/static.zone
 delete mode 100644 src/lib/python/isc/log_messages/bind10_messages.py
 create mode 100644 src/lib/python/isc/log_messages/init_messages.py
 create mode 100644 src/lib/python/isc/log_messages/pycc_messages.py
 create mode 100644 src/lib/util/python/const2hdr.py
 create mode 100644 src/lib/util/python/pythonize_constants.py
 copy tests/lettuce/configurations/xfrin/{retransfer_master.conf.orig => retransfer_master_nons.conf.orig} (87%)
 copy tests/lettuce/data/{example.org.sqlite3 => example.org-nons.sqlite3} (89%)
 create mode 100644 tests/lettuce/features/stats_httpd.feature
 create mode 100644 tests/lettuce/features/terrain/http.py

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index ce45dbc..fa50a5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,232 @@
+581.	[func]*		y-aharen
+	Added statistics items in b10-auth based on
+	http://bind10.isc.org/wiki/StatisticsItems. Qtype counters are
+	dropped as it requires further spec design discussion.
+	(Trac #2154, Trac #2155,
+	             git 61d7c3959eb991b22bc1c0ef8f4ecb96b65d9325)
+	(Trac #2157, git e653adac032f871cbd66cd500c37407a56d14589)
+
+bind10-1.0.0-rc released on February 14, 2013
+
+580.	[func]*		muks
+	There is no longer a default user account. The old default account
+	with username 'root' has been removed. In a fresh installation of
+	BIND 10, the administrator has to configure a user account using
+	the b10-cmdctl-usermgr program.
+	(Trac #2641, git 54e8f4061f92c2f9e5b8564240937515efa6d934)
+
+579.	[bug]		jinmei
+	libdatasrc/b10-auth: corrected some corner cases in query handling
+	of in-memory data source that led to the following invalid/odd
+	responses from b10-auth:
+	- duplicate RRs in answer and additional for type ANY query
+	- incorrect NSEC for no error, no data (NXRRSET) response that
+	  matches a wildcard
+	(Trac #2585, git abe78fae4ba3aca5eb01806dd4e05607b1241745)
+
+578.	[bug]		jinmei
+	b10-auth now returns closest encloser NSEC3 proof to queries for
+	an empty non terminal derived from an Opt-Out NSEC3 RR, as clarified
+	in errata 3441 for RFC5155.  Previously it regarded such case as
+	broken zone and returned SERVFAIL.
+	(Trac #2659, git 24c235cb1b379c6472772d340e21577c3460b742)
+
+577.	[func]		muks
+	Added an SQLite3 index on records(rname, rdtype). This decreases
+	insert performance by ~28% and adds about ~20% to the file size,
+	but increases zone iteration performance. As it introduces a new
+	index, a database upgrade would be required.
+	(Trac #1756, git 9b3c959af13111af1fa248c5010aa33ee7e307ee)
+
+576.	[bug]		tmark, tomek
+	b10-dhcp6: Fixed bug when the server aborts operation when
+	receiving renew and there are no IPv6 subnets configured.
+	(Trac #2719, git 3132b8b19495470bbfd0f2ba0fe7da443926034b)
+
+575.	[bug]		marcin
+	b10-dhcp6: Fixed the bug whereby the subnet for the incoming
+	packet was selected using only its source address. The subnet
+	is now selected using either source address or the name of the
+	server's interface on which the packet has been received.
+	(Trac #2704, git 1cbacf19a28bdae50bb9bd3767bca0147fde37ed)
+
+574.	[func]		tmark
+	b10-dhcp4, b10-dhcp6: Composite key indexes were added to the lease
+	tables to reduce lease search time. The lease4 table now has two
+	additional indexes: a) hwaddr/subnet_id and b) client_id/subnet_id.
+	The lease6 now has the one additional index: iaid/subnet_id/duid.
+	Adding these indexes significantly improves lease acquisition
+	performance.
+	(Trac #2699,#2703, git 54bbed5fcbe237c5a49b515ae4c55148723406ce)
+
+573.	[bug]		stephen
+	Fixed problem whereby the DHCP server crashed if it ran out of
+	addresses.  Such a condition now causes a packet to be returned
+	to the client refusing the allocation of an address.
+	(Trac #2681, git 87ce14cdb121b37afb5b1931af51bed7f6323dd6)
+
+572.	[bug]		marcin
+	perfdhcp: Fixed bug where the command line switches used to
+	run the perfdhcp where printed as ASCII codes.
+	(Trac #2700, git b8d6b949eb7f4705e32fbdfd7694ca2e6a6a5cdc)
+
+571.	[build]		jinmei
+	The ./configure script can now handle output from python-config
+	--ldflags that contains a space after -L switches.  This fixes
+	failure reported on some Solaris environments.
+	(Trac #2661, git e6f86f2f5eec8e6003c13d36804a767a840d96d6)
+
+570.	[bug]		tmark, marcin, tomek
+	b10-dhcp4: Address renewal now works properly for DHCPv4 clients
+	that do not send client ID.
+	(Trac #2702, git daf2abe68ce9c111334a15c14e440730f3a085e2)
+
+569.	[bug]		tomek
+	b10-dhcp4: Fix bug whereby a DHCP packet without a client ID
+	could crash the MySQL lease database backend.
+	(Trac #2697, git b5e2be95d21ed750ad7cf5e15de2058aa8bc45f4)
+
+568.	[func]		muks
+	Various message IDs have been renamed to remove the word 'ERROR'
+	from them when they are not logged at ERROR severity level.
+	(Trac #2672, git 660a0d164feaf055677f375977f7ed327ead893e)
+
+567.	[doc]		marcin, stephen, tomek
+	Update DHCP sections of the BIND 10 guide.
+	(Trac #2657, git 1d0c2004865d1bf322bf78d13630d992e39179fd)
+
+566.	[func]*		jinmei
+	libdns++/Python isc.dns: In Python isc.dns, function style
+	constants for RRType, RRClass, Rcode and Opcode were deprecated
+	and replaced with straightforward object constants, e.g., from
+	RRType.AAAA() to RRType.AAAA.  This is a backward incompatible
+	change (see the Trac ticket for a conversion script if needed).
+	Also, these constants are now more consistent between C++
+	and Python, and RRType constants for all currently standardized
+	types are now supported (even if Rdata for these are not yet
+	available).
+	(Trac #1866 and #2409, git e5005185351cf73d4a611407c2cfcd163f80e428)
+
+565.	[func]*		jelte
+	The main initializer script (formerly known as either 'bind10',
+	'boss', or 'bob'), has been renamed to b10-init (and Init in
+	configuration). Configuring which components are run is henceforth
+	done through '/Init/components', and the sbin/bind10 script is now
+	simply a shellscript that runs b10-init. Existing configuration is
+	automatically updated. NOTE: once configuration with this update
+	has been saved (by committing any new change with bindctl), you
+	cannot run older versions of BIND 10 anymore with this configuration.
+	(Trac #1901, git bae3798603affdb276f370c1ac6b33b011a5ed4f)
+
+564.	[func]		muks
+	libdns++: the CNAME, DNAME, MX, NS, PTR and SRV Rdata classes now
+	use the generic lexer in constructors from text.  This means that
+	the name fields in such RRs in a zone file can now be non-absolute
+	(the origin name in that context will be used), e.g., when loaded
+	by b10-loadzone. One additional change to the libdns++ API is that
+	the existing string constructors for these Rdata classes also use
+	the generic lexer, and they now expect an absolute name (with the
+	trailing '.') in the name fields.
+	(Trac #2390, git a01569277cda3f78b1171bbf79f15ecf502e81e2)
+	(Trac #2656, git 5a0d055137287f81e23fbeedd35236fee274596d)
+
+563.	[build]		jinmei
+	Added --disable-rpath configure option to avoid embedding library
+	paths to binaries.  Patch from Adam Tkac.
+	(Trac #2667, git 1c50c5a6ee7e9675e3ab154f2c7f975ef519fca2)
+
+562.	[func]*		vorner
+	The b10-xfrin now performs basic sanity check on just received
+	zone. It'll reject severely broken zones (such as missing NS
+	records).
+	(Trac #2439, git 44699b4b18162581cd1dd39be5fb76ca536012e6)
+
+561.	[bug]		kambe, jelte
+	b10-stats-httpd no longer dumps request information to the console,
+	but uses the bind10 logging system. Additionally, the logging
+	identifiers have been changed from STATHTTPD_* to STATSHTTPD_*
+	(Trac #1897, git 93716b025a4755a8a2cbf250a9e4187741dbc9bb)
+
+560.	[bug]		jinmei
+	b10-auth now sets the TTL of SOA RR for negative responses to
+	the minimum of the RR TTL and the minimum TTL of the SOA RDATA
+	as specified in RFC2308; previously the RR TTL was always used.
+	The ZoneFinder class was extended partly for implementing this
+	and partly for allowing further optimization.
+	(Trac #2309 and #2635, git ee17e979fcde48b59d91c74ac368244169065f3b)
+
+559.	[bug]		jelte
+	b10-cmdctl no longer aborts on basic file issues with its https
+	certificate or private key file. It performs additional checks, and
+	provides better error logs if these fail. Additionally, bindctl
+	provides a better error report if it is unable to connect over
+	https connection. This issue could occur if BIND 10 was installed
+	with root privileges but then started as a normal user.
+	(Trac #2595, git 09b1a2f927483b407d70e98f5982f424cc872149)
+
+558.	[func]		marcin
+	b10-dhcp4: server now adds configured options to its
+	responses to a client when client requests them.
+	A few basic options: Routers, Domain Name, Domain
+	Name Servers and Subnet Mask are added regardless
+	if client requested them or not.
+	(Trac #2591, git aeec2dc1b9c511d17971ac63138576c37e7c5164)
+
+557.	[doc]		stephen
+	Update DHCP sections of the BIND 10 guide.
+	(Trac #2642, git e5faeb5fa84b7218fde486347359504cf692510e)
+
+556.	[bug]		marcin
+	Fixed DHCP servers configuration whereby the servers did not
+	receive a configuration stored in the database on their startup.
+	Also, the configuration handler function now uses full configuration
+	instead of partial to configure the server. This guarantees that
+	dependencies between various configuration parameters are
+	fulfilled.
+	(Trac #2637, git 91aa998226f1f91a232f2be59a53c9568c4ece77)
+
+555.	[func]		marcin
+	The encapsulated option space name can be specified for
+	a DHCP option. It comprises sub-options being sent within
+	an option that encapsulates this option space.
+	(Trac #2314, git 27e6119093723a1e46a239ec245a8b4b10677635)
+
+554.	[func]		jinmei
+	b10-loadzone: improved completion log message and intermediate
+	reports: It now logs the precise number of loaded RRs on
+	completion, and intermediate reports show additional information
+	such as the estimated progress in percentage and estimated time
+	to complete.
+	(Trac #2574, git 5b8a824054313bdecb8988b46e55cb2e94cb2d6c)
+
+553.	[func]		stephen
+	Values of the parameters to access the DHCP server lease database
+	can now be set through the BIND 10 configuration mechanism.
+	(Trac #2559, git 6c6f405188cc02d2358e114c33daff58edabd52a)
+
+552.	[bug]		shane
+	Build on Raspberry PI.
+	The main issue was use of char for reading from input streams,
+	which is incorrect, as EOF is returned as an int -1, which would
+	then get cast into a char -1.
+	A number of other minor issues were also fixed.
+	(Trac #2571, git 525333e187cc4bbbbde288105c9582c1024caa4a)
+
+551.	[bug]		shane
+	Kill msgq if we cannot connect to it on startup.
+	When the boss process was unable to connect to the msgq, it would
+	exit. However, it would leave the msgq process running. This has
+	been fixed, and the msgq is now stopped in this case.
+	(Trac #2608, git 016925ef2437e0396127e135c937d3a55539d224)
+
+550.	[func]		tomek
+	b10-dhcp4: The DHCPv4 server now generates a server identifier
+	the first time it is run. The identifier is preserved in a file
+	across server restarts.
+	b10-dhcp6: The server identifier is now preserved in a file across
+	server restarts.
+	(Trac #2597, git fa342a994de5dbefe32996be7eebe58f6304cff7)
+
 549.	[func]		tomek
 	b10-dhcp6: It is now possible to specify that a configured subnet
 	is reachable locally over specified interface (see "interface"
@@ -47,8 +276,8 @@
 543.	[func]*		jelte
 	When calling getFullConfig() as a module, , the configuration is now
 	returned as properly-structured JSON.  Previously, the structure had
-	been flattened, with all data being labelled by fully-qualified element
-	names.
+	been flattened, with all data being labelled by fully-qualified
+	element names.
 	(Trac #2619, git bed3c88c25ea8f7e951317775e99ebce3340ca22)
 
 542.	[func]		marcin
@@ -112,7 +341,7 @@
 	compile-time option --enable-debug.
 	(Trac #1081, git db55f102b30e76b72b134cbd77bd183cd01f95c0)
 
-534.	[func]*			vorner
+534.	[func]*		vorner
 	The b10-msgq now uses the same logging format as the rest
 	of the system. However, it still doesn't obey the common
 	configuration, as due to technical issues it is not able
@@ -689,7 +918,7 @@ bind10-devel-20120816 released on August 16, 2012
 460.	[bug]		muks
 	SSHFP's algorithm and fingerprint type checks have been relaxed
 	such that they will accept any values in [0,255]. This is so that
-	future algorithm and fingerprint types are accomodated.
+	future algorithm and fingerprint types are accommodated.
 	(Trac #2124, git 49e6644811a7ad09e1326f20dd73ab43116dfd21)
 
 459.	[func]		tomek
@@ -2709,7 +2938,7 @@ bind10-devel-20110224 released on February 24, 2011
 	(Trac #496, git b9296ca023cc9e76cda48a7eeebb0119166592c5)
 
 160.	[func]		jelte
-  	Updated the resolver to take 3 different timeout values;
+	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
 	timeout_lookup for stopping the resolving
@@ -2888,7 +3117,7 @@ bind10-devel-20110120 released on January 20, 2011
 	(Trac #226, svn r3989)
 
 136.	[bug]		jelte
-  	bindctl (and the configuration manager in general) now no longer
+	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.
@@ -3130,7 +3359,7 @@ bind10-devel-20100917 released on September 17, 2010
 	(Trac #342, svn r2949)
 
 94.	[bug]		jelte
-  	bin/xfrout:  Fixed a problem in xfrout where only 2 or 3 RRs
+	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)
 
@@ -3264,7 +3493,7 @@ bind10-devel-20100812 released on August 12, 2010
 	module. (Trac #275, r2459)
 
 73.	[bug]		jelte
-  	Fixed a bug where in bindctl, locally changed settings were
+	Fixed a bug where in bindctl, locally changed settings were
 	reset when the list of running modules is updated. (Trac #285,
 	r2452)
 
@@ -3275,11 +3504,11 @@ bind10-devel-20100812 released on August 12, 2010
 	known such platform. (Trac #148, r2427)
 
 71.	[func]		each
-  	Add "-a" (address) option to bind10 to specify an address for
+	Add "-a" (address) option to bind10 to specify an address for
 	the auth server to listen on.
 
 70.	[func]		each
-  	Added a hot-spot cache to libdatasrc to speed up access to
+	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
 	performance.  Also added a "-n" ("no cache") option to
diff --git a/README b/README
index 306b7d8..70c6bee 100644
--- a/README
+++ b/README
@@ -12,15 +12,18 @@ manager, b10-stats statistics collection and reporting daemon, and
 b10-stats-httpd for HTTP access to XML-formatted stats.
 
 For DNS services, it provides the b10-auth authoritative DNS server
-(with SQLite3 and in-memory backends), b10-resolver recursive or
-forwarding DNS server, b10-xfrin IXFR/AXFR inbound service, b10-xfrout
-outgoing IXFR/AXFR service, b10-zonemgr secondary manager, libdns++
-library for C++ with a python wrapper, and many tests and example
-programs.
+(with SQLite3 and in-memory backends), b10-xfrin IXFR/AXFR inbound
+service, b10-xfrout outgoing IXFR/AXFR service, b10-zonemgr secondary
+manager, libdns++ library for C++ with a python wrapper, and many
+tests and example programs. (It also includes an experimental proof
+of concept recursive or forwarding DNS server, b10-resolver.)
 
 BIND 10 also provides experimental DHCPv4 and DHCPv6 servers,
 b10-dhcp4 and b10-dhcp6, a portable DHCP library, libdhcp++, and
-a DHCP benchmarking tool, perfdhcp.
+a DHCP benchmarking tool, perfdhcp.  In this release of BIND 10,
+the DHCPv4 and DHCPv6 servers must be considered experimental.
+Limitations and known issues with this DHCP release can be found
+at http://bind10.isc.org/wiki/KeaKnownIssues
 
 Documentation is included with the source. See doc/guide/bind10-guide.txt
 (or bind10-guide.html) for installation instructions.  The
diff --git a/configure.ac b/configure.ac
index 9ae7a30..f2bdf0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,9 +2,15 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT(bind10, 20121219, bind10-dev at isc.org)
+AC_INIT(bind10, 20130221, bind10-dev at isc.org)
 AC_CONFIG_SRCDIR(README)
-AM_INIT_AUTOMAKE([foreign])
+# serial-tests is not available in automake version before 1.13. In
+# automake 1.13 and higher, AM_PROG_INSTALL is undefined, so we'll check
+# that and conditionally use serial-tests.
+AM_INIT_AUTOMAKE(
+	[foreign]
+	m4_ifndef([AM_PROG_INSTALL], [serial-tests])
+)
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])dnl be backward compatible
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4macros])
@@ -155,8 +161,10 @@ if test $with_werror = 1; then
    CXXFLAGS_SAVED="$CXXFLAGS"
    CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
    AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
-   AC_TRY_COMPILE([namespace { class Foo {}; }
-   namespace isc {class Bar {Foo foo_;};} ],,
+   # We use struct, not class, here, because some compilers complain about
+   # "unused private members", causing a false positive.
+   AC_TRY_COMPILE([namespace { struct Foo {}; }
+   namespace isc {struct Bar {Foo foo_;};} ],,
 	[AC_MSG_RESULT(no)
 	 werror_ok=1
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
@@ -232,7 +240,22 @@ AM_CONDITIONAL(SET_ENV_LIBRARY_PATH, test $SET_ENV_LIBRARY_PATH = yes)
 AC_SUBST(SET_ENV_LIBRARY_PATH)
 AC_SUBST(ENV_LIBRARY_PATH)
 
-m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3.2 python3.1 python3])
+# Our experiments have shown Solaris 10 has broken support for the
+# IPV6_USE_MIN_MTU socket option for getsockopt(); it doesn't return the value
+# previously set via setsockopt().  We know it doesn't happen on one instance
+# on Solaris 11, but we don't know whether it happens for any Solaris 10
+# implementations or for earlier versions of Solaris.  In any case, at the
+# moment this matters for only one unittest case, so we'll simply disable
+# the affected test using the following definition with the specific hardcoding
+# of that version of Solaris.
+case "$host" in
+*-solaris2.10)
+	AC_DEFINE([HAVE_BROKEN_GET_IPV6_USE_MIN_MTU], [1],
+	[Define to 1 if getsockopt(IPV6_USE_MIN_MTU) does not work])
+	;;
+esac
+
+m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3.3 python3.2 python3.1 python3])
 AC_ARG_WITH([pythonpath],
 AC_HELP_STRING([--with-pythonpath=PATH],
   [specify an absolute path to python executable when automatic version check (incorrectly) fails]),
@@ -282,15 +305,26 @@ AC_SUBST(PYTHON_LOGMSGPKG_DIR)
 
 # This is python package paths commonly used in python tests.  See
 # README of log_messages for why it's included.
-COMMON_PYTHON_PATH="\$(abs_top_builddir)/src/lib/python/isc/log_messages:\$(abs_top_srcdir)/src/lib/python:\$(abs_top_builddir)/src/lib/python"
+# lib/dns/python/.libs is necessary because __init__.py of isc package
+# automatically imports isc.datasrc, which then requires the DNS loadable
+# module.  #2145 should eliminate the need for it.
+COMMON_PYTHON_PATH="\$(abs_top_builddir)/src/lib/python/isc/log_messages:\$(abs_top_builddir)/src/lib/python/isc/cc:\$(abs_top_srcdir)/src/lib/python:\$(abs_top_builddir)/src/lib/python:\$(abs_top_builddir)/src/lib/dns/python/.libs"
 AC_SUBST(COMMON_PYTHON_PATH)
 
 # Check for python development environments
 if test -x ${PYTHON}-config; then
 	PYTHON_INCLUDES=`${PYTHON}-config --includes`
 
-	for flag in `${PYTHON}-config --ldflags`; do
-		# add any '-L..." flags to PYTHON_LDFLAGS
+	# Add any '-L..." flags to PYTHON_LDFLAGS.  We first make a copy of
+	# python-config --ldflags, removing any spaces and tabs
+	# between "-L" and its argument (some instances of python-config
+	# insert a space, which would confuse the code below).
+	# Notes: if -L isn't contained at all we can simply skip this process,
+	# so we only go through the flag if it's contained; also, protecting
+	# the output with [] seems necessary for environment to avoid getting
+	# an empty output accidentally.
+	python_config_ldflags=[`${PYTHON}-config --ldflags | sed -ne 's/\([ \t]*-L\)[ ]*\([^ \t]*[ \t]*\)/\1\2/pg'`]
+	for flag in $python_config_ldflags; do
 		flag=`echo $flag | sed -ne 's/^\(\-L.*\)$/\1/p'`
 		if test "X${flag}" != X; then
 			PYTHON_LDFLAGS="$PYTHON_LDFLAGS ${flag}"
@@ -1124,6 +1158,7 @@ AC_CONFIG_FILES([Makefile
                  compatcheck/Makefile
                  src/Makefile
                  src/bin/Makefile
+                 src/bin/bind10/bind10
                  src/bin/bind10/Makefile
                  src/bin/bind10/tests/Makefile
                  src/bin/cmdctl/Makefile
@@ -1192,6 +1227,7 @@ AC_CONFIG_FILES([Makefile
                  src/lib/python/isc/datasrc/tests/Makefile
                  src/lib/python/isc/dns/Makefile
                  src/lib/python/isc/cc/Makefile
+                 src/lib/python/isc/cc/cc_generated/Makefile
                  src/lib/python/isc/cc/tests/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/tests/Makefile
@@ -1307,9 +1343,9 @@ AC_OUTPUT([doc/version.ent
            src/bin/sysinfo/run_sysinfo.sh
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
-           src/bin/bind10/bind10_src.py
+           src/bin/bind10/init.py
            src/bin/bind10/run_bind10.sh
-           src/bin/bind10/tests/bind10_test.py
+           src/bin/bind10/tests/init_test.py
            src/bin/bindctl/run_bindctl.sh
            src/bin/bindctl/bindctl_main.py
            src/bin/bindctl/tests/bindctl_test
@@ -1325,6 +1361,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/auth/tests/testdata/example.zone
            src/bin/auth/tests/testdata/example-base.zone
            src/bin/auth/tests/testdata/example-nsec3.zone
+           src/bin/auth/gen-statisticsitems.py.pre
            src/bin/dhcp4/spec_config.h.pre
            src/bin/dhcp6/spec_config.h.pre
            src/bin/tests/process_rename_test.py
@@ -1373,6 +1410,7 @@ 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/bind10/bind10
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/dbutil/run_dbutil.sh
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 7642220..3120280 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,6 +1,6 @@
 SUBDIRS = guide
 
-EXTRA_DIST = version.ent.in
+EXTRA_DIST = version.ent.in differences.txt
 
 devel:
 	mkdir -p html
diff --git a/doc/differences.txt b/doc/differences.txt
new file mode 100644
index 0000000..2bc77c6
--- /dev/null
+++ b/doc/differences.txt
@@ -0,0 +1,12 @@
+Differences of Bind 10 to other software
+========================================
+
+Bind 9
+------
+
+TODO: There are definitely more differences than just this.
+
+* When an incoming zone transfer fails, for example because the
+  received zone doesn't contain a NS record, bind 9 stops serving the
+  zone and returns SERVFAIL to queries for that zone. Bind 10 still
+  uses the previous version of zone.
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index f1f5859..583ee60 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -7,7 +7,7 @@
 ]>
 
 <!--
- - Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2013  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
@@ -30,7 +30,7 @@
     <subtitle>Administrator Reference for BIND 10</subtitle>
 
     <copyright>
-      <year>2010-2012</year><holder>Internet Systems Consortium, Inc.</holder>
+      <year>2010-2013</year><holder>Internet Systems Consortium, Inc.</holder>
     </copyright>
 
     <abstract>
@@ -59,11 +59,35 @@
     <section id="acknowledgements">
       <title>Acknowledgements</title>
 
-<!-- TODO: acknowledge all sponsors and CNNIC and CZNIC too -->
+      <para>BIND 10 is a sponsored development project, and would not
+      be possible without the generous support of the sponsors.</para>
 
-      <para>ISC would like to acknowledge generous support for
-      BIND 10 development of DHCPv4 and DHCPv6 components provided
-      by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
+      <para><ulink url="http://jprs.co.jp/">JPRS</ulink> and
+      <ulink url="http://cira.ca/">CIRA</ulink> are Patron Level
+      sponsors.</para>
+
+      <para><ulink url="https://www.afnic.fr/">AFNIC</ulink>,
+      <ulink url="https://www.cnnic.net.cn/">CNNIC</ulink>,
+      <ulink url="https://www.nic.cz/">CZ.NIC</ulink>,
+      <ulink url="http://www.denic.de/">DENIC eG</ulink>,
+      <ulink url="https://www.google.com/">Google</ulink>,
+      <ulink url="https://www.ripe.net/">RIPE NCC</ulink>,
+      <ulink url="https://registro.br/">Registro.br</ulink>,
+      <ulink url="https://nzrs.net.nz/">.nz Registry Services</ulink>, and
+      <ulink url="https://www.tcinet.ru/">Technical Center of Internet</ulink>
+      are current sponsors.</para>
+
+      <para><ulink url="https://www.afilias.info/">Afilias</ulink>,
+      <ulink url="https://www.iis.se/">IIS.SE</ulink>,
+      <ulink url="http://www.nominet.org.uk/">Nominet</ulink>, and
+      <ulink url="https://www.sidn.nl/">SIDN</ulink> were founding
+      sponsors of the project.</para>
+
+<!-- DHCP sponsorship by Comcast -->
+
+      <para>Support for BIND 10 development of the DHCPv4 and DHCPv6
+      components is provided by
+      <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
 
     </section>
 
@@ -164,12 +188,12 @@
 
       <para>
         At first, running many different processes may seem confusing.
-        However, these processes are started, stopped, and maintained
-        by a single command, <command>bind10</command>.
-        This command starts a master process which will start other
-        required processes and other processes when configured.
-        The processes that may be started by the <command>bind10</command>
-        command have names starting with "b10-", including:
+        However, these processes are started by running a single
+	command, <command>bind10</command>.  This command starts
+	a master process, <command>b10-init</command>, which will
+	start other required processes and other processes when
+	configured.  The processes that may be started have names
+	starting with "b10-", including:
       </para>
 
       <para>
@@ -225,6 +249,7 @@
               Recursive name server.
               This process handles incoming DNS queries and provides
               answers from its cache or by recursively doing remote lookups.
+              (This is an experimental proof of concept.)
             </simpara>
           </listitem>
 
@@ -347,7 +372,7 @@ share/
   share/bind10/
     auth.spec
     b10-cmdctl.pem
-    bob.spec
+    init.spec
     passwd.csv
   man/
 var/
@@ -419,6 +444,13 @@ var/
         </listitem>
 
         <listitem>
+          <para>Create a user for yourself:
+            <screen>$ <userinput>cd /usr/local/etc/bind10/</userinput></screen>
+            <screen>$ <userinput>/usr/local/sbin/b10-cmdctl-usermgr</userinput></screen>
+          </para>
+        </listitem>
+
+        <listitem>
           <para>Start the server (as root):
             <screen>$ <userinput>/usr/local/sbin/bind10</userinput></screen>
           </para>
@@ -430,11 +462,11 @@ var/
 	    DNS service (by using the <command>bindctl</command> utility
 	    to configure the <command>b10-auth</command> component to
 	    run): <screen>$ <userinput>bindctl</userinput></screen>
-	    (Login with the provided default username and password.)
+	    (Login with the username and password you used above to create a user.)
             <screen>
-> <userinput>config add Boss/components b10-auth</userinput>
-> <userinput>config set Boss/components/b10-auth/special auth</userinput>
-> <userinput>config set Boss/components/b10-auth/kind needed</userinput>
+> <userinput>config add Init/components b10-auth</userinput>
+> <userinput>config set Init/components/b10-auth/special auth</userinput>
+> <userinput>config set Init/components/b10-auth/kind needed</userinput>
 > <userinput>config commit</userinput>
 > <userinput>quit</userinput>
             </screen>
@@ -519,7 +551,7 @@ var/
               executables that a user wouldn't normally run directly and
               are not run independently.
               These are the BIND 10 modules which are daemons started by
-              the <command>bind10</command> tool.
+              the <command>b10-init</command> master process.
             </simpara>
           </listitem>
           <listitem>
@@ -741,7 +773,12 @@ as a dependency earlier -->
           </varlistentry>
 
           </variablelist>
-
+          <note>
+            <para>
+              For additional instructions concerning the building and installation of
+              BIND 10 DHCP, see <xref linkend="dhcp-install-configure"/>.
+            </para>
+          </note>
         </para>
   <!-- TODO: lcov -->
 
@@ -761,9 +798,7 @@ as a dependency earlier -->
           dependencies.
         </para>
 
-        <note>
-          <para>For notes on configuring and building DHCPv6 with MySQL see <xref linkend="dhcp6-install">.</xref></para>
-        </note>
+
       </section>
 
       <section>
@@ -823,16 +858,17 @@ as a dependency earlier -->
   <chapter id="bind10">
     <title>Starting BIND 10 with <command>bind10</command></title>
     <para>
-      BIND 10 provides the <command>bind10</command> command which
-      starts up the required processes.
-      <command>bind10</command>
+      BIND 10 is started with the <command>bind10</command> command.
+      It runs the <command>b10-init</command> daemon which
+      starts up the required processes, and
       will also restart some processes that exit unexpectedly.
-      This is the only command needed to start the BIND 10 system.
+      <command>bind10</command> is the only command needed to start
+      the BIND 10 system.
     </para>
 
     <para>
       After starting the <command>b10-msgq</command> communications channel,
-      <command>bind10</command> connects to it,
+      <command>b10-init</command> connects to it,
       runs the configuration manager, and reads its own configuration.
       Then it starts the other modules.
     </para>
@@ -851,7 +887,7 @@ as a dependency earlier -->
     </para>
 
     <para>
-      In its default configuration, the <command>bind10</command>
+      In its default configuration, the <command>b10-init</command>
       master process will also start up
       <command>b10-cmdctl</command> for administration tools to
       communicate with the system, and
@@ -1000,7 +1036,7 @@ through bindctl and friends
     <para>
       The configuration manager does not have any command line arguments.
       Normally it is not started manually, but is automatically
-      started using the <command>bind10</command> master process
+      started using the <command>b10-init</command> master process
       (as covered in <xref linkend="bind10"/>).
     </para>
 
@@ -1110,10 +1146,6 @@ but that is a single file, maybe this should go back to that format?
       <filename>/usr/local/etc/bind10/cmdctl-accounts.csv</filename>.
       This comma-delimited file lists the accounts with a user name,
       hashed password, and salt.
-      (A sample file is at
-      <filename>/usr/local/share/bind10/cmdctl-accounts.csv</filename>.
-      It contains the user named <quote>root</quote> with the password
-      <quote>bind10</quote>.)
     </para>
 
     <para>
@@ -1267,10 +1299,10 @@ TODO
 
         <screen><userinput><module> <command> <replaceable>[argument(s)]</replaceable></userinput></screen>
 
-        For example, the Boss module has a 'shutdown' command to shut down
+        For example, the Init module has a 'shutdown' command to shut down
         BIND 10, with an optional argument 'help':
 
-        <screen>> <userinput>Boss shutdown help</userinput>
+        <screen>> <userinput>Init shutdown help</userinput>
 Command  shutdown 	(Shut down BIND 10)
 		help (Get help for command)
 This command has no parameters
@@ -1293,12 +1325,12 @@ Available module names:
         </screen>
 
         When 'help' is used as a command to a module, it shows the supported commands for the module; for example:
-        <screen>> <userinput>Boss help</userinput>
-Module  Boss 	Master process
+        <screen>> <userinput>Init help</userinput>
+Module  Init 	Master process
 Available commands:
     help        Get help for module.
     shutdown    Shut down BIND 10
-    ping        Ping the boss process
+    ping        Ping the Init process
     show_processes
             List the running BIND 10 processes
         </screen>
@@ -1639,7 +1671,7 @@ Parameters:
                         to maps.
                     </simpara>
                     <simpara>
-                        For example, the <command>Boss/components</command>
+                        For example, the <command>Init/components</command>
                         elements is a named set;
                         adding, showing, and then removing an element
                         can be done with the following three commands (note
@@ -1647,13 +1679,13 @@ Parameters:
                         'example_module'):
                     </simpara>
                     <simpara>
-                        <command>config add Boss/components example_module</command>
+                        <command>config add Init/components example_module</command>
                     </simpara>
                     <simpara>
-                        <command>config show Boss/components/example_module</command>
+                        <command>config show Init/components/example_module</command>
                     </simpara>
                     <simpara>
-                        <command>config remove Boss/components example_module</command>
+                        <command>config remove Init/components example_module</command>
                     </simpara>
                 </listitem>
             </varlistentry>
@@ -1701,21 +1733,21 @@ Parameters:
 
         <screen>> <userinput>execute init_authoritative_server show</userinput>
 !echo adding Authoritative server component
-config add /Boss/components b10-auth
-config set /Boss/components/b10-auth/kind needed
-config set /Boss/components/b10-auth/special auth
+config add /Init/components b10-auth
+config set /Init/components/b10-auth/kind needed
+config set /Init/components/b10-auth/special auth
 !echo adding Xfrin component
-config add /Boss/components b10-xfrin
-config set /Boss/components/b10-xfrin/address Xfrin
-config set /Boss/components/b10-xfrin/kind dispensable
+config add /Init/components b10-xfrin
+config set /Init/components/b10-xfrin/address Xfrin
+config set /Init/components/b10-xfrin/kind dispensable
 !echo adding Xfrout component
-config add /Boss/components b10-xfrout
-config set /Boss/components/b10-xfrout/address Xfrout
-config set /Boss/components/b10-xfrout/kind dispensable
+config add /Init/components b10-xfrout
+config set /Init/components/b10-xfrout/address Xfrout
+config set /Init/components/b10-xfrout/kind dispensable
 !echo adding Zone Manager component
-config add /Boss/components b10-zonemgr
-config set /Boss/components/b10-zonemgr/address Zonemgr
-config set /Boss/components/b10-zonemgr/kind dispensable
+config add /Init/components b10-zonemgr
+config set /Init/components/b10-zonemgr/address Zonemgr
+config set /Init/components/b10-zonemgr/kind dispensable
 !echo Components added. Please enter "config commit" to
 !echo finalize initial setup and run the components.
         </screen>
@@ -1763,7 +1795,7 @@ config set /Boss/components/b10-zonemgr/kind dispensable
         <section id="bindctl_execute_notes">
             <title>Notes on execute scripts</title>
             Within scripts, you can add or remove modules with the normal
-            configuration commands for <command>Boss/components</command>.
+            configuration commands for <command>Init/components</command>.
             However, as module
             configuration and commands do not show up until the module is
             running, it is currently not possible to add a module and set
@@ -2074,7 +2106,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
 
     <para>
       This chapter explains how to control and configure the
-      <command>bind10</command> parent.
+      <command>b10-init</command> parent.
       The startup of this resident process that runs the BIND 10
       daemons is covered in <xref linkend="bind10"/>.
     </para>
@@ -2083,8 +2115,8 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
       <title>Stopping bind10</title>
       <para>
         The BIND 10 suite may be shut down by stopping the
-        parent <command>bind10</command> process. This may be done
-        by running the <userinput>Boss shutdown</userinput> command
+        parent <command>b10-init</command> process. This may be done
+        by running the <userinput>Init shutdown</userinput> command
         at the <command>bindctl</command> prompt.
       </para>
     </section>
@@ -2094,11 +2126,11 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
 
       <para>
 	The processes to be used can be configured for
-	<command>bind10</command> to start, with the exception
+	<command>b10-init</command> to start, with the exception
 	of the required <command>b10-sockcreator</command>,
 	<command>b10-msgq</command> and <command>b10-cfgmgr</command>
 	components.
-	The configuration is in the <varname>Boss/components</varname>
+	The configuration is in the <varname>Init/components</varname>
 	section. Each element represents one component, which is
 	an abstraction of a process.
       </para>
@@ -2106,10 +2138,10 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
       <para>
 	To add a process to the set, let's say the resolver (which
 	is not started by default), you would do this:
-        <screen>> <userinput>config add Boss/components b10-resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
-> <userinput>config set Boss/components/b10-resolver/priority 10</userinput>
+        <screen>> <userinput>config add Init/components b10-resolver</userinput>
+> <userinput>config set Init/components/b10-resolver/special resolver</userinput>
+> <userinput>config set Init/components/b10-resolver/kind needed</userinput>
+> <userinput>config set Init/components/b10-resolver/priority 10</userinput>
 > <userinput>config commit</userinput></screen></para>
 
       <para>
@@ -2139,7 +2171,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
             <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative DNS server</entry></row>
             <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
             <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>Command control (remote control interface)</entry></row>
-            <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
+            <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in b10-init before the release -->
           </tbody>
           </tgroup>
         </table>
@@ -2151,7 +2183,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
 	<quote>dispensable</quote> (the default unless you set
 	something else), it will get started again if it fails. If
 	it is set to <quote>needed</quote> and it fails at startup,
-	the whole <command>bind10</command> shuts down and exits
+	the whole <command>b10-init</command> shuts down and exits
 	with an error exit code. But if it fails some time later, it
 	is just started again. If you set it to <quote>core</quote>,
 	you indicate that the system is not usable without the
@@ -2223,9 +2255,9 @@ address, but the usual ones don't." mean? -->
         You might want to do that to gain more performance (each one uses only
         single core). Just put multiple entries under different names, like
         this, with the same config:
-        <screen>> <userinput>config add Boss/components b10-resolver-2</userinput>
-> <userinput>config set Boss/components/b10-resolver-2/special resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver-2/kind needed</userinput>
+        <screen>> <userinput>config add Init/components b10-resolver-2</userinput>
+> <userinput>config set Init/components/b10-resolver-2/special resolver</userinput>
+> <userinput>config set Init/components/b10-resolver-2/kind needed</userinput>
 > <userinput>config commit</userinput></screen>
       </para>
       <para>
@@ -2240,8 +2272,8 @@ address, but the usual ones don't." mean? -->
       </para>
 
       <para>
-        The running processes started by <command>bind10</command>
-        may be listed by running <userinput>Boss show_processes</userinput>
+        The running processes started by <command>b10-init</command>
+        may be listed by running <userinput>Init show_processes</userinput>
         using <command>bindctl</command>.
       </para>
 
@@ -2255,7 +2287,7 @@ address, but the usual ones don't." mean? -->
       The <command>b10-auth</command> is the authoritative DNS server.
       It supports EDNS0, DNSSEC, IPv6, and SQLite3 and in-memory zone
       data backends.
-      Normally it is started by the <command>bind10</command> master
+      Normally it is started by the <command>b10-init</command> master
       process.
     </para>
 
@@ -2413,7 +2445,7 @@ can use various data source backends.
               <simpara>Stop the authoritative DNS server.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the BIND 10 init process may restart this service
       if configured.)
               </simpara>
             </listitem>
@@ -2672,7 +2704,7 @@ TODO
 
     <para>
       Incoming zones are transferred using the <command>b10-xfrin</command>
-      process which is started by <command>bind10</command>.
+      process which is started by <command>b10-init</command>.
       When received, the zone is stored in the corresponding BIND 10
       data source, and its records can be served by
       <command>b10-auth</command>.
@@ -2767,7 +2799,7 @@ what if a NOTIFY is sent?
 
       <para>
         The <command>b10-zonemgr</command> process is started by
-        <command>bind10</command>.
+        <command>b10-init</command>.
         It keeps track of SOA refresh, retry, and expire timers
         and other details for BIND 10 to perform as a slave.
         When the <command>b10-auth</command> authoritative DNS server
@@ -2846,7 +2878,7 @@ http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
     <title>Outbound Zone Transfers</title>
     <para>
       The <command>b10-xfrout</command> process is started by
-      <command>bind10</command>.
+      <command>b10-init</command>.
       When the <command>b10-auth</command> authoritative DNS server
       receives an AXFR or IXFR request, <command>b10-auth</command>
       internally forwards the request to <command>b10-xfrout</command>,
@@ -2912,7 +2944,7 @@ what is XfroutClient xfr_client??
       BIND 10 supports the server side of the Dynamic DNS Update
       (DDNS) protocol as defined in RFC 2136.
       This service is provided by the <command>b10-ddns</command>
-      component, which is started by the <command>bind10</command>
+      component, which is started by the <command>b10-init</command>
       process if configured so.
     </para>
 
@@ -3017,9 +3049,9 @@ what is XfroutClient xfr_client??
         It can be done by using the <command>bindctl</command>
         utility.  For example:
       <screen>
-> <userinput>config add Boss/components b10-ddns</userinput>
-> <userinput>config set Boss/components/b10-ddns/address DDNS</userinput>
-> <userinput>config set Boss/components/b10-ddns/kind dispensable</userinput>
+> <userinput>config add Init/components b10-ddns</userinput>
+> <userinput>config set Init/components/b10-ddns/address DDNS</userinput>
+> <userinput>config set Init/components/b10-ddns/kind dispensable</userinput>
 > <userinput>config commit</userinput>
 </screen>
       <note><simpara>
@@ -3194,9 +3226,15 @@ what is XfroutClient xfr_client??
   <chapter id="resolverserver">
     <title>Recursive Name Server</title>
 
+    <note><simpara>
+      The <command>b10-resolver</command> is an experimental proof
+      of concept.
+    </simpara></note>
+
     <para>
-      The <command>b10-resolver</command> process is started by
-      <command>bind10</command>.
+      The <command>b10-resolver</command> daemon provides an
+      iterative caching and forwarding DNS server.
+      The process is started by <command>b10-init</command>.
 <!-- TODO
       It provides a resolver so DNS clients can ask it to do recursion
       and it will return answers.
@@ -3204,23 +3242,23 @@ what is XfroutClient xfr_client??
     </para>
 
     <para>
-      The main <command>bind10</command> process can be configured
+      The main <command>b10-init</command> process can be configured
       to select to run either the authoritative or resolver or both.
       By default, it doesn't start either one. You may change this using
       <command>bindctl</command>, for example:
 
       <screen>
-> <userinput>config add Boss/components b10-resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
-> <userinput>config set Boss/components/b10-resolver/priority 10</userinput>
+> <userinput>config add Init/components b10-resolver</userinput>
+> <userinput>config set Init/components/b10-resolver/special resolver</userinput>
+> <userinput>config set Init/components/b10-resolver/kind needed</userinput>
+> <userinput>config set Init/components/b10-resolver/priority 10</userinput>
 > <userinput>config commit</userinput>
 </screen>
 
     </para>
 
     <para>
-       The master <command>bind10</command> will stop and start
+       The master <command>b10-init</command> process will stop and start
        the desired services.
     </para>
 
@@ -3317,9 +3355,9 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
 
   </chapter>
 
-  <chapter id="dhcp4">
-    <title>DHCPv4 Server</title>
-    <para>Dynamic Host Configuration Protocol for IPv4 (DHCP or
+  <chapter id="dhcp">
+  <title>DHCP</title>
+     <para>The Dynamic Host Configuration Protocol for IPv4 (DHCP or
     DHCPv4) and Dynamic Host Configuration Protocol for IPv6 (DHCPv6)
     are protocols that allow one node (server) to provision
     configuration parameters to many hosts and devices (clients). To
@@ -3327,57 +3365,120 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
     be deployed that facilitate communication between servers and
     clients. Even though principles of both DHCPv4 and DHCPv6 are
     somewhat similar, these are two radically different
-    protocols. BIND 10 offers server implementations for both DHCPv4
-    and DHCPv6. This chapter is about DHCP for IPv4. For a description
-    of the DHCPv6 server, see <xref linkend="dhcp6"/>.</para>
-
-    <para>The DHCPv4 server component is currently under intense
-    development. You may want to check out <ulink
-    url="http://bind10.isc.org/wiki/Kea">BIND 10 DHCP (Kea) wiki</ulink>
-    and recent posts on <ulink
-    url="https://lists.isc.org/mailman/listinfo/bind10-dev">BIND 10
-    developers mailing list</ulink>.</para>
-
-    <para>The DHCPv4 and DHCPv6 components in BIND 10 architecture are
-    internally code named <quote>Kea</quote>.</para>
+    protocols. BIND 10 offers two server implementations, one for DHCPv4
+    and one for DHCPv6.</para>
+    <para>This chapter covers those parts of BIND 10 that are common to
+    both servers.  DHCPv4-specific details are covered in <xref linkend="dhcp4"/>,
+    while those details specific to DHCPv6 are described in <xref linkend="dhcp6"/>
+    </para>
 
     <note>
-      <para>
-        As of January 2013, the DHCPv4 component is a work in progress.
-        That means that while it is capable of performing DHCP configuration,
-        it is not fully functional.  The server is able to offer,
-        assign, renew, release and reuse expired leases, but some of the
-        options are not configurable yet. In particular Router option is hardcoded.
-        This means that the server is not really usable in actual deployments
-        yet. See <xref linkend="dhcp4-limit"/> for a detailed description.
-      </para>
+      <simpara>
+	In this release of BIND 10, the DHCPv4 and DHCPv6 servers
+	must be considered experimental.
+      </simpara>
     </note>
 
-    <section id="dhcp4-usage">
-      <title>DHCPv4 Server Usage</title>
-      <para>BIND 10 has provided the DHCPv4 server component since December
-      2011. It is current experimental implementation and is not fully functional
-      yet. It is mature enough to conduct tests in lab environment, but it has
-      significant limitations. See <xref linkend="dhcp4-limit"/> for
-      details.
+    <section id="dhcp-install-configure">
+      <title>DHCP Database Installation and Configuration</title>
+      <para>
+      BIND 10 DHCP stores its leases in a lease database.  The software has been written in
+      a way that makes it possible to choose which database product should be used to
+      store the lease information.  At present, only support for MySQL is provided, and that support must
+      be explicitly included when BIND 10 is built.  This section covers the building of
+      BIND 10 with MySQL and the creation of the lease database.
       </para>
+      <section>
+        <title>Install MySQL</title>
+        <para>
+          Install MySQL according to the instructions for your system.  The client development
+          libraries must be installed.
+        </para>
+      </section>
+      <section>
+        <title>Build and Install BIND 10</title>
+        <para>
+          Build and install BIND 10 as described in <xref linkend="installation"/>, with
+          the following modification: to enable the MySQL database code, at the
+          "configure" step (see <xref linkend="configure"/>), specify the location of the
+          MySQL configuration program "mysql_config" with the "--with-dhcp-mysql" switch,
+          i.e.
+          <screen><userinput>./configure [other-options] --with-dhcp-mysql</userinput></screen>
+          ...if MySQL was installed in the default location, or:
+          <screen><userinput>./configure [other-options] --with-dhcp-mysql=<replaceable>path-to-mysql_config</replaceable></userinput></screen>
+          ...if not.
+        </para>
+      </section>
+      <section id="dhcp-database-create">
+        <title>Create MySQL Database and BIND 10 User</title>
+        <para>
+          The next task is to create both the lease database and the user under which the servers will
+          access it. A number of steps are required:
+        </para>
+        <para>
+          1. Log into MySQL as "root":
+          <screen>$ <userinput>mysql -u root -p</userinput>
+Enter password:<userinput/>
+   :<userinput/>
+mysql></screen>
+        </para>
+        <para>
+          2. Create the database:
+          <screen>mysql> <userinput>CREATE DATABASE <replaceable>database-name</replaceable>;</userinput></screen>
+          ... <replaceable>database-name</replaceable> is the name you have chosen for the database.
+        </para>
+         <para>
+          3. Create the database tables:
+          <screen>mysql> <userinput>CONNECT <replaceable>database-name</replaceable>;</userinput>
+mysql> <userinput>SOURCE <replaceable>path-to-bind10</replaceable>/share/bind10/dhcpdb_create.mysql</userinput></screen>
+        </para>
+         <para>
+          4. Create the user under which BIND 10 will access the database (and give it a password), then grant it access to the database tables:
+          <screen>mysql> <userinput>CREATE USER '<replaceable>user-name</replaceable>'@'localhost' IDENTIFIED BY '<replaceable>password</replaceable>';</userinput>
+mysql> <userinput>GRANT ALL ON <replaceable>database-name</replaceable>.* TO '<replaceable>user-name</replaceable>'@'localhost';</userinput></screen>
+        </para>
+        <para>
+          5. Exit MySQL:
+          <screen>mysql> <userinput>quit</userinput>
+Bye<userinput/>
+$</screen>
+       </para>
+     </section>
+   </section>
 
-      <para>
-        <command>b10-dhcp4</command> is a BIND 10 component and is being
-        run under BIND 10 framework. To add a DHCPv4 process to the set of running
-        BIND 10 services, you can use following commands in <command>bindctl</command>:
-        <screen>> <userinput>config add Boss/components b10-dhcp4</userinput>
-> <userinput>config set Boss/components/b10-dhcp4/kind dispensable</userinput>
-> <userinput>config commit</userinput></screen></para>
+  </chapter>
 
-       <para>
-         To stop running <command>b10-dhcp4</command>, please use the
-         following command:
-         <screen>> <userinput>config remove Boss/components b10-dhcp4</userinput>
-> <userinput>config commit</userinput></screen></para>
+  <chapter id="dhcp4">
+    <title>The DHCPv4 Server</title>
+
+    <section id="dhcp4-start-stop">
+      <title>Starting and Stopping the DHCPv4 Server</title>
 
       <para>
-        During start-up the server will detect available network interfaces
+        <command>b10-dhcp4</command> is the BIND 10 DHCPv4 server and, like other
+        parts of BIND 10, is configured through the <command>bindctl</command>
+        program.
+      </para>
+      <para>
+        After starting BIND 10 and entering bindctl, the first step
+        in configuring the server is to add it to the list of running BIND 10 services.
+<screen>
+> <userinput>config add Init/components b10-dhcp4</userinput>
+> <userinput>config set Init/components/b10-dhcp4/kind dispensable</userinput>
+> <userinput>config commit</userinput>
+</screen>
+      </para>
+      <para>
+         To remove <command>b10-dhcp4</command> from the set of running services,
+         the <command>b10-dhcp4</command> is removed from list of Init components:
+<screen>
+> <userinput>config remove Init/components b10-dhcp4</userinput>
+> <userinput>config commit</userinput>
+</screen>
+      </para>
+
+      <para>
+        On start-up, the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, and have IPv4 address
         assigned.
@@ -3392,23 +3493,29 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
 
     </section>
 
-    <section id="dhcp4-config">
-      <title>DHCPv4 Server Configuration</title>
+    <section id="dhcp4-configuration">
+      <title>Configuring the DHCPv4 Server</title>
       <para>
         Once the server is started, it can be configured. To view the
         current configuration, use the following command in <command>bindctl</command>:
         <screen>
 > <userinput>config show Dhcp4</userinput></screen>
-        When starting Dhcp4 daemon for the first time, the default configuration
+        When starting the DHCPv4 daemon for the first time, the default configuration
         will be available. It will look similar to this:
-        <screen>
+<screen>
 > <userinput>config show Dhcp4</userinput>
-Dhcp4/interface/                list    (default)
-Dhcp4/renew-timer        1000   integer	(default)
-Dhcp4/rebind-timer       2000   integer	(default)
-Dhcp4/preferred-lifetime 3000   integer	(default)
-Dhcp4/valid-lifetime	 4000   integer	(default)
-Dhcp4/subnet4	         []     list    (default)</screen>
+Dhcp4/interface/	list	(default)
+Dhcp4/renew-timer	1000	integer	(default)
+Dhcp4/rebind-timer	2000	integer	(default)
+Dhcp4/valid-lifetime	4000	integer	(default)
+Dhcp4/option-data	[]	list	(default)
+Dhcp4/lease-database/type	"memfile"	string	(default)
+Dhcp4/lease-database/name	""	string	(default)
+Dhcp4/lease-database/user	""	string	(default)
+Dhcp4/lease-database/host	""	string	(default)
+Dhcp4/lease-database/password	""	string	(default)
+Dhcp4/subnet4	[]	list	(default)
+</screen>
       </para>
 
       <para>
@@ -3423,6 +3530,69 @@ Dhcp4/subnet4	         []     list    (default)</screen>
         per-subnet basis.
       </para>
 
+      <section>
+      <title>Database Configuration</title>
+      <para>
+      All leases issued by the server are stored in the lease database.  Currently,
+      the only supported database is MySQL
+      <footnote>
+      <para>
+      The server comes with an in-memory database ("memfile") configured as the default
+      database. This is used for internal testing and is not supported.  In addition,
+      it does not store lease information on disk: lease information will be lost if the
+      server is restarted.
+      </para>
+      </footnote>, and so the server must be configured to
+      access the correct database with the appropriate credentials.
+      </para>
+        <note>
+            <para>
+            Database access information must be configured for the DHCPv4 server, even if
+            it has already been configured for the DHCPv6 server.  The servers store their
+            information independently, so each server can use a separate
+            database or both servers can use the same database.
+            </para>
+        </note>
+      <para>
+      Database configuration is controlled through the Dhcp4/lease-database parameters.
+      The type of the database must be set to MySQL (although the string entered is "mysql"):
+<screen>
+> <userinput>config set Dhcp4/lease-database/type "mysql"</userinput>
+</screen>
+      Next, the name of the database is to hold the leases must be set: this is the
+      name used when the lease database was created (see <xref linkend="dhcp-database-create"/>).
+<screen>
+> <userinput>config set Dhcp4/lease-database/name "<replaceable>database-name</replaceable>"</userinput>
+</screen>
+      If the database is located on a different system to the DHCPv4 server, the
+      database host name must also be specified (although note that this configuration
+      may have a severe impact on server performance):
+<screen>
+> <userinput>config set Dhcp4/lease-database/host "<replaceable>remote-host-name</replaceable>"</userinput>
+</screen>
+      The usual state of affairs will be to have the database on the same machine as the
+      DHCPv4 server.  In this case, set the value to the empty string (this is the default):
+<screen>
+> <userinput>config set Dhcp4/lease-database/host ""</userinput>
+</screen>
+      </para>
+      <para>
+      Finally, the credentials of the account under which the server will access the database
+      should be set:
+<screen>
+> <userinput>config set Dhcp4/lease-database/user "<replaceable>user-name</replaceable>"</userinput>
+> <userinput>config set Dhcp4/lease-database/password "<replaceable>password</replaceable>"</userinput>
+</screen>
+      If there is no password to the account, set the password to the empty string "". (This is also the default.)
+      </para>
+      <note>
+      <para>The password is echoed when entered and is stored in clear text in the BIND 10 configuration
+      database.  Improved password security will be added in a future version of BIND 10 DHCP</para>
+      </note>
+      </section>
+
+      <section id="dhcp4-address-config">
+      <title>Configuration of Address Pools</title>
       <para>
         The essential role of DHCPv4 server is address assignment. The server
         has to be configured with at least one subnet and one pool of dynamic
@@ -3462,7 +3632,7 @@ Dhcp4/subnet4	         []     list    (default)</screen>
 > <userinput>config set Dhcp4/subnet4[1]/pool [ "192.0.3.0/24" ]</userinput>
 > <userinput>config commit</userinput></screen>
         Arrays are counted from 0. subnet[0] refers to the subnet defined in the
-        previous example.  The <command>config add Dhcp4/subnet4</command> adds
+        previous example.  The <command>config add Dhcp4/subnet4</command> command adds
         another (second) subnet. It can be referred to as
         <command>Dhcp4/subnet4[1]</command>. In this example, we allow server to
         dynamically assign all addresses available in the whole subnet.
@@ -3474,60 +3644,540 @@ Dhcp4/subnet4	         []     list    (default)</screen>
         address) and the last (typically broadcast address) address from that pool.
         In the aforementioned example of pool 192.0.3.0/24, both 192.0.3.0 and
         192.0.3.255 addresses may be assigned as well. This may be invalid in some
-        network configurations. If you want to avoid this, please use min-max notation.
+        network configurations. If you want to avoid this, please use the "min-max" notation.
       </para>
+      </section>
 
+    <section id="dhcp4-std-options">
+      <title>Standard DHCPv4 options</title>
       <para>
-        Note: Although configuration is now accepted, some parts of it is not internally used
-        by they server yet. Address pools are used, but option definitons are not.
-        The only way to alter some options (e.g. Router Option or DNS servers and Domain name)
-        is to modify source code. To do so, please edit
-        src/bin/dhcp6/dhcp4_srv.cc file, modify the following parameters and
-        recompile:
+        One of the major features of DHCPv4 server is to provide configuration
+        options to clients. Although there are several options that require
+        special behavior, most options are sent by the server only if the client
+        explicitly requested them.  The following example shows how to
+        configure DNS servers, which is one of the most frequently used
+        options. Options specified in this way are considered global and apply
+        to all configured subnets.
+
         <screen>
-const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
-const std::string HARDCODED_NETMASK = "255.255.255.0";
-const uint32_t    HARDCODED_LEASE_TIME = 60; // in seconds
-const std::string HARDCODED_GATEWAY = "192.0.2.1";
-const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
-const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
-const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.3.1, 192.0.3.2"</userinput>
+> <userinput>config commit</userinput>
+</screen>
+      </para>
+    <para>
+      The first line creates new entry in option-data table. It
+      contains information on all global options that the server is
+      supposed to configure in all subnets. The second line specifies
+      option name. For a complete list of currently supported names,
+      see <xref linkend="dhcp4-std-options-list"/> below.
+      The third line specifies option code, which must match one of the
+      values from that list. Line 4 specifies option space, which must always
+      be set to "dhcp4" as these are standard DHCPv4 options. For
+      other option spaces, including custom option spaces, see <xref
+      linkend="dhcp4-option-spaces"/>. The fifth line specifies the format in
+      which the data will be entered: use of CSV (comma
+      separated values) is recommended. The sixth line gives the actual value to
+      be sent to clients. Data is specified as a normal text, with
+      values separated by commas if more than one value is
+      allowed.
+    </para>
 
-        Lease database and configuration support is planned for end of 2012.
+    <para>
+      Options can also be configured as hexadecimal values. If csv-format is
+      set to false, option data must be specified as a hex string. The
+      following commands configure the domain-name-servers option for all
+      subnets with the following addresses: 192.0.3.1 and 192.0.3.2.
+      Note that csv-format is set to false.
+      <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format false</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "C0 00 03 01 C0 00 03 02"</userinput>
+> <userinput>config commit</userinput>
+        </screen>
+      </para>
+
+      <para>
+        It is possible to override options on a per-subnet basis.  If
+        clients connected to most of your subnets are expected to get the
+        same values of a given option, you should use global options: you
+        can then override specific values for a small number of subnets.
+        On the other hand, if you use different values in each subnet,
+        it does not make sense to specify global option values
+        (Dhcp4/option-data), rather you should set only subnet-specific values
+        (Dhcp4/subnet[X]/option-data[Y]).
+      </para>
+      <para>
+        The following commands override the global
+        DNS servers option for a particular subnet, setting a single DNS
+        server with address 2001:db8:1::3.
+        <screen>
+> <userinput>config add Dhcp4/subnet4[0]/option-data</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/data "192.0.2.3"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+
+      <note>
+        <para>In a future version of Kea, it will not be necessary to specify
+        the option code, space and csv-format fields as they will be set
+        automatically.</para>
+      </note>
+
+      <para>
+        Below is a list of currently supported standard DHCPv4 options. The "Name" and "Code"
+        are the values that should be used as a name in the option-data
+        structures. "Type" designates the format of the data: the meanings of
+        the various types is given in <xref linkend="dhcp-types"/>.
+      </para>
+      <para>
+        Some options are designated as arrays, which means that more than one
+        value is allowed in such an option. For example the option time-servers
+        allows the specification of more than one IPv4 address, so allowing
+        clients to obtain the the addresses of multiple NTP servers.
+      </para>
+      <!-- @todo: describe record types -->
+
+      <para>
+        <table border="1" cellpadding="5%" id="dhcp4-std-options-list">
+          <caption>List of standard DHCPv4 options</caption>
+          <thead>
+            <tr><th>Name</th><th>Code</th><th>Type</th><th>Array?</th></tr>
+          </thead>
+          <tbody>
+<tr><td>subnet-mask</td><td>1</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>time-offset</td><td>2</td><td>uint32</td><td>false</td></tr>
+<tr><td>routers</td><td>3</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>time-servers</td><td>4</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>name-servers</td><td>5</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>domain-name-servers</td><td>6</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>log-servers</td><td>7</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>cookie-servers</td><td>8</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>lpr-servers</td><td>9</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>impress-servers</td><td>10</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>resource-location-servers</td><td>11</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>host-name</td><td>12</td><td>string</td><td>false</td></tr>
+<tr><td>boot-size</td><td>13</td><td>uint16</td><td>false</td></tr>
+<tr><td>merit-dump</td><td>14</td><td>string</td><td>false</td></tr>
+<tr><td>domain-name</td><td>15</td><td>fqdn</td><td>false</td></tr>
+<tr><td>swap-server</td><td>16</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>root-path</td><td>17</td><td>string</td><td>false</td></tr>
+<tr><td>extensions-path</td><td>18</td><td>string</td><td>false</td></tr>
+<tr><td>ip-forwarding</td><td>19</td><td>boolean</td><td>false</td></tr>
+<tr><td>non-local-source-routing</td><td>20</td><td>boolean</td><td>false</td></tr>
+<tr><td>policy-filter</td><td>21</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>max-dgram-reassembly</td><td>22</td><td>uint16</td><td>false</td></tr>
+<tr><td>default-ip-ttl</td><td>23</td><td>uint8</td><td>false</td></tr>
+<tr><td>path-mtu-aging-timeout</td><td>24</td><td>uint32</td><td>false</td></tr>
+<tr><td>path-mtu-plateau-table</td><td>25</td><td>uint16</td><td>true</td></tr>
+<tr><td>interface-mtu</td><td>26</td><td>uint16</td><td>false</td></tr>
+<tr><td>all-subnets-local</td><td>27</td><td>boolean</td><td>false</td></tr>
+<tr><td>broadcast-address</td><td>28</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>perform-mask-discovery</td><td>29</td><td>boolean</td><td>false</td></tr>
+<tr><td>mask-supplier</td><td>30</td><td>boolean</td><td>false</td></tr>
+<tr><td>router-discovery</td><td>31</td><td>boolean</td><td>false</td></tr>
+<tr><td>router-solicitation-address</td><td>32</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>static-routes</td><td>33</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>trailer-encapsulation</td><td>34</td><td>boolean</td><td>false</td></tr>
+<tr><td>arp-cache-timeout</td><td>35</td><td>uint32</td><td>false</td></tr>
+<tr><td>ieee802-3-encapsulation</td><td>36</td><td>boolean</td><td>false</td></tr>
+<tr><td>default-tcp-ttl</td><td>37</td><td>uint8</td><td>false</td></tr>
+<tr><td>tcp-keepalive-internal</td><td>38</td><td>uint32</td><td>false</td></tr>
+<tr><td>tcp-keepalive-garbage</td><td>39</td><td>boolean</td><td>false</td></tr>
+<tr><td>nis-domain</td><td>40</td><td>string</td><td>false</td></tr>
+<tr><td>nis-servers</td><td>41</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>ntp-servers</td><td>42</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>vendor-encapsulated-options</td><td>43</td><td>empty</td><td>false</td></tr>
+<tr><td>netbios-name-servers</td><td>44</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>netbios-dd-server</td><td>45</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>netbios-node-type</td><td>46</td><td>uint8</td><td>false</td></tr>
+<tr><td>netbios-scope</td><td>47</td><td>string</td><td>false</td></tr>
+<tr><td>font-servers</td><td>48</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>x-display-manager</td><td>49</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>dhcp-requested-address</td><td>50</td><td>ipv4-address</td><td>false</td></tr>
+<!-- Lease time should not be configured by a user.
+<tr><td>dhcp-lease-time</td><td>51</td><td>uint32</td><td>false</td></tr>
+-->
+<tr><td>dhcp-option-overload</td><td>52</td><td>uint8</td><td>false</td></tr>
+<!-- Message Type, Server Identifier and Parameter Request List should not be configured by a user.
+<tr><td>dhcp-message-type</td><td>53</td><td>uint8</td><td>false</td></tr>
+<tr><td>dhcp-server-identifier</td><td>54</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>dhcp-parameter-request-list</td><td>55</td><td>uint8</td><td>true</td></tr>
+-->
+<tr><td>dhcp-message</td><td>56</td><td>string</td><td>false</td></tr>
+<tr><td>dhcp-max-message-size</td><td>57</td><td>uint16</td><td>false</td></tr>
+<!-- Renewal and rebinding time should not be configured by a user.
+<tr><td>dhcp-renewal-time</td><td>58</td><td>uint32</td><td>false</td></tr>
+<tr><td>dhcp-rebinding-time</td><td>59</td><td>uint32</td><td>false</td></tr>
+-->
+<tr><td>vendor-class-identifier</td><td>60</td><td>binary</td><td>false</td></tr>
+<!-- Client identifier should not be configured by a user.
+<tr><td>dhcp-client-identifier</td><td>61</td><td>binary</td><td>false</td></tr>
+-->
+<tr><td>nwip-domain-name</td><td>62</td><td>string</td><td>false</td></tr>
+<tr><td>nwip-suboptions</td><td>63</td><td>binary</td><td>false</td></tr>
+<tr><td>user-class</td><td>77</td><td>binary</td><td>false</td></tr>
+<tr><td>fqdn</td><td>81</td><td>record</td><td>false</td></tr>
+<tr><td>dhcp-agent-options</td><td>82</td><td>empty</td><td>false</td></tr>
+<tr><td>authenticate</td><td>90</td><td>binary</td><td>false</td></tr>
+<tr><td>client-last-transaction-time</td><td>91</td><td>uint32</td><td>false</td></tr>
+<tr><td>associated-ip</td><td>92</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>subnet-selection</td><td>118</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>domain-search</td><td>119</td><td>binary</td><td>false</td></tr>
+<tr><td>vivco-suboptions</td><td>124</td><td>binary</td><td>false</td></tr>
+<tr><td>vivso-suboptions</td><td>125</td><td>binary</td><td>false</td></tr>
+          </tbody>
+        </table>
+      </para>
+      <para>
+        <table border="1" cellpadding="5%" id="dhcp-types">
+          <caption>List of standard DHCP option types</caption>
+          <thead>
+            <tr><th>Name</th><th>Meaning</th></tr>
+          </thead>
+          <tbody>
+            <tr><td>binary</td><td>An arbitrary string of bytes, specified as a set of hexadecimal digits.</td></tr>
+            <tr><td>boolean</td><td>Boolean value with allowed values true or false</td></tr>
+            <tr><td>empty</td><td>No value, data is carried in suboptions</td></tr>
+            <tr><td>fqdn</td><td>Fully qualified domain name (e.g. www.example.com)</td></tr>
+            <tr><td>ipv4-address</td><td>IPv4 address in the usual dotted-decimal notation (e.g. 192.0.2.1)</td></tr>
+            <tr><td>ipv6-address</td><td>IPv6 address in the usual colon notation (e.g. 2001:db8::1)</td></tr>
+            <tr><td>record</td><td>Structured data that may comprise any types (except "record" and "empty")</td></tr>
+            <tr><td>string</td><td>Any text</td></tr>
+            <tr><td>uint8</td><td>8 bit unsigned integer with allowed values 0 to 255</td></tr>
+            <tr><td>uint16</td><td>16 bit unsinged integer with allowed values 0 to 65535</td></tr>
+            <tr><td>uint32</td><td>32 bit unsigned integer with allowed values 0 to 4294967295</td></tr>
+          </tbody>
+       </table>
+      </para>
+    </section>
+
+    <section id="dhcp4-custom-options">
+      <title>Custom DHCPv4 options</title>
+      <para>It is also possible to define options other than the standard ones.
+      Assume that we want to define a new DHCPv4 option called "foo" which will have
+      code 222 and will convey a single unsigned 32 bit integer value. We can define
+      such an option by using the following commands:
+      <screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 222</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "uint32"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput></screen>
+      The "false" value of the "array" parameter determines that the option
+      does NOT comprise an array of "uint32" values but rather a single value.
+      Two other parameters have been left blank: "record-types" and "encapsulate".
+      The former specifies the comma separated list of option data fields if the
+      option comprises a record of data fields. The "record-fields" value should
+      be non-empty if the "type" is set to "record". Otherwise it must be left
+      blank. The latter parameter specifies the name of the option space being
+      encapsulated by the particular option. If the particular option does not
+      encapsulate any option space it should be left blank.
+      Note that the above set of comments define the format of the new option and do not
+      set its values.
+      </para>
+      <note>
+        <para>
+          In the current release the default values are not propagated to the
+          parser when the new configuration is being set. Therefore, all
+          parameters must be specified at all times, even if their values are
+          left blank.
+        </para>
+      </note>
+
+      <para>Once the new option format is defined, its value is set
+      in the same way as for a standard option. For example the following
+      commands set a global value that applies to all subnets.
+        <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 222</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+
+      <para>New options can take more complex forms than simple use of
+      primitives (uint8, string, ipv4-address etc): it is possible to
+      define an option comprising a number of existing primitives.
+      </para>
+      <para>Assume we
+      want to define a new option that will consist of an IPv4
+      address, followed by unsigned 16 bit integer, followed by a text
+      string. Such an option could be defined in the following way:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "bar"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 223</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types "ipv4-address, uint16, string"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+</screen>
+      The "type" is set to "record" to indicate that the option contains
+      multiple values of different types.  These types are given as a comma-separated
+      list in the "record-types" field and should be those listed in <xref linkend="dhcp-types"/>.
+      </para>
+      <para>
+      The values of the option are set as follows:
+<screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "bar"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 223</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.100, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+      "csv-format" is set "true" to indicate that the "data" field comprises a command-separated
+      list of values.  The values in the "data" must correspond to the types set in
+      the "record-types" field of the option definition.
+    </section>
+
+    <section id="dhcp4-vendor-opts">
+      <title>DHCPv4 vendor specific options</title>
+      <para>
+      Currently there are three option spaces defined: dhcp4 (to
+      be used in DHCPv4 daemon) and dhcp6 (for the DHCPv6 daemon); there
+      is also vendor-encapsulated-options-space, which is empty by default, but options
+      can be defined in it. Those options are called vendor-specific
+      information options. The following examples show how to define
+      an option "foo" with code 1 that consists of an IPv4 address, an
+      unsigned 16 bit integer and a string. The "foo" option is conveyed
+      in a vendor specific information option.
+      </para>
+      <para>
+      The first step is to define the format of the option:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "vendor-encapsulated-options-space"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types "ipv4-address, uint16, string"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulates ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+     (Note that the option space is set to "vendor-encapsulated-options-space".)
+     Once the option format is defined, the next step is to define actual values
+     for that option:
+     <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "vendor-encapsulated-options-space"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.3, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+    We also set up a dummy value for vendor-opts, the option that conveys our sub-option "foo".
+    This is required else the option will not be included in messages sent to the client.
+     <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[1]/name "vendor-encapsulated-options"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/code 43</userinput>
+> <userinput>config set Dhcp4/option-data[1]/csv-format false</userinput>
+> <userinput>config set Dhcp4/option-data[1]/data ""</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+
+      <note>
+        <para>
+          With this version of BIND 10, the "vendor-encapsulated-options" option
+          must be specified in the configuration although it has no configurable
+          parameters. If it is not specified, the server will assume that it is
+          not configured and will not send it to a client. In the future there
+          will be no need to include this option in the configuration.
+        </para>
+      </note>
+
+    </section>
+
+    <section id="dhcp4-option-spaces">
+
+      <title>Nested DHCPv4 options (custom option spaces)</title>
+      <para>It is sometimes useful to define completely new option
+      space. This is the case when user creates new option in the
+      standard option space ("dhcp4 or "dhcp6") and wants this option
+      to convey sub-options. Thanks to being in the separate space,
+      sub-option codes will have a separate numbering scheme and may
+      overlap with codes of standard options.
+      </para>
+      <para>Note that creation of a new option space when defining
+      sub-options for a standard option is not required, because it is
+      created by default if the standard option is meant to convey any
+      sub-options (see <xref linkend="dhcp4-vendor-opts"/>).
+      </para>
+      <para>
+      Assume that we want to have a DHCPv4 option called "container" with
+      code 222 that conveys two sub-options with codes 1 and 2.
+      First we need to define the new sub-options:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "ipv4-address"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/code 2</userinput>
+> <userinput>config set Dhcp4/option-def[1]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/type "string"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[1]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[1]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+    Note that we have defined the options to belong to a new option space
+    (in this case, "isc").
+    </para>
+    <para>
+    The next step is to define a regular DHCPv4 option with our desired
+    code and specify that it should include options from the new option space:
+<screen>
+> <userinput>add Dhcp4/option-def</userinput>
+> <userinput>set Dhcp4/option-def[2]/name "container"</userinput>
+> <userinput>set Dhcp4/option-def[2]/code 222</userinput>
+> <userinput>set Dhcp4/option-def[2]/space "dhcp4"</userinput>
+> <userinput>set Dhcp4/option-def[2]/type "empty"</userinput>
+> <userinput>set Dhcp4/option-def[2]/array false</userinput>
+> <userinput>set Dhcp4/option-def[2]/record-types ""</userinput>
+> <userinput>set Dhcp4/option-def[2]/encapsulate "isc"</userinput>
+> <userinput>commit</userinput>
+</screen>
+    The name of the option space in which the sub-options are defined
+    is set in the "encapsulate" field. The "type" field is set to "empty"
+    to indicate that this option does not carry any data other than
+    sub-options.
+    </para>
+    <para>
+    Finally, we can set values for the new options:
+<screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.3"</userinput>
+> <userinput>config commit</userinput>
+<userinput></userinput>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/code 2</userinput>
+> <userinput>config set Dhcp4/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[1]/data "Hello world"</userinput>
+> <userinput>config commit</userinput>
+<userinput></userinput>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[2]/name "container"</userinput>
+> <userinput>config set Dhcp4/option-data[2]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[2]/code 222</userinput>
+> <userinput>config set Dhcp4/option-data[2]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[2]/data ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+    Even though the "container" option does not carry any data except
+    sub-options, the "data" field must be explictly set to an empty value.
+    This is required because in the current version of BIND 10 DHCP, the
+    default configuration values are not propagated to the configuration parsers:
+    if the "data" is not set the parser will assume that this
+    parameter is not specified and an error will be reported.
+    </para>
+    <para>Note that it is possible to create an option which carries some data
+    in addition to the sub-options defined in the encapsulated option space.  For example,
+    if the "container" option from the previous example was required to carry an uint16
+    value as well as the sub-options, the "type" value would have to be set to "uint16" in
+    the option definition. (Such an option would then have the following
+    data structure: DHCP header, uint16 value, sub-options.) The value specified
+    with the "data" parameter - which should be a valid integer enclosed in quotes,
+    e.g. "123" - would then be assigned to the uint16 field in the "container" option.
+    </para>
+    </section>
+        </section>
+    <section id="dhcp4-serverid">
+      <title>Server Identifier in DHCPv4</title>
+      <para>
+        The DHCPv4 protocol uses a "server identifier" for clients to be able
+        to discriminate between several servers present on the same link: this
+        value is an IPv4 address of the server. When started for the first time,
+        the DHCPv4 server will choose one of its IPv4 addresses as its server-id,
+        and store the chosen value to a file. That file will be read by the server
+        and the contained value used whenever the server is subsequently started.
+      </para>
+      <para>
+        It is unlikely that this parameter should ever need to be changed.
+        However, if such a need arises, stop the server, edit the file and restart
+        the server. (The file is named b10-dhcp4-serverid and by default is
+        stored in the "var" subdirectory of the directory in which BIND 10 is installed.
+        This can be changed when BIND 10 is built by using "--localstatedir"
+        on the "configure" command line.)  The file is a text file that should
+        contain an IPv4 address. Spaces are ignored, and no extra characters are allowed
+        in this file.
       </para>
     </section>
 
     <section id="dhcp4-std">
-      <title>Supported standards</title>
+      <title>Supported Standards</title>
       <para>The following standards and draft standards are currently
       supported:</para>
       <itemizedlist>
           <listitem>
-            <simpara>RFC2131: Supported messages are DISCOVER, OFFER,
-            REQUEST, ACK, NAK, RELEASE.</simpara>
+            <simpara><ulink url="http://tools.ietf.org/html/rfc2131">RFC 2131</ulink>: Supported messages are DISCOVER, OFFER,
+            REQUEST, RELEASE, ACK, and NAK.</simpara>
           </listitem>
           <listitem>
-            <simpara>RFC2132: Supported options are: PAD (0),
+            <simpara><ulink url="http://tools.ietf.org/html/rfc2132">RFC 2132</ulink>: Supported options are: PAD (0),
             END(255), Message Type(53), DHCP Server Identifier (54),
             Domain Name (15), DNS Servers (6), IP Address Lease Time
             (51), Subnet mask (1), and Routers (3).</simpara>
           </listitem>
-          <listitem>
-            <simpara>RFC6842: Server responses include client-id option
-            if client sent it in its message.</simpara>
-          </listitem>
       </itemizedlist>
     </section>
 
     <section id="dhcp4-limit">
       <title>DHCPv4 Server Limitations</title>
       <para>These are the current limitations of the DHCPv4 server
-      software. Most of them are reflections of the early stage of
+      software. Most of them are reflections of the current stage of
       development and should be treated as <quote>not implemented
       yet</quote>, rather than actual limitations.</para>
       <itemizedlist>
           <listitem>
-            <simpara>During initial IPv4 node configuration, the
+          <para>
+            On startup, the DHCPv4 server does not get the full configuration from
+            BIND 10.  To remedy this, after starting BIND 10, modify any parameter
+            and commit the changes, e.g.
+            <screen>
+> <userinput>config show Dhcp4/renew-timer</userinput>
+Dhcp4/renew-timer	1000	integer	(default)
+> <userinput>config set Dhcp4/renew-timer 1001</userinput>
+> <userinput>config commit</userinput></screen>
+          </para>
+        </listitem>
+          <listitem>
+            <simpara>During the initial IPv4 node configuration, the
             server is expected to send packets to a node that does not
             have IPv4 address assigned yet. The server requires
             certain tricks (or hacks) to transmit such packets. This
@@ -3535,44 +4185,36 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
             relayed traffic only (that is, normal point to point
             communication).</simpara>
           </listitem>
+
           <listitem>
             <simpara>Upon start, the server will open sockets on all
             interfaces that are not loopback, are up and running and
             have IPv4 address.</simpara>
           </listitem>
+
           <listitem>
-            <simpara>PRL (Parameter Request List, a list of options
-            requested by a client) is currently ignored and server
-            assigns DNS SERVER and DOMAIN NAME options.</simpara>
-          </listitem>
-          <listitem>
-            <simpara><command>b10-dhcp4</command> does not support
-            BOOTP. That is a design choice. This limitation is
+            <simpara>The DHCPv4 server does not support
+            BOOTP. That is a design choice and the limitation is
             permanent. If you have legacy nodes that can't use DHCP and
-            require BOOTP support, please use the latest version of ISC DHCP
-            via <ulink url="http://www.isc.org/software/dhcp"/>.</simpara>
+            require BOOTP support, please use the latest version of ISC DHCP,
+            available from <ulink url="http://www.isc.org/software/dhcp"/>.</simpara>
           </listitem>
           <listitem>
             <simpara>Interface detection is currently working on Linux
             only. See <xref linkend="iface-detect"/> for details.</simpara>
           </listitem>
           <listitem>
-            <simpara><command>b10-dhcp4</command> does not verify that
-            assigned address is unused. According to RFC2131, the
-            allocating server should verify that address is no used by
+            <simpara>The DHCPv4 server does not  verify that
+            assigned address is unused. According to <ulink url="http://tools.ietf.org/html/rfc2131">RFC 2131</ulink>, the
+            allocating server should verify that address is not used by
             sending ICMP echo request.</simpara>
           </listitem>
           <listitem>
-            <simpara>Address rebinding (REQUEST/Rebinding), confirmation
-            (CONFIRM) and duplication report (DECLINE) are not supported
-            yet.</simpara>
+            <simpara>Address rebinding (REBIND) and duplication report (DECLINE)
+            are not supported yet.</simpara>
           </listitem>
           <listitem>
-            <simpara>DNS Update is not supported yet.</simpara>
-          </listitem>
-          <listitem>
-            <simpara>-v (verbose) command line option is currently
-            the default, and cannot be disabled.</simpara>
+          <simpara>DNS Update is not yet supported.</simpara>
           </listitem>
       </itemizedlist>
     </section>
@@ -3580,139 +4222,46 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
   </chapter>
 
   <chapter id="dhcp6">
-    <title>DHCPv6 Server</title>
-    <para>The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is
-    specified in RFC3315. BIND 10 provides a DHCPv6 server implementation
-    that is described in this chapter. For a description of the DHCPv4
-    server implementation, see <xref linkend="dhcp4"/>.
-    </para>
+    <title>The DHCPv6 Server</title>
 
-    <para>The DHCPv6 server component is currently under intense
-    development. You may want to check out <ulink
-    url="http://bind10.isc.org/wiki/Kea">BIND 10 DHCP (Kea) wiki</ulink>
-    and recent posts on <ulink
-    url="https://lists.isc.org/mailman/listinfo/bind10-dev">BIND 10
-    developers mailing list</ulink>.</para>
+    <section id="dhcp6-start-stop">
+      <title>Starting and Stopping the DHCPv6 Server</title>
 
-    <note>
       <para>
-        As of November 2012, the DHCPv6 component is partially functioning,
-        having the following capabilities:
+        <command>b10-dhcp6</command> is the BIND 10 DHCPv6 server and, like other
+        parts of BIND 10, is configured through the <command>bindctl</command>
+        program.
       </para>
-      <itemizedlist>
-          <listitem>
-            <simpara>DHCPv6 server able to allocate leases (but not renew them).</simpara>
-          </listitem>
-          <listitem>
-            <simpara>Some configuration available through the BIND 10 configuration mechanism.</simpara>
-          </listitem>
-          <listitem>
-            <simpara>Lease storage in a MySQL database.</simpara>
-          </listitem>
-      </itemizedlist>
-    </note>
-
-    <section id="dhcp6-install">
-      <title>DHCPv6 Server Build and Installation</title>
       <para>
-      DHCPv6 is part of the BIND 10 suite of programs and is built as part of
-      the build of BIND 10.  With the use of MySQL, some additional
-      installation steps are needed:
+        After starting BIND 10 and starting <command>bindctl</command>, the first step
+        in configuring the server is to add <command>b10-dhcp6</command> to the list of running BIND 10 services.
+<screen>
+> <userinput>config add Init/components b10-dhcp6</userinput>
+> <userinput>config set Init/components/b10-dhcp6/kind dispensable</userinput>
+> <userinput>config commit</userinput>
+</screen>
       </para>
-      <section>
-        <title>Install MySQL</title>
-        <para>
-          Install MySQL according to the instructions for your system.  The client development
-          libraries must be installed.
-        </para>
-      </section>
-      <section>
-        <title>Build and Install BIND 10</title>
-        <para>
-          Build and install BIND 10 as described in <xref linkend="installation"/>, with
-          the following modification: to enable the MySQL database code, the
-          "configure" step (see <xref linkend="configure"/>), specify the location of the
-          MySQL configuration program "mysql_config" with the "--with-mysql-config" switch,
-          i.e.
-          <screen><userinput>./configure [other-options] --with-dhcp-mysql</userinput></screen>
-          ...if MySQL was installed in the default location, or:
-          <screen><userinput>./configure [other-options] --with-dhcp-mysql=<replaceable><path-to-mysql_config></replaceable></userinput></screen>
-          ...if not.
-        </para>
-      </section>
-      <section>
-        <title>Create MySQL Database and BIND 10 User</title>
-        <para>
-          The next task is to create both the DHCPv6 lease database and the user under which the DHCPv6 server will
-          access it.  Although the intention is to have the name of the database and the user configurable,
-          at the moment they are hard-coded as "kea", as is the associated password.  ("kea" is an internal
-          code name for BIND 10 DHCP.) There are a number of steps required:
-        </para>
-        <para>
-          1. Log into MySQL as "root":
-          <screen>$ <userinput>mysql -u root -p</userinput>
-Enter password:<userinput/>
-   :<userinput/>
-mysql></screen>
-        </para>
-        <para>
-          2. Create the database:
-          <screen>mysql> <userinput>CREATE DATABASE kea;</userinput></screen>
-        </para>
-         <para>
-          3. Create the database tables:
-          <screen>mysql> <userinput>CONNECT kea;</userinput>
-mysql> <userinput>SOURCE <replaceable><path-to-bind10></replaceable>/share/bind10/dhcpdb_create.mysql</userinput></screen>
-        </para>
-         <para>
-          4. Create the user under which BIND 10 will access the database and grant it access to the database tables:
-          <screen>mysql> <userinput>CREATE USER 'kea'@'localhost' IDENTIFIED BY 'kea';</userinput>
-mysql> <userinput>GRANT ALL ON kea.* TO 'kea'@'localhost';</userinput></screen>
-        </para>
-        <para>
-          5. Exit MySQL:
-          <screen>mysql> <userinput>quit</userinput>
-Bye<userinput/>
-$</screen>
-       </para>
-     </section>
-   </section>
-
-    <section id="dhcp6-usage">
-      <title>DHCPv6 Server Usage</title>
-
       <para>
-        <command>b10-dhcp6</command> is a BIND 10 component and is being
-        run under BIND 10 framework. To add a DHCPv6 process to the set of running
-        BIND 10 services, you can use following commands in <command>bindctl</command>:
-        <screen>> <userinput>config add Boss/components b10-dhcp6</userinput>
-> <userinput>config set Boss/components/b10-dhcp6/kind dispensable</userinput>
-> <userinput>config commit</userinput></screen>
+         To remove <command>b10-dhcp6</command> from the set of running services,
+         the <command>b10-dhcp4</command> is removed from list of Init components:
+<screen>
+> <userinput>config remove Init/components b10-dhcp6</userinput>
+> <userinput>config commit</userinput>
+</screen>
       </para>
 
-       <para>
-         To stop running <command>b10-dhcp6</command>, use the
-         following command:
-         <screen>> <userinput>config remove Boss/components b10-dhcp6</userinput>
-> <userinput>config commit</userinput></screen>
-       </para>
 
       <para>
         During start-up the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, are multicast-capable, and
-        have IPv6 address assigned. It will then listen to incoming traffic. The
-        currently supported client messages are SOLICIT and REQUEST. The server
-        will respond to them with ADVERTISE and REPLY, respectively.
-      </para>
-      <para>
-        Since the DHCPv6 server opens privileged ports, it requires root
-        access. Make sure you run this daemon as root.
+        have IPv6 address assigned. It will then listen to incoming traffic.
       </para>
 
+
     </section>
 
-    <section id="dhcp6-config">
+    <section id="dhcp6-configuration">
       <title>DHCPv6 Server Configuration</title>
       <para>
         Once the server has been started, it can be configured. To view the
@@ -3720,16 +4269,22 @@ $</screen>
         <screen>> <userinput>config show Dhcp6</userinput></screen>
         When starting the Dhcp6 daemon for the first time, the default configuration
         will be available. It will look similar to this:
-        <screen>
+<screen>
 > <userinput>config show Dhcp6</userinput>
-Dhcp6/interface	         "eth0" string	(default)
-Dhcp6/renew-timer        1000   integer	(default)
-Dhcp6/rebind-timer       2000   integer	(default)
-Dhcp6/preferred-lifetime 3000   integer	(default)
-Dhcp6/valid-lifetime	 4000   integer	(default)
-Dhcp6/subnet6	         []     list    (default)</screen>
+Dhcp6/interface/	list	(default)
+Dhcp6/renew-timer	1000	integer	(default)
+Dhcp6/rebind-timer	2000	integer	(default)
+Dhcp6/preferred-lifetime	3000	integer	(default)
+Dhcp6/valid-lifetime	4000	integer	(default)
+Dhcp6/option-data	[]	list	(default)
+Dhcp6/lease-database/type	"memfile"	string	(default)
+Dhcp6/lease-database/name	""	string	(default)
+Dhcp6/lease-database/user	""	string	(default)
+Dhcp6/lease-database/host	""	string	(default)
+Dhcp6/lease-database/password	""	string	(default)
+Dhcp6/subnet6/	list
+</screen>
       </para>
-
       <para>
         To change one of the parameters, simply follow
         the usual <command>bindctl</command> procedure. For example, to make the
@@ -3741,7 +4296,77 @@ Dhcp6/subnet6	         []     list    (default)</screen>
         and apply to all defined subnets, unless they are overridden on a
         per-subnet basis.
       </para>
+      <note>
+        <para>
+          With this version of BIND 10, there are a number of known limitations
+          and problems in the DHCPv6 server. See <xref linkend="dhcp6-limit"/>.
+        </para>
+      </note>
+
+      <section>
+      <title>Database Configuration</title>
+      <para>
+      All leases issued by the server are stored in the lease database.  Currently,
+      the only supported database is MySQL
+      <footnote>
+      <para>
+      The server comes with an in-memory database ("memfile") configured as the default
+      database. This is used for internal testing and is not supported.  In addition,
+      it does not store lease information on disk: lease information will be lost if the
+      server is restarted.
+      </para>
+      </footnote>, and so the server must be configured to
+      access the correct database with the appropriate credentials.
+      </para>
+      <note>
+        <para>
+            Database access information must be configured for the DHCPv6 server, even if
+            it has already been configured for the DHCPv4 server.  The servers store their
+            information independently, so each server can use a separate
+            database or both servers can use the same database.
+          </para>
+        </note>
+      <para>
+      Database configuration is controlled through the Dhcp6/lease-database parameters.
+      The type of the database must be set to MySQL (although the string entered is "mysql"):
+<screen>
+> <userinput>config set Dhcp6/lease-database/type "mysql"</userinput>
+</screen>
+      Next, the name of the database is to hold the leases must be set: this is the
+      name used when the lease database was created (see <xref linkend="dhcp-database-create"/>).
+<screen>
+> <userinput>config set Dhcp6/lease-database/name "<replaceable>database-name</replaceable>"</userinput>
+</screen>
+      If the database is located on a different system to the DHCPv6 server, the
+      database host name must also be specified (although note that this configuration
+      may have a severe impact on server performance):
+<screen>
+> <userinput>config set Dhcp6/lease-database/host "<replaceable>remote-host-name</replaceable>"</userinput>
+</screen>
+      The usual state of affairs will be to have the database on the same machine as the
+      DHCPv6 server.  In this case, set the value to the empty string (this is the default):
+<screen>
+> <userinput>config set Dhcp6/lease-database/host ""</userinput>
+</screen>
+      </para>
+      <para>
+      Finally, the credentials of the account under which the server will access the database
+      should be set:
+<screen>
+> <userinput>config set Dhcp6/lease-database/user "<replaceable>user-name</replaceable>"</userinput>
+> <userinput>config set Dhcp6/lease-database/password "<replaceable>password</replaceable>"</userinput>
+</screen>
+      If there is no password to the account, set the password to the empty string "". (This is also the default.)
+      </para>
+      <note>
+      <para>The password is echoed when entered and is stored in clear text in the BIND 10 configuration
+      database.  Improved password security will be added in a future version of BIND 10 DHCP</para>
+      </note>
+      </section>
+
 
+    <section>
+      <title>Subnet and Address Pool</title>
       <para>
         The essential role of a DHCPv6 server is address assignment. For this,
         the server has to be configured with at least one subnet and one pool of dynamic
@@ -3781,7 +4406,7 @@ Dhcp6/subnet6	         []     list    (default)</screen>
 > <userinput>config set Dhcp6/subnet6[1]/pool [ "2001:db8:beef::/48" ]</userinput>
 > <userinput>config commit</userinput></screen>
         Arrays are counted from 0. subnet[0] refers to the subnet defined in the
-        previous example.  The <command>config add Dhcp6/subnet6</command> adds
+        previous example.  The <command>config add Dhcp6/subnet6</command> command adds
         another (second) subnet. It can be referred to as
         <command>Dhcp6/subnet6[1]</command>. In this example, we allow server to
         dynamically assign all addresses available in the whole subnet. Although
@@ -3794,65 +4419,492 @@ Dhcp6/subnet6	         []     list    (default)</screen>
         a given pool, it will be able to allocate also first (typically network
         address) address from that pool. For example for pool 2001:db8::/64 the
         2001:db8:: address may be assigned as well. If you want to avoid this,
-        please use min-max notation.
+        please use the "min-max" notation.
       </para>
+    </section>
+
+    <section id="dhcp6-std-options">
+      <title>Standard DHCPv6 options</title>
       <para>
-        Options can also be configured: the following commands configure
-        the DNS-SERVERS option for all subnets with the following addresses:
-        2001:db8:1::1 and 2001:db8:1::2
+        One of the major features of DHCPv6 server is to provide configuration
+        options to clients. Although there are several options that require
+        special behavior, most options are sent by the server only if the client
+        explicitly requested them.  The following example shows how to
+        configure DNS servers, which is one of the most frequently used
+        options. Numbers in the first column are added for easier reference and
+        will not appear on screen. Options specified in this way are considered
+        global and apply to all configured subnets.
+
         <screen>
+1. > <userinput>config add Dhcp6/option-data</userinput>
+2. > <userinput>config set Dhcp6/option-data[0]/name "dns-servers"</userinput>
+3. > <userinput>config set Dhcp6/option-data[0]/code 23</userinput>
+4. > <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+5. > <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+6. > <userinput>config set Dhcp6/option-data[0]/data "2001:db8::cafe, 2001:db8::babe"</userinput>
+7. > <userinput>config commit</userinput>
+</screen>
+      </para>
+    <para>
+      The first line creates new entry in option-data table. It
+      contains information on all global options that the server is
+      supposed to configure in all subnets. The second line specifies
+      option name. For a complete list of currently supported names,
+      see <xref linkend="dhcp6-std-options-list"/> below.
+      The third line specifies option code, which must match one of the
+      values from that
+      list. Line 4 specifies option space, which must always
+      be set to "dhcp6" as these are standard DHCPv6 options. For
+      other name spaces, including custom option spaces, see <xref
+      linkend="dhcp6-option-spaces"/>. The fifth line specifies the format in
+      which the data will be entered: use of CSV (comma
+      separated values) is recommended. The sixth line gives the actual value to
+      be sent to clients. Data is specified as a normal text, with
+      values separated by commas if more than one value is
+      allowed.
+    </para>
+
+    <para>
+      Options can also be configured as hexadecimal values. If csv-format is
+      set to false, the option data must be specified as a string of hexadecimal
+      numbers. The
+      following commands configure the DNS-SERVERS option for all
+      subnets with the following addresses: 2001:db8:1::cafe and
+      2001:db8:1::babe.
+      <screen>
 > <userinput>config add Dhcp6/option-data</userinput>
 > <userinput>config set Dhcp6/option-data[0]/name "dns-servers"</userinput>
 > <userinput>config set Dhcp6/option-data[0]/code 23</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format false</userinput>
 > <userinput>config set Dhcp6/option-data[0]/data "2001 0DB8 0001 0000 0000 0000</userinput>
-        <userinput>0000 0001 2001 0DB8 0001 0000 0000 0000 0000 0002"</userinput>
+        <userinput>0000 CAFE 2001 0DB8 0001 0000 0000 0000 0000 BABE"</userinput>
 > <userinput>config commit</userinput>
         </screen>
        (The value for the setting of the "data" element is split across two
-        lines in this document for clarity: when entering the command, all the
-        string should be entered on the same line.)
+        lines in this document for clarity: when entering the command, the
+        whole string should be entered on the same line.)
       </para>
-      <para>
-        Currently the only way to set option data is to specify the
-        data as a string of hexadecimal digits.  It is planned to allow
-        alternative ways of specifying the data as a comma-separated list,
-        e.g. "2001:db8:1::1,2001:db8:1::2".
-      </para>
-      <para>
-        As with global settings, it is also possible to override options on a
-        per-subnet basis, e.g.  the following commands override the global DNS
-        servers option for a particular subnet, setting a single DNS server with
-        address 2001:db8:1::3.
-        <screen>
+
+    <para>
+      It is possible to override options on a per-subnet basis.  If
+      clients connected to most of your subnets are expected to get the
+      same values of a given option, you should use global options: you
+      can then override specific values for a small number of subnets.
+      On the other hand, if you use different values in each subnet,
+      it does not make sense to specify global option values
+      (Dhcp6/option-data), rather you should set only subnet-specific values
+      (Dhcp6/subnet[X]/option-data[Y]).
+     </para>
+     <para>
+      The following commands override the global
+      DNS servers option for a particular subnet, setting a single DNS
+      server with address 2001:db8:1::3.
+      <screen>
 > <userinput>config add Dhcp6/subnet6[0]/option-data</userinput>
 > <userinput>config set Dhcp6/subnet6[0]/option-data[0]/name "dns-servers"</userinput>
 > <userinput>config set Dhcp6/subnet6[0]/option-data[0]/code 23</userinput>
-> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/data "2001 0DB8 0001 0000</userinput>
-        <userinput>0000 0000 0000 0003"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/data "2001:db8:1::3"</userinput>
 > <userinput>config commit</userinput></screen>
-        (As before, the setting of the "data" element has been split across two
-        lines for clarity.)
+    </para>
+
+    <note>
+      <para>
+        In future versions of BIND 10 DHCP, it will not be necessary to specify
+        option code, space and csv-format fields, as those fields will be set
+        automatically.
       </para>
-      <note>
-        <para>
-          With this version of BIND 10, there are a number of known limitations
-          and problems in the DHCPv6 server. See <xref linkend="dhcp6-limit"/>.
+    </note>
+
+
+    <para>
+      Below is a list of currently supported standard DHCPv6 options. The "Name" and "Code"
+      are the values that should be used as a name in the option-data
+      structures. "Type" designates the format of the data: the meanings of
+      the various types is given in <xref linkend="dhcp-types"/>.
+    </para>
+    <para>
+      Some options are designated as arrays, which means that more than one
+      value is allowed in such an option. For example the option dns-servers
+      allows the specification of more than one IPv6 address, so allowing
+      clients to obtain the the addresses of multiple DNS servers.
+    </para>
+
+<!-- @todo: describe record types -->
+
+    <para>
+      <table border="1" cellpadding="5%" id="dhcp6-std-options-list">
+        <caption>List of standard DHCPv6 options</caption>
+        <thead>
+          <tr><th>Name</th><th>Code</th><th>Type</th><th>Array?</th></tr>
+          <tr></tr>
+        </thead>
+        <tbody>
+<!-- Our engine uses those options on its own, admin must not configure them on his own
+<tr><td>clientid</td><td>1</td><td>binary</td><td>false</td></tr>
+<tr><td>serverid</td><td>2</td><td>binary</td><td>false</td></tr>
+<tr><td>ia-na</td><td>3</td><td>record</td><td>false</td></tr>
+<tr><td>ia-ta</td><td>4</td><td>uint32</td><td>false</td></tr>
+<tr><td>iaaddr</td><td>5</td><td>record</td><td>false</td></tr>
+<tr><td>oro</td><td>6</td><td>uint16</td><td>true</td></tr> -->
+<tr><td>preference</td><td>7</td><td>uint8</td><td>false</td></tr>
+
+<!-- Our engine uses those options on its own, admin must not configure them on his own
+<tr><td>elapsed-time</td><td>8</td><td>uint16</td><td>false</td></tr>
+<tr><td>relay-msg</td><td>9</td><td>binary</td><td>false</td></tr>
+<tr><td>auth</td><td>11</td><td>binary</td><td>false</td></tr>
+<tr><td>unicast</td><td>12</td><td>ipv6-address</td><td>false</td></tr>
+<tr><td>status-code</td><td>13</td><td>record</td><td>false</td></tr>
+<tr><td>rapid-commit</td><td>14</td><td>empty</td><td>false</td></tr>
+<tr><td>user-class</td><td>15</td><td>binary</td><td>false</td></tr>
+<tr><td>vendor-class</td><td>16</td><td>record</td><td>false</td></tr>
+<tr><td>vendor-opts</td><td>17</td><td>uint32</td><td>false</td></tr>
+<tr><td>interface-id</td><td>18</td><td>binary</td><td>false</td></tr>
+<tr><td>reconf-msg</td><td>19</td><td>uint8</td><td>false</td></tr>
+<tr><td>reconf-accept</td><td>20</td><td>empty</td><td>false</td></tr> -->
+<tr><td>sip-server-dns</td><td>21</td><td>fqdn</td><td>true</td></tr>
+<tr><td>sip-server-addr</td><td>22</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>dns-servers</td><td>23</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>domain-search</td><td>24</td><td>fqdn</td><td>true</td></tr>
+<!-- <tr><td>ia-pd</td><td>25</td><td>record</td><td>false</td></tr> -->
+<!-- <tr><td>iaprefix</td><td>26</td><td>record</td><td>false</td></tr> -->
+<tr><td>nis-servers</td><td>27</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>nisp-servers</td><td>28</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>nis-domain-name</td><td>29</td><td>fqdn</td><td>true</td></tr>
+<tr><td>nisp-domain-name</td><td>30</td><td>fqdn</td><td>true</td></tr>
+<tr><td>sntp-servers</td><td>31</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>information-refresh-time</td><td>32</td><td>uint32</td><td>false</td></tr>
+<tr><td>bcmcs-server-dns</td><td>33</td><td>fqdn</td><td>true</td></tr>
+<tr><td>bcmcs-server-addr</td><td>34</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>geoconf-civic</td><td>36</td><td>record</td><td>false</td></tr>
+<tr><td>remote-id</td><td>37</td><td>record</td><td>false</td></tr>
+<tr><td>subscriber-id</td><td>38</td><td>binary</td><td>false</td></tr>
+<tr><td>client-fqdn</td><td>39</td><td>record</td><td>false</td></tr>
+<tr><td>pana-agent</td><td>40</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>new-posix-timezone</td><td>41</td><td>string</td><td>false</td></tr>
+<tr><td>new-tzdb-timezone</td><td>42</td><td>string</td><td>false</td></tr>
+<tr><td>ero</td><td>43</td><td>uint16</td><td>true</td></tr>
+<tr><td>lq-query</td><td>44</td><td>record</td><td>false</td></tr>
+<tr><td>client-data</td><td>45</td><td>empty</td><td>false</td></tr>
+<tr><td>clt-time</td><td>46</td><td>uint32</td><td>false</td></tr>
+<tr><td>lq-relay-data</td><td>47</td><td>record</td><td>false</td></tr>
+<tr><td>lq-client-link</td><td>48</td><td>ipv6-address</td><td>true</td></tr>
+        </tbody>
+      </table>
+    </para>
+    </section>
+
+    <section id="dhcp6-custom-options">
+      <title>Custom DHCPv6 options</title>
+      <para>It is also possible to define options other than the standard ones.
+      Assume that we want to define a new DHCPv6 option called "foo" which will have
+      code 100 and will convey a single unsigned 32 bit integer value. We can define
+      such an option by using the following commands:
+      <screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 100</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "uint32"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput></screen>
+      The "false" value of the "array" parameter determines that the option
+      does NOT comprise an array of "uint32" values but rather a single value.
+      Two other parameters have been left blank: "record-types" and "encapsulate".
+      The former specifies the comma separated list of option data fields if the
+      option comprises a record of data fields. The "record-fields" value should
+      be non-empty if the "type" is set to "record". Otherwise it must be left
+      blank. The latter parameter specifies the name of the option space being
+      encapsulated by the particular option. If the particular option does not
+      encapsulate any option space it should be left blank.
+      Note that the above set of comments define the format of the new option and do not
+      set its values.
+      </para>
+      <para>Once the new option format is defined, its value is set
+      in the same way as for a standard option. For example the following
+      commands set a global value that applies to all subnets.
+        <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 100</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+
+      <para>New options can take more complex forms than simple use of
+      primitives (uint8, string, ipv6-address etc): it is possible to
+      define an option comprising a number of existing primitives.
+      </para>
+      <para>
+      Assume we
+      want to define a new option that will consist of an IPv6
+      address, followed by unsigned 16 bit integer, followed by a text
+      string. Such an option could be defined in the following way:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "bar"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 101</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types "ipv6-address, uint16, string"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+</screen>
+      The "type" is set to "record" to indicate that the option contains
+      multiple values of different types.  These types are given as a comma-separated
+      list in the "record-types" field and should be those listed in <xref linkend="dhcp-types"/>.
+      </para>
+      <para>
+      The values of the option are set as follows:
+<screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "bar"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 101</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8:1::10, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+      "csv-format" is set "true" to indicate that the "data" field comprises a command-separated
+      list of values.  The values in the "data" must correspond to the types set in
+      the "record-types" field of the option definition.
+    </section>
+
+    <section id="dhcp6-vendor-opts">
+      <title>DHCPv6 vendor specific options</title>
+      <para>
+      Currently there are three option spaces defined: dhcp4 (to be used
+      in DHCPv4 daemon) and dhcp6 (for the DHCPv6 daemon); there is also
+      vendor-opts-space, which is empty by default, but options can be
+      defined in it. Those options are called vendor-specific information
+      options. The following examples show how to define an option "foo"
+      with code 1 that consists of an IPv6 address, an unsigned 16 bit integer
+      and a string. The "foo" option is conveyed in a vendor specific
+      information option. This option comprises a single uint32 value
+      that is set to "12345". The sub-option "foo" follows the data
+      field holding this value.
+      <screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "vendor-opts-space"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types "ipv6-address, uint16, string"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulates ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+     (Note that the option space is set to "vendor-opts-space".)
+     Once the option format is defined, the next step is to define actual values
+     for that option:
+     <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "vendor-opts-space"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8:1::10, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+    We should also define values for the vendor-opts, that will convey our option foo.
+     <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[1]/name "vendor-opts"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/code 17</userinput>
+> <userinput>config set Dhcp6/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[1]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+      </para>
+    </section>
+
+    <section id="dhcp6-option-spaces">
+      <title>Nested DHCPv6 options (custom option spaces)</title>
+      <para>It is sometimes useful to define completely new option
+      spaces.  This is useful if the user wants his new option to
+      convey sub-options that use separate numbering scheme, for
+      example sub-options with codes 1 and 2. Those option codes
+      conflict with standard DHCPv6 options, so a separate option
+      space must be defined.
+      </para>
+      <para>Note that it is not required to create new option space when
+      defining sub-options for a standard option because it is by
+      default created if the standard option is meant to convey
+      any sub-options (see <xref linkend="dhcp6-vendor-opts"/>).
+      </para>
+      <para>
+      Assume that we want to have a DHCPv6 option called "container"
+      with code 102 that conveys two sub-options with codes 1 and 2.
+      First we need to define the new sub-options:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "ipv6-address"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/code 2</userinput>
+> <userinput>config set Dhcp6/option-def[1]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/type "string"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[1]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[1]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+    Note that we have defined the options to belong to a new option space
+    (in this case, "isc").
+    </para>
+    <para>
+The next step is to define a regular DHCPv6 option and specify that it
+should include options from the isc option space:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[2]/name "container"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/code 102</userinput>
+> <userinput>config set Dhcp6/option-def[2]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/type "empty"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[2]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[2]/encapsulate "isc"</userinput>
+> <userinput>config commit</userinput>
+</screen>
+    The name of the option space in which the sub-options are defined
+    is set in the "encapsulate" field. The "type" field is set to "empty"
+    which imposes that this option does not carry any data other than
+    sub-options.
+    </para>
+    <para>
+    Finally, we can set values for the new options:
+<screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8::abcd"</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/code 2</userinput>
+> <userinput>config set Dhcp6/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[1]/data "Hello world"</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[2]/name "container"</userinput>
+> <userinput>config set Dhcp6/option-data[2]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[2]/code 102</userinput>
+> <userinput>config set Dhcp6/option-data[2]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[2]/data ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+    Even though the "container" option does not carry any data except
+    sub-options, the "data" field must be explictly set to an empty value.
+    This is required because in the current version of BIND 10 DHCP, the
+    default configuration values are not propagated to the configuration parsers:
+    if the "data" is not set the parser will assume that this
+    parameter is not specified and an error will be reported.
+    </para>
+    <para>Note that it is possible to create an option which carries some data
+    in addition to the sub-options defined in the encapsulated option space.  For example,
+    if the "container" option from the previous example was required to carry an uint16
+    value as well as the sub-options, the "type" value would have to be set to "uint16" in
+    the option definition. (Such an option would then have the following
+    data structure: DHCP header, uint16 value, sub-options.) The value specified
+    with the "data" parameter - which should be a valid integer enclosed in quotes,
+    e.g. "123" - would then be assigned to the uint16 field in the "container" option.
+    </para>
+    </section>
+
+      <section id="dhcp6-config-subnets">
+        <title>Subnet Selection</title>
+          <para>
+          The DHCPv6 server may receive requests from local (connected
+          to the same subnet as the server) and remote (connecting via
+          relays) clients.
+          <note>
+          <para>
+          Currently relayed DHCPv6 traffic is not supported.  The server will
+          only respond to local DHCPv6 requests - see <xref linkend="dhcp6-limit"/>
+          </para>
+          </note>
+          As it may have many subnet configurations defined, it
+          must select appropriate subnet for a given request. To do this, the server first
+          checks if there is only one subnet defined and source of the packet is
+          link-local. If this is the case, the server assumes that the only subnet
+          defined is local and client is indeed connected to it. This check
+          simplifies small deployments.
+          </para>
+          <para>
+          If there are two or more subnets defined, the server can not assume
+          which of those (if any) subnets are local. Therefore an optional
+          "interface" parameter is available within a subnet definition to designate that a given subnet
+          is local, i.e. reachable directly over specified interface. For example
+          the server that is intended to serve a local subnet over eth0 may be configured
+          as follows:
+<screen>
+> <userinput>config add Dhcp6/subnet6</userinput>
+> <userinput>config set Dhcp6/subnet6[1]/subnet "2001:db8:beef::/48"</userinput>
+> <userinput>config set Dhcp6/subnet6[1]/pool [ "2001:db8:beef::/48" ]</userinput>
+> <userinput>config set Dhcp6/subnet6[1]/interface "eth0"</userinput>
+> <userinput>config commit</userinput>
+</screen>
         </para>
-      </note>
+      </section>
+
+   </section>
+
+    <section id="dhcp6-serverid">
+      <title>Server Identifier in DHCPv6</title>
+      <para>The DHCPv6 protocol uses a "server identifier" (also known
+      as a DUID) for clients to be able to discriminate between several
+      servers present on the same link.  There are several types of
+      DUIDs defined, but <ulink url="http://tools.ietf.org/html/rfc3315">RFC 3315</ulink> instructs servers to use DUID-LLT if
+      possible. This format consists of a link-layer (MAC) address and a
+      timestamp. When started for the first time, the DHCPv6 server will
+      automatically generate such a DUID and store the chosen value to
+      a file.  That file is read by the server
+      and the contained value used whenever the server is subsequently started.
+      </para>
+      <para>
+        It is unlikely that this parameter should ever need to be changed.
+        However, if such a need arises, stop the server, edit the file and restart
+        the server. (The file is named b10-dhcp6-serverid and by default is
+        stored in the "var" subdirectory of the directory in which BIND 10 is installed.
+        This can be changed when BIND 10 is built by using "--localstatedir"
+        on the "configure" command line.)  The file is a text file that contains
+        double digit hexadecimal values
+        separated by colons. This format is similar to typical MAC address
+        format. Spaces are ignored. No extra characters are allowed in this
+        file.
+      </para>
+
     </section>
 
     <section id="dhcp6-std">
-      <title>Supported DHCPv6 Standards</title>
+      <title>Supported Standards</title>
       <para>The following standards and draft standards are currently
       supported:</para>
       <itemizedlist>
           <listitem>
-            <simpara>RFC3315: Supported messages are SOLICIT,
-            ADVERTISE, REQUEST, and REPLY. Supported options are
-            SERVER_ID, CLIENT_ID, IA_NA, and IAADDRESS.</simpara>
+            <simpara><ulink url="http://tools.ietf.org/html/rfc3315">RFC 3315</ulink>: Supported messages are SOLICIT,
+            ADVERTISE, REQUEST, RELEASE, RENEW, and REPLY.</simpara>
           </listitem>
           <listitem>
-            <simpara>RFC3646: Supported option is DNS_SERVERS.</simpara>
+            <simpara><ulink url="http://tools.ietf.org/html/rfc3646">RFC 3646</ulink>: Supported option is DNS_SERVERS.</simpara>
           </listitem>
       </itemizedlist>
     </section>
@@ -3864,20 +4916,8 @@ Dhcp6/subnet6	         []     list    (default)</screen>
       software. Most of them are reflections of the early stage of
       development and should be treated as <quote>not implemented
       yet</quote>, rather than actual limitations.</para>
-      <para>
       <itemizedlist>
-        <listitem>
-          <para>The DHCPv6 server has only been tested on Debian
-          operating systems.  There are known problems with the
-          handling of packets in CentOS and RHEL.</para>
-        </listitem>
-        <listitem>
-          <para>Relayed traffic is not supported.</para>
-        </listitem>
-       <listitem>
-          <para><command>b10-dhcp6</command> only supports
-          a limited number of configuration options.</para>
-        </listitem>
+
         <listitem>
           <para>
             On startup, the DHCPv6 server does not get the full configuration from
@@ -3891,40 +4931,26 @@ Dhcp6/renew-timer	1000	integer	(default)
           </para>
         </listitem>
         <listitem>
-          <para>Upon start, the server will open sockets on all
-          interfaces that are not loopback, are up, running and are
-          multicast capable and have IPv6 address.  Support for
-          multiple interfaces is not coded in reception routines yet,
-          so if you are running this code on a machine that has many
-          interfaces and <command>b10-dhcp6</command> happens to
-          listen on wrong interface, the easiest way to work around
-          this problem is to turn down other interfaces. This
-          limitation will be fixed shortly.</para>
+          <simpara>Relayed traffic is not supported.</simpara>
         </listitem>
         <listitem>
-          <para>ORO (Option Request Option, a list of options
-          requested by a client) is currently unsupported.</para>
+          <simpara>Temporary addresses are not supported.</simpara>
         </listitem>
         <listitem>
-          <para>Temporary addresses are not supported.</para>
+          <simpara>Prefix delegation is not supported.</simpara>
         </listitem>
         <listitem>
-          <para>Prefix delegation is not supported.</para>
+          <simpara>Rebinding (REBIND), confirmation (CONFIRM),
+          and duplication report (DECLINE) are not yet supported.</simpara>
         </listitem>
         <listitem>
-          <para>Address renewal (RENEW), rebinding (REBIND),
-          confirmation (CONFIRM), duplication report (DECLINE) and
-          release (RELEASE) are not supported.</para>
+          <simpara>DNS Update is not supported.</simpara>
         </listitem>
         <listitem>
-          <para>DNS Update is not supported.</para>
-        </listitem>
-        <listitem>
-          <para>Interface detection is currently working on Linux
-          only. See <xref linkend="iface-detect"/> for details.</para>
+          <simpara>Interface detection is currently working on Linux
+          only. See <xref linkend="iface-detect"/> for details.</simpara>
         </listitem>
       </itemizedlist>
-      </para>
     </section>
 
   </chapter>
@@ -3933,7 +4959,7 @@ Dhcp6/renew-timer	1000	integer	(default)
     <title>libdhcp++ library</title>
     <para>
       libdhcp++ is a common library written in C++ that handles
-      many DHCP-related tasks, including
+      many DHCP-related tasks, including:
       <itemizedlist>
         <listitem>
           <simpara>DHCPv4 and DHCPv6 packets parsing, manipulation and assembly</simpara>
@@ -3951,10 +4977,8 @@ Dhcp6/renew-timer	1000	integer	(default)
     </para>
 
     <para>
-    While this library is currently used by
-    <command>b10-dhcp4</command> and <command>b10-dhcp6</command>
-    only, it is designed to be a portable, universal library, useful for
-    any kind of DHCP-related software.
+    While this library is currently used by BIND 10 DHCP, it is designed to
+    be a portable, universal library, useful for any kind of DHCP-related software.
     </para>
 
 <!-- TODO: point to doxygen docs -->
@@ -3986,7 +5010,7 @@ Dhcp6/renew-timer	1000	integer	(default)
 
     <para>
       The <command>b10-stats</command> process is started by
-      <command>bind10</command>.
+      <command>b10-init</command>.
       It periodically collects statistics data from various modules
       and aggregates it.
 <!-- TODO -->
@@ -4011,7 +5035,7 @@ Dhcp6/renew-timer	1000	integer	(default)
         "queries.tcp": 1749,
         "queries.udp": 867868
     },
-    "Boss": {
+    "Init": {
         "boot_time": "2011-01-20T16:59:03Z"
     },
     "Stats": {
diff --git a/examples/configure.ac b/examples/configure.ac
index 37515d9..850e7ef 100644
--- a/examples/configure.ac
+++ b/examples/configure.ac
@@ -14,9 +14,10 @@ AC_LANG([C++])
 # Checks for BIND 10 headers and libraries
 AX_ISC_BIND10
 
-# We use -R, -rpath etc so the resulting program will be more likekly to
+# We use -R option etc so the resulting program will be more likekly to
 # "just work" by default.  Embedding a specific library path is a controversial
-# practice, though; if you don't like it you can remove the following setting.
+# practice, though; if you don't like it you can remove the following setting,
+# or use the --disable-rpath option.
 if test "x$BIND10_RPATH" != "x"; then
    LDFLAGS="$LDFLAGS $BIND10_RPATH"
 fi
diff --git a/examples/m4/ax_isc_rpath.m4 b/examples/m4/ax_isc_rpath.m4
index 91d9b8a..ee1e472 100644
--- a/examples/m4/ax_isc_rpath.m4
+++ b/examples/m4/ax_isc_rpath.m4
@@ -3,44 +3,54 @@ dnl
 dnl @summary figure out whether and which "rpath" linker option is available
 dnl
 dnl This macro checks if the linker supports an option to embed a path
-dnl to a runtime library (often installed in an uncommon place), such as
-dnl gcc's -rpath option.  If found, it sets the ISC_RPATH_FLAG variable to
+dnl to a runtime library (often installed in an uncommon place), such as the
+dnl commonly used -R option.  If found, it sets the ISC_RPATH_FLAG variable to
 dnl the found option flag.  The main configure.ac can use it as follows:
 dnl if test "x$ISC_RPATH_FLAG" != "x"; then
 dnl     LDFLAGS="$LDFLAGS ${ISC_RPATH_FLAG}/usr/local/lib/some_library"
 dnl fi
+dnl
+dnl If you pass --disable-rpath to configure, ISC_RPATH_FLAG is not set
 
 AC_DEFUN([AX_ISC_RPATH], [
 
-# We'll tweak both CXXFLAGS and CCFLAGS so this function will work whichever
-# language is used in the main script.  Note also that it's not LDFLAGS;
-# technically this is a linker flag, but we've noticed $LDFLAGS can be placed
-# where the compiler could interpret it as a compiler option, leading to
-# subtle failure mode.  So, in the check below using the compiler flag is
-# safer (in the actual Makefiles the flag should be set in LDFLAGS).
-CXXFLAGS_SAVED="$CXXFLAGS"
-CXXFLAGS="$CXXFLAGS -Wl,-R/usr/lib"
-CCFLAGS_SAVED="$CCFLAGS"
-CCFLAGS="$CCFLAGS -Wl,-R/usr/lib"
+AC_ARG_ENABLE(rpath,
+    [AC_HELP_STRING([--disable-rpath], [don't hardcode library path into binaries])],
+    rpath=$enableval, rpath=yes)
+
+if test x$rpath != xno; then
+    # We'll tweak both CXXFLAGS and CCFLAGS so this function will work
+    # whichever language is used in the main script.  Note also that it's not
+    #LDFLAGS; technically this is a linker flag, but we've noticed $LDFLAGS
+    # can be placed where the compiler could interpret it as a compiler
+    # option, leading to subtle failure mode.  So, in the check below using
+    # the compiler flag is safer (in the actual Makefiles the flag should be
+    # set in LDFLAGS).
+    CXXFLAGS_SAVED="$CXXFLAGS"
+    CXXFLAGS="$CXXFLAGS -Wl,-R/usr/lib"
+    CCFLAGS_SAVED="$CCFLAGS"
+    CCFLAGS="$CCFLAGS -Wl,-R/usr/lib"
 
-# check -Wl,-R and -R rather than gcc specific -rpath to be as portable
-# as possible.  -Wl,-R seems to be safer, so we try it first.  In some cases
-# -R is not actually recognized but AC_TRY_LINK doesn't fail due to that.
-AC_MSG_CHECKING([whether -Wl,-R flag is available in linker])
-AC_TRY_LINK([],[],
-    [ AC_MSG_RESULT(yes)
-        ISC_RPATH_FLAG=-Wl,-R
-    ],[ AC_MSG_RESULT(no)
-        AC_MSG_CHECKING([whether -R flag is available in linker])
-	CXXFLAGS="$CXXFLAGS_SAVED -R"
-	CCFLAGS="$CCFLAGS_SAVED -R"
+    # check -Wl,-R and -R rather than gcc specific -rpath to be as portable
+    # as possible.  -Wl,-R seems to be safer, so we try it first.  In some
+    # cases -R is not actually recognized but AC_TRY_LINK doesn't fail due to
+    # that.
+    AC_MSG_CHECKING([whether -Wl,-R flag is available in linker])
+    AC_TRY_LINK([],[],
+        [ AC_MSG_RESULT(yes)
+            ISC_RPATH_FLAG=-Wl,-R
+        ],[ AC_MSG_RESULT(no)
+            AC_MSG_CHECKING([whether -R flag is available in linker])
+            CXXFLAGS="$CXXFLAGS_SAVED -R"
+            CCFLAGS="$CCFLAGS_SAVED -R"
         AC_TRY_LINK([], [],
             [ AC_MSG_RESULT([yes; note that -R is more sensitive about the position in option arguments])
                 ISC_RPATH_FLAG=-R
             ],[ AC_MSG_RESULT(no) ])
-    ])
+        ])
 
-CXXFLAGS=$CXXFLAGS_SAVED
-CCFLAGS=$CCFLAGS_SAVED
+    CXXFLAGS=$CXXFLAGS_SAVED
+    CCFLAGS=$CCFLAGS_SAVED
+fi
 
 ])dnl AX_ISC_RPATH
diff --git a/src/bin/auth/.gitignore b/src/bin/auth/.gitignore
index fb06b83..c3db95b 100644
--- a/src/bin/auth/.gitignore
+++ b/src/bin/auth/.gitignore
@@ -6,3 +6,8 @@
 /spec_config.h
 /spec_config.h.pre
 /b10-auth.8
+/b10-auth.xml
+/gen-statisticsitems.py
+/gen-statisticsitems.py.pre
+/statistics.cc
+/statistics_items.h
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 7d29fcc..1bb5ee9 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -18,6 +18,9 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 CLEANFILES  = *.gcno *.gcda auth.spec spec_config.h
 CLEANFILES += auth_messages.h auth_messages.cc
+CLEANFILES += gen-statisticsitems.py
+# auto-generated by gen-statisticsitems.py
+CLEANFILES += statistics.cc statistics_items.h b10-auth.xml tests/statistics_unittest.cc
 
 man_MANS = b10-auth.8
 DISTCLEANFILES = $(man_MANS)
@@ -26,7 +29,7 @@ EXTRA_DIST = $(man_MANS) b10-auth.xml
 if GENERATE_DOCS
 
 b10-auth.8: b10-auth.xml
-	@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-auth.xml
+	@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(builddir)/b10-auth.xml
 
 else
 
@@ -36,8 +39,18 @@ $(man_MANS):
 
 endif
 
-auth.spec: auth.spec.pre
-	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" auth.spec.pre >$@
+auth.spec: auth.spec.pre statistics_msg_items.def
+b10-auth.xml: b10-auth.xml.pre statistics_msg_items.def
+statistics_items.h: statistics_items.h.pre statistics_msg_items.def
+statistics.cc: statistics.cc.pre statistics_msg_items.def
+tests/statistics_unittest.cc: tests/statistics_unittest.cc.pre statistics_msg_items.def
+
+gen-statisticsitems.py: gen-statisticsitems.py.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" gen-statisticsitems.py.pre >$@
+	chmod +x $@
+
+auth.spec b10-auth.xml statistics_items.h statistics.cc tests/statistics_unittest.cc: Makefile gen-statisticsitems.py
+	./gen-statisticsitems.py
 
 spec_config.h: spec_config.h.pre
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
@@ -46,6 +59,8 @@ auth_messages.h auth_messages.cc: auth_messages.mes
 	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/bin/auth/auth_messages.mes
 
 BUILT_SOURCES = spec_config.h auth_messages.h auth_messages.cc
+# auto-generated by gen-statisticsitems.py
+BUILT_SOURCES += statistics_items.h statistics.cc
 
 pkglibexec_PROGRAMS = b10-auth
 b10_auth_SOURCES = query.cc query.h
@@ -54,13 +69,18 @@ b10_auth_SOURCES += auth_log.cc auth_log.h
 b10_auth_SOURCES += auth_config.cc auth_config.h
 b10_auth_SOURCES += command.cc command.h
 b10_auth_SOURCES += common.h common.cc
-b10_auth_SOURCES += statistics.cc statistics.h statistics_items.h
+b10_auth_SOURCES += statistics.h
 b10_auth_SOURCES += datasrc_clients_mgr.h
 b10_auth_SOURCES += datasrc_config.h datasrc_config.cc
 b10_auth_SOURCES += main.cc
 
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
+nodist_b10_auth_SOURCES += statistics.cc statistics_items.h
 EXTRA_DIST += auth_messages.mes
+EXTRA_DIST += statistics_msg_items.def
+EXTRA_DIST += b10-auth.xml.pre
+EXTRA_DIST += statistics_items.h.pre statistics.cc.pre
+EXTRA_DIST += tests/statistics_unittest.cc.pre
 
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
 b10_auth_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in
index 30a455d..a235da3 100644
--- a/src/bin/auth/auth.spec.pre.in
+++ b/src/bin/auth/auth.spec.pre.in
@@ -122,7 +122,7 @@
             "item_name": "class", "item_type": "string",
             "item_optional": true, "item_default": "IN"
           },
-	  {
+          {
             "item_name": "origin", "item_type": "string",
             "item_optional": false, "item_default": ""
           }
@@ -140,222 +140,6 @@
       }
     ],
     "statistics": [
-      {
-        "item_name": "queries.tcp",
-        "item_type": "integer",
-        "item_optional": false,
-        "item_default": 0,
-        "item_title": "Queries TCP",
-        "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
-      },
-      {
-        "item_name": "queries.udp",
-        "item_type": "integer",
-        "item_optional": false,
-        "item_default": 0,
-        "item_title": "Queries UDP",
-        "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
-      },
-      {
-        "item_name": "opcode.query",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received query requests",
-        "item_description": "The number of total request counts whose opcode is query"
-      },
-      {
-        "item_name": "opcode.iquery",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received inverse query requests",
-        "item_description": "The number of total request counts whose opcode is inverse query"
-      },
-      {
-        "item_name": "opcode.status",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received status requests",
-        "item_description": "The number of total request counts whose opcode is status"
-      },
-      {
-        "item_name": "opcode.notify",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received notify requests",
-        "item_description": "The number of total request counts whose opcode is notify"
-      },
-      {
-        "item_name": "opcode.update",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received update requests",
-        "item_description": "The number of total request counts whose opcode is update"
-      },
-      {
-        "item_name": "opcode.other",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode other",
-        "item_description": "The number of total request counts whose opcode is other (not well-known)"
-      },
-      {
-        "item_name": "rcode.noerror",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent success response",
-        "item_description": "The number of total responses with rcode 0 (NOERROR)"
-      },
-      {
-        "item_name": "rcode.formerr",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'format error' response",
-        "item_description": "The number of total responses with rcode 1 (FORMERR)"
-      },
-      {
-        "item_name": "rcode.servfail",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'server failure' response",
-        "item_description": "The number of total responses with rcode 2 (SERVFAIL)"
-      },
-      {
-        "item_name": "rcode.nxdomain",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'name error' response",
-        "item_description": "The number of total responses with rcode 3 (NXDOMAIN)"
-      },
-      {
-        "item_name": "rcode.notimp",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'not implemented' response",
-        "item_description": "The number of total responses with rcode 4 (NOTIMP)"
-      },
-      {
-        "item_name": "rcode.refused",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'refused' response",
-        "item_description": "The number of total responses with rcode 5 (REFUSED)"
-      },
-      {
-        "item_name": "rcode.yxdomain",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'name unexpectedly exists' response",
-        "item_description": "The number of total responses with rcode 6 (YXDOMAIN)"
-      },
-      {
-        "item_name": "rcode.yxrrset",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'rrset unexpectedly exists' response",
-        "item_description": "The number of total responses with rcode 7 (YXRRSET)"
-      },
-      {
-        "item_name": "rcode.nxrrset",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'no such rrset' response",
-        "item_description": "The number of total responses with rcode 8 (NXRRSET)"
-      },
-      {
-        "item_name": "rcode.notauth",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'not authoritative' response",
-        "item_description": "The number of total responses with rcode 9 (NOTAUTH)"
-      },
-      {
-        "item_name": "rcode.notzone",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'name not in zone' response",
-        "item_description": "The number of total responses with rcode 10 (NOTZONE)"
-      },
-      {
-        "item_name": "rcode.badsigvers",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'EDNS version not implemented' response",
-        "item_description": "The number of total responses with rcode 16 (BADVERS)"
-      },
-      {
-        "item_name": "rcode.badkey",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Key not recognized' response",
-        "item_description": "The number of total responses with rcode 17 (BADKEY)"
-      },
-      {
-        "item_name": "rcode.badtime",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Signature out of time window' response",
-        "item_description": "The number of total responses with rcode 18 (BADTIME)"
-      },
-      {
-        "item_name": "rcode.badmode",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Bad TKEY Mode' response",
-        "item_description": "The number of total responses with rcode 19 (BADMODE)"
-      },
-      {
-        "item_name": "rcode.badname",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Duplicate key name' response",
-        "item_description": "The number of total responses with rcode 20 (BADNAME)"
-      },
-      {
-        "item_name": "rcode.badalg",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Algorithm not supported' response",
-        "item_description": "The number of total responses with rcode 21 (BADALG)"
-      },
-      {
-        "item_name": "rcode.badtrunc",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent 'Bad Truncation' response",
-        "item_description": "The number of total responses with rcode 22 (BADTRUNC)"
-      },
-      {
-        "item_name": "rcode.other",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Sent responses with rcode other",
-        "item_description": "The number of total responses with rcode other (not well-known)"
-      }
     ]
   }
 }
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
index e8592ac..58526da 100644
--- a/src/bin/auth/auth_config.cc
+++ b/src/bin/auth/auth_config.cc
@@ -17,8 +17,6 @@
 
 #include <cc/data.h>
 
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/zonetable.h>
 #include <datasrc/factory.h>
 
 #include <auth/auth_srv.h>
@@ -106,7 +104,7 @@ public:
         rollbackAddresses_ = old;
     }
     virtual void commit() {
-        rollbackAddresses_.release();
+        rollbackAddresses_.reset();
     }
 private:
     AuthSrv& server_;
diff --git a/src/bin/auth/auth_messages.mes b/src/bin/auth/auth_messages.mes
index d93da51..77b20b1 100644
--- a/src/bin/auth/auth_messages.mes
+++ b/src/bin/auth/auth_messages.mes
@@ -14,7 +14,7 @@
 
 $NAMESPACE isc::auth
 
-% AUTH_AXFR_ERROR error handling AXFR request: %1
+% AUTH_AXFR_PROBLEM error handling AXFR request: %1
 This is a debug message produced by the authoritative server when it
 has encountered an error processing an AXFR request. The message gives
 the reason for the error, and the server will return a SERVFAIL code to
@@ -232,13 +232,13 @@ This is a debug message produced by the authoritative server when it receives
 a NOTIFY packet but the XFRIN process is not running. The packet will be
 dropped and nothing returned to the sender.
 
-% AUTH_PACKET_PARSE_ERROR unable to parse received DNS packet: %1
+% AUTH_PACKET_PARSE_FAILED unable to parse received DNS packet: %1
 This is a debug message, generated by the authoritative server when an
 attempt to parse a received DNS packet has failed due to something other
 than a protocol error. The reason for the failure is given in the message;
 the server will return a SERVFAIL error code to the sender.
 
-% AUTH_PACKET_PROTOCOL_ERROR DNS packet protocol error: %1. Returning %2
+% AUTH_PACKET_PROTOCOL_FAILURE DNS packet protocol error: %1. Returning %2
 This is a debug message, generated by the authoritative server when an
 attempt to parse a received DNS packet has failed due to a protocol error.
 The reason for the failure is given in the message, as is the error code
@@ -312,6 +312,9 @@ been created and is initializing. The AUTH_SERVER_STARTED message will be
 output when initialization has successfully completed and the server starts
 accepting queries.
 
+% AUTH_SERVER_EXITING exiting
+The authoritative server is exiting.
+
 % AUTH_SERVER_FAILED server failed: %1
 The authoritative server has encountered a fatal error and is terminating. The
 reason for the failure is included in the message.
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 26a8489..30875e5 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -86,6 +86,7 @@ using namespace isc::asiolink;
 using namespace isc::asiodns;
 using namespace isc::server_common::portconfig;
 using isc::auth::statistics::Counters;
+using isc::auth::statistics::MessageAttributes;
 
 namespace {
 // A helper class for cleaning up message renderer.
@@ -102,17 +103,21 @@ namespace {
 // user of this class, so we hide it within the implementation.
 class RendererHolder {
 public:
-    RendererHolder(MessageRenderer& renderer, OutputBuffer* buffer) :
-        renderer_(renderer)
+    RendererHolder(MessageRenderer& renderer, OutputBuffer* buffer,
+                   MessageAttributes& stats_attrs) :
+        renderer_(renderer),
+        stats_attrs_(stats_attrs)
     {
         renderer.setBuffer(buffer);
     }
     ~RendererHolder() {
+        stats_attrs_.setResponseTruncated(renderer_.isTruncated());
         renderer_.setBuffer(NULL);
         renderer_.clear();
     }
 private:
     MessageRenderer& renderer_;
+    MessageAttributes& stats_attrs_;
 };
 
 // Similar to Renderer holder, this is a very basic RAII-style class
@@ -239,15 +244,19 @@ public:
                 BaseSocketSessionForwarder& ddns_forwarder);
     ~AuthSrvImpl();
 
-    bool processNormalQuery(const IOMessage& io_message, Message& message,
+    bool processNormalQuery(const IOMessage& io_message,
+                            ConstEDNSPtr remote_edns, Message& message,
                             OutputBuffer& buffer,
-                            auto_ptr<TSIGContext> tsig_context);
+                            auto_ptr<TSIGContext> tsig_context,
+                            MessageAttributes& stats_attrs);
     bool processXfrQuery(const IOMessage& io_message, Message& message,
                          OutputBuffer& buffer,
-                         auto_ptr<TSIGContext> tsig_context);
+                         auto_ptr<TSIGContext> tsig_context,
+                         MessageAttributes& stats_attrs);
     bool processNotify(const IOMessage& io_message, Message& message,
                        OutputBuffer& buffer,
-                       auto_ptr<TSIGContext> tsig_context);
+                       auto_ptr<TSIGContext> tsig_context,
+                       MessageAttributes& stats_attrs);
     bool processUpdate(const IOMessage& io_message);
 
     IOService io_service_;
@@ -272,10 +281,6 @@ public:
     /// The data source client list manager
     auth::DataSrcClientsMgr datasrc_clients_mgr_;
 
-    /// Bind the ModuleSpec object in config_session_ with
-    /// isc:config::ModuleSpec::validateStatistics.
-    void registerStatisticsValidator();
-
     /// Socket session forwarder for dynamic update requests
     BaseSocketSessionForwarder& ddns_base_forwarder_;
 
@@ -293,25 +298,17 @@ public:
     ///
     /// \param server The DNSServer as passed to processMessage()
     /// \param message The response as constructed by processMessage()
-    /// \param stats_attrs Query/response attributes for statistics which is
-    ///                    not in \p messsage.
-    ///                    Note: This parameter is modified inside this method
-    ///                          to store whether the answer has been sent and
-    ///                          the response is truncated.
     /// \param done If true, it indicates there is a response.
     ///             this value will be passed to server->resume(bool)
     void resumeServer(isc::asiodns::DNSServer* server,
                       isc::dns::Message& message,
-                      statistics::QRAttributes& stats_attrs,
+                      MessageAttributes& stats_attrs,
                       const bool done);
 
 private:
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
 
-    // validateStatistics
-    bool validateStatistics(isc::data::ConstElementPtr data) const;
-
     auth::Query query_;
 };
 
@@ -423,6 +420,7 @@ public:
 void
 makeErrorMessage(MessageRenderer& renderer, Message& message,
                  OutputBuffer& buffer, const Rcode& rcode,
+                 MessageAttributes& stats_attrs,
                  std::auto_ptr<TSIGContext> tsig_context =
                  std::auto_ptr<TSIGContext>())
 {
@@ -455,9 +453,10 @@ makeErrorMessage(MessageRenderer& renderer, Message& message,
 
     message.setRcode(rcode);
 
-    RendererHolder holder(renderer, &buffer);
+    RendererHolder holder(renderer, &buffer, stats_attrs);
     if (tsig_context.get() != NULL) {
         message.toWire(renderer, *tsig_context);
+        stats_attrs.setResponseTSIG(true);
     } else {
         message.toWire(renderer);
     }
@@ -484,7 +483,6 @@ AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
 void
 AuthSrv::setConfigSession(ModuleCCSession* config_session) {
     impl_->config_session_ = config_session;
-    impl_->registerStatisticsValidator();
 }
 
 ModuleCCSession*
@@ -497,11 +495,11 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
                         OutputBuffer& buffer, DNSServer* server)
 {
     InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
-    statistics::QRAttributes stats_attrs;
+    MessageAttributes stats_attrs;
 
-    // statistics: check transport carrying the message (IP, transport)
-    stats_attrs.setQueryIPVersion(io_message.getRemoteEndpoint().getFamily());
-    stats_attrs.setQueryTransportProtocol(
+    stats_attrs.setRequestIPVersion(
+        io_message.getRemoteEndpoint().getFamily());
+    stats_attrs.setRequestTransportProtocol(
         io_message.getRemoteEndpoint().getProtocol());
 
     // First, check the header part.  If we fail even for the base header,
@@ -522,19 +520,26 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         return;
     }
 
+    const Opcode& opcode = message.getOpcode();
+    // Get opcode at this point; for all requests regardless of message body
+    // sanity check.
+    stats_attrs.setRequestOpCode(opcode);
+
     try {
         // Parse the message.
         message.fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
+        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_FAILURE)
                   .arg(error.getRcode().toText()).arg(error.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode());
+        makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode(),
+                         stats_attrs);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } catch (const Exception& ex) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
+        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_FAILED)
                   .arg(ex.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } // other exceptions will be handled at a higher layer.
@@ -558,85 +563,82 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
                                            **impl_->keyring_));
         tsig_error = tsig_context->verify(tsig_record, io_message.getData(),
                                           io_message.getDataSize());
-        // statistics: check TSIG attributes
-        // SIG(0) is currently not implemented in Auth, but it is implemented
-        // in BIND 9. At the point we support it, the code to check if the
-        // signature is valid would be around here.
-        stats_attrs.setQuerySig(true, false,
-                                tsig_error == TSIGError::NOERROR());
+        stats_attrs.setRequestTSIG(true, tsig_error != TSIGError::NOERROR());
     }
 
     if (tsig_error != TSIGError::NOERROR()) {
         makeErrorMessage(impl_->renderer_, message, buffer,
-                         tsig_error.toRcode(), tsig_context);
+                         tsig_error.toRcode(), stats_attrs, tsig_context);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     }
 
-    const Opcode opcode = message.getOpcode();
     bool send_answer = true;
     try {
-        // statistics: check EDNS
-        //     note: This can only be reliable after TSIG check succeeds.
+        // note: This can only be reliable after TSIG check succeeds.
         ConstEDNSPtr edns = message.getEDNS();
-        if (edns != NULL) {
-            stats_attrs.setQueryEDNS(true, edns->getVersion() == 0);
-            stats_attrs.setQueryDO(edns->getDNSSECAwareness());
+        if (edns) {
+            stats_attrs.setRequestEDNS0(true);
+            stats_attrs.setRequestDO(edns->getDNSSECAwareness());
         }
 
-        // statistics: check OpCode
-        //     note: This can only be reliable after TSIG check succeeds.
-        stats_attrs.setQueryOpCode(opcode.getCode());
-
+        // note: This can only be reliable after TSIG check succeeds.
         if (opcode == Opcode::NOTIFY()) {
             send_answer = impl_->processNotify(io_message, message, buffer,
-                                               tsig_context);
+                                               tsig_context, stats_attrs);
         } else if (opcode == Opcode::UPDATE()) {
             if (impl_->ddns_forwarder_) {
                 send_answer = impl_->processUpdate(io_message);
             } else {
                 makeErrorMessage(impl_->renderer_, message, buffer,
-                                 Rcode::NOTIMP(), tsig_context);
+                                 Rcode::NOTIMP(), stats_attrs, tsig_context);
             }
         } else if (opcode != Opcode::QUERY()) {
             LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_UNSUPPORTED_OPCODE)
                       .arg(message.getOpcode().toText());
             makeErrorMessage(impl_->renderer_, message, buffer,
-                             Rcode::NOTIMP(), tsig_context);
+                             Rcode::NOTIMP(), stats_attrs, tsig_context);
         } else if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
             makeErrorMessage(impl_->renderer_, message, buffer,
-                             Rcode::FORMERR(), tsig_context);
+                             Rcode::FORMERR(), stats_attrs, tsig_context);
         } else {
             ConstQuestionPtr question = *message.beginQuestion();
             const RRType& qtype = question->getType();
             if (qtype == RRType::AXFR()) {
                 send_answer = impl_->processXfrQuery(io_message, message,
-                                                     buffer, tsig_context);
+                                                     buffer, tsig_context,
+                                                     stats_attrs);
             } else if (qtype == RRType::IXFR()) {
                 send_answer = impl_->processXfrQuery(io_message, message,
-                                                     buffer, tsig_context);
+                                                     buffer, tsig_context,
+                                                     stats_attrs);
             } else {
-                send_answer = impl_->processNormalQuery(io_message, message,
-                                                        buffer, tsig_context);
+                send_answer = impl_->processNormalQuery(io_message, edns,
+                                                        message, buffer,
+                                                        tsig_context,
+                                                        stats_attrs);
             }
         }
     } catch (const std::exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE)
                   .arg(ex.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
     } catch (...) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE_UNKNOWN);
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
     }
     impl_->resumeServer(server, message, stats_attrs, send_answer);
 }
 
 bool
-AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
+AuthSrvImpl::processNormalQuery(const IOMessage& io_message,
+                                ConstEDNSPtr remote_edns, Message& message,
                                 OutputBuffer& buffer,
-                                auto_ptr<TSIGContext> tsig_context)
+                                auto_ptr<TSIGContext> tsig_context,
+                                MessageAttributes& stats_attrs)
 {
-    ConstEDNSPtr remote_edns = message.getEDNS();
     const bool dnssec_ok = remote_edns && remote_edns->getDNSSECAwareness();
     const uint16_t remote_bufsize = remote_edns ? remote_edns->getUDPSize() :
         Message::DEFAULT_MAX_UDPSIZE;
@@ -666,21 +668,24 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
             const Name& qname = question->getName();
             query_.process(*list, qname, qtype, message, dnssec_ok);
         } else {
-            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED());
+            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED(),
+                             stats_attrs);
             return (true);
         }
     } catch (const Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
-        makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
         return (true);
     }
 
-    RendererHolder holder(renderer_, &buffer);
+    RendererHolder holder(renderer_, &buffer, stats_attrs);
     const bool udp_buffer =
         (io_message.getSocket().getProtocol() == IPPROTO_UDP);
     renderer_.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
     if (tsig_context.get() != NULL) {
         message.toWire(renderer_, *tsig_context);
+        stats_attrs.setResponseTSIG(true);
     } else {
         message.toWire(renderer_);
     }
@@ -697,12 +702,13 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
 bool
 AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
                              OutputBuffer& buffer,
-                             auto_ptr<TSIGContext> tsig_context)
+                             auto_ptr<TSIGContext> tsig_context,
+                             MessageAttributes& stats_attrs)
 {
     if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_UDP);
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -725,10 +731,10 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
             xfrout_connected_ = false;
         }
 
-        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_ERROR)
+        LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_PROBLEM)
                   .arg(err.what());
         makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -738,7 +744,8 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
 bool
 AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
                            OutputBuffer& buffer,
-                           std::auto_ptr<TSIGContext> tsig_context)
+                           std::auto_ptr<TSIGContext> tsig_context,
+                           MessageAttributes& stats_attrs)
 {
     // The incoming notify must contain exactly one question for SOA of the
     // zone name.
@@ -746,7 +753,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_NOTIFY_QUESTIONS)
                   .arg(message.getRRCount(Message::SECTION_QUESTION));
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
     ConstQuestionPtr question = *message.beginQuestion();
@@ -754,7 +761,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_NOTIFY_RRTYPE)
                   .arg(question->getType().toText());
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -812,9 +819,10 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     message.setHeaderFlag(Message::HEADERFLAG_AA);
     message.setRcode(Rcode::NOERROR());
 
-    RendererHolder holder(renderer_, &buffer);
+    RendererHolder holder(renderer_, &buffer, stats_attrs);
     if (tsig_context.get() != NULL) {
         message.toWire(renderer_, *tsig_context);
+        stats_attrs.setResponseTSIG(true);
     } else {
         message.toWire(renderer_);
     }
@@ -822,7 +830,8 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
 }
 
 bool
-AuthSrvImpl::processUpdate(const IOMessage& io_message) {
+AuthSrvImpl::processUpdate(const IOMessage& io_message)
+{
     // Push the update request to a separate process via the forwarder.
     // On successful push, the request shouldn't be responded from b10-auth,
     // so we return false.
@@ -831,31 +840,10 @@ AuthSrvImpl::processUpdate(const IOMessage& io_message) {
 }
 
 void
-AuthSrvImpl::registerStatisticsValidator() {
-    counters_.registerStatisticsValidator(
-        boost::bind(&AuthSrvImpl::validateStatistics, this, _1));
-}
-
-bool
-AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
-    if (config_session_ == NULL) {
-        return (false);
-    }
-    return (
-        config_session_->getModuleSpec().validateStatistics(
-            data, true));
-}
-
-void
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message,
-                          statistics::QRAttributes& stats_attrs,
+                          MessageAttributes& stats_attrs,
                           const bool done) {
-    if (done) {
-        stats_attrs.answerWasSent();
-        // isTruncated from MessageRenderer
-        stats_attrs.setResponseTruncated(renderer_.isTruncated());
-    }
-    counters_.inc(stats_attrs, message);
+    counters_.inc(stats_attrs, message, done);
     server->resume(done);
 }
 
@@ -875,7 +863,7 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
 }
 
 ConstElementPtr AuthSrv::getStatistics() const {
-    return (impl_->counters_.getStatistics());
+    return (impl_->counters_.get());
 }
 
 const AddressList&
@@ -905,7 +893,8 @@ void
 AuthSrv::createDDNSForwarder() {
     LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_START_DDNS_FORWARDER);
     impl_->ddns_forwarder_.reset(
-        new SocketSessionForwarderHolder("update", impl_->ddns_base_forwarder_));
+        new SocketSessionForwarderHolder("update",
+                                         impl_->ddns_base_forwarder_));
 }
 
 void
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index ebd3034..107e2e6 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -41,9 +41,6 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include <map>
-#include <string>
-
 namespace isc {
 namespace util {
 namespace io {
@@ -222,7 +219,7 @@ public:
     /// \brief Returns statistics data
     ///
     /// This function can throw an exception from
-    /// Counters::getStatistics().
+    /// Counters::get().
     ///
     /// \return JSON format statistics data.
     isc::data::ConstElementPtr getStatistics() const;
diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml
deleted file mode 100644
index 88f80e2..0000000
--- a/src/bin/auth/b10-auth.xml
+++ /dev/null
@@ -1,303 +0,0 @@
-<!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) 2010-2012  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>December 18, 2012</date>
-  </refentryinfo>
-
-  <refmeta>
-    <refentrytitle>b10-auth</refentrytitle>
-    <manvolnum>8</manvolnum>
-    <refmiscinfo>BIND10</refmiscinfo>
-  </refmeta>
-
-  <refnamediv>
-    <refname>b10-auth</refname>
-    <refpurpose>Authoritative DNS server</refpurpose>
-  </refnamediv>
-
-  <docinfo>
-    <copyright>
-      <year>2010-2012</year>
-      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
-    </copyright>
-  </docinfo>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>b10-auth</command>
-      <arg><option>-v</option></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>DESCRIPTION</title>
-    <para>The <command>b10-auth</command> daemon provides the BIND 10
-      authoritative DNS server.
-      Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
-    </para>
-
-    <para>
-      This daemon communicates with other BIND 10 components over a
-      <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      C-Channel connection.  If this connection is not established,
-      <command>b10-auth</command> will exit.
-<!-- TODO what if msgq connection closes later, will b10-auth exit? -->
-      It receives its configurations from
-<citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-
-    </para>
-
-<!-- TODO: mention xfrin, xfrout, zonemgr ? -->
-
-  </refsect1>
-
-  <refsect1>
-    <title>OPTIONS</title>
-
-    <para>The arguments are as follows:</para>
-
-    <variablelist>
-      <varlistentry>
-        <term><option>-v</option></term>
-        <listitem><para>
-	  Enable verbose logging mode. This enables logging of
-	  diagnostic messages at the maximum debug level.
-        </para></listitem>
-      </varlistentry>
-
-    </variablelist>
-
-  </refsect1>
-
-  <refsect1>
-    <title>CONFIGURATION AND COMMANDS</title>
-    <para>
-      The configurable settings are:
-    </para>
-
-    <para>
-      <varname>database_file</varname> defines the path to the
-      SQLite3 zone file when using the sqlite datasource.
-      The default is
-      <filename>/usr/local/var/bind10/zone.sqlite3</filename>.
-    </para>
-
-    <para>
-      <varname>datasources</varname> configures data sources.
-      The list items include:
-      <varname>type</varname> to define the required data source type
-      (such as <quote>memory</quote>);
-      <varname>class</varname> to optionally select the class
-      (it defaults to <quote>IN</quote>);
-      and
-      <varname>zones</varname> to define the
-      <varname>file</varname> path name,
-      <varname>origin</varname> (default domain), and optional
-      <varname>filetype</varname>.
-      By default, <varname>zones</varname> is empty.
-      For the in-memory data source (i.e., the <varname>type</varname>
-      is <quote>memory</quote>), the optional <varname>filetype</varname>
-      configuration item for <varname>zones</varname> can be
-      specified so the in-memory zone data can be built from another
-      data source that is based on a database backend (in practice
-      with current implementation, it would be an SQLite3 database
-      file for the SQLite3 data source).
-      See the <citetitle>BIND 10 Guide</citetitle> for configuration
-      details.
-
-      <note><simpara>
-        Only the IN class is supported at this time.
-        By default, the memory data source is disabled.
-        Also, currently the zone file must be canonical such as
-        generated by <command>named-compilezone -D</command>.
-      </simpara></note>
-    </para>
-
-    <para>
-      <varname>listen_on</varname> is a list of addresses and ports for
-      <command>b10-auth</command> to listen on.
-      The list items are the <varname>address</varname> string
-      and <varname>port</varname> number.
-      By default, <command>b10-auth</command> listens on port 53
-      on the IPv6 (::) and IPv4 (0.0.0.0) wildcard addresses.
-    </para>
-
-    <para>
-      <varname>statistics-interval</varname> is the timer interval
-      in seconds for <command>b10-auth</command> to share its
-      statistics information to
-      <citerefentry><refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-      Statistics updates can be disabled by setting this to 0.
-      The default is 60.
-    </para>
-
-    <para>
-      <varname>tcp_recv_timeout</varname> is the timeout used on
-      incoming TCP connections, in milliseconds. If the query
-      is not sent within this time, the connection is closed.
-      Setting this to 0 will disable TCP timeouts completely.
-      The default is 5000 (five seconds).
-    </para>
-
-<!-- TODO: formating -->
-    <para>
-      The configuration commands are:
-    </para>
-
-    <para>
-      <command>getstats</command> tells <command>b10-auth</command>
-      to report its defined statistics data in JSON format.
-      It will not report about unused counters.
-      This is used by the
-      <citerefentry><refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum></citerefentry> daemon.
-      (The <command>sendstats</command> command is deprecated.)
-    </para>
-
-    <para>
-      <command>loadzone</command> tells <command>b10-auth</command>
-      to load or reload a zone file. The arguments include:
-      <varname>class</varname> which optionally defines the class
-      (it defaults to <quote>IN</quote>);
-      <varname>origin</varname> is the domain name of the zone;
-      and
-      <varname>datasrc</varname> optionally defines the type of datasource
-      (it defaults to <quote>memory</quote>).
-
-      <note><simpara>
-        In this development version, currently this only supports the
-        IN class and the memory data source.
-      </simpara></note>
-    </para>
-
-    <para>
-      <command>shutdown</command> exits <command>b10-auth</command>.
-      This has an optional <varname>pid</varname> argument to
-      select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
-      if configured.)
-    </para>
-
-    <para>
-      <command>start_ddns_forwarder</command> starts (or restarts) the
-      internal forwarding of DDNS Update messages.
-      This is used by the
-      <citerefentry><refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      daemon to tell <command>b10-auth</command> that DDNS Update
-      messages can be forwarded.
-      <note><simpara>This is not expected to be called by administrators;
-        it will be removed as a public command in the future.</simpara></note>
-    </para>
-
-    <para>
-      <command>stop_ddns_forwarder</command> stops the internal
-      forwarding of DDNS Update messages.
-      This is used by the
-      <citerefentry><refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      daemon to tell <command>b10-auth</command> that DDNS Update
-      messages should not be forwarded.
-      <note><simpara>This is not expected to be called by administrators;
-        it will be removed as a public command in the future.</simpara></note>
-    </para>
-
-  </refsect1>
-
-  <refsect1>
-    <title>STATISTICS DATA</title>
-
-    <para>
-      The statistics data collected by the <command>b10-stats</command>
-      daemon for <quote>Auth</quote> include:
-    </para>
-
-    <variablelist>
-
-      <varlistentry>
-        <term>queries.tcp</term>
-        <listitem><simpara>Total count of queries received by the
-          <command>b10-auth</command> server over TCP since startup.
-        </simpara></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>queries.udp</term>
-        <listitem><simpara>Total count of queries received by the
-          <command>b10-auth</command> server over UDP since startup.
-        </simpara></listitem>
-      </varlistentry>
-
-    </variablelist>
-
-<!-- TODO: missing stats docs. See ticket #1721 -->
-
-  </refsect1>
-
-  <refsect1>
-    <title>FILES</title>
-    <para>
-      <filename>/usr/local/var/bind10/zone.sqlite3</filename>
-      — Location for the SQLite3 zone database
-      when <emphasis>database_file</emphasis> configuration is not
-      defined.
-    </para>
-  </refsect1>
-
-  <refsect1>
-    <title>SEE ALSO</title>
-    <para>
-      <citerefentry>
-        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-loadzone</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citetitle>BIND 10 Guide</citetitle>.
-    </para>
-  </refsect1>
-
-  <refsect1>
-    <title>HISTORY</title>
-    <para>
-      The <command>b10-auth</command> daemon was first coded in October 2009.
-    </para>
-  </refsect1>
-</refentry><!--
- - Local variables:
- - mode: sgml
- - End:
--->
diff --git a/src/bin/auth/b10-auth.xml.pre b/src/bin/auth/b10-auth.xml.pre
new file mode 100644
index 0000000..db5be3e
--- /dev/null
+++ b/src/bin/auth/b10-auth.xml.pre
@@ -0,0 +1,306 @@
+<!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) 2010-2012  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>February 5, 2013</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-auth</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-auth</refname>
+    <refpurpose>Authoritative DNS server</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2010-2012</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-auth</command>
+      <arg><option>-v</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>The <command>b10-auth</command> daemon provides the BIND 10
+      authoritative DNS server.
+      Normally it is started by the
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
+    </para>
+
+    <para>
+      This daemon communicates with other BIND 10 components over a
+      <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      C-Channel connection.  If this connection is not established,
+      <command>b10-auth</command> will exit.
+<!-- TODO what if msgq connection closes later, will b10-auth exit? -->
+      It receives its configurations from
+<citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+
+    </para>
+
+<!-- TODO: mention xfrin, xfrout, zonemgr ? -->
+
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>-v</option></term>
+        <listitem><para>
+	  Enable verbose logging mode. This enables logging of
+	  diagnostic messages at the maximum debug level.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>CONFIGURATION AND COMMANDS</title>
+    <para>
+      The configurable settings are:
+    </para>
+
+    <para>
+      <varname>database_file</varname> defines the path to the
+      SQLite3 zone file when using the sqlite datasource.
+      The default is
+      <filename>@@LOCALSTATEDIR@@/bind10/zone.sqlite3</filename>.
+    </para>
+
+    <para>
+      <varname>datasources</varname> configures data sources.
+      The list items include:
+      <varname>type</varname> to define the required data source type
+      (such as <quote>memory</quote>);
+      <varname>class</varname> to optionally select the class
+      (it defaults to <quote>IN</quote>);
+      and
+      <varname>zones</varname> to define the
+      <varname>file</varname> path name,
+      <varname>origin</varname> (default domain), and optional
+      <varname>filetype</varname>.
+      By default, <varname>zones</varname> is empty.
+      For the in-memory data source (i.e., the <varname>type</varname>
+      is <quote>memory</quote>), the optional <varname>filetype</varname>
+      configuration item for <varname>zones</varname> can be
+      specified so the in-memory zone data can be built from another
+      data source that is based on a database backend (in practice
+      with current implementation, it would be an SQLite3 database
+      file for the SQLite3 data source).
+      See the <citetitle>BIND 10 Guide</citetitle> for configuration
+      details.
+
+      <note><simpara>
+        Only the IN class is supported at this time.
+        By default, the memory data source is disabled.
+        Also, currently the zone file must be canonical such as
+        generated by <command>named-compilezone -D</command>.
+      </simpara></note>
+    </para>
+
+    <para>
+      <varname>listen_on</varname> is a list of addresses and ports for
+      <command>b10-auth</command> to listen on.
+      The list items are the <varname>address</varname> string
+      and <varname>port</varname> number.
+      By default, <command>b10-auth</command> listens on port 53
+      on the IPv6 (::) and IPv4 (0.0.0.0) wildcard addresses.
+    </para>
+
+    <para>
+      <varname>tcp_recv_timeout</varname> is the timeout used on
+      incoming TCP connections, in milliseconds. If the query
+      is not sent within this time, the connection is closed.
+      Setting this to 0 will disable TCP timeouts completely.
+      The default is 5000 (five seconds).
+    </para>
+
+<!-- TODO: formating -->
+    <para>
+      The configuration commands are:
+    </para>
+
+    <para>
+      <command>getstats</command> tells <command>b10-auth</command>
+      to report its defined statistics data in JSON format.
+      It will not report about unused counters.
+      This is used by the
+      <citerefentry><refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum></citerefentry> daemon.
+      (The <command>sendstats</command> command is deprecated.)
+    </para>
+
+    <para>
+      <command>loadzone</command> tells <command>b10-auth</command>
+      to load or reload a zone file. The arguments include:
+      <varname>class</varname> which optionally defines the class
+      (it defaults to <quote>IN</quote>);
+      <varname>origin</varname> is the domain name of the zone;
+      and
+      <varname>datasrc</varname> optionally defines the type of datasource
+      (it defaults to <quote>memory</quote>).
+
+      <note><simpara>
+        In this development version, currently this only supports the
+        IN class and the memory data source.
+      </simpara></note>
+    </para>
+
+    <para>
+      <command>getstats</command> tells <command>b10-auth</command>
+      to send its statistics data.
+    </para>
+
+    <para>
+      <command>shutdown</command> exits <command>b10-auth</command>.
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the b10-init process may restart this service
+      if configured.)
+    </para>
+
+    <para>
+      <command>start_ddns_forwarder</command> starts (or restarts) the
+      internal forwarding of DDNS Update messages.
+      This is used by the
+      <citerefentry><refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      daemon to tell <command>b10-auth</command> that DDNS Update
+      messages can be forwarded.
+      <note><simpara>This is not expected to be called by administrators;
+        it will be removed as a public command in the future.</simpara></note>
+    </para>
+
+    <para>
+      <command>stop_ddns_forwarder</command> stops the internal
+      forwarding of DDNS Update messages.
+      This is used by the
+      <citerefentry><refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      daemon to tell <command>b10-auth</command> that DDNS Update
+      messages should not be forwarded.
+      <note><simpara>This is not expected to be called by administrators;
+        it will be removed as a public command in the future.</simpara></note>
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>STATISTICS DATA</title>
+
+    <para>
+      The statistics data collected by the <command>b10-stats</command>
+      daemon for <quote>Auth</quote> include:
+    </para>
+
+<!-- ### STATISTICS DATA PLACEHOLDER ### -->
+
+    <note>
+      <para>
+        Opcode of a request message will not be counted if:
+        <itemizedlist>
+          <listitem><para>
+            The request message is too short to parse the message header
+          </para></listitem>
+          <listitem><para>
+            The request message is a response (i.e. QR bit is set)
+          </para></listitem>
+        </itemizedlist>
+      </para>
+
+      <para>
+        Request attributes except for opcode will not be counted if TSIG
+        validation failed as they are not reliable.
+        We always count opcode mainly for compatibility with BIND 9,
+        but remember that if there's any error related to TSIG, some
+        of the counted opcode may not be trustworthy.
+      </para>
+    </note>
+
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+    <para>
+      <filename>@@LOCALSTATEDIR@@/bind10/zone.sqlite3</filename>
+      — Location for the SQLite3 zone database
+      when <emphasis>database_file</emphasis> configuration is not
+      defined.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-ddns</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-loadzone</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-auth</command> daemon was first coded in October 2009.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/auth/gen-statisticsitems.py.pre.in b/src/bin/auth/gen-statisticsitems.py.pre.in
new file mode 100755
index 0000000..e2d1623
--- /dev/null
+++ b/src/bin/auth/gen-statisticsitems.py.pre.in
@@ -0,0 +1,385 @@
+#!@PYTHON@
+
+# Copyright (C) 2012  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 script generates spec file, docbook XML and some part of statistics code
+from statistics_msg_items.def.
+"""
+
+import os
+import re
+import sys
+import json
+from xml.etree import ElementTree
+
+item_list = []
+localstatedir = '@@LOCALSTATEDIR@@'
+builddir = '@builddir@'
+srcdir = '@srcdir@'
+pre_suffix = '.pre'
+
+xmldocument_command_name = 'b10-auth'
+
+def need_generate(filepath, prepath, mtime):
+    '''Check if we need to generate the specified file.
+
+    To avoid unnecessary compilation, we skip (re)generating the file when
+    the file already exists and newer than the base file, and definition file
+    specified with mtime.
+    '''
+    if os.path.exists(filepath) and\
+        (os.path.getmtime(filepath) > mtime and
+         os.path.getmtime(filepath) > os.path.getmtime(prepath)):
+        return False
+    return True
+
+def import_definitions():
+    '''Load statsitics items definitions from statistics_msg_items.def.
+
+    statistics_msg_items.def defines a tree of message statistics items.
+    Syntax:
+        Each line describes a node; branch node for subset of counters,
+        leaf node for a counter item.
+        Each fields are separated with one or more field separator (Tab).
+        Field separator in the head of a line is ignored.
+
+        branch node:
+        (item name)\t+(internal branch name)\t+(description of the item)\t+'='
+        leaf node:
+        (item name)\t+(internal item counter name)\t+(description of the item)
+
+        Branch nodes contain leaf nodes and/or branch nodes. The end of
+        a branch node is indicated with ';' as item name (first column).
+
+        Internal branch name and internal item counter name must be unique.
+
+    Returns mtime of statistics_msg_items.def. It will be used to check
+    auto-generated files need to be regenerated.
+    '''
+    global item_list
+
+    items_definition_file = srcdir + os.sep + 'statistics_msg_items.def'
+    with open(items_definition_file, 'r') as item_definition:
+        re_splitter = re.compile('\t+')
+        l = item_list
+        lp = None
+        for line in item_definition.readlines():
+            element = re_splitter.split(line.rstrip())
+            # pop first element if it is empty to skip indent
+            if element[0] == '':
+                element.pop(0)
+
+            # last element is '=': a branch node definition.
+            if element[-1] == '=':
+                l.append({'name': element[0], 'child': [], 'index': element[1],
+                          'description': element[2], 'parent': lp})
+                lp = l
+                l = l[-1]['child']
+            # last element is ';': end of a branch node.
+            elif element[-1] == ';':
+                l = lp
+                lp = l[-1]['parent']
+            # otherwise, a leaf node definition.
+            else:
+                l.append({'name': element[0], 'child': None,
+                          'index': element[1], 'description': element[2],
+                          'parent': lp})
+    return os.path.getmtime(items_definition_file)
+
+def generate_specfile(specfile, def_mtime):
+    '''Generate spec in specfile from skeleton (specfille+'.pre').
+    If the specfile is newer than both skeleton and def_mtime, file generation
+    will be skipped.
+
+    This method reads the content of skeleton and appends statistics items
+    definition into { "module_spec": { "statistics": } }.
+    LOCALSTATEDIR is also expanded.
+
+    Returns nothing.
+    '''
+
+    def convert_list(items, prefix=''):
+        spec_list = []
+        default_map = {}
+        for item in items:
+            full_item_name = prefix + item['name']
+            if item['child'] is None:
+                default_map[item['name']] = 0
+                spec_list.append({
+                        'item_name': item['name'],
+                        'item_optional': False,
+                        'item_type': 'integer',
+                        'item_default': 0,
+                        'item_title': full_item_name,
+                        'item_description': item['description'],
+                    })
+            else:
+                child_spec_list, child_default_map = \
+                    convert_list(item['child'], full_item_name + '.')
+                spec_list.append({
+                        'item_name': item['name'],
+                        'item_type': 'map',
+                        'item_optional': False,
+                        'item_title': full_item_name,
+                        'item_description': item['description'],
+                        'item_default': child_default_map,
+                        'map_item_spec': child_spec_list,
+                    })
+                default_map[item['name']] = child_default_map
+        return spec_list, default_map
+
+    item_spec_list, item_default_map = convert_list(item_list)
+
+    statistics_spec_list = [{
+        'item_name': 'zones',
+        'item_type': 'named_set',
+        'item_optional': False,
+        'item_title': 'Zone statistics',
+        'item_description':
+                'Zone statistics items. ' +
+                "Items for all zones are stored in '_SERVER_'.",
+        'item_default': { '_SERVER_': item_default_map },
+        'named_set_item_spec': {
+            'item_name': 'zone',
+            'item_type': 'map',
+            'item_optional': False,
+            'item_default': {},
+            'map_item_spec': item_spec_list,
+            },
+        }]
+
+    if need_generate(builddir+os.sep+specfile,
+                     builddir+os.sep+specfile+pre_suffix, def_mtime):
+        with open(builddir+os.sep+specfile+pre_suffix, 'r') as stats_pre:
+            # split LOCALSTATEDIR to avoid substitution
+            stats_pre_json = \
+                json.loads(stats_pre.read().replace('@@LOCAL'+'STATEDIR@@',
+                                                    localstatedir))
+        stats_pre_json['module_spec']['statistics'] = statistics_spec_list
+        statistics_spec_json = json.dumps(stats_pre_json, sort_keys=True,
+                                          indent=2)
+        with open(builddir+os.sep+specfile, 'w') as stats_spec:
+            stats_spec.write(statistics_spec_json)
+    else:
+        print('skip generating ' + specfile)
+    return
+
+def generate_docfile(docfile, def_mtime):
+    '''Generate docbook XML in docfile from skeleton (docfile+'.pre').
+    If the docfile is newer than both skeleton and def_mtime, file generation
+    will be skipped.
+
+    This method reads the content of skeleton and replaces
+    <!-- ### STATISTICS DATA PLACEHOLDER ### --> with statistics items
+    definition. LOCALSTATEDIR is also expanded.
+
+    Returns nothing.
+    '''
+    def convert_list(items, tree, prefix=''):
+        '''
+        Build XML tree from items.
+            <varlistentry>
+              <term>##item_full_name##</term>
+              <listitem><simpara>##item_description##</simpara></listitem>
+            </varlistentry>
+        xmldocument_command_name in item_description is put inside <command>
+        element.
+        '''
+        for item in items:
+            full_item_name = prefix + item['name']
+            if item['child'] is None:
+                # the item is a leaf node: build varlistentry
+                child_element = ElementTree.SubElement(tree, 'varlistentry')
+                term = ElementTree.SubElement(child_element, 'term')
+                term.text = full_item_name
+                list_item = ElementTree.SubElement(child_element, 'listitem')
+                sim_para = ElementTree.SubElement(list_item, 'simpara')
+                sim_para.text = ''
+                prev = None
+                # put xmldocument_command_name in <command> node
+                for word in item['description'].split():
+                    if word == xmldocument_command_name:
+                        command = ElementTree.SubElement(sim_para, 'command')
+                        command.text = word
+                        # at this point command.tail is None
+                        # append a space as trailing text for the next word
+                        # so it can be concatenated with trailing words
+                        command.tail = ' '
+                        prev = command
+                    else:
+                        if prev is None:
+                            sim_para.text += word + ' '
+                        else:
+                            prev.tail += word + ' '
+                # remove trailing whitespaces at the end of the description
+                if prev is None:
+                    sim_para.text = sim_para.text.rstrip()
+                else:
+                    prev.tail = prev.tail.rstrip()
+            else:
+                # the item is a branch node: call myself for child nodes
+                convert_list(item['child'], tree, full_item_name + '.')
+        return
+
+    if need_generate(builddir+os.sep+docfile,
+                     srcdir+os.sep+docfile+pre_suffix, def_mtime):
+        with open(srcdir+os.sep+docfile+pre_suffix, 'r') as doc_pre:
+            # split LOCALSTATEDIR to avoid substitution
+            doc_pre_xml = doc_pre.read().replace('@@LOCAL'+'STATEDIR@@',
+                                                 localstatedir)
+
+        variable_tree = ElementTree.Element('variablelist')
+        convert_list(item_list, variable_tree)
+        pretty_xml = ElementTree.tostring(variable_tree)
+        if not isinstance(pretty_xml, str):
+            pretty_xml = pretty_xml.decode('utf-8')
+        # put newline around <variablelist> and <varlistentry> element
+        pretty_xml = \
+            re.sub(r'(</?var(?:iablelist|listentry)>)', r'\1\n', pretty_xml)
+        # indent <term> and <listitem>
+        pretty_xml = \
+            re.sub(r'(<(?:term|listitem)>)', r'  \1', pretty_xml)
+        # put newline after </term> and </listitem>
+        pretty_xml = \
+            re.sub(r'(</(?:term|listitem)>)', r'\1\n', pretty_xml)
+
+        with open(builddir+os.sep+docfile, 'w') as doc:
+            doc.write(doc_pre_xml.replace(
+                '<!-- ### STATISTICS DATA PLACEHOLDER ### -->',
+                pretty_xml))
+    else:
+        print('skip generating ' + docfile)
+    return
+
+def generate_cxx(itemsfile, ccfile, utfile, def_mtime):
+    '''Generate some part of statistics code in itemsfile, ccfile, utfile from
+    skeleton (itemsfile+'.pre', ccfile+'.pre', utfile+'.pre').
+    If the file is newer than both skeleton and def_mtime, file generation
+    will be skipped.
+
+    This method reads the content of skeleton and replaces
+    // ### STATISTICS ITEMS DEFINITION ### with statistics items definition in
+    ccfile and utfile,
+    // ### STATISTICS ITEMS DECLARATION ### with statistics items declaration
+    in itemsfile.
+
+    Returns nothing.
+    '''
+    msg_counter_types = ['enum MSGCounterType {']
+    item_names =  ['// using -1 as counter_id to state it is not a '
+                   + 'counter item']
+    item_names += ['const int NOT_ITEM = -1;', '']
+
+    def convert_list(items, item_head, msg_counter_types, item_names):
+        '''Convert item tree to a set of C++ code fragment in given lists.
+
+        This method recursively builds two lists:
+        - msg_counter_types consists of strings for all leaf items, each
+          defines one enum element with a comment, e.g.
+          COUNTER_ITEM, ///< item's descriptin
+        - item_names consists of tuples of three elements, depending on
+          whether it's a leaf element (no child from it) or not:
+          (leaf)   ( "item_name", NULL, COUNTER_ITEM )
+          (branch) ( "item_name", CHILD_NAME, NOT_ITEM )
+
+        Each single call to this function builds a C++ structure beginning
+        with the given item_head, which is a string that reads like
+        'const struct CounterSpec some_counters[] = {'
+        followed by the item_names tuples corresponding to that level.
+        If some of the items of this level have a child, recursive calls
+        to this function extends msg_counter_types and item_names.
+        item_names for this level will be concatenated at the end end of
+        the given item_names.
+
+        '''
+        item_names_current = [item_head]
+        for item in items:
+            item_spec = '    { "' + item['name'] + '", '
+            if item['child'] is None:
+                item_spec += 'NULL, ' + item['index']
+                msg_counter_types.append('    ' + item['index'] + ',    ' +
+                                         '///< ' + item['description'])
+            else:
+                item_spec += item['index'] + ', NOT_ITEM'
+                child_head = 'const struct CounterSpec ' + \
+                    item['index'] + '[] = {'
+                convert_list(item['child'], child_head,
+                             msg_counter_types, item_names)
+            item_names_current.append(item_spec + ' },')
+
+        item_names_current.append('    { NULL, NULL, NOT_ITEM }\n};')
+        item_names.extend(item_names_current)
+
+    convert_list(item_list, 'const struct CounterSpec msg_counter_tree[] = {',
+                 msg_counter_types, item_names)
+    msg_counter_types.extend([
+            '    // End of counter types',
+            '    MSG_COUNTER_TYPES  ///< The number of defined counters',
+            '};'])
+
+    item_decls = '\n'.join(msg_counter_types)
+    item_defs = '\n'.join(item_names)
+
+    if need_generate(builddir+os.sep+itemsfile,
+                     srcdir+os.sep+itemsfile+pre_suffix, def_mtime):
+        with open(srcdir+os.sep+itemsfile+pre_suffix, 'r') \
+            as statistics_items_h_pre:
+            items_pre = statistics_items_h_pre.read()
+
+        with open(builddir+os.sep+itemsfile, 'w') as statistics_items_h:
+            statistics_items_h.write(items_pre.replace(
+                '// ### STATISTICS ITEMS DECLARATION ###', item_decls))
+    else:
+        print('skip generating ' + itemsfile)
+
+    if need_generate(builddir+os.sep+ccfile,
+                     srcdir+os.sep+ccfile+pre_suffix, def_mtime):
+        with open(srcdir+os.sep+ccfile+pre_suffix, 'r') as statistics_cc_pre:
+            items_pre = statistics_cc_pre.read()
+
+        with open(builddir+os.sep+ccfile, 'w') as statistics_cc:
+            statistics_cc.write(items_pre.replace(
+                '// ### STATISTICS ITEMS DEFINITION ###', item_defs))
+    else:
+        print('skip generating ' + ccfile)
+
+    if need_generate(builddir+os.sep+utfile,
+                     srcdir+os.sep+utfile+pre_suffix, def_mtime):
+        with open(srcdir+os.sep+utfile+pre_suffix, 'r') \
+            as statistics_ut_cc_pre:
+            items_pre = statistics_ut_cc_pre.read()
+
+        with open(builddir+os.sep+utfile, 'w') as statistics_ut_cc:
+            statistics_ut_cc.write(items_pre.replace(
+                '// ### STATISTICS ITEMS DEFINITION ###', item_defs))
+    else:
+        print('skip generating ' + utfile)
+
+    return
+
+if __name__ == "__main__":
+    try:
+        def_mtime = import_definitions()
+        generate_specfile('auth.spec', def_mtime)
+        generate_docfile('b10-auth.xml', def_mtime)
+        generate_cxx('statistics_items.h',
+                     'statistics.cc',
+                     'tests'+os.sep+'statistics_unittest.cc',
+                     def_mtime)
+    except:
+        sys.stderr.write('File generation failed due to exception: %s\n' %
+                         sys.exc_info()[1])
+        exit(1)
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index e90d199..dc03be2 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -44,6 +44,7 @@
 #include <server_common/socket_request.h>
 
 #include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -152,10 +153,11 @@ main(int argc, char* argv[]) {
     int ret = 0;
 
     // XXX: we should eventually pass io_service here.
-    Session* cc_session = NULL;
-    Session* xfrin_session = NULL;
+    boost::scoped_ptr<AuthSrv> auth_server_; // placeholder
+    boost::scoped_ptr<Session> cc_session;
+    boost::scoped_ptr<Session> xfrin_session;
     bool xfrin_session_established = false; // XXX (see Trac #287)
-    ModuleCCSession* config_session = NULL;
+    boost::scoped_ptr<ModuleCCSession> config_session;
     XfroutClient xfrout_client(getXfroutSocketPath());
     SocketSessionForwarder ddns_forwarder(getDDNSSocketPath());
     try {
@@ -167,7 +169,8 @@ main(int argc, char* argv[]) {
             specfile = string(AUTH_SPECFILE_LOCATION);
         }
 
-        auth_server = new AuthSrv(xfrout_client, ddns_forwarder);
+        auth_server_.reset(new AuthSrv(xfrout_client, ddns_forwarder));
+        auth_server = auth_server_.get();
         LOG_INFO(auth_logger, AUTH_SERVER_CREATED);
 
         SimpleCallback* checkin = auth_server->getCheckinProvider();
@@ -179,7 +182,7 @@ main(int argc, char* argv[]) {
         auth_server->setDNSService(dns_service);
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_DNS_SERVICES_CREATED);
 
-        cc_session = new Session(io_service.get_io_service());
+        cc_session.reset(new Session(io_service.get_io_service()));
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_CREATED);
         // Initialize the Socket Requestor
         isc::server_common::initSocketRequestor(*cc_session, AUTH_NAME);
@@ -187,22 +190,22 @@ main(int argc, char* argv[]) {
         // We delay starting listening to new commands/config just before we
         // go into the main loop to avoid confusion due to mixture of
         // synchronous and asynchronous operations (this would happen in
-        // initial communication with the boss that takes place in
+        // initial communication with b10-init that takes place in
         // updateConfig() for listen_on and in initializing TSIG keys below).
         // Until then all operations on the CC session will take place
         // synchronously.
-        config_session = new ModuleCCSession(specfile, *cc_session,
-                                             my_config_handler,
-                                             my_command_handler, false);
+        config_session.reset(new ModuleCCSession(specfile, *cc_session,
+                                                 my_config_handler,
+                                                 my_command_handler, false));
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_ESTABLISHED);
 
-        xfrin_session = new Session(io_service.get_io_service());
+        xfrin_session.reset(new Session(io_service.get_io_service()));
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_XFRIN_CHANNEL_CREATED);
         xfrin_session->establish(NULL);
         xfrin_session_established = true;
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_XFRIN_CHANNEL_ESTABLISHED);
 
-        auth_server->setXfrinSession(xfrin_session);
+        auth_server->setXfrinSession(xfrin_session.get());
 
         // Configure the server.  configureAuthServer() is expected to install
         // all initial configurations, but as a short term workaround we
@@ -210,7 +213,7 @@ main(int argc, char* argv[]) {
         // updateConfig().
         // if server load configure failed, we won't exit, give user second
         // chance to correct the configure.
-        auth_server->setConfigSession(config_session);
+        auth_server->setConfigSession(config_session.get());
         try {
             configureAuthServer(*auth_server, config_session->getFullConfig());
             auth_server->updateConfig(ElementPtr());
@@ -228,7 +231,7 @@ main(int argc, char* argv[]) {
         config_session->addRemoteConfig("data_sources",
                                         boost::bind(datasrcConfigHandler,
                                                     auth_server, &first_time,
-                                                    config_session,
+                                                    config_session.get(),
                                                     _1, _2, _3),
                                         false);
 
@@ -260,10 +263,7 @@ main(int argc, char* argv[]) {
         config_session->removeRemoteConfig("data_sources");
     }
 
-    delete xfrin_session;
-    delete config_session;
-    delete cc_session;
-    delete auth_server;
+    LOG_INFO(auth_logger, AUTH_SERVER_EXITING);
 
     return (ret);
 }
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 5b71565..c5b9b16 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -101,8 +101,11 @@ Query::ResponseCreator::create(Message& response,
 
 void
 Query::addSOA(ZoneFinder& finder) {
-    ZoneFinderContextPtr soa_ctx = finder.find(finder.getOrigin(),
-                                               RRType::SOA(), dnssec_opt_);
+    // This method is always called in finding SOA for a negative response,
+    // so we specify the use of min(RRTTL, SOA MINTTL) as specified in
+    // Section 3 of RFC2308.
+    ZoneFinderContextPtr soa_ctx = finder.findAtOrigin(RRType::SOA(), true,
+                                                       dnssec_opt_);
     if (soa_ctx->code != ZoneFinder::SUCCESS) {
         isc_throw(NoSOA, "There's no SOA record in zone " <<
             finder.getOrigin().toText());
@@ -295,14 +298,18 @@ Query::addNXRRsetProof(ZoneFinder& finder,
             addWildcardNXRRSETProof(finder, db_context.rrset);
         }
     } else if (db_context.isNSEC3Signed() && !db_context.isWildcard()) {
-        if (*qtype_ == RRType::DS()) {
-            // RFC 5155, Section 7.2.4.  Add either NSEC3 for the qname or
-            // closest (provable) encloser proof in case of optout.
-            addClosestEncloserProof(finder, *qname_, true);
-        } else {
-            // RFC 5155, Section 7.2.3.  Just add NSEC3 for the qname.
-            addNSEC3ForName(finder, *qname_, true);
-        }
+        // Section 7.2.3 and 7.2.4 of RFC 5155 with clarification by errata
+        // http://www.rfc-editor.org/errata_search.php?rfc=5155&eid=3441
+        // In the end, these two cases are basically the same: if the qname is
+        // equal to or derived from insecure delegation covered by an Opt-Out
+        // NSEC3 RR, include the closest provable encloser proof; otherwise we
+        // have a matching NSEC3, so we include it.
+        //
+        // Note: This implementation does not check in the former case whether
+        // the NSEC3 for the next closer has Opt-Out bit on; this must be the
+        // case as long as the zone is correctly signed, and if it's broken
+        // we'd just return what we are given and have the validator detect it.
+        addClosestEncloserProof(finder, *qname_, true);
     } else if (db_context.isNSEC3Signed() && db_context.isWildcard()) {
         // Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
         // qname, construct the matched wildcard name and add NSEC3 for it.
@@ -318,11 +325,9 @@ void
 Query::addAuthAdditional(ZoneFinder& finder,
                          vector<ConstRRsetPtr>& additionals)
 {
-    const Name& origin = finder.getOrigin();
-
     // Fill in authority and addtional sections.
-    ConstZoneFinderContextPtr ns_context = finder.find(origin, RRType::NS(),
-                                                       dnssec_opt_);
+    ConstZoneFinderContextPtr ns_context =
+        finder.findAtOrigin(RRType::NS(), false, dnssec_opt_);
 
     // zone origin name should have NS records
     if (ns_context->code != ZoneFinder::SUCCESS) {
diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc
deleted file mode 100644
index b310b23..0000000
--- a/src/bin/auth/statistics.cc
+++ /dev/null
@@ -1,284 +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 <auth/statistics.h>
-#include <auth/statistics_items.h>
-#include <auth/auth_log.h>
-
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-
-#include <cc/data.h>
-#include <cc/session.h>
-
-#include <statistics/counter.h>
-#include <statistics/counter_dict.h>
-
-#include <algorithm>
-#include <cctype>
-#include <cassert>
-#include <string>
-#include <sstream>
-#include <iostream>
-
-#include <boost/noncopyable.hpp>
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-using namespace isc::dns;
-using namespace isc::auth;
-using namespace isc::statistics;
-
-namespace isc {
-namespace auth {
-namespace statistics {
-
-// TODO: Make use of wrappers like isc::dns::Opcode
-// for counter item type.
-
-class CountersImpl : boost::noncopyable {
-public:
-    CountersImpl();
-    ~CountersImpl();
-    void inc(const QRAttributes& qrattrs, const Message& response);
-    isc::data::ConstElementPtr getStatistics() const;
-    void registerStatisticsValidator(Counters::validator_type validator);
-private:
-    // counter for query/response
-    Counter server_qr_counter_;
-    // set of counters for zones
-    CounterDictionary zone_qr_counters_;
-    // validator
-    Counters::validator_type validator_;
-};
-
-CountersImpl::CountersImpl() :
-    // size of server_qr_counter_, zone_qr_counters_: QR_COUNTER_TYPES
-    server_qr_counter_(QR_COUNTER_TYPES),
-    zone_qr_counters_(QR_COUNTER_TYPES),
-    validator_()
-{}
-
-CountersImpl::~CountersImpl()
-{}
-
-void
-CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) {
-    // protocols carrying request
-    if (qrattrs.req_ip_version_ == AF_INET) {
-        server_qr_counter_.inc(QR_REQUEST_IPV4);
-    } else if (qrattrs.req_ip_version_ == AF_INET6) {
-        server_qr_counter_.inc(QR_REQUEST_IPV6);
-    }
-    if (qrattrs.req_transport_protocol_ == IPPROTO_UDP) {
-        server_qr_counter_.inc(QR_REQUEST_UDP);
-    } else if (qrattrs.req_transport_protocol_ == IPPROTO_TCP) {
-        server_qr_counter_.inc(QR_REQUEST_TCP);
-    }
-
-    // query TSIG
-    if (qrattrs.req_is_tsig_) {
-        server_qr_counter_.inc(QR_REQUEST_TSIG);
-    }
-    if (qrattrs.req_is_sig0_) {
-        server_qr_counter_.inc(QR_REQUEST_SIG0);
-    }
-    if (qrattrs.req_is_badsig_) {
-        server_qr_counter_.inc(QR_REQUEST_BADSIG);
-        // If signature validation is failed, no other attributes are reliable
-        return;
-    }
-
-    // query EDNS
-    if (qrattrs.req_is_edns_0_) {
-        server_qr_counter_.inc(QR_REQUEST_EDNS0);
-    }
-    if (qrattrs.req_is_edns_badver_) {
-        server_qr_counter_.inc(QR_REQUEST_BADEDNSVER);
-    }
-
-    // query DNSSEC
-    if (qrattrs.req_is_dnssec_ok_) {
-        server_qr_counter_.inc(QR_REQUEST_DNSSEC_OK);
-    }
-
-    // QTYPE
-    unsigned int qtype_type = QR_QTYPE_OTHER;
-    const QuestionIterator qiter = response.beginQuestion();
-    if (qiter != response.endQuestion()) {
-        // get the first and only question section and
-        // get the qtype code
-        const unsigned int qtype = (*qiter)->getType().getCode();
-        if (qtype < 258) {
-            // qtype 0..257: lookup qtype-countertype table
-            qtype_type = QRQTypeToQRCounterType[qtype];
-        } else if (qtype < 32768) {
-            // qtype 258..32767: (Unassigned)
-            qtype_type = QR_QTYPE_OTHER;
-        } else if (qtype < 32770) {
-            // qtype 32768..32769: TA and DLV
-            qtype_type = QR_QTYPE_TA + (qtype - 32768);
-        } else {
-            // qtype 32770..65535: (Unassigned, Private use, Reserved)
-            qtype_type = QR_QTYPE_OTHER;
-        }
-    }
-    server_qr_counter_.inc(qtype_type);
-    // OPCODE
-    server_qr_counter_.inc(QROpCodeToQRCounterType[qrattrs.req_opcode_]);
-
-    // response
-    if (qrattrs.answer_sent_) {
-        // responded
-        server_qr_counter_.inc(QR_RESPONSE);
-
-        // response truncated
-        if (qrattrs.res_is_truncated_) {
-            server_qr_counter_.inc(QR_RESPONSE_TRUNCATED);
-        }
-
-        // response EDNS
-        ConstEDNSPtr response_edns = response.getEDNS();
-        if (response_edns != NULL && response_edns->getVersion() == 0) {
-            server_qr_counter_.inc(QR_RESPONSE_EDNS0);
-        }
-
-        // response TSIG
-        if (qrattrs.req_is_tsig_) {
-            // assume response is TSIG signed if request is TSIG signed
-            server_qr_counter_.inc(QR_RESPONSE_TSIG);
-        }
-
-        // response SIG(0) is currently not implemented
-
-        // RCODE
-        const unsigned int rcode = response.getRcode().getCode();
-        unsigned int rcode_type = QR_RCODE_OTHER;
-        if (rcode < 23) {
-            // rcode 0..22: lookup rcode-countertype table
-            rcode_type = QRRCodeToQRCounterType[rcode];
-        } else {
-            // opcode larger than 22 is reserved or unassigned
-            rcode_type = QR_RCODE_OTHER;
-        }
-        server_qr_counter_.inc(rcode_type);
-
-        // compound attributes
-        const unsigned int answer_rrs =
-            response.getRRCount(Message::SECTION_ANSWER);
-        const bool is_aa_set = response.getHeaderFlag(Message::HEADERFLAG_AA);
-
-        if (is_aa_set) {
-            // QryAuthAns
-            server_qr_counter_.inc(QR_QRYAUTHANS);
-        } else {
-            // QryNoAuthAns
-            server_qr_counter_.inc(QR_QRYNOAUTHANS);
-        }
-
-        if (rcode == Rcode::NOERROR_CODE) {
-            if (answer_rrs > 0) {
-                // QrySuccess
-                server_qr_counter_.inc(QR_QRYSUCCESS);
-            } else {
-                if (is_aa_set) {
-                    // QryNxrrset
-                    server_qr_counter_.inc(QR_QRYNXRRSET);
-                } else {
-                    // QryReferral
-                    server_qr_counter_.inc(QR_QRYREFERRAL);
-                }
-            }
-        } else if (rcode == Rcode::REFUSED_CODE) {
-            // AuthRej
-            server_qr_counter_.inc(QR_QRYREJECT);
-        }
-    }
-}
-
-isc::data::ConstElementPtr
-CountersImpl::getStatistics() const {
-    std::stringstream statistics_string;
-    statistics_string << "{ \"queries.udp\": "
-                      << server_qr_counter_.get(QR_REQUEST_UDP)
-                      << ", \"queries.tcp\": "
-                      << server_qr_counter_.get(QR_REQUEST_TCP);
-    // Insert non 0 Opcode counters.
-    for (int i = QR_OPCODE_QUERY; i <= QR_OPCODE_OTHER; ++i) {
-        const Counter::Type counter = server_qr_counter_.get(i);
-        if (counter != 0) {
-            statistics_string << ", \"" << "opcode." <<
-                                 QRCounterOpcode[i - QR_OPCODE_QUERY].name <<
-                                 "\": " << counter;
-        }
-    }
-    // Insert non 0 Rcode counters.
-    for (int i = QR_RCODE_NOERROR; i <= QR_RCODE_OTHER; ++i) {
-        const Counter::Type counter = server_qr_counter_.get(i);
-        if (counter != 0) {
-            statistics_string << ", \"" << "rcode." <<
-                                 QRCounterRcode[i - QR_RCODE_NOERROR].name <<
-                                 "\": " << counter;
-        }
-    }
-    statistics_string << "}";
-
-    isc::data::ConstElementPtr statistics_element =
-        isc::data::Element::fromJSON(statistics_string);
-    // validate the statistics data before send
-    if (validator_) {
-        if (!validator_(statistics_element)) {
-            LOG_ERROR(auth_logger, AUTH_INVALID_STATISTICS_DATA);
-            return (isc::data::ElementPtr());
-        }
-    }
-    return (statistics_element);
-}
-
-void
-CountersImpl::registerStatisticsValidator
-    (Counters::validator_type validator)
-{
-    validator_ = validator;
-}
-
-Counters::Counters() : impl_(new CountersImpl())
-{}
-
-Counters::~Counters() {}
-
-void
-Counters::inc(const QRAttributes& qrattrs, const Message& response) {
-    impl_->inc(qrattrs, response);
-}
-
-isc::data::ConstElementPtr
-Counters::getStatistics() const {
-    return (impl_->getStatistics());
-}
-
-void
-Counters::registerStatisticsValidator
-    (Counters::validator_type validator) const
-{
-    return (impl_->registerStatisticsValidator(validator));
-}
-
-} // namespace statistics
-} // namespace auth
-} // namespace isc
diff --git a/src/bin/auth/statistics.cc.pre b/src/bin/auth/statistics.cc.pre
new file mode 100644
index 0000000..21141b0
--- /dev/null
+++ b/src/bin/auth/statistics.cc.pre
@@ -0,0 +1,277 @@
+// 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 <auth/statistics.h>
+#include <auth/statistics_items.h>
+#include <auth/auth_log.h>
+
+#include <cc/data.h>
+
+#include <dns/message.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+
+#include <statistics/counter.h>
+
+#include <boost/optional.hpp>
+
+using namespace isc::dns;
+using namespace isc::auth;
+using namespace isc::statistics;
+using namespace isc::auth::statistics;
+
+namespace {
+
+/// \brief Fill isc::data::ElementPtr with given counter.
+/// \param counter Counter which stores values to fill
+/// \param type_tree CounterSpec corresponding to counter for building item
+///                  name
+/// \param trees isc::data::ElementPtr to be filled in; caller has ownership of
+///              isc::data::ElementPtr
+void
+fillNodes(const Counter& counter,
+          const struct isc::auth::statistics::CounterSpec type_tree[],
+          isc::data::ElementPtr& trees)
+{
+    using namespace isc::data;
+
+    for (int i = 0; type_tree[i].name != NULL; ++i) {
+        if (type_tree[i].sub_counters != NULL) {
+            isc::data::ElementPtr sub_counters = Element::createMap();
+            trees->set(type_tree[i].name, sub_counters);
+            fillNodes(counter, type_tree[i].sub_counters, sub_counters);
+        } else {
+            trees->set(type_tree[i].name,
+                       Element::create(static_cast<long int>(
+                           counter.get(type_tree[i].counter_id)))
+                       );
+        }
+    }
+}
+
+// ### STATISTICS ITEMS DEFINITION ###
+
+} // anonymous namespace
+
+namespace isc {
+namespace auth {
+namespace statistics {
+
+// Note: opcode in this array must be start with 0 and be sequential
+const int opcode_to_msgcounter[] = {
+    MSG_OPCODE_QUERY,    // Opcode =  0: Query
+    MSG_OPCODE_IQUERY,   // Opcode =  1: IQuery
+    MSG_OPCODE_STATUS,   // Opcode =  2: Status
+    MSG_OPCODE_OTHER,    // Opcode =  3: (Unassigned)
+    MSG_OPCODE_NOTIFY,   // Opcode =  4: Notify
+    MSG_OPCODE_UPDATE,   // Opcode =  5: Update
+    MSG_OPCODE_OTHER,    // Opcode =  6: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode =  7: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode =  8: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode =  9: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode = 10: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode = 11: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode = 12: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode = 13: (Unassigned)
+    MSG_OPCODE_OTHER,    // Opcode = 14: (Unassigned)
+    MSG_OPCODE_OTHER     // Opcode = 15: (Unassigned)
+};
+const size_t num_opcode_to_msgcounter =
+    sizeof(opcode_to_msgcounter) / sizeof(opcode_to_msgcounter[0]);
+
+// Note: rcode in this array must be start with 0 and be sequential
+const int rcode_to_msgcounter[] = {
+    MSG_RCODE_NOERROR,       // Rcode =  0: NoError
+    MSG_RCODE_FORMERR,       // Rcode =  1: FormErr
+    MSG_RCODE_SERVFAIL,      // Rcode =  2: ServFail
+    MSG_RCODE_NXDOMAIN,      // Rcode =  3: NXDomain
+    MSG_RCODE_NOTIMP,        // Rcode =  4: NotImp
+    MSG_RCODE_REFUSED,       // Rcode =  5: Refused
+    MSG_RCODE_YXDOMAIN,      // Rcode =  6: YXDomain
+    MSG_RCODE_YXRRSET,       // Rcode =  7: YXRRSet
+    MSG_RCODE_NXRRSET,       // Rcode =  8: NXRRSet
+    MSG_RCODE_NOTAUTH,       // Rcode =  9: NotAuth
+    MSG_RCODE_NOTZONE,       // Rcode = 10: NotZone
+    MSG_RCODE_OTHER,         // Rcode = 11: (Unassigned)
+    MSG_RCODE_OTHER,         // Rcode = 12: (Unassigned)
+    MSG_RCODE_OTHER,         // Rcode = 13: (Unassigned)
+    MSG_RCODE_OTHER,         // Rcode = 14: (Unassigned)
+    MSG_RCODE_OTHER,         // Rcode = 15: (Unassigned)
+    MSG_RCODE_BADVERS        // Rcode = 16: BADVERS
+};
+const size_t num_rcode_to_msgcounter =
+    sizeof(rcode_to_msgcounter) / sizeof(rcode_to_msgcounter[0]);
+
+Counters::Counters() :
+    server_msg_counter_(MSG_COUNTER_TYPES)
+{}
+
+void
+Counters::incRequest(const MessageAttributes& msgattrs) {
+    // protocols carrying request
+    if (msgattrs.getRequestIPVersion() == AF_INET) {
+        server_msg_counter_.inc(MSG_REQUEST_IPV4);
+    } else if (msgattrs.getRequestIPVersion() == AF_INET6) {
+        server_msg_counter_.inc(MSG_REQUEST_IPV6);
+    }
+    if (msgattrs.getRequestTransportProtocol() == IPPROTO_UDP) {
+        server_msg_counter_.inc(MSG_REQUEST_UDP);
+    } else if (msgattrs.getRequestTransportProtocol() == IPPROTO_TCP) {
+        server_msg_counter_.inc(MSG_REQUEST_TCP);
+    }
+
+    // Opcode
+    const boost::optional<isc::dns::Opcode>& opcode =
+        msgattrs.getRequestOpCode();
+    // Increment opcode counter only if the opcode exists; opcode can be empty
+    // if a short message which does not contain DNS header is received, or
+    // a response message (i.e. QR bit is set) is received.
+    if (opcode) {
+        server_msg_counter_.inc(opcode_to_msgcounter[opcode.get().getCode()]);
+    }
+
+    // TSIG
+    if (msgattrs.requestHasTSIG()) {
+        server_msg_counter_.inc(MSG_REQUEST_TSIG);
+    }
+    if (msgattrs.requestHasBadSig()) {
+        server_msg_counter_.inc(MSG_REQUEST_BADSIG);
+        // If signature validation failed, no other request attributes (except
+        // for opcode) are reliable. Skip processing of the rest of request
+        // counters.
+        return;
+    }
+
+    // EDNS0
+    if (msgattrs.requestHasEDNS0()) {
+        server_msg_counter_.inc(MSG_REQUEST_EDNS0);
+    }
+
+    // DNSSEC OK bit
+    if (msgattrs.requestHasDO()) {
+        server_msg_counter_.inc(MSG_REQUEST_DNSSEC_OK);
+    }
+}
+
+void
+Counters::incResponse(const MessageAttributes& msgattrs,
+                      const Message& response)
+{
+    // responded
+    server_msg_counter_.inc(MSG_RESPONSE);
+
+    // response truncated
+    if (msgattrs.responseIsTruncated()) {
+        server_msg_counter_.inc(MSG_RESPONSE_TRUNCATED);
+    }
+
+    // response EDNS
+    ConstEDNSPtr response_edns = response.getEDNS();
+    if (response_edns && response_edns->getVersion() == 0) {
+        server_msg_counter_.inc(MSG_RESPONSE_EDNS0);
+    }
+
+    // response TSIG
+    if (msgattrs.responseHasTSIG()) {
+        server_msg_counter_.inc(MSG_RESPONSE_TSIG);
+    }
+
+    // response SIG(0) is currently not implemented
+
+    // RCODE
+    const unsigned int rcode = response.getRcode().getCode();
+    const unsigned int rcode_type =
+        rcode < num_rcode_to_msgcounter ?
+        rcode_to_msgcounter[rcode] : MSG_RCODE_OTHER;
+    server_msg_counter_.inc(rcode_type);
+    // Unsupported EDNS version
+    if (rcode == Rcode::BADVERS().getCode()) {
+        server_msg_counter_.inc(MSG_REQUEST_BADEDNSVER);
+    }
+
+    const boost::optional<isc::dns::Opcode>& opcode =
+        msgattrs.getRequestOpCode();
+    if (!opcode) {
+        isc_throw(isc::Unexpected, "Opcode of the request is empty while it is"
+                                   " responded");
+    }
+    if (!msgattrs.requestHasBadSig() && opcode.get() == Opcode::QUERY()) {
+        // compound attributes
+        const unsigned int answer_rrs =
+            response.getRRCount(Message::SECTION_ANSWER);
+        const bool is_aa_set =
+            response.getHeaderFlag(Message::HEADERFLAG_AA);
+
+        if (is_aa_set) {
+            // QryAuthAns
+            server_msg_counter_.inc(MSG_QRYAUTHANS);
+        } else {
+            // QryNoAuthAns
+            server_msg_counter_.inc(MSG_QRYNOAUTHANS);
+        }
+
+        if (rcode == Rcode::NOERROR_CODE) {
+            if (answer_rrs > 0) {
+                // QrySuccess
+                server_msg_counter_.inc(MSG_QRYSUCCESS);
+            } else {
+                if (is_aa_set) {
+                    // QryNxrrset
+                    server_msg_counter_.inc(MSG_QRYNXRRSET);
+                } else {
+                    // QryReferral
+                    server_msg_counter_.inc(MSG_QRYREFERRAL);
+                }
+            }
+        } else if (rcode == Rcode::REFUSED_CODE) {
+            if (!response.getHeaderFlag(Message::HEADERFLAG_RD)) {
+                // AuthRej
+                server_msg_counter_.inc(MSG_QRYREJECT);
+            }
+        }
+    }
+}
+
+void
+Counters::inc(const MessageAttributes& msgattrs, const Message& response,
+              const bool done)
+{
+    // increment request counters
+    incRequest(msgattrs);
+
+    if (done) {
+        // increment response counters if answer was sent
+        incResponse(msgattrs, response);
+    }
+}
+
+Counters::ConstItemTreePtr
+Counters::get() const {
+    using namespace isc::data;
+
+    isc::data::ElementPtr item_tree = Element::createMap();
+
+    isc::data::ElementPtr zones = Element::createMap();
+    item_tree->set("zones", zones);
+
+    isc::data::ElementPtr server = Element::createMap();
+    fillNodes(server_msg_counter_, msg_counter_tree, server);
+    zones->set("_SERVER_", server);
+
+    return (item_tree);
+}
+
+} // namespace statistics
+} // namespace auth
+} // namespace isc
diff --git a/src/bin/auth/statistics.h b/src/bin/auth/statistics.h
index d60c681..52f9bad 100644
--- a/src/bin/auth/statistics.h
+++ b/src/bin/auth/statistics.h
@@ -15,208 +15,289 @@
 #ifndef STATISTICS_H
 #define STATISTICS_H 1
 
-#include <cc/session.h>
 #include <cc/data.h>
 
 #include <dns/message.h>
+#include <dns/opcode.h>
 
-#include <string>
+#include <statistics/counter.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/optional.hpp>
+
+#include <bitset>
 
 #include <stdint.h>
-#include <boost/scoped_ptr.hpp>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
 
 namespace isc {
 namespace auth {
 namespace statistics {
 
-class CountersImpl;
-
-class QRAttributes {
-/// \brief Query/Response attributes for statistics.
+/// \brief DNS Message attributes for statistics.
 ///
-/// This class holds some attributes related to a query/response
+/// This class holds some attributes related to a DNS message
 /// for statistics data collection.
-///
-/// This class does not have getter methods since it exposes private members
-/// to \c CountersImpl directly.
-friend class CountersImpl;
+class MessageAttributes {
+public:
+    /// \brief IP version of DNS message.
+    enum IPVersionType {
+        IP_VERSION_UNSPEC,          // (initial value; internal use only)
+        IP_VERSION_IPV4,            ///< IPv4 message
+        IP_VERSION_IPV6             ///< IPv6 message
+    };
+
+    /// \brief Transport protocol of DNS message.
+    enum TransportProtocolType {
+        TRANSPORT_UNSPEC,           // (initial value; internal use only)
+        TRANSPORT_UDP,              ///< UDP message
+        TRANSPORT_TCP               ///< TCP message
+    };
 private:
     // request attributes
-    int req_ip_version_;            // IP version
+    int req_address_family_;        // IP version
     int req_transport_protocol_;    // Transport layer protocol
-    int req_opcode_;                // OpCode
-    bool req_is_edns_0_;            // EDNS ver.0
-    bool req_is_edns_badver_;       // other EDNS version
-    bool req_is_dnssec_ok_;         // DO bit
-    bool req_is_tsig_;              // signed with valid TSIG
-    bool req_is_sig0_;              // signed with valid SIG(0)
-    bool req_is_badsig_;            // signed but bad signature
-    // zone origin
-    std::string zone_origin_;       // zone origin
-    // response attributes
-    bool answer_sent_;              // DNS message has sent
-    bool res_is_truncated_;         // DNS message is truncated
+    boost::optional<isc::dns::Opcode> req_opcode_;  // OpCode
+    enum BitAttributes {
+        REQ_WITH_EDNS_0,            // request with EDNS ver.0
+        REQ_WITH_DNSSEC_OK,         // DNSSEC OK (DO) bit is set in request
+        REQ_TSIG_SIGNED,            // request is signed with valid TSIG
+        REQ_BADSIG,                 // request is signed but bad signature
+        RES_IS_TRUNCATED,           // response is truncated
+        RES_TSIG_SIGNED,            // response is signed with TSIG
+        BIT_ATTRIBUTES_TYPES
+    };
+    std::bitset<BIT_ATTRIBUTES_TYPES> bit_attributes_;
 public:
-    /// The constructor.
+    /// \brief The constructor.
     ///
-    /// This constructor is mostly exception free. But it may still throw
-    /// a standard exception if memory allocation fails inside the method.
-    ///
-    QRAttributes() {
-        reset();
-    };
+    /// \throw None
+    MessageAttributes() : req_address_family_(0), req_transport_protocol_(0)
+    {}
 
-    /// The destructor.
+    /// \brief Return opcode of the request.
     ///
-    /// This method never throws an exception.
+    /// \return opcode of the request wrapped with boost::optional; it's
+    ///         converted to false if Opcode hasn't been set.
+    /// \throw None
+    const boost::optional<isc::dns::Opcode>& getRequestOpCode() const {
+        return (req_opcode_);
+    }
+
+    /// \brief Set opcode of the request.
     ///
-    ~QRAttributes() {};
-    /// \brief Set query opcode.
+    /// \param opcode Opcode of the request
     /// \throw None
-    void setQueryOpCode(const int opcode) {
+    void setRequestOpCode(const isc::dns::Opcode& opcode) {
         req_opcode_ = opcode;
-    };
-    /// \brief Set IP version carrying a query.
+    }
+
+    /// \brief Get IP version carrying a request.
+    ///
+    /// \return IP address family carrying a request (AF_INET or AF_INET6)
     /// \throw None
-    void setQueryIPVersion(const int ip_version) {
-        req_ip_version_ = ip_version;
-    };
-    /// \brief Set transport protocol carrying a query.
+    int getRequestIPVersion() const {
+        return (req_address_family_);
+    }
+
+    /// \brief Set IP address family carrying a request.
+    ///
+    /// \param address_family AF_INET or AF_INET6
+    /// \throw None
+    void setRequestIPVersion(const int address_family) {
+        if (address_family != AF_INET && address_family != AF_INET6) {
+            isc_throw(isc::InvalidParameter, "Unknown address family");
+        }
+        req_address_family_ = address_family;
+    }
+
+    /// \brief Get transport protocol carrying a request.
+    ///
+    /// \return Transport protocol carrying a request
+    ///         (IPPROTO_UDP or IPPROTO_TCP)
     /// \throw None
-    void setQueryTransportProtocol(const int transport_protocol) {
+    int getRequestTransportProtocol() const {
+        return (req_transport_protocol_);
+    }
+
+    /// \brief Set transport protocol carrying a request.
+    ///
+    /// \param transport_protocol IPPROTO_UDP or IPPROTO_TCP
+    /// \throw None
+    void setRequestTransportProtocol(const int transport_protocol) {
+        if (transport_protocol != IPPROTO_UDP &&
+            transport_protocol != IPPROTO_TCP)
+        {
+            isc_throw(isc::InvalidParameter, "Unknown transport protocol");
+        }
         req_transport_protocol_ = transport_protocol;
-    };
-    /// \brief Set query EDNS attributes.
+    }
+
+    /// \brief Return whether EDNS version of the request is 0 or not.
+    ///
+    /// \return true if EDNS version of the request is 0
     /// \throw None
-    void setQueryEDNS(const bool is_edns_0, const bool is_edns_badver) {
-        req_is_edns_0_ = is_edns_0;
-        req_is_edns_badver_ = is_edns_badver;
-    };
-    /// \brief Set query DO bit.
+    bool requestHasEDNS0() const {
+        return (bit_attributes_[REQ_WITH_EDNS_0]);
+    }
+
+    /// \brief Set whether EDNS version of the request is 0 or not.
+    ///
+    /// \param with_edns_0 true if EDNS version of the request is 0
     /// \throw None
-    void setQueryDO(const bool is_dnssec_ok) {
-        req_is_dnssec_ok_ = is_dnssec_ok;
-    };
-    /// \brief Set query TSIG attributes.
-    /// \throw None
-    void setQuerySig(const bool is_tsig, const bool is_sig0,
-                            const bool is_badsig)
-    {
-        req_is_tsig_ = is_tsig;
-        req_is_sig0_ = is_sig0;
-        req_is_badsig_ = is_badsig;
-    };
-    /// \brief Set zone origin.
+    void setRequestEDNS0(const bool with_edns_0) {
+        bit_attributes_[REQ_WITH_EDNS_0] = with_edns_0;
+    }
+
+    /// \brief Return DNSSEC OK (DO) bit of the request.
+    ///
+    /// \return true if DNSSEC OK (DO) bit of the request is set
     /// \throw None
-    void setOrigin(const std::string& origin) {
-        zone_origin_ = origin;
-    };
-    /// \brief Set if the answer was sent.
+    bool requestHasDO() const {
+        return (bit_attributes_[REQ_WITH_DNSSEC_OK]);
+    }
+
+    /// \brief Set DNSSEC OK (DO) bit of the request.
+    ///
+    /// \param with_dnssec_ok true if DNSSEC OK (DO) bit of the request is set
     /// \throw None
-    void answerWasSent() {
-        answer_sent_ = true;
-    };
-    /// \brief Set if the response is truncated.
+    void setRequestDO(const bool with_dnssec_ok) {
+        bit_attributes_[REQ_WITH_DNSSEC_OK] = with_dnssec_ok;
+    }
+
+    /// \brief Return whether the request is TSIG signed or not.
+    ///
+    /// \return true if the request is TSIG signed
+    /// \throw None
+    bool requestHasTSIG() const {
+        return (bit_attributes_[REQ_TSIG_SIGNED]);
+    }
+
+    /// \brief Return whether the signature of the request is bad or not.
+    ///
+    /// \return true if the signature of the request is bad
+    /// \throw None
+    bool requestHasBadSig() const {
+        return (bit_attributes_[REQ_BADSIG]);
+    }
+
+    /// \brief Set TSIG attributes of the request.
+    ///
+    /// \param signed_tsig true if the request is signed with TSIG
+    /// \param badsig true if the signature of the request is bad; it must not
+    //                be true unless signed_tsig is true
+    /// \throw isc::InvalidParameter if badsig is true though the request is
+    ///                              not signed
+    void setRequestTSIG(const bool signed_tsig, const bool badsig) {
+        if (!signed_tsig && badsig) {
+            isc_throw(isc::InvalidParameter, "Message is not signed but badsig"
+                                             " is true");
+        }
+        bit_attributes_[REQ_TSIG_SIGNED] = signed_tsig;
+        bit_attributes_[REQ_BADSIG] = badsig;
+    }
+
+    /// \brief Return TC (truncated) bit of the response.
+    ///
+    /// \return true if the response is truncated
+    /// \throw None
+    bool responseIsTruncated() const {
+        return (bit_attributes_[RES_IS_TRUNCATED]);
+    }
+
+    /// \brief Set TC (truncated) bit of the response.
+    ///
+    /// \param is_truncated true if the response is truncated
     /// \throw None
     void setResponseTruncated(const bool is_truncated) {
-        res_is_truncated_ = is_truncated;
-    };
-    /// \brief Reset attributes.
-    /// \throw None
-    void reset() {
-        req_ip_version_ = 0;
-        req_transport_protocol_ = 0;
-        req_opcode_ = 0;
-        req_is_edns_0_ = false;
-        req_is_edns_badver_ = false;
-        req_is_dnssec_ok_ = false;
-        req_is_tsig_ = false;
-        req_is_sig0_ = false;
-        req_is_badsig_ = false;
-        zone_origin_.clear();
-        answer_sent_ = false;
-        res_is_truncated_ = false;
-    };
+        bit_attributes_[RES_IS_TRUNCATED] = is_truncated;
+    }
+
+    /// \brief Return whether the response is TSIG signed or not.
+    ///
+    /// \return true if the response is signed with TSIG
+    /// \throw None
+    bool responseHasTSIG() const {
+        return (bit_attributes_[RES_TSIG_SIGNED]);
+    }
+
+    /// \brief Set whether the response is TSIG signed or not.
+    ///
+    /// \param signed_tsig true if the response is signed with TSIG
+    /// \throw None
+    void setResponseTSIG(const bool signed_tsig) {
+        bit_attributes_[RES_TSIG_SIGNED] = signed_tsig;
+    }
 };
 
-/// \brief Set of query counters.
+/// \brief Set of DNS message counters.
 ///
-/// \c Counters is set of query counters class. It holds query counters
-/// and provides an interface to increment the counter of specified type
-/// (e.g. UDP query, TCP query).
-///
-/// This class also provides a function to send statistics information to
-/// statistics module.
+/// \c Counters is a set of DNS message counters class. It holds DNS message
+/// counters and provides an interface to increment the counter of specified
+/// type (e.g. UDP message, TCP message).
 ///
 /// This class is designed to be a part of \c AuthSrv.
-/// Call \c inc() to increment a counter for the query.
-/// Call \c getStatistics() to answer statistics information to statistics
-/// module with statistics_session, when the command \c getstats is received.
+/// Call \c inc() to increment a counter for the message.
+/// Call \c get() to get a set of DNS message counters.
 ///
 /// We may eventually want to change the structure to hold values that are
 /// not counters (such as concurrent TCP connections), or seperate generic
 /// part to src/lib to share with the other modules.
 ///
-/// This class uses pimpl idiom and hides detailed implementation.
 /// This class is constructed on startup of the server, so
 /// construction overhead of this approach should be acceptable.
 ///
-/// \todo Hold counters for each query types (Notify, Axfr, Ixfr, Normal)
 /// \todo Consider overhead of \c Counters::inc()
-class Counters {
+class Counters : boost::noncopyable {
 private:
-    boost::scoped_ptr<CountersImpl> impl_;
+    // counter for DNS message attributes
+    isc::statistics::Counter server_msg_counter_;
+    void incRequest(const MessageAttributes& msgattrs);
+    void incResponse(const MessageAttributes& msgattrs,
+                     const isc::dns::Message& response);
 public:
-    /// The constructor.
+    /// \brief A type of statistics item tree in isc::data::MapElement.
+    /// \verbatim
+    ///        {
+    ///          zone_name => {
+    ///                         item_name => item_value,
+    ///                         item_name => item_value, ...
+    ///                       },
+    ///          ...
+    ///        }
+    ///        item_name is a string seperated by '.'.
+    ///        item_value is an integer.
+    /// \endverbatim
+    typedef isc::data::ConstElementPtr ConstItemTreePtr;
+
+    /// \brief The constructor.
     ///
     /// This constructor is mostly exception free. But it may still throw
     /// a standard exception if memory allocation fails inside the method.
-    ///
     Counters();
-    /// The destructor.
-    ///
-    /// This method never throws an exception.
-    ///
-    ~Counters();
 
     /// \brief Increment counters according to the parameters.
     ///
-    /// \param qrattrs Query/Response attributes.
+    /// \param msgattrs DNS message attributes.
     /// \param response DNS response message.
-    ///
-    /// \throw None
-    ///
-    void inc(const QRAttributes& qrattrs, const isc::dns::Message& response);
+    /// \param done DNS response was sent to the client.
+    /// \throw isc::Unexpected Internal condition check failed.
+    void inc(const MessageAttributes& msgattrs,
+             const isc::dns::Message& response, const bool done);
 
-    /// \brief Answers statistics counters to statistics module.
+    /// \brief Get statistics counters.
     ///
-    /// This method is mostly exception free (error conditions are
-    /// represented via the return value). But it may still throw
-    /// a standard exception if memory allocation fails inside the method.
+    /// This method is mostly exception free. But it may still throw a
+    /// standard exception if memory allocation fails inside the method.
     ///
     /// \return statistics data
-    ///
-    isc::data::ConstElementPtr getStatistics() const;
-
-    /// \brief A type of validation function for the specification in
-    /// isc::config::ModuleSpec.
-    ///
-    /// This type might be useful for not only statistics
-    /// specificatoin but also for config_data specification and for
-    /// commnad.
-    ///
-    typedef boost::function<bool(const isc::data::ConstElementPtr&)>
-    validator_type;
-
-    /// \brief Register a function type of the statistics validation
-    /// function for Counters.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param validator A function type of the validation of
-    /// statistics specification.
-    ///
-    void registerStatisticsValidator(Counters::validator_type validator) const;
+    /// \throw std::bad_alloc Internal resource allocation fails
+    ConstItemTreePtr get() const;
 };
 
 } // namespace statistics
diff --git a/src/bin/auth/statistics_items.h b/src/bin/auth/statistics_items.h
deleted file mode 100644
index 5839206..0000000
--- a/src/bin/auth/statistics_items.h
+++ /dev/null
@@ -1,609 +0,0 @@
-// Copyright (C) 2012  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 __STATISTICS_ITEMS_H
-#define __STATISTICS_ITEMS_H 1
-
-/// This file defines a set of statistics items in Auth module for internal
-/// use. This file is intended to be included in statistics.cc.
-
-namespace {
-
-struct CounterTypeTree {
-    const char* const name;
-    const struct CounterTypeTree* const sub_tree;
-    const int counter_id;
-};
-
-// enum for query/response counters
-enum QRCounterType {
-    // Request Attributes
-    QR_REQUEST_IPV4,        ///< Number of IPv4 requests received
-    QR_REQUEST_IPV6,        ///< Number of IPv6 requests received
-    QR_REQUEST_EDNS0,       ///< Number of requests with EDNS(0) received
-    QR_REQUEST_BADEDNSVER,  ///< Number of requests with unsupported EDNS version received
-    QR_REQUEST_TSIG,        ///< Number of requests with TSIG received
-    QR_REQUEST_SIG0,        ///< Number of requests with SIG(0) received; not implemented in BIND 10
-    QR_REQUEST_BADSIG,      ///< Number of requests with invalid TSIG or SIG(0) signature received
-    QR_REQUEST_UDP,         ///< Number of UDP requests received
-    QR_REQUEST_TCP,         ///< Number of TCP requests received
-    QR_REQUEST_DNSSEC_OK,   ///< Number of requests with DO bit
-    // Request Opcodes
-    QR_OPCODE_QUERY,        ///< Number of Opcode=QUERY requests received
-    QR_OPCODE_IQUERY,       ///< Number of Opcode=IQUERY requests received
-    QR_OPCODE_STATUS,       ///< Number of Opcode=STATUS requests received
-    QR_OPCODE_NOTIFY,       ///< Number of Opcode=NOTIFY requests received
-    QR_OPCODE_UPDATE,       ///< Number of Opcode=UPDATE requests received
-    QR_OPCODE_OTHER,        ///< Number of requests in other OpCode received
-    // Query Types
-    QR_QTYPE_A,             ///< Number of QTYPE = A queries received
-    QR_QTYPE_NS,            ///< Number of QTYPE = NS queries received
-    QR_QTYPE_MD,            ///< Number of QTYPE = MD queries received
-    QR_QTYPE_MF,            ///< Number of QTYPE = MF queries received
-    QR_QTYPE_CNAME,         ///< Number of QTYPE = CNAME queries received
-    QR_QTYPE_SOA,           ///< Number of QTYPE = SOA queries received
-    QR_QTYPE_MB,            ///< Number of QTYPE = MB queries received
-    QR_QTYPE_MG,            ///< Number of QTYPE = MG queries received
-    QR_QTYPE_MR,            ///< Number of QTYPE = MR queries received
-    QR_QTYPE_NULL,          ///< Number of QTYPE = NULL queries received
-    QR_QTYPE_WKS,           ///< Number of QTYPE = WKS queries received
-    QR_QTYPE_PTR,           ///< Number of QTYPE = PTR queries received
-    QR_QTYPE_HINFO,         ///< Number of QTYPE = HINFO queries received
-    QR_QTYPE_MINFO,         ///< Number of QTYPE = MINFO queries received
-    QR_QTYPE_MX,            ///< Number of QTYPE = MX queries received
-    QR_QTYPE_TXT,           ///< Number of QTYPE = TXT queries received
-    QR_QTYPE_RP,            ///< Number of QTYPE = RP queries received
-    QR_QTYPE_AFSDB,         ///< Number of QTYPE = AFSDB queries received
-    QR_QTYPE_X25,           ///< Number of QTYPE = X25 queries received
-    QR_QTYPE_ISDN,          ///< Number of QTYPE = ISDN queries received
-    QR_QTYPE_RT,            ///< Number of QTYPE = RT queries received
-    QR_QTYPE_NSAP,          ///< Number of QTYPE = NSAP queries received
-    QR_QTYPE_NSAP_PTR,      ///< Number of QTYPE = NSAP-PTR queries received
-    QR_QTYPE_SIG,           ///< Number of QTYPE = SIG queries received
-    QR_QTYPE_KEY,           ///< Number of QTYPE = KEY queries received
-    QR_QTYPE_PX,            ///< Number of QTYPE = PX queries received
-    QR_QTYPE_GPOS,          ///< Number of QTYPE = GPOS queries received
-    QR_QTYPE_AAAA,          ///< Number of QTYPE = AAAA queries received
-    QR_QTYPE_LOC,           ///< Number of QTYPE = LOC queries received
-    QR_QTYPE_NXT,           ///< Number of QTYPE = NXT queries received
-    QR_QTYPE_EID,           ///< Number of QTYPE = EID queries received
-    QR_QTYPE_NIMLOC,        ///< Number of QTYPE = NIMLOC queries received
-    QR_QTYPE_SRV,           ///< Number of QTYPE = SRV queries received
-    QR_QTYPE_ATMA,          ///< Number of QTYPE = ATMA queries received
-    QR_QTYPE_NAPTR,         ///< Number of QTYPE = NAPTR queries received
-    QR_QTYPE_KX,            ///< Number of QTYPE = KX queries received
-    QR_QTYPE_CERT,          ///< Number of QTYPE = CERT queries received
-    QR_QTYPE_A6,            ///< Number of QTYPE = A6 queries received
-    QR_QTYPE_DNAME,         ///< Number of QTYPE = DNAME queries received
-    QR_QTYPE_SINK,          ///< Number of QTYPE = SINK queries received
-    QR_QTYPE_OPT,           ///< Number of QTYPE = OPT queries received
-    QR_QTYPE_APL,           ///< Number of QTYPE = APL queries received
-    QR_QTYPE_DS,            ///< Number of QTYPE = DS queries received
-    QR_QTYPE_SSHFP,         ///< Number of QTYPE = SSHFP queries received
-    QR_QTYPE_IPSECKEY,      ///< Number of QTYPE = IPSECKEY queries received
-    QR_QTYPE_RRSIG,         ///< Number of QTYPE = RRSIG queries received
-    QR_QTYPE_NSEC,          ///< Number of QTYPE = NSEC queries received
-    QR_QTYPE_DNSKEY,        ///< Number of QTYPE = DNSKEY queries received
-    QR_QTYPE_DHCID,         ///< Number of QTYPE = DHCID queries received
-    QR_QTYPE_NSEC3,         ///< Number of QTYPE = NSEC3 queries received
-    QR_QTYPE_NSEC3PARAM,    ///< Number of QTYPE = NSEC3PARAM queries received
-    QR_QTYPE_HIP,           ///< Number of QTYPE = HIP queries received
-    QR_QTYPE_NINFO,         ///< Number of QTYPE = NINFO queries received
-    QR_QTYPE_RKEY,          ///< Number of QTYPE = RKEY queries received
-    QR_QTYPE_TALINK,        ///< Number of QTYPE = TALINK queries received
-    QR_QTYPE_SPF,           ///< Number of QTYPE = SPF queries received
-    QR_QTYPE_UINFO,         ///< Number of QTYPE = UINFO queries received
-    QR_QTYPE_UID,           ///< Number of QTYPE = UID queries received
-    QR_QTYPE_GID,           ///< Number of QTYPE = GID queries received
-    QR_QTYPE_UNSPEC,        ///< Number of QTYPE = UNSPEC queries received
-    QR_QTYPE_TKEY,          ///< Number of QTYPE = TKEY queries received
-    QR_QTYPE_TSIG,          ///< Number of QTYPE = TSIG queries received
-    QR_QTYPE_IXFR,          ///< Number of QTYPE = IXFR queries received
-    QR_QTYPE_AXFR,          ///< Number of QTYPE = AXFR queries received
-    QR_QTYPE_MAILB,         ///< Number of QTYPE = MAILB queries received
-    QR_QTYPE_MAILA,         ///< Number of QTYPE = MAILA queries received
-    QR_QTYPE_URI,           ///< Number of QTYPE = URI queries received
-    QR_QTYPE_CAA,           ///< Number of QTYPE = CAA queries received
-    QR_QTYPE_TA,            ///< Number of QTYPE = TA queries received
-    QR_QTYPE_DLV,           ///< Number of QTYPE = DLV queries received
-    QR_QTYPE_OTHER,         ///< Number of queries in other QTYPE received
-    // Respose Attributes
-    QR_RESPONSE,            ///< Number of responses sent
-    QR_RESPONSE_TRUNCATED,  ///< Number of truncated responses sent
-    QR_RESPONSE_EDNS0,      ///< Number of responses with EDNS0; not implemented in BIND 10
-    QR_RESPONSE_TSIG,       ///< Number of responses with TSIG
-    QR_RESPONSE_SIG0,       ///< Number of responses with SIG(0); not implemented in BIND 10
-    QR_QRYSUCCESS,          ///< Number of queries resulted in rcode = NOERROR and answer RR >= 1
-    QR_QRYAUTHANS,          ///< Number of queries resulted in authoritative answer
-    QR_QRYNOAUTHANS,        ///< Number of queries resulted in non-authoritative answer
-    QR_QRYREFERRAL,         ///< Number of queries resulted in referral answer
-    QR_QRYNXRRSET,          ///< Number of queries resulted in NOERROR but answer RR == 0
-    QR_QRYREJECT,           ///< Number of queries rejected
-    // Response Rcodes
-    QR_RCODE_NOERROR,       ///< Number of queries resulted in RCODE = 0 (NoError)
-    QR_RCODE_FORMERR,       ///< Number of queries resulted in RCODE = 1 (FormErr)
-    QR_RCODE_SERVFAIL,      ///< Number of queries resulted in RCODE = 2 (ServFail)
-    QR_RCODE_NXDOMAIN,      ///< Number of queries resulted in RCODE = 3 (NXDomain)
-    QR_RCODE_NOTIMP,        ///< Number of queries resulted in RCODE = 4 (NotImp)
-    QR_RCODE_REFUSED,       ///< Number of queries resulted in RCODE = 5 (Refused)
-    QR_RCODE_YXDOMAIN,      ///< Number of queries resulted in RCODE = 6 (YXDomain)
-    QR_RCODE_YXRRSET,       ///< Number of queries resulted in RCODE = 7 (YXRRSet)
-    QR_RCODE_NXRRSET,       ///< Number of queries resulted in RCODE = 8 (NXRRSet)
-    QR_RCODE_NOTAUTH,       ///< Number of queries resulted in RCODE = 9 (NotAuth)
-    QR_RCODE_NOTZONE,       ///< Number of queries resulted in RCODE = 10 (NotZone)
-    QR_RCODE_BADSIGVERS,    ///< Number of queries resulted in RCODE = 16 (BADVERS, BADSIG)
-    QR_RCODE_BADKEY,        ///< Number of queries resulted in RCODE = 17 (BADKEY)
-    QR_RCODE_BADTIME,       ///< Number of queries resulted in RCODE = 18 (BADTIME)
-    QR_RCODE_BADMODE,       ///< Number of queries resulted in RCODE = 19 (BADMODE)
-    QR_RCODE_BADNAME,       ///< Number of queries resulted in RCODE = 20 (BADNAME)
-    QR_RCODE_BADALG,        ///< Number of queries resulted in RCODE = 21 (BADALG)
-    QR_RCODE_BADTRUNC,      ///< Number of queries resulted in RCODE = 22 (BADTRUNC)
-    QR_RCODE_OTHER,         ///< Number of queries resulted in other RCODEs
-    // End of counter types
-    QR_COUNTER_TYPES  ///< The number of defined counters
-};
-
-// item names for query/response counters
-const struct CounterTypeTree QRCounterRequest[] = {
-    { "v4",         NULL,   QR_REQUEST_IPV4       },
-    { "v6",         NULL,   QR_REQUEST_IPV6       },
-    { "edns0",      NULL,   QR_REQUEST_EDNS0      },
-    { "badednsver", NULL,   QR_REQUEST_BADEDNSVER },
-    { "tsig",       NULL,   QR_REQUEST_TSIG       },
-    { "sig0",       NULL,   QR_REQUEST_SIG0       },
-    { "badsig",     NULL,   QR_REQUEST_BADSIG     },
-    { "udp",        NULL,   QR_REQUEST_UDP        },
-    { "tcp",        NULL,   QR_REQUEST_TCP        },
-    { "dnssec_ok",  NULL,   QR_REQUEST_DNSSEC_OK  },
-    { NULL,         NULL,   -1                    }
-};
-const struct CounterTypeTree QRCounterOpcode[] = {
-    { "query",  NULL,   QR_OPCODE_QUERY  },
-    { "iquery", NULL,   QR_OPCODE_IQUERY },
-    { "status", NULL,   QR_OPCODE_STATUS },
-    { "notify", NULL,   QR_OPCODE_NOTIFY },
-    { "update", NULL,   QR_OPCODE_UPDATE },
-    { "other",  NULL,   QR_OPCODE_OTHER  },
-    { NULL,     NULL,   -1               }
-};
-const struct CounterTypeTree QRCounterQtype[] = {
-    { "a",          NULL,   QR_QTYPE_A,         },
-    { "ns",         NULL,   QR_QTYPE_NS         },
-    { "md",         NULL,   QR_QTYPE_MD         },
-    { "mf",         NULL,   QR_QTYPE_MF         },
-    { "cname",      NULL,   QR_QTYPE_CNAME      },
-    { "soa",        NULL,   QR_QTYPE_SOA        },
-    { "mb",         NULL,   QR_QTYPE_MB         },
-    { "mg",         NULL,   QR_QTYPE_MG         },
-    { "mr",         NULL,   QR_QTYPE_MR         },
-    { "null",       NULL,   QR_QTYPE_NULL       },
-    { "wks",        NULL,   QR_QTYPE_WKS        },
-    { "ptr",        NULL,   QR_QTYPE_PTR        },
-    { "hinfo",      NULL,   QR_QTYPE_HINFO      },
-    { "minfo",      NULL,   QR_QTYPE_MINFO      },
-    { "mx",         NULL,   QR_QTYPE_MX         },
-    { "txt",        NULL,   QR_QTYPE_TXT        },
-    { "rp",         NULL,   QR_QTYPE_RP         },
-    { "afsdb",      NULL,   QR_QTYPE_AFSDB      },
-    { "x25",        NULL,   QR_QTYPE_X25        },
-    { "isdn",       NULL,   QR_QTYPE_ISDN       },
-    { "rt",         NULL,   QR_QTYPE_RT         },
-    { "nsap",       NULL,   QR_QTYPE_NSAP       },
-    { "nsap-ptr",   NULL,   QR_QTYPE_NSAP_PTR   },
-    { "sig",        NULL,   QR_QTYPE_SIG        },
-    { "key",        NULL,   QR_QTYPE_KEY        },
-    { "px",         NULL,   QR_QTYPE_PX         },
-    { "gpos",       NULL,   QR_QTYPE_GPOS       },
-    { "aaaa",       NULL,   QR_QTYPE_AAAA       },
-    { "loc",        NULL,   QR_QTYPE_LOC        },
-    { "nxt",        NULL,   QR_QTYPE_NXT        },
-    { "eid",        NULL,   QR_QTYPE_EID        },
-    { "nimloc",     NULL,   QR_QTYPE_NIMLOC     },
-    { "srv",        NULL,   QR_QTYPE_SRV        },
-    { "atma",       NULL,   QR_QTYPE_ATMA       },
-    { "naptr",      NULL,   QR_QTYPE_NAPTR      },
-    { "kx",         NULL,   QR_QTYPE_KX         },
-    { "cert",       NULL,   QR_QTYPE_CERT       },
-    { "a6",         NULL,   QR_QTYPE_A6         },
-    { "dname",      NULL,   QR_QTYPE_DNAME      },
-    { "sink",       NULL,   QR_QTYPE_SINK       },
-    { "opt",        NULL,   QR_QTYPE_OPT        },
-    { "apl",        NULL,   QR_QTYPE_APL        },
-    { "ds",         NULL,   QR_QTYPE_DS         },
-    { "sshfp",      NULL,   QR_QTYPE_SSHFP      },
-    { "ipseckey",   NULL,   QR_QTYPE_IPSECKEY   },
-    { "rrsig",      NULL,   QR_QTYPE_RRSIG      },
-    { "nsec",       NULL,   QR_QTYPE_NSEC       },
-    { "dnskey",     NULL,   QR_QTYPE_DNSKEY     },
-    { "dhcid",      NULL,   QR_QTYPE_DHCID      },
-    { "nsec3",      NULL,   QR_QTYPE_NSEC3      },
-    { "nsec3param", NULL,   QR_QTYPE_NSEC3PARAM },
-    { "hip",        NULL,   QR_QTYPE_HIP        },
-    { "ninfo",      NULL,   QR_QTYPE_NINFO      },
-    { "rkey",       NULL,   QR_QTYPE_RKEY       },
-    { "talink",     NULL,   QR_QTYPE_TALINK     },
-    { "spf",        NULL,   QR_QTYPE_SPF        },
-    { "uinfo",      NULL,   QR_QTYPE_UINFO      },
-    { "uid",        NULL,   QR_QTYPE_UID        },
-    { "gid",        NULL,   QR_QTYPE_GID        },
-    { "unspec",     NULL,   QR_QTYPE_UNSPEC     },
-    { "tkey",       NULL,   QR_QTYPE_TKEY       },
-    { "tsig",       NULL,   QR_QTYPE_TSIG       },
-    { "ixfr",       NULL,   QR_QTYPE_IXFR       },
-    { "axfr",       NULL,   QR_QTYPE_AXFR       },
-    { "mailb",      NULL,   QR_QTYPE_MAILB      },
-    { "maila",      NULL,   QR_QTYPE_MAILA      },
-    { "uri",        NULL,   QR_QTYPE_URI        },
-    { "caa",        NULL,   QR_QTYPE_CAA        },
-    { "ta",         NULL,   QR_QTYPE_TA         },
-    { "dlv",        NULL,   QR_QTYPE_DLV        },
-    { "other",      NULL,   QR_QTYPE_OTHER      },
-    { NULL,         NULL,   -1                  }
-};
-const struct CounterTypeTree QRCounterResponse[] = {
-    { "truncated",  NULL,   QR_RESPONSE_TRUNCATED },
-    { "edns0",      NULL,   QR_RESPONSE_EDNS0     },
-    { "tsig",       NULL,   QR_RESPONSE_TSIG      },
-    { "sig0",       NULL,   QR_RESPONSE_SIG0      },
-    { NULL,         NULL,   -1                    }
-};
-const struct CounterTypeTree QRCounterRcode[] = {
-    { "noerror",    NULL,   QR_RCODE_NOERROR    },
-    { "formerr",    NULL,   QR_RCODE_FORMERR    },
-    { "servfail",   NULL,   QR_RCODE_SERVFAIL   },
-    { "nxdomain",   NULL,   QR_RCODE_NXDOMAIN   },
-    { "notimp",     NULL,   QR_RCODE_NOTIMP     },
-    { "refused",    NULL,   QR_RCODE_REFUSED    },
-    { "yxdomain",   NULL,   QR_RCODE_YXDOMAIN   },
-    { "yxrrset",    NULL,   QR_RCODE_YXRRSET    },
-    { "nxrrset",    NULL,   QR_RCODE_NXRRSET    },
-    { "notauth",    NULL,   QR_RCODE_NOTAUTH    },
-    { "notzone",    NULL,   QR_RCODE_NOTZONE    },
-    { "badsigvers", NULL,   QR_RCODE_BADSIGVERS },
-    { "badkey",     NULL,   QR_RCODE_BADKEY     },
-    { "badtime",    NULL,   QR_RCODE_BADTIME    },
-    { "badmode",    NULL,   QR_RCODE_BADMODE    },
-    { "badname",    NULL,   QR_RCODE_BADNAME    },
-    { "badalg",     NULL,   QR_RCODE_BADALG     },
-    { "badtrunc",   NULL,   QR_RCODE_BADTRUNC   },
-    { "other",      NULL,   QR_RCODE_OTHER      },
-    { NULL,         NULL,   -1 }
-};
-const struct CounterTypeTree QRCounterTree[] = {
-    { "request",        QRCounterRequest,   -1              },
-    { "opcode",         QRCounterOpcode,    -1              },
-    { "qtype",          QRCounterQtype,     -1              },
-    { "responses",      NULL,               QR_RESPONSE     },
-    { "response",       QRCounterResponse,  -1              },
-    { "qrysuccess",     NULL,               QR_QRYSUCCESS   },
-    { "qryauthans",     NULL,               QR_QRYAUTHANS   },
-    { "qrynoauthans",   NULL,               QR_QRYNOAUTHANS },
-    { "qryreferral",    NULL,               QR_QRYREFERRAL  },
-    { "qrynxrrset",     NULL,               QR_QRYNXRRSET   },
-    { "authqryrej",     NULL,               QR_QRYREJECT    },
-    { "rcode",          QRCounterRcode,     -1              },
-    { NULL,             NULL,               -1              }
-};
-
-const int QROpCodeToQRCounterType[16] = {
-    QR_OPCODE_QUERY,    // Opcode =  0: Query
-    QR_OPCODE_IQUERY,   // Opcode =  1: Iquery
-    QR_OPCODE_STATUS,   // Opcode =  2: STATUS
-    QR_OPCODE_OTHER,    // Opcode =  3: (Unassigned)
-    QR_OPCODE_NOTIFY,   // Opcode =  4: Notify
-    QR_OPCODE_UPDATE,   // Opcode =  5: Update
-    QR_OPCODE_OTHER,    // Opcode =  6: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode =  7: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode =  8: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode =  9: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode = 10: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode = 11: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode = 12: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode = 13: (Unassigned)
-    QR_OPCODE_OTHER,    // Opcode = 14: (Unassigned)
-    QR_OPCODE_OTHER     // Opcode = 15: (Unassigned)
-};
-const int QRQTypeToQRCounterType[258] = {
-    QR_QTYPE_OTHER,         // RRtype =   0: special use
-    QR_QTYPE_A,             // RRtype =   1: A
-    QR_QTYPE_NS,            // RRtype =   2: NS
-    QR_QTYPE_MD,            // RRtype =   3: MD
-    QR_QTYPE_MF,            // RRtype =   4: MF
-    QR_QTYPE_CNAME,         // RRtype =   5: CNAME
-    QR_QTYPE_SOA,           // RRtype =   6: SOA
-    QR_QTYPE_MB,            // RRtype =   7: MB
-    QR_QTYPE_MG,            // RRtype =   8: MG
-    QR_QTYPE_MR,            // RRtype =   9: MR
-    QR_QTYPE_NULL,          // RRtype =  10: NULL
-    QR_QTYPE_WKS,           // RRtype =  11: WKS
-    QR_QTYPE_PTR,           // RRtype =  12: PTR
-    QR_QTYPE_HINFO,         // RRtype =  13: HINFO
-    QR_QTYPE_MINFO,         // RRtype =  14: MINFO
-    QR_QTYPE_MX,            // RRtype =  15: MX
-    QR_QTYPE_TXT,           // RRtype =  16: TXT
-    QR_QTYPE_RP,            // RRtype =  17: RP
-    QR_QTYPE_AFSDB,         // RRtype =  18: AFSDB
-    QR_QTYPE_X25,           // RRtype =  19: X25
-    QR_QTYPE_ISDN,          // RRtype =  20: ISDN
-    QR_QTYPE_RT,            // RRtype =  21: RT
-    QR_QTYPE_NSAP,          // RRtype =  22: NSAP
-    QR_QTYPE_NSAP_PTR,      // RRtype =  23: NSAP-PTR
-    QR_QTYPE_SIG,           // RRtype =  24: SIG
-    QR_QTYPE_KEY,           // RRtype =  25: KEY
-    QR_QTYPE_PX,            // RRtype =  26: PX
-    QR_QTYPE_GPOS,          // RRtype =  27: GPOS
-    QR_QTYPE_AAAA,          // RRtype =  28: AAAA
-    QR_QTYPE_LOC,           // RRtype =  29: LOC
-    QR_QTYPE_NXT,           // RRtype =  30: NXT
-    QR_QTYPE_EID,           // RRtype =  31: EID        
-    QR_QTYPE_NIMLOC,        // RRtype =  32: NIMLOC     
-    QR_QTYPE_SRV,           // RRtype =  33: SRV        
-    QR_QTYPE_ATMA,          // RRtype =  34: ATMA       
-    QR_QTYPE_NAPTR,         // RRtype =  35: NAPTR      
-    QR_QTYPE_KX,            // RRtype =  36: KX         
-    QR_QTYPE_CERT,          // RRtype =  37: CERT       
-    QR_QTYPE_A6,            // RRtype =  38: A6         
-    QR_QTYPE_DNAME,         // RRtype =  39: DNAME      
-    QR_QTYPE_SINK,          // RRtype =  40: SINK       
-    QR_QTYPE_OPT,           // RRtype =  41: OPT        
-    QR_QTYPE_APL,           // RRtype =  42: APL        
-    QR_QTYPE_DS,            // RRtype =  43: DS         
-    QR_QTYPE_SSHFP,         // RRtype =  44: SSHFP      
-    QR_QTYPE_IPSECKEY,      // RRtype =  45: IPSECKEY   
-    QR_QTYPE_RRSIG,         // RRtype =  46: RRSIG      
-    QR_QTYPE_NSEC,          // RRtype =  47: NSEC       
-    QR_QTYPE_DNSKEY,        // RRtype =  48: DNSKEY     
-    QR_QTYPE_DHCID,         // RRtype =  49: DHCID      
-    QR_QTYPE_NSEC3,         // RRtype =  50: NSEC3      
-    QR_QTYPE_NSEC3PARAM,    // RRtype =  51: NSEC3PARAM 
-    QR_QTYPE_OTHER,         // RRtype =  52: TLSA
-    QR_QTYPE_OTHER,         // RRtype =  53: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  54: (Unassigned)
-    QR_QTYPE_HIP,           // RRtype =  55: HIP
-    QR_QTYPE_NINFO,         // RRtype =  56: NINFO
-    QR_QTYPE_RKEY,          // RRtype =  57: RKEY
-    QR_QTYPE_TALINK,        // RRtype =  58: TALINK
-    QR_QTYPE_OTHER,         // RRtype =  59: CDS
-    QR_QTYPE_OTHER,         // RRtype =  60: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  61: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  62: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  63: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  64: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  65: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  66: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  67: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  68: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  69: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  70: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  71: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  72: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  73: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  74: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  75: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  76: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  77: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  78: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  79: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  80: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  81: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  82: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  83: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  84: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  85: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  86: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  87: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  88: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  89: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  90: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  91: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  92: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  93: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  94: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  95: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  96: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  97: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype =  98: (Unassigned)
-    QR_QTYPE_SPF,           // RRtype =  99: SPF
-    QR_QTYPE_UINFO,         // RRtype = 100: UINFO
-    QR_QTYPE_UID,           // RRtype = 101: UID
-    QR_QTYPE_GID,           // RRtype = 102: GID
-    QR_QTYPE_UNSPEC,        // RRtype = 103: UNSPEC
-    QR_QTYPE_OTHER,         // RRtype = 104: NID
-    QR_QTYPE_OTHER,         // RRtype = 105: L32
-    QR_QTYPE_OTHER,         // RRtype = 106: L64
-    QR_QTYPE_OTHER,         // RRtype = 107: LP 
-    QR_QTYPE_OTHER,         // RRtype = 108: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 109: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 110: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 111: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 112: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 113: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 114: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 115: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 116: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 117: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 118: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 119: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 120: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 121: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 122: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 123: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 124: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 125: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 126: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 127: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 128: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 129: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 130: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 131: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 132: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 133: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 134: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 135: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 136: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 137: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 138: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 139: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 140: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 141: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 142: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 143: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 144: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 145: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 146: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 147: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 148: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 149: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 150: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 151: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 152: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 153: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 154: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 155: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 156: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 157: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 158: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 159: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 160: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 161: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 162: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 163: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 164: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 165: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 166: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 167: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 168: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 169: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 170: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 171: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 172: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 173: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 174: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 175: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 176: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 177: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 178: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 179: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 180: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 181: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 182: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 183: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 184: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 185: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 186: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 187: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 188: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 189: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 190: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 191: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 192: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 193: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 194: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 195: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 196: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 197: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 198: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 199: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 200: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 201: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 202: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 203: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 204: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 205: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 206: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 207: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 208: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 209: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 210: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 211: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 212: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 213: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 214: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 215: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 216: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 217: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 218: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 219: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 220: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 221: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 222: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 223: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 224: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 225: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 226: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 227: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 228: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 229: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 230: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 231: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 232: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 233: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 234: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 235: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 236: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 237: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 238: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 239: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 240: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 241: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 242: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 243: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 244: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 245: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 246: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 247: (Unassigned)
-    QR_QTYPE_OTHER,         // RRtype = 248: (Unassigned)
-    QR_QTYPE_TKEY,          // RRtype = 249: TKEY
-    QR_QTYPE_TSIG,          // RRtype = 250: TSIG
-    QR_QTYPE_IXFR,          // RRtype = 251: IXFR
-    QR_QTYPE_AXFR,          // RRtype = 252: AXFR
-    QR_QTYPE_MAILB,         // RRtype = 253: MAILB
-    QR_QTYPE_MAILA,         // RRtype = 254: MAILA
-    QR_QTYPE_OTHER,         // RRtype = 255: for All records
-    QR_QTYPE_URI,           // RRtype = 256: URI
-    QR_QTYPE_CAA            // RRtype = 257: CAA
-};
-const int QRRCodeToQRCounterType[23] = {
-    QR_RCODE_NOERROR,       // Rcode =  0: NoError
-    QR_RCODE_FORMERR,       // Rcode =  1: FormErr
-    QR_RCODE_SERVFAIL,      // Rcode =  2: ServFail
-    QR_RCODE_NXDOMAIN,      // Rcode =  3: NXDomain
-    QR_RCODE_NOTIMP,        // Rcode =  4: NotImp
-    QR_RCODE_REFUSED,       // Rcode =  5: Refused
-    QR_RCODE_YXDOMAIN,      // Rcode =  6: YXDomain
-    QR_RCODE_YXRRSET,       // Rcode =  7: YXRRSet
-    QR_RCODE_NXRRSET,       // Rcode =  8: NXRRSet
-    QR_RCODE_NOTAUTH,       // Rcode =  9: NotAuth
-    QR_RCODE_NOTZONE,       // Rcode = 10: NotZone
-    QR_RCODE_OTHER,         // Rcode = 11: (Unassigned)
-    QR_RCODE_OTHER,         // Rcode = 12: (Unassigned)
-    QR_RCODE_OTHER,         // Rcode = 13: (Unassigned)
-    QR_RCODE_OTHER,         // Rcode = 14: (Unassigned)
-    QR_RCODE_OTHER,         // Rcode = 15: (Unassigned)
-    QR_RCODE_BADSIGVERS,    // Rcode = 16: BADVERS, BADSIG
-    QR_RCODE_BADKEY,        // Rcode = 17: BADKEY
-    QR_RCODE_BADTIME,       // Rcode = 18: BADTIME
-    QR_RCODE_BADMODE,       // Rcode = 19: BADMODE
-    QR_RCODE_BADNAME,       // Rcode = 20: BADNAME
-    QR_RCODE_BADALG,        // Rcode = 21: BADALG
-    QR_RCODE_BADTRUNC       // Rcode = 22: BADTRUNC
-};
-
-} // anonymous namespace
-
-#endif // __STATISTICS_ITEMS_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/bin/auth/statistics_items.h.pre b/src/bin/auth/statistics_items.h.pre
new file mode 100644
index 0000000..80317c0
--- /dev/null
+++ b/src/bin/auth/statistics_items.h.pre
@@ -0,0 +1,53 @@
+// Copyright (C) 2012  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 __STATISTICS_ITEMS_H
+#define __STATISTICS_ITEMS_H 1
+
+/// This file declares a set of statistics items in Auth module for internal
+/// use. This file is intended to be included in statistics.cc and unittests.
+
+namespace isc {
+namespace auth {
+namespace statistics {
+
+struct CounterSpec {
+    /// \brief name Name of this node. This appears in the spec file.
+    const char* const name;
+    /// \brief sub_counters If this is a branch node, sub_counters points to
+    ///                     CounterSpec which contains child nodes. Otherwise,
+    ///                     for leaf nodes, sub_counters is NULL.
+    const struct CounterSpec* const sub_counters;
+    /// \brief counter_id If this is a leaf node, counter_id is an enumerator
+    ///                   of this item. Otherwise, for branch nodes, counter_id
+    ///                   is NOT_ITEM.
+    const int counter_id;
+};
+
+// ### STATISTICS ITEMS DECLARATION ###
+
+extern const int opcode_to_msgcounter[];
+extern const size_t num_opcode_to_msgcounter;
+extern const int rcode_to_msgcounter[];
+extern const size_t num_rcode_to_msgcounter;
+
+} // namespace statistics
+} // namespace auth
+} // namespace isc
+
+#endif // __STATISTICS_ITEMS_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/auth/statistics_msg_items.def b/src/bin/auth/statistics_msg_items.def
new file mode 100644
index 0000000..d8d3597
--- /dev/null
+++ b/src/bin/auth/statistics_msg_items.def
@@ -0,0 +1,48 @@
+request	msg_counter_request		Request statistics	=
+	v4		MSG_REQUEST_IPV4	Number of IPv4 requests received by the b10-auth server.
+	v6		MSG_REQUEST_IPV6	Number of IPv6 requests received by the b10-auth server.
+	edns0		MSG_REQUEST_EDNS0	Number of requests with EDNS0 received by the b10-auth server.
+	badednsver	MSG_REQUEST_BADEDNSVER	Number of requests with unsupported EDNS version received by the b10-auth server.
+	tsig		MSG_REQUEST_TSIG	Number of requests with TSIG received by the b10-auth server.
+	sig0		MSG_REQUEST_SIG0	Number of requests with SIG(0) received by the b10-auth server; currently not implemented in BIND 10.
+	badsig		MSG_REQUEST_BADSIG	Number of requests with invalid TSIG or SIG(0) signature received by the b10-auth server.
+	udp		MSG_REQUEST_UDP		Number of UDP requests received by the b10-auth server.
+	tcp		MSG_REQUEST_TCP		Number of TCP requests received by the b10-auth server.
+	dnssec_ok	MSG_REQUEST_DNSSEC_OK	Number of requests with "DNSSEC OK" (DO) bit was set received by the b10-auth server.
+	;
+opcode	msg_counter_opcode		OpCode statistics	=
+	query		MSG_OPCODE_QUERY	Number of OpCode=Query requests received by the b10-auth server.
+	iquery		MSG_OPCODE_IQUERY	Number of OpCode=IQuery requests received by the b10-auth server.
+	status		MSG_OPCODE_STATUS	Number of OpCode=Status requests received by the b10-auth server.
+	notify		MSG_OPCODE_NOTIFY	Number of OpCode=Notify requests received by the b10-auth server.
+	update		MSG_OPCODE_UPDATE	Number of OpCode=Update requests received by the b10-auth server.
+	other		MSG_OPCODE_OTHER	Number of requests in other OpCode received by the b10-auth server.
+	;
+responses	MSG_RESPONSE			Number of responses sent by the b10-auth server.
+response	msg_counter_response	Response statistics	=
+	truncated	MSG_RESPONSE_TRUNCATED	Number of truncated responses sent by the b10-auth server.
+	edns0		MSG_RESPONSE_EDNS0	Number of responses with EDNS0 sent by the b10-auth server.
+	tsig		MSG_RESPONSE_TSIG	Number of responses with TSIG sent by the b10-auth server.
+	sig0		MSG_RESPONSE_SIG0	Number of responses with SIG(0) sent by the b10-auth server; currently not implemented in BIND 10.
+	;
+qrysuccess	MSG_QRYSUCCESS			Number of queries received by the b10-auth server resulted in rcode = NoError and the number of answer RR >= 1.
+qryauthans	MSG_QRYAUTHANS			Number of queries received by the b10-auth server resulted in authoritative answer.
+qrynoauthans	MSG_QRYNOAUTHANS		Number of queries received by the b10-auth server resulted in non-authoritative answer.
+qryreferral	MSG_QRYREFERRAL			Number of queries received by the b10-auth server resulted in referral answer.
+qrynxrrset	MSG_QRYNXRRSET			Number of queries received by the b10-auth server resulted in NoError and AA bit is set in the response, but the number of answer RR == 0.
+authqryrej	MSG_QRYREJECT			Number of authoritative queries rejected by the b10-auth server.
+rcode		msg_counter_rcode	Rcode statistics	=
+	noerror		MSG_RCODE_NOERROR	Number of requests received by the b10-auth server resulted in RCODE = 0 (NoError).
+	formerr		MSG_RCODE_FORMERR	Number of requests received by the b10-auth server resulted in RCODE = 1 (FormErr).
+	servfail	MSG_RCODE_SERVFAIL	Number of requests received by the b10-auth server resulted in RCODE = 2 (ServFail).
+	nxdomain	MSG_RCODE_NXDOMAIN	Number of requests received by the b10-auth server resulted in RCODE = 3 (NXDomain).
+	notimp		MSG_RCODE_NOTIMP	Number of requests received by the b10-auth server resulted in RCODE = 4 (NotImp).
+	refused		MSG_RCODE_REFUSED	Number of requests received by the b10-auth server resulted in RCODE = 5 (Refused).
+	yxdomain	MSG_RCODE_YXDOMAIN	Number of requests received by the b10-auth server resulted in RCODE = 6 (YXDomain).
+	yxrrset		MSG_RCODE_YXRRSET	Number of requests received by the b10-auth server resulted in RCODE = 7 (YXRRSet).
+	nxrrset		MSG_RCODE_NXRRSET	Number of requests received by the b10-auth server resulted in RCODE = 8 (NXRRSet).
+	notauth		MSG_RCODE_NOTAUTH	Number of requests received by the b10-auth server resulted in RCODE = 9 (NotAuth).
+	notzone		MSG_RCODE_NOTZONE	Number of requests received by the b10-auth server resulted in RCODE = 10 (NotZone).
+	badvers		MSG_RCODE_BADVERS	Number of requests received by the b10-auth server resulted in RCODE = 16 (BADVERS).
+	other		MSG_RCODE_OTHER		Number of requests received by the b10-auth server resulted in other RCODEs.
+	;
diff --git a/src/bin/auth/tests/.gitignore b/src/bin/auth/tests/.gitignore
index a45eff7..337acc7 100644
--- a/src/bin/auth/tests/.gitignore
+++ b/src/bin/auth/tests/.gitignore
@@ -1,3 +1,4 @@
 /run_unittests
 /example_base_inc.cc
 /example_nsec3_inc.cc
+/statistics_unittest.cc
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index d1bde4d..8fbdb4c 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -34,6 +34,9 @@ TESTS_ENVIRONMENT = \
 TESTS =
 if HAVE_GTEST
 
+# auto-generated by statistics_items.py
+BUILT_SOURCES = statistics_unittest.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 += ../auth_srv.h ../auth_srv.cc
@@ -45,13 +48,13 @@ run_unittests_SOURCES += ../common.h ../common.cc
 run_unittests_SOURCES += ../statistics.h ../statistics.cc ../statistics_items.h
 run_unittests_SOURCES += ../datasrc_config.h ../datasrc_config.cc
 run_unittests_SOURCES += datasrc_util.h datasrc_util.cc
+run_unittests_SOURCES += statistics_util.h statistics_util.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
 run_unittests_SOURCES += config_unittest.cc
 run_unittests_SOURCES += config_syntax_unittest.cc
 run_unittests_SOURCES += command_unittest.cc
 run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
-run_unittests_SOURCES += statistics_unittest.cc
 run_unittests_SOURCES += test_datasrc_clients_mgr.h test_datasrc_clients_mgr.cc
 run_unittests_SOURCES += datasrc_clients_builder_unittest.cc
 run_unittests_SOURCES += datasrc_clients_mgr_unittest.cc
@@ -59,6 +62,7 @@ run_unittests_SOURCES += datasrc_config_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 
 nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
+nodist_run_unittests_SOURCES += statistics_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -83,7 +87,7 @@ run_unittests_LDADD += $(SQLITE_LIBS)
 
 # The following are definitions for auto-generating test data for query
 # tests.
-BUILT_SOURCES = example_base_inc.cc example_nsec3_inc.cc
+BUILT_SOURCES += example_base_inc.cc example_nsec3_inc.cc
 BUILT_SOURCES += testdata/example-base.sqlite3
 BUILT_SOURCES += testdata/example-nsec3.sqlite3
 
@@ -114,8 +118,11 @@ testdata/example-nsec3.sqlite3: testdata/example-nsec3.zone testdata/example-com
 		-c "{\"database_file\": \"$(builddir)/testdata/example-nsec3.sqlite3\"}" \
 		example.com testdata/example-nsec3.zone
 
+EXTRA_DIST += gen-statisticsitems_test.py
+
 check-local:
 	B10_FROM_BUILD=${abs_top_builddir} ./run_unittests
+	$(PYTHON) $(srcdir)/gen-statisticsitems_test.py $(top_builddir)/src/bin/auth/b10-auth.xml
 
 noinst_PROGRAMS = run_unittests
 
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 826d1b8..0a77a11 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -29,7 +29,6 @@
 #include <server_common/portconfig.h>
 #include <server_common/keyring.h>
 
-#include <datasrc/memory_datasrc.h>
 #include <datasrc/client_list.h>
 #include <auth/auth_srv.h>
 #include <auth/command.h>
@@ -46,6 +45,8 @@
 #include <testutils/portconfig.h>
 #include <testutils/socket_request.h>
 
+#include "statistics_util.h"
+
 #include <gtest/gtest.h>
 
 #include <boost/lexical_cast.hpp>
@@ -74,6 +75,7 @@ using namespace isc::asiodns;
 using namespace isc::asiolink;
 using namespace isc::testutils;
 using namespace isc::server_common::portconfig;
+using namespace isc::auth::unittest;
 using isc::datasrc::memory::ZoneTableSegment;
 using isc::UnitTestUtil;
 using boost::scoped_ptr;
@@ -91,7 +93,8 @@ const char* const STATIC_DSRC_FILE = DSRC_DIR "/static.zone";
 
 // This is a configuration that uses the in-memory data source containing
 // a signed example zone.
-const char* const CONFIG_INMEMORY_EXAMPLE = TEST_DATA_DIR "/rfc5155-example.zone.signed";
+const char* const CONFIG_INMEMORY_EXAMPLE =
+    TEST_DATA_DIR "/rfc5155-example.zone.signed";
 
 // shortcut commonly used in tests
 typedef boost::shared_ptr<ConfigurableClientList> ListPtr;
@@ -109,6 +112,7 @@ protected:
         server.setDNSService(dnss_);
         server.setXfrinSession(&notify_session);
         server.createDDNSForwarder();
+        checkCountersAreInitialized();
     }
 
     ~AuthSrvTest() {
@@ -125,7 +129,8 @@ protected:
 
     // Helper for checking Rcode statistic counters;
     // Checks for one specific Rcode statistics counter value
-    void checkRcodeCounter(const std::string& rcode_name, const int rcode_value,
+    void checkRcodeCounter(const std::string& rcode_name,
+                           const int rcode_value,
                            const int expected_value) const
     {
             EXPECT_EQ(expected_value, rcode_value) <<
@@ -134,38 +139,26 @@ protected:
                       rcode_value;
     }
 
-    // Checks whether all Rcode counters are set to zero
-    void checkAllRcodeCountersZero() const {
-        // with checking NOERROR == 0 and the others are 0
-        checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 0);
-    }
-
     // Checks whether all Rcode counters are set to zero except the given
     // rcode (it is checked to be set to 'value')
     void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const {
         std::string target_rcode_name = rcode.toText();
         std::transform(target_rcode_name.begin(), target_rcode_name.end(),
                        target_rcode_name.begin(), ::tolower);
-        // rcode 16 is registered as both BADVERS and BADSIG
-        if (target_rcode_name == "badvers") {
-            target_rcode_name = "badsigvers";
-        }
 
         const std::map<std::string, ConstElementPtr>
-            stats_map(server.getStatistics()->mapValue());
+            stats_map(server.getStatistics()->get("zones")->get("_SERVER_")->
+                      get("rcode")->mapValue());
 
-        const std::string rcode_prefix("rcode.");
         for (std::map<std::string, ConstElementPtr>::const_iterator
                  i = stats_map.begin(), e = stats_map.end();
              i != e;
              ++i)
         {
-            if (i->first.compare(0, rcode_prefix.size(), rcode_prefix) == 0) {
-                if (i->first.compare(rcode_prefix + target_rcode_name) == 0) {
-                    checkRcodeCounter(i->first, i->second->intValue(), value);
-                } else {
-                    checkRcodeCounter(i->first, i->second->intValue(), 0);
-                }
+            if (i->first.compare(target_rcode_name) == 0) {
+                checkRcodeCounter(i->first, i->second->intValue(), value);
+            } else {
+                checkRcodeCounter(i->first, i->second->intValue(), 0);
             }
         }
     }
@@ -200,6 +193,15 @@ protected:
                               &dnsserv);
     }
 
+    // Check if the counters exist and are initialized to 0.
+    void
+    checkCountersAreInitialized() {
+        const std::map<std::string, int> expect;
+        ConstElementPtr stats = server.getStatistics()->
+            get("zones")->get("_SERVER_");
+        checkStatisticsCounters(stats, expect);
+    }
+
     MockDNSService dnss_;
     MockXfroutClient xfrout;
     MockSocketSessionForwarder ddns_forwarder;
@@ -242,29 +244,6 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
                 renderer.getLength());
 }
 
-// Check if the item has expected value.
-// Before reading the item, check the item exists.
-void
-expectCounterItem(ConstElementPtr stats,
-                  const std::string& item, const int expected) {
-    ConstElementPtr value(Element::create(0));
-    if (item == "queries.udp" || item == "queries.tcp" || expected != 0) {
-        // if the value of the item is not zero, the item exists and has
-        // expected value
-        // item "queries.udp" and "queries.tcp" exists whether the value
-        // is zero or nonzero
-        ASSERT_TRUE(stats->find(item, value)) << "    Item: " << item;
-        // Get the value of the item with another method because of API bug
-        // (ticket #2302)
-        value = stats->find(item);
-        EXPECT_EQ(expected, value->intValue()) << "    Item: " << item;
-    } else {
-        // otherwise the item does not exist
-        ASSERT_FALSE(stats->find(item, value)) << "    Item: " << item <<
-            std::endl << "   Value: " << value->intValue();
-    }
-}
-
 // We did not configure any client lists. Therefore it should be REFUSED
 TEST_F(AuthSrvTest, noClientList) {
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
@@ -277,6 +256,18 @@ TEST_F(AuthSrvTest, noClientList) {
     EXPECT_TRUE(dnsserv.hasAnswer());
     headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["qrynoauthans"] = 1;
+    expect["authqryrej"] = 1;
+    expect["rcode.refused"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Unsupported requests.  Should result in NOTIMP.
@@ -296,32 +287,74 @@ TEST_F(AuthSrvTest, multiQuestion) {
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
     shortMessage();
-    checkAllRcodeCountersZero();
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // or malformed or could otherwise cause a protocol error.
 TEST_F(AuthSrvTest, response) {
+    // isc::testutils::SrvTestBase::response() processes 3 messages.
     response();
-    checkAllRcodeCountersZero();
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 3;
+    expect["request.udp"] = 3;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
     shortQuestion();
-    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.formerr"] = 1;
+    expect["qrynoauthans"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
     shortAnswer();
-    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.formerr"] = 1;
+    expect["qrynoauthans"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
     ednsBadVers();
-    checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.badednsver"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.badvers"] = 1;
+    expect["qrynoauthans"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, AXFROverUDP) {
@@ -340,7 +373,14 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
                           &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
     EXPECT_TRUE(xfrout.isConnected());
-    checkAllRcodeCountersZero();
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tcp"] = 1;
+    expect["opcode.query"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Give the server a signed request, but don't give it the key. It will
@@ -374,7 +414,20 @@ TEST_F(AuthSrvTest, TSIGSignedBadKey) {
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
         "It should be unsigned with this error";
 
+    // check Rcode counters and TSIG counters
     checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tsig"] = 1;
+    expect["request.badsig"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["response.tsig"] = 1;
+    expect["rcode.notauth"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Give the server a signed request, but signed by a different key
@@ -409,7 +462,18 @@ TEST_F(AuthSrvTest, TSIGBadSig) {
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
         "It should be unsigned with this error";
 
-    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tsig"] = 1;
+    expect["request.badsig"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["response.tsig"] = 1;
+    expect["rcode.notauth"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Give the server a signed unsupported request with a bad signature.
@@ -446,13 +510,19 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
     EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
         "It should be unsigned with this error";
-    // TSIG should have failed, and so the per opcode counter shouldn't be
-    // incremented.
-    ConstElementPtr stats = server.getStatistics();
-    expectCounterItem(stats, "opcode.normal", 0);
-    expectCounterItem(stats, "opcode.other", 0);
 
-    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tsig"] = 1;
+    expect["request.badsig"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.other"] = 1;
+    expect["responses"] = 1;
+    expect["response.tsig"] = 1;
+    expect["rcode.notauth"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, AXFRConnectFail) {
@@ -590,7 +660,8 @@ TEST_F(AuthSrvTest, notify) {
     // external module.  Check them.
     EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
     EXPECT_EQ("notify",
-              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
+              notify_session.getSentMessage()->get("command")->get(0)->
+                  stringValue());
     ConstElementPtr notify_args =
         notify_session.getSentMessage()->get("command")->get(1);
     EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
@@ -608,7 +679,15 @@ TEST_F(AuthSrvTest, notify) {
     EXPECT_EQ(RRClass::IN(), question->getClass());
     EXPECT_EQ(RRType::SOA(), question->getType());
 
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.notify"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.noerror"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, notifyForCHClass) {
@@ -627,6 +706,16 @@ TEST_F(AuthSrvTest, notifyForCHClass) {
     ConstElementPtr notify_args =
         notify_session.getSentMessage()->get("command")->get(1);
     EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.notify"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.noerror"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, notifyEmptyQuestion) {
@@ -642,6 +731,16 @@ TEST_F(AuthSrvTest, notifyEmptyQuestion) {
     EXPECT_TRUE(dnsserv.hasAnswer());
     headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
+
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.notify"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.formerr"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, notifyMultiQuestions) {
@@ -855,6 +954,19 @@ TEST_F(AuthSrvTest, TSIGSigned) {
         "The server signed the response, but it doesn't seem to be valid";
 
     checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tsig"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["response.tsig"] = 1;
+    expect["qrysuccess"] = 1;
+    expect["qryauthans"] = 1;
+    expect["rcode.noerror"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Same test emulating the UDPServer class behavior (defined in libasiolink).
@@ -955,8 +1067,8 @@ TEST_F(AuthSrvTest, updateConfig) {
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
-                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
 #ifdef USE_STATIC_LINK
@@ -976,6 +1088,18 @@ TEST_F(AuthSrvTest, datasourceFail) {
     EXPECT_TRUE(dnsserv.hasAnswer());
     headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+
+    checkAllRcodeCountersZeroExcept(Rcode::SERVFAIL(), 1);
+    ConstElementPtr stats = server.getStatistics()->get("zones")->
+        get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["qrynoauthans"] = 1;
+    expect["rcode.servfail"] = 1;
+    checkStatisticsCounters(stats, expect);
 }
 
 #ifdef USE_STATIC_LINK
@@ -1084,14 +1208,39 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_queryCounterTruncTest) {
+#else
+TEST_F(AuthSrvTest, queryCounterTruncTest) {
+#endif
+    // use CONFIG_TESTDB for large-rdata.example.com.
+    updateDatabase(server, CONFIG_TESTDB);
+
+    // Create UDP message and process.
+    // large-rdata.example.com. TXT; expect it exceeds 512 octet
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid,
+                                       Name("large-rdata.example.com."),
+                                       RRClass::IN(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["response.truncated"] = 1;
+    expect["qrysuccess"] = 1;
+    expect["qryauthans"] = 1;
+    expect["rcode.noerror"] = 1;
+    checkStatisticsCounters(stats_after, expect);
+}
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
-    // The counters should be initialized to 0.
-    ConstElementPtr stats_init = server.getStatistics();
-    expectCounterItem(stats_init, "queries.udp", 0);
-    expectCounterItem(stats_init, "queries.tcp", 0);
-    expectCounterItem(stats_init, "opcode.query", 0);
-    expectCounterItem(stats_init, "rcode.refused", 0);
     // Create UDP message and process.
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("example.com"),
@@ -1099,25 +1248,50 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    // After processing the UDP query, these counters should be incremented:
-    //   queries.udp, opcode.query, rcode.refused
-    // and these counters should not be incremented:
-    //   queries.tcp
-    ConstElementPtr stats_after = server.getStatistics();
-    expectCounterItem(stats_after, "queries.udp", 1);
-    expectCounterItem(stats_after, "queries.tcp", 0);
-    expectCounterItem(stats_after, "opcode.query", 1);
-    expectCounterItem(stats_after, "rcode.refused", 1);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["qrynoauthans"] = 1;
+    expect["authqryrej"] = 1;
+    expect["rcode.refused"] = 1;
+    checkStatisticsCounters(stats_after, expect);
+}
+
+// Submit UDP normal query with DNSSEC and check query counter
+TEST_F(AuthSrvTest, queryCounterUDPNormalWithDNSSEC) {
+    // Create UDP message and process.
+    UnitTestUtil::createDNSSECRequestMessage(request_message, Opcode::QUERY(),
+                                             default_qid, Name("example.com"),
+                                             RRClass::IN(), RRType::NS());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.edns0"] = 1;
+    expect["request.udp"] = 1;
+    expect["request.dnssec_ok"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["qrynoauthans"] = 1;
+    expect["authqryrej"] = 1;
+    expect["rcode.refused"] = 1;
+    // XXX: with the current implementation, EDNS0 is omitted in
+    // makeErrorMessage.
+    expect["response.edns0"] = 0;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Submit TCP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPNormal) {
-    // The counters should be initialized to 0.
-    ConstElementPtr stats_init = server.getStatistics();
-    expectCounterItem(stats_init, "queries.udp", 0);
-    expectCounterItem(stats_init, "queries.tcp", 0);
-    expectCounterItem(stats_init, "opcode.query", 0);
-    expectCounterItem(stats_init, "rcode.refused", 0);
     // Create TCP message and process.
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("example.com"),
@@ -1125,24 +1299,22 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
     createRequestPacket(request_message, IPPROTO_TCP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    // After processing the TCP query, these counters should be incremented:
-    //   queries.tcp, opcode.query, rcode.refused
-    // and these counters should not be incremented:
-    //   queries.udp
-    ConstElementPtr stats_after = server.getStatistics();
-    expectCounterItem(stats_after, "queries.udp", 0);
-    expectCounterItem(stats_after, "queries.tcp", 1);
-    expectCounterItem(stats_after, "opcode.query", 1);
-    expectCounterItem(stats_after, "rcode.refused", 1);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tcp"] = 1;
+    expect["opcode.query"] = 1;
+    expect["responses"] = 1;
+    expect["qrynoauthans"] = 1;
+    expect["authqryrej"] = 1;
+    expect["rcode.refused"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Submit TCP AXFR query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
-    // The counters should be initialized to 0.
-    ConstElementPtr stats_init = server.getStatistics();
-    expectCounterItem(stats_init, "queries.udp", 0);
-    expectCounterItem(stats_init, "queries.tcp", 0);
-    expectCounterItem(stats_init, "opcode.query", 0);
     UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                          Name("example.com"), RRClass::IN(), RRType::AXFR());
     createRequestPacket(request_message, IPPROTO_TCP);
@@ -1151,24 +1323,18 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
-    // After processing the TCP AXFR query, these counters should be
-    // incremented:
-    //   queries.tcp, opcode.query
-    // and these counters should not be incremented:
-    //   queries.udp
-    ConstElementPtr stats_after = server.getStatistics();
-    expectCounterItem(stats_after, "queries.udp", 0);
-    expectCounterItem(stats_after, "queries.tcp", 1);
-    expectCounterItem(stats_after, "opcode.query", 1);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tcp"] = 1;
+    expect["opcode.query"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 // Submit TCP IXFR query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
-    // The counters should be initialized to 0.
-    ConstElementPtr stats_init = server.getStatistics();
-    expectCounterItem(stats_init, "queries.udp", 0);
-    expectCounterItem(stats_init, "queries.tcp", 0);
-    expectCounterItem(stats_init, "opcode.query", 0);
     UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                          Name("example.com"), RRClass::IN(), RRType::IXFR());
     createRequestPacket(request_message, IPPROTO_TCP);
@@ -1177,27 +1343,38 @@ TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
-    // After processing the TCP IXFR query, these counters should be
-    // incremented:
-    //   queries.tcp, opcode.query
-    // and these counters should not be incremented:
-    //   queries.udp
-    ConstElementPtr stats_after = server.getStatistics();
-    expectCounterItem(stats_after, "queries.udp", 0);
-    expectCounterItem(stats_after, "queries.tcp", 1);
-    expectCounterItem(stats_after, "opcode.query", 1);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    std::map<std::string, int> expect;
+    expect["request.v4"] = 1;
+    expect["request.tcp"] = 1;
+    expect["opcode.query"] = 1;
+    checkStatisticsCounters(stats_after, expect);
 }
 
 TEST_F(AuthSrvTest, queryCounterOpcodes) {
-    // Check for 0..2, 3(=other), 4..5
-    // The counter should be initialized to 0.
-    for (int i = 0; i < 6; ++i) {
-        // The counter should be initialized to 0.
-        expectCounterItem(server.getStatistics(),
-                          std::string("opcode.") +
-                              QRCounterOpcode[QROpCodeToQRCounterType[i] -
-                                                  QR_OPCODE_QUERY].name,
-                          0);
+    int other_expected = 0;
+    for (int i = 0; i < isc::auth::statistics::num_opcode_to_msgcounter; ++i) {
+        std::string item_name;
+        int expected;
+        if (isc::auth::statistics::opcode_to_msgcounter[i] ==
+                isc::auth::statistics::MSG_OPCODE_OTHER)
+        {
+            item_name = "OTHER";
+            other_expected += i + 1;
+            expected = other_expected;
+        } else {
+            item_name = Opcode(i).toText();
+            expected = i + 1;
+        }
+        std::transform(item_name.begin(), item_name.end(), item_name.begin(),
+                       ::tolower);
+
+        // The counter should be initialized to expected value.
+        EXPECT_EQ(expected - (i + 1),
+                  server.getStatistics()->get("zones")->get("_SERVER_")->
+                  get("opcode")->get(item_name)->intValue());
 
         // For each possible opcode, create a request message and send it
         UnitTestUtil::createRequestMessage(request_message, Opcode(i),
@@ -1215,45 +1392,11 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) {
         }
 
         // Confirm the counter.
-        expectCounterItem(server.getStatistics(),
-                          std::string("opcode.") +
-                              QRCounterOpcode[QROpCodeToQRCounterType[i] -
-                                                  QR_OPCODE_QUERY].name,
-                          i + 1);
-    }
-    // Check for 6..15
-    // they are treated as the 'other' opcode
-    // the 'other' opcode counter is 4 at this point
-    int expected = 4;
-    for (int i = 6; i < 16; ++i) {
-        // The counter should be initialized to 0.
-        expectCounterItem(server.getStatistics(),
-                          std::string("opcode.") +
-                              QRCounterOpcode[QROpCodeToQRCounterType[i] -
-                                              QR_OPCODE_QUERY].name,
-                          expected);
-
-        // For each possible opcode, create a request message and send it
-        UnitTestUtil::createRequestMessage(request_message, Opcode(i),
-                                           default_qid, Name("example.com"),
-                                           RRClass::IN(), RRType::NS());
-        createRequestPacket(request_message, IPPROTO_UDP);
-
-        // "send" the request once
-        parse_message->clear(Message::PARSE);
-        server.processMessage(*io_message, *parse_message,
-                              *response_obuffer,
-                              &dnsserv);
-
-        // the 'other' opcode counter should be incremented
-        ++expected;
-
-        // Confirm the counter.
-        expectCounterItem(server.getStatistics(),
-                          std::string("opcode.") +
-                              QRCounterOpcode[QROpCodeToQRCounterType[i] -
-                                              QR_OPCODE_QUERY].name,
-                          expected);
+        // This test only checks for opcodes; some part of the other items
+        // depends on the opcode.
+        EXPECT_EQ(expected,
+                  server.getStatistics()->get("zones")->get("_SERVER_")->
+                  get("opcode")->get(item_name)->intValue());
     }
 }
 
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index be90d73..180cd2c 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -29,8 +29,6 @@
 
 #include <config/ccsession.h>
 
-#include <datasrc/memory_datasrc.h>
-
 #include <asiolink/asiolink.h>
 
 #include <util/unittests/mock_socketsession.h>
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 830de0d..0d6cbf8 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -22,7 +22,6 @@
 #include <cc/data.h>
 
 #include <datasrc/data_source.h>
-#include <datasrc/memory_datasrc.h>
 
 #include <xfr/xfrout_client.h>
 
@@ -130,7 +129,7 @@ TEST_F(AuthConfigTest, invalidListenAddressConfig) {
     isc::testutils::portconfig::invalidListenAddressConfig(server);
 }
 
-// Try setting addresses trough config
+// Try setting addresses through config
 TEST_F(AuthConfigTest, listenAddressConfig) {
     isc::testutils::portconfig::listenAddressConfig(server);
 
diff --git a/src/bin/auth/tests/datasrc_clients_builder_unittest.cc b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
index 838e032..01ac47e 100644
--- a/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
+++ b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
@@ -328,7 +328,8 @@ TEST_F(DataSrcClientsBuilderTest,
 {
     // Prepare the database first
     const std::string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
-    std::stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
+    std::stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n"
+                         "example.org. 3600 IN NS ns1.example.org.\n");
     createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
     // This describes the data source in the configuration
     const ConstElementPtr config(Element::fromJSON("{"
diff --git a/src/bin/auth/tests/gen-statisticsitems_test.py b/src/bin/auth/tests/gen-statisticsitems_test.py
new file mode 100644
index 0000000..0cc7bcf
--- /dev/null
+++ b/src/bin/auth/tests/gen-statisticsitems_test.py
@@ -0,0 +1,90 @@
+# Copyright (C) 2012  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 script checks output of gen-statisticsitems.py.
+
+This script checks XML file. Spec file, C++ code and header files syntax is
+checked in the other unittests or system tests.
+"""
+
+import os
+import sys
+from xml.etree import ElementTree
+
+"""\
+User-defined exception for parse error. It is thrown if a file is not
+formatted as expected.
+"""
+class ParseError(Exception):
+    pass
+
+"""\
+Test XML file.
+
+It should have <refsect1> which has <title>STATISTICS DATA</title>.
+Inside the section, it should have one or more <varlistentry> of each item
+inside <variablelist>.
+Each <varlistentry> should have <term> for item name and <simpara> inside
+<listitem> for item description.
+
+Example:
+    <refsect1>
+        <title>STATISTICS DATA</title>
+        <variablelist>
+        <varlistentry>
+          <term>item1</term>
+          <listitem><simpara>statistics item</simpara></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>item2</term>
+          <listitem><simpara>another statistics item</simpara></listitem>
+        </varlistentry>
+        </variablelist>
+    </refsect1>
+"""
+def test_xml_file(xmlfilepath):
+    xmltree = ElementTree.parse(xmlfilepath)
+    root = xmltree.getroot()
+    # find <refsect1> which has <title> of 'STATISTICS DATA'
+    stats_node = [t for t in root.findall('./refsect1')
+            if t.find('./title').text == 'STATISTICS DATA']
+    if not stats_node:
+        raise ParseError('Statistics data section does not exist')
+    # find all <varlistentry> inside <variablelist>
+    entries = stats_node[0].find('./variablelist').findall('./varlistentry')
+    if not entries:
+        raise ParseError('<varlistentry> does not exist inside section')
+    for entry in entries:
+        # find <term> for item name
+        name = entry.find('./term')
+        if name is None or name.text == '':
+            raise ParseError('<term> for item name does not exist')
+        # find <simpara> inside <listitem> for item description
+        description = entry.find('./listitem/simpara')
+        if description is None or description.text == '':
+            raise ParseError('<listitem> nor <simpara> for item description'
+                             ' does not exist')
+    return
+
+if __name__ == "__main__":
+    xmlfilepath = sys.argv[1]
+    try:
+        test_xml_file(xmlfilepath)
+    except ImportError:
+        # pyexpat library is required for ElementTree.parse() but it is
+        # missing in some environment. Just skip this test.
+        print ("Required library is missing, skipping this test.")
+        print ("Detailed information:")
+        print (sys.exc_info()[1])
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index a22d2d7..9bf1358 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -30,7 +30,7 @@
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/client.h>
 #include <datasrc/client_list.h>
 
 #include <auth/query.h>
@@ -90,6 +90,10 @@ private:
 #include <auth/tests/example_base_inc.cc>
 #include <auth/tests/example_nsec3_inc.cc>
 
+// This SOA is used in negative responses; its RRTTL is set to SOA's MINTTL
+const char* const soa_minttl_txt =
+    "example.com. 0 IN SOA . . 1 0 0 0 0\n";
+
 // This is used only in one pathological test case.
 const char* const zone_ds_txt =
     "example.com. 3600 IN DS 57855 5 1 "
@@ -213,6 +217,13 @@ public:
             "t644ebqk9bibcna874givr6joj62mlhv";
         hash_map_[Name("www1.uwild.example.com")] =
             "q04jkcevqvmu85r014c7dkba38o0ji6r"; // a bit larger than H(www)
+
+        // For empty-non-terminal derived from insecure delegation (we don't
+        // need a hash for the delegation point itself for that test).  the
+        // hash for empty name is the same as that for unsigned-delegation
+        // above, as the case is similar to that.
+        hash_map_[Name("empty.example.com")] =
+            "q81r598950igr1eqvc60aedlq66425b5"; // a bit larger than H(www)
     }
     virtual string calculate(const Name& name) const {
         const NSEC3HashMap::const_iterator found = hash_map_.find(name);
@@ -258,8 +269,6 @@ public:
 // to child zones are identified by the existence of non origin NS records.
 // Another special name is "dname.example.com".  Query names under this name
 // will result in DNAME.
-// This mock zone doesn't handle empty non terminal nodes (if we need to test
-// such cases find() should have specialized code for it).
 class MockZoneFinder : public ZoneFinder {
 public:
     MockZoneFinder() :
@@ -822,6 +831,68 @@ createDataSrcClientList(DataSrcType type, DataSourceClient& client) {
     }
 }
 
+class MockClient : public DataSourceClient {
+public:
+    virtual FindResult findZone(const isc::dns::Name& origin) const {
+        const Name r_origin(origin.reverse());
+        std::map<Name, ZoneFinderPtr>::const_iterator it =
+            zone_finders_.lower_bound(r_origin);
+
+        if (it != zone_finders_.end()) {
+            const NameComparisonResult result =
+                origin.compare((it->first).reverse());
+            if (result.getRelation() == NameComparisonResult::EQUAL) {
+                return (FindResult(result::SUCCESS, it->second));
+            } else if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
+                return (FindResult(result::PARTIALMATCH, it->second));
+            }
+        }
+
+        // If it is at the beginning of the map, then the name was not
+        // found (we have already handled the element the iterator
+        // points to).
+        if (it == zone_finders_.begin()) {
+            return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+        }
+
+        // Check if the previous element is a partial match.
+        --it;
+        const NameComparisonResult result =
+            origin.compare((it->first).reverse());
+        if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
+            return (FindResult(result::PARTIALMATCH, it->second));
+        }
+
+        return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+    }
+
+    virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name&, bool, bool) const {
+        isc_throw(isc::NotImplemented,
+                  "Updater isn't supported in the MockClient");
+    }
+
+    virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
+    getJournalReader(const isc::dns::Name&, uint32_t, uint32_t) const {
+        isc_throw(isc::NotImplemented,
+                  "Journaling isn't supported in the MockClient");
+    }
+
+    result::Result addZone(ZoneFinderPtr finder) {
+        // Use the reverse of the name as the key, so we can quickly
+        // find partial matches in the map.
+        zone_finders_[finder->getOrigin().reverse()] = finder;
+        return (result::SUCCESS);
+    }
+
+private:
+    // Note that because we no longer have the old RBTree, and the new
+    // in-memory DomainTree is not useful as it returns const nodes, we
+    // use a std::map instead. In this map, the key is a name stored in
+    // reverse order of labels to aid in finding partial matches
+    // quickly.
+    std::map<Name, ZoneFinderPtr> zone_finders_;
+};
+
 class QueryTest : public ::testing::TestWithParam<DataSrcType> {
 protected:
     QueryTest() :
@@ -847,7 +918,7 @@ protected:
         response.setOpcode(Opcode::QUERY());
         // create and add a matching zone.
         mock_finder = new MockZoneFinder();
-        memory_client.addZone(ZoneFinderPtr(mock_finder));
+        mock_client.addZone(ZoneFinderPtr(mock_finder));
     }
 
     virtual void SetUp() {
@@ -861,7 +932,7 @@ protected:
         // doesn't happen for derived test class.  This also ensures the
         // data source clients are configured after setting NSEC3 hash in case
         // there's dependency.
-        list_ = createDataSrcClientList(GetParam(), memory_client);
+        list_ = createDataSrcClientList(GetParam(), mock_client);
     }
 
     virtual void TearDown() {
@@ -987,11 +1058,7 @@ private:
 
 protected:
     MockZoneFinder* mock_finder;
-    // We use InMemoryClient here. We could have some kind of mock client
-    // here, but historically, the Query supported only InMemoryClient
-    // (originally named MemoryDataSrc) and was tested with it, so we keep
-    // it like this for now.
-    InMemoryClient memory_client;
+    MockClient mock_client;
 
     boost::shared_ptr<ClientList> list_;
     const Name qname;
@@ -1031,7 +1098,7 @@ class QueryTestForMockOnly : public QueryTest {
 protected:
     // Override SetUp() to avoid parameterized setup
     virtual void SetUp() {
-        list_ = createDataSrcClientList(MOCK, memory_client);
+        list_ = createDataSrcClientList(MOCK, mock_client);
     }
 };
 
@@ -1075,8 +1142,8 @@ responseCheck(Message& response, const isc::dns::Rcode& rcode,
 TEST_P(QueryTest, noZone) {
     // There's no zone in the memory datasource.  So the response should have
     // REFUSED.
-    InMemoryClient empty_memory_client;
-    SingletonList empty_list(empty_memory_client);
+    MockClient empty_mock_client;
+    SingletonList empty_list(empty_mock_client);
     EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
                                   response));
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
@@ -1158,12 +1225,6 @@ TEST_P(QueryTest, apexNSMatch) {
 
 // test type any query logic
 TEST_P(QueryTest, exactAnyMatch) {
-    // This is an in-memory specific bug (#2585), until it's fixed we
-    // tentatively skip the test for in-memory
-    if (GetParam() == INMEMORY) {
-        return;
-    }
-
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
     EXPECT_NO_THROW(query.process(*list_, Name("noglue.example.com"),
@@ -1207,7 +1268,7 @@ TEST_P(QueryTest, nodomainANY) {
     EXPECT_NO_THROW(query.process(*list_, Name("nxdomain.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
-                  NULL, soa_txt, NULL, mock_finder->getOrigin());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 // This tests that when we need to look up Zone's apex NS records for
@@ -1345,7 +1406,7 @@ TEST_P(QueryTest, nxdomain) {
                                   Name("nxdomain.example.com"), qtype,
                                   response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
-                  NULL, soa_txt, NULL, mock_finder->getOrigin());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxdomainWithNSEC) {
@@ -1356,8 +1417,8 @@ TEST_P(QueryTest, nxdomainWithNSEC) {
                                   Name("nxdomain.example.com"), qtype,
                                   response, true));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_nxdomain_txt) + "\n" +
                          string("noglue.example.com. 3600 IN RRSIG ") +
@@ -1369,49 +1430,36 @@ TEST_P(QueryTest, nxdomainWithNSEC) {
 }
 
 TEST_P(QueryTest, nxdomainWithNSEC2) {
-    // there seems to be a bug in the SQLite3 (or database in general) data
-    // source and this doesn't work (Trac #2586).
-    if (GetParam() == SQLITE3) {
-        return;
-    }
-
     // See comments about no_txt.  In this case the best possible wildcard
     // is derived from the next domain of the NSEC that proves NXDOMAIN, and
     // the NSEC to provide the non existence of wildcard is different from
     // the first NSEC.
-    query.process(*list_, Name("(.no.example.com"), qtype, response,
+    query.process(*list_, Name("!.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_mx_txt) + "\n" +
                          string("mx.example.com. 3600 IN RRSIG ") +
                          getCommonRRSIGText("NSEC") + "\n" +
                          string(nsec_no_txt) + "\n" +
-                         string(").no.example.com. 3600 IN RRSIG ") +
+                         string("&.no.example.com. 3600 IN RRSIG ") +
                          getCommonRRSIGText("NSEC")).c_str(),
                   NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxdomainWithNSECDuplicate) {
-    // there seems to be a bug in the SQLite3 (or database in general) data
-    // source and this doesn't work.  This is probably the same type of bug
-    // as nxdomainWithNSEC2 (Trac #2586).
-    if (GetParam() == SQLITE3) {
-        return;
-    }
-
     // See comments about nz_txt.  In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence of wildcard.
     query.process(*list_, Name("nx.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_no_txt) + "\n" +
-                         string(").no.example.com. 3600 IN RRSIG ") +
+                         string("&.no.example.com. 3600 IN RRSIG ") +
                          getCommonRRSIGText("NSEC")).c_str(),
                   NULL, mock_finder->getOrigin());
 }
@@ -1474,8 +1522,8 @@ TEST_F(QueryTestForMockOnly, nxdomainBadNSEC5) {
     query.process(*list_, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_nxdomain_txt) + "\n" +
                          string("noglue.example.com. 3600 IN RRSIG ") +
@@ -1503,7 +1551,7 @@ TEST_P(QueryTest, nxrrset) {
                                   RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
-                  NULL, soa_txt, NULL, mock_finder->getOrigin());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxrrsetWithNSEC) {
@@ -1513,7 +1561,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_www_txt) + "\n" +
                    string("www.example.com. 3600 IN RRSIG ") +
@@ -1524,7 +1573,7 @@ TEST_P(QueryTest, nxrrsetWithNSEC) {
 TEST_P(QueryTest, emptyNameWithNSEC) {
     // Empty non terminal with DNSSEC proof.  This is one of the cases of
     // Section 3.1.3.2 of RFC4035.
-    // mx.example.com. NSEC ).no.example.com. proves no.example.com. is a
+    // mx.example.com. NSEC &.no.example.com. proves no.example.com. is a
     // non empty terminal node.  Note that it also implicitly proves there
     // should be no closer wildcard match (because the empty name is an
     // exact match), so we only need one NSEC.
@@ -1534,7 +1583,8 @@ TEST_P(QueryTest, emptyNameWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_mx_txt) + "\n" +
                    string("mx.example.com. 3600 IN RRSIG ") +
@@ -1550,7 +1600,8 @@ TEST_P(QueryTest, nxrrsetWithoutNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n").c_str(),
                   NULL, mock_finder->getOrigin());
 }
@@ -1693,12 +1744,6 @@ TEST_F(QueryTestForMockOnly, badWildcardProof3) {
 }
 
 TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
-    // This is an in-memory specific bug (#2585), until it's fixed we
-    // tentatively skip the test for in-memory
-    if (GetParam() == INMEMORY) {
-        return;
-    }
-
     // NXRRSET on WILDCARD with DNSSEC proof.  We should have SOA, NSEC that
     // proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
@@ -1706,7 +1751,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_wild_txt) +
                    string("*.wild.example.com. 3600 IN RRSIG ") +
@@ -1715,12 +1761,6 @@ TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
 }
 
 TEST_P(QueryTest, wildcardNxrrsetWithNSEC) {
-    // This is an in-memory specific bug (#2585), until it's fixed we
-    // tentatively skip the test for in-memory
-    if (GetParam() == INMEMORY) {
-        return;
-    }
-
     // WILDCARD + NXRRSET with DNSSEC proof.  We should have SOA, NSEC that
     // proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence RRSETs of
@@ -1729,7 +1769,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithNSEC) {
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_wild_txt_nxrrset) +
                    string("*.uwild.example.com. 3600 IN RRSIG ") +
@@ -1753,7 +1794,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithNSEC3) {
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    // NSEC3 for the closest encloser + its RRSIG
                    string(nsec3_uwild_txt) +
@@ -1816,7 +1858,8 @@ TEST_P(QueryTest, wildcardEmptyWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_empty_prev_txt) +
                    string("t.example.com. 3600 IN RRSIG ") +
@@ -2043,7 +2086,7 @@ TEST_P(QueryTest, DNAME_NX_RRSET) {
                     RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
-        NULL, soa_txt, NULL, mock_finder->getOrigin());
+        NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 /*
@@ -2273,8 +2316,8 @@ TEST_F(QueryTestForMockOnly, dsAboveDelegation) {
     // simple addition.  For now we test it for mock only.
 
     // Pretending to have authority for the child zone, too.
-    memory_client.addZone(ZoneFinderPtr(new AlternateZoneFinder(
-                                            Name("delegation.example.com"))));
+    mock_client.addZone(ZoneFinderPtr(new AlternateZoneFinder(
+                                           Name("delegation.example.com"))));
 
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
@@ -2296,8 +2339,8 @@ TEST_P(QueryTest, dsAboveDelegationNoData) {
     // Similar to the previous case, but the query is for an unsigned zone
     // (which doesn't have a DS at the parent).  The response should be a
     // "no data" error.  The query should still be handled at the parent.
-    memory_client.addZone(ZoneFinderPtr(
-                              new AlternateZoneFinder(
+    mock_client.addZone(ZoneFinderPtr(
+                             new AlternateZoneFinder(
                                   Name("unsigned-delegation.example.com"))));
 
     // The following will succeed only if the search goes to the parent
@@ -2307,8 +2350,8 @@ TEST_P(QueryTest, dsAboveDelegationNoData) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) +
-                   string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(unsigned_delegation_nsec_txt) +
                    "unsigned-delegation.example.com. 3600 IN RRSIG " +
@@ -2324,7 +2367,8 @@ TEST_P(QueryTest, dsBelowDelegation) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_apex_txt) + "\n" +
                    string("example.com. 3600 IN RRSIG ") +
@@ -2342,7 +2386,8 @@ TEST_P(QueryTest, dsBelowDelegationWithDS) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA")).c_str(), NULL,
                   mock_finder->getOrigin());
 }
@@ -2379,12 +2424,13 @@ TEST_F(QueryTestForMockOnly, dsAtGrandParentAndChild) {
 
     // Pretending to have authority for the child zone, too.
     const Name childname("grand.delegation.example.com");
-    memory_client.addZone(ZoneFinderPtr(
-                              new AlternateZoneFinder(childname)));
+    mock_client.addZone(ZoneFinderPtr(
+                             new AlternateZoneFinder(childname)));
     query.process(*list_, childname, RRType::DS(), response, true);
+    // Note that RR TTL of SOA and its RRSIG are set to SOA MINTTL, 0
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
-                   childname.toText() + " 3600 IN RRSIG " +
+                  (childname.toText() + " 0 IN SOA . . 0 0 0 0 0\n" +
+                   childname.toText() + " 0 IN RRSIG " +
                    getCommonRRSIGText("SOA") + "\n" +
                    childname.toText() + " 3600 IN NSEC " +
                    childname.toText() + " SOA NSEC RRSIG\n" +
@@ -2400,13 +2446,14 @@ TEST_F(QueryTestForMockOnly, dsAtRoot) {
     // won't be simple addition.  For now we test it for mock only.
 
     // Pretend to be a root server.
-    memory_client.addZone(ZoneFinderPtr(
-                              new AlternateZoneFinder(Name::ROOT_NAME())));
+    mock_client.addZone(ZoneFinderPtr(
+                             new AlternateZoneFinder(Name::ROOT_NAME())));
     query.process(*list_, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
+    // Note that RR TTL of SOA and its RRSIG are set to SOA MINTTL, 0
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
-                   ". 3600 IN RRSIG " + getCommonRRSIGText("SOA") + "\n" +
+                  (string(". 0 IN SOA . . 0 0 0 0 0\n") +
+                   ". 0 IN RRSIG " + getCommonRRSIGText("SOA") + "\n" +
                    ". 3600 IN NSEC " + ". SOA NSEC RRSIG\n" +
                    ". 3600 IN RRSIG " +
                    getCommonRRSIGText("NSEC")).c_str(), NULL);
@@ -2419,9 +2466,8 @@ TEST_F(QueryTestForMockOnly, dsAtRootWithDS) {
     // We could setup the additional zone for other data sources, but it
     // won't be simple addition.  For now we test it for mock only.
 
-    memory_client.addZone(ZoneFinderPtr(
-                              new AlternateZoneFinder(Name::ROOT_NAME(),
-                                                      true)));
+    mock_client.addZone(ZoneFinderPtr(
+                             new AlternateZoneFinder(Name::ROOT_NAME(), true)));
     query.process(*list_, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
@@ -2443,7 +2489,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec3_www_txt) + "\n" +
                    nsec3_hash_.calculate(Name("www.example.com.")) +
@@ -2452,21 +2499,32 @@ TEST_P(QueryTest, nxrrsetWithNSEC3) {
                   NULL, mock_finder->getOrigin());
 }
 
-// Check the exception is correctly raised when the NSEC3 thing isn't in the
-// zone
-TEST_F(QueryTestForMockOnly, nxrrsetMissingNSEC3) {
-    // This is a broken data source scenario; works only with mock.
-
-    mock_finder->setNSEC3Flag(true);
-    // We just need it to return false for "matched". This indicates
-    // there's no exact match for NSEC3 on www.example.com.
-    ZoneFinder::FindNSEC3Result nsec3(false, 0, ConstRRsetPtr(),
-                                      ConstRRsetPtr());
-    mock_finder->setNSEC3Result(&nsec3);
+TEST_P(QueryTest, nxrrsetDerivedFromOptOutNSEC3) {
+    // In this test we emulate the situation where an empty non-terminal name
+    // is derived from insecure delegation and covered by an opt-out NSEC3.
+    // In the actual test data the covering NSEC3 really has the opt-out
+    // bit set, although the implementation doesn't check it anyway.
+    enableNSEC3(rrsets_to_add_);
+    query.process(*list_, Name("empty.example.com"), RRType::TXT(), response,
+                  true);
 
-    EXPECT_THROW(query.process(*list_, Name("www.example.com"),
-                               RRType::TXT(), response, true),
-                 Query::BadNSEC3);
+    // The closest provable encloser is the origin name (example.com.), and
+    // the next closer is the empty name itself, which is expected to be
+    // covered by an opt-out NSEC3 RR.  The response should contain these 2
+    // NSEC3s.
+    responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
+                   getCommonRRSIGText("SOA") + "\n" +
+                   string(nsec3_apex_txt) + "\n" +
+                   nsec3_hash_.calculate(Name("example.com.")) +
+                   ".example.com. 3600 IN RRSIG " +
+                   getCommonRRSIGText("NSEC3") + "\n" +
+                   string(nsec3_www_txt) + "\n" +
+                   nsec3_hash_.calculate(Name("www.example.com.")) +
+                   ".example.com. 3600 IN RRSIG " +
+                   getCommonRRSIGText("NSEC3") + "\n").c_str(),
+                  NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxrrsetWithNSEC3_ds_exact) {
@@ -2478,7 +2536,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3_ds_exact) {
     query.process(*list_, Name("unsigned-delegation.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(unsigned_delegation_nsec3_txt) + "\n" +
                    nsec3_hash_.calculate(
@@ -2500,7 +2559,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
     query.process(*list_, Name("unsigned-delegation-optout.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec3_apex_txt) + "\n" +
                    nsec3_hash_.calculate(Name("example.com.")) +
@@ -2528,8 +2588,8 @@ TEST_P(QueryTest, nxdomainWithNSEC3Proof) {
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
-                  (string(soa_txt) +
-                   string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    // NSEC3 for the closest encloser + its RRSIG
                    string(nsec3_apex_txt) + "\n" +
diff --git a/src/bin/auth/tests/statistics_unittest.cc b/src/bin/auth/tests/statistics_unittest.cc
deleted file mode 100644
index 052a70e..0000000
--- a/src/bin/auth/tests/statistics_unittest.cc
+++ /dev/null
@@ -1,123 +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 <string>
-
-#include <gtest/gtest.h>
-
-#include <boost/bind.hpp>
-
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-
-#include <cc/data.h>
-#include <cc/session.h>
-
-#include <auth/statistics.h>
-#include <auth/statistics_items.h>
-
-#include <dns/tests/unittest_util.h>
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-using namespace std;
-using namespace isc::cc;
-using namespace isc::dns;
-using namespace isc::data;
-using isc::auth::statistics::Counters;
-using isc::auth::statistics::QRAttributes;
-
-namespace {
-
-class CountersTest : public ::testing::Test {
-protected:
-    CountersTest() : counters() {}
-    ~CountersTest() {}
-    Counters counters;
-};
-
-// Test if the values of the counters are all zero except for the items
-// specified in except_for.
-void
-checkCountersAllZeroExcept(const isc::data::ConstElementPtr counters,
-                           const std::set<std::string>& except_for) {
-    std::map<std::string, ConstElementPtr> stats_map = counters->mapValue();
-
-    for (std::map<std::string, ConstElementPtr>::const_iterator
-            i = stats_map.begin(), e = stats_map.end();
-            i != e;
-            ++i)
-    {
-        int expect = 0;
-        if (except_for.count(i->first) != 0) {
-            expect = 1;
-        }
-        EXPECT_EQ(expect, i->second->intValue()) << "Expected counter "
-            << i->first << " = " << expect << ", actual: "
-            << i->second->intValue();
-    }
-}
-
-TEST_F(CountersTest, incrementNormalQuery) {
-    Message response(Message::RENDER);
-    QRAttributes qrattrs;
-    std::set<std::string> expect_nonzero;
-
-    expect_nonzero.clear();
-    checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero);
-
-    qrattrs.setQueryIPVersion(AF_INET6);
-    qrattrs.setQueryTransportProtocol(IPPROTO_UDP);
-    qrattrs.setQueryOpCode(Opcode::QUERY_CODE);
-    qrattrs.setQueryEDNS(true, false);
-    qrattrs.setQueryDO(true);
-    qrattrs.answerWasSent();
-
-    response.setRcode(Rcode::REFUSED());
-    response.addQuestion(Question(Name("example.com"),
-                                  RRClass::IN(), RRType::AAAA()));
-
-    counters.inc(qrattrs, response);
-
-    expect_nonzero.clear();
-    expect_nonzero.insert("opcode.query");
-    expect_nonzero.insert("queries.udp");
-    expect_nonzero.insert("rcode.refused");
-    checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero);
-}
-
-int
-countTreeElements(const struct CounterTypeTree* tree) {
-    int count = 0;
-    for (int i = 0; tree[i].name != NULL; ++i) {
-        if (tree[i].sub_tree == NULL) {
-            ++count;
-        } else {
-            count += countTreeElements(tree[i].sub_tree);
-        }
-    }
-    return count;
-}
-
-TEST(StatisticsItemsTest, QRItemNamesCheck) {
-    EXPECT_EQ(QR_COUNTER_TYPES, countTreeElements(QRCounterTree));
-}
-
-}
diff --git a/src/bin/auth/tests/statistics_unittest.cc.pre b/src/bin/auth/tests/statistics_unittest.cc.pre
new file mode 100644
index 0000000..cf6f29a
--- /dev/null
+++ b/src/bin/auth/tests/statistics_unittest.cc.pre
@@ -0,0 +1,714 @@
+// 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/bind.hpp>
+
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrttl.h>
+
+#include <cc/data.h>
+
+#include <auth/statistics.h>
+#include <auth/statistics_items.h>
+
+#include <dns/tests/unittest_util.h>
+
+#include "statistics_util.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::auth::statistics;
+using namespace isc::auth::unittest;
+
+namespace {
+
+// ### STATISTICS ITEMS DEFINITION ###
+
+class CountersTest : public ::testing::Test {
+protected:
+    CountersTest() : counters() {}
+    ~CountersTest() {}
+    Counters counters;
+};
+
+void
+buildSkeletonMessage(MessageAttributes& msgattrs) {
+    msgattrs.setRequestIPVersion(AF_INET);
+    msgattrs.setRequestTransportProtocol(IPPROTO_UDP);
+    msgattrs.setRequestOpCode(Opcode::QUERY());
+    msgattrs.setRequestEDNS0(true);
+    msgattrs.setRequestDO(true);
+}
+
+TEST_F(CountersTest, invalidParameterForSetRequestIPVersion) {
+    MessageAttributes msgattrs;
+
+    // It should not throw if the parameter is AF_INET or AF_INET6.
+    EXPECT_NO_THROW(msgattrs.setRequestIPVersion(AF_INET));
+    EXPECT_NO_THROW(msgattrs.setRequestIPVersion(AF_INET6));
+
+    // It should throw isc::InvalidParameter if the parameter is not AF_INET
+    // nor AF_INET6.
+    EXPECT_THROW(msgattrs.setRequestIPVersion(AF_UNIX), isc::InvalidParameter);
+}
+
+TEST_F(CountersTest, invalidParameterForSetRequestTransportProtocol) {
+    MessageAttributes msgattrs;
+
+    // It should not throw if the parameter is IPPROTO_UDP or IPPROTO_TCP.
+    EXPECT_NO_THROW(msgattrs.setRequestTransportProtocol(IPPROTO_UDP));
+    EXPECT_NO_THROW(msgattrs.setRequestTransportProtocol(IPPROTO_TCP));
+
+    // It should throw isc::InvalidParameter if the parameter is not
+    // IPPROTO_UDP nor IPPROTO_TCP.
+    EXPECT_THROW(msgattrs.setRequestTransportProtocol(IPPROTO_IP),
+                 isc::InvalidParameter);
+}
+
+TEST_F(CountersTest, invalidOperationForGetRequestOpCode) {
+    MessageAttributes msgattrs;
+
+    // getRequestOpCode() should return boost::none when called before
+    // opcode is set with setRequestOpCode().
+    EXPECT_FALSE(msgattrs.getRequestOpCode());
+
+    msgattrs.setRequestOpCode(Opcode::QUERY());
+    // getRequestOpCode() should be Opcode::QUERY.
+    EXPECT_EQ(Opcode::QUERY(), msgattrs.getRequestOpCode().get());
+}
+
+TEST_F(CountersTest, invalidParameterForSetRequestTSIG) {
+    MessageAttributes msgattrs;
+
+    // These patterns should not throw:
+    //      request signature  badsig
+    //     --------------------------
+    //      (none)             false
+    //      TSIG               false
+    //      TSIG               true
+    EXPECT_NO_THROW(msgattrs.setRequestTSIG(false, false));
+    EXPECT_NO_THROW(msgattrs.setRequestTSIG(true, false));
+    EXPECT_NO_THROW(msgattrs.setRequestTSIG(true, true));
+
+    // It should throw isc::InvalidParameter if a message is not signed but
+    // badsig is true
+    EXPECT_THROW(msgattrs.setRequestTSIG(false, true), isc::InvalidParameter);
+}
+
+TEST_F(CountersTest, incrementResponse) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test response counters are incremented only if responded == true.
+    for (int i = 0; i < 2; ++i) {
+        const bool responded = i & 1;
+
+        buildSkeletonMessage(msgattrs);
+
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        counters.inc(msgattrs, response, responded);
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = i+1;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = responded ? 1 : 0;
+        expect["qrynoauthans"] = responded ? 1 : 0;
+        expect["rcode.refused"] = responded ? 1 : 0;
+        expect["authqryrej"] = responded ? 1 : 0;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementProtocolType) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test these patterns:
+    //      af     proto
+    //     -----------------
+    //      ipv6   tcp
+    //      ipv4   tcp
+    //      ipv6   udp
+    //      ipv4   udp
+    int count_v4 = 0, count_v6 = 0, count_udp = 0, count_tcp = 0;
+    for (int i = 0; i < 4; ++i) {
+        const int af = i & 1 ? AF_INET : AF_INET6;
+        const int proto = i & 2 ? IPPROTO_UDP : IPPROTO_TCP;
+
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestIPVersion(af);
+        msgattrs.setRequestTransportProtocol(proto);
+
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        counters.inc(msgattrs, response, true);
+
+        if (af == AF_INET) {
+            ++count_v4;
+        } else {
+            ++count_v6;
+        }
+        if (proto == IPPROTO_UDP) {
+            ++count_udp;
+        } else {
+            ++count_tcp;
+        }
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = count_v4;
+        expect["request.v6"] = count_v6;
+        expect["request.udp"] = count_udp;
+        expect["request.tcp"] = count_tcp;
+        expect["request.edns0"] = i+1;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = i+1;
+        expect["qrynoauthans"] = i+1;
+        expect["rcode.refused"] = i+1;
+        expect["authqryrej"] = i+1;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementDO) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test these patterns:
+    //     DNSSEC OK
+    //    -----------
+    //     false
+    //     true
+    for (int i = 0; i < 2; ++i) {
+        const bool is_dnssec_ok = i & 1;
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestDO(is_dnssec_ok);
+
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        counters.inc(msgattrs, response, true);
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = i+1;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = i & 1;
+        expect["responses"] = i+1;
+        expect["qrynoauthans"] = i+1;
+        expect["rcode.refused"] = i+1;
+        expect["authqryrej"] = i+1;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementEDNS) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test these patterns:
+    //     request edns0   response edns0
+    //    --------------------------------
+    //     false           true
+    //     true            false
+    //
+    // They can't be both true since edns0 and badednsver are exclusive.
+    int count_req_edns0 = 0, count_res_edns0 = 0;
+    for (int i = 0; i < 2; ++i) {
+        const bool is_edns0 = i & 1;
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestEDNS0(is_edns0);
+
+        if (!is_edns0) {
+            ConstEDNSPtr edns = EDNSPtr(new EDNS(0));
+            response.setEDNS(edns);
+        } else {
+            response.setEDNS(EDNSPtr());
+        }
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        counters.inc(msgattrs, response, true);
+
+        if (is_edns0) {
+            ++count_req_edns0;
+        } else {
+            ++count_res_edns0;
+        }
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = count_req_edns0;
+        expect["response.edns0"] = count_res_edns0;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = i+1;
+        expect["qrynoauthans"] = i+1;
+        expect["rcode.refused"] = i+1;
+        expect["authqryrej"] = i+1;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementTSIG) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test these patterns:
+    //      request signature  badsig   response signature
+    //     -----------------------------------------------
+    //      (none)             false    (none)
+    //      TSIG               false    TSIG
+    //      TSIG               true     (none)
+    //
+    // badsig can't be true if the message does not have signature.
+    int count_req_tsig = 0, count_res_tsig = 0, count_badsig = 0;
+    for (int i = 0; i < 3; ++i) {
+        const bool is_req_tsig = (i == 2) ? true : (i & 1) != 0;
+        const bool is_res_tsig = (i & 1) != 0;
+        const bool is_badsig = (i & 2) != 0;
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestTSIG(is_req_tsig, is_badsig);
+        msgattrs.setResponseTSIG(is_res_tsig);
+
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        // don't increment response counters if signature is bad
+        counters.inc(msgattrs, response, !is_badsig);
+
+        if (is_req_tsig) {
+            ++count_req_tsig;
+        }
+        if (is_res_tsig) {
+            ++count_res_tsig;
+        }
+        if (is_badsig) {
+            ++count_badsig;
+        }
+
+        expect.clear();
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["opcode.query"] = i+1;
+        expect["request.edns0"] = i+1 - count_badsig;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = i+1 - count_badsig;
+        expect["request.tsig"] = count_req_tsig;
+        expect["response.tsig"] = count_res_tsig;
+        expect["request.sig0"] = 0;
+        expect["request.badsig"] = count_badsig;
+        expect["responses"] = i+1 - count_badsig;
+        expect["qrynoauthans"] = i+1 - count_badsig;
+        expect["rcode.refused"] = i+1 - count_badsig;
+        expect["authqryrej"] = i+1 - count_badsig;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementOpcode) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test all opcodes (QUERY..RESERVED15)
+    int count_all = 0, count_opcode_other = 0;
+    for (uint8_t i = Opcode::QUERY().getCode(),
+                 e = Opcode::RESERVED15().getCode();
+         i <= e;
+         ++i)
+    {
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestOpCode(Opcode(i));
+        msgattrs.setRequestTSIG(false, false);
+
+        response.setRcode(Rcode::REFUSED());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        for (uint8_t j = 0; j < i; ++j) {
+            // count up i times for i-th opcode to identify counters
+            counters.inc(msgattrs, response, true);
+            ++count_all;
+        }
+
+        expect.clear();
+        expect["request.v4"] = count_all;
+        expect["request.udp"] = count_all;
+        expect["request.edns0"] = count_all;
+        expect["request.badednsver"] = 0;
+        expect["request.dnssec_ok"] = count_all;
+        expect["request.tsig"] = 0;
+        expect["request.sig0"] = 0;
+        expect["request.badsig"] = 0;
+        expect["responses"] = count_all;
+        expect["rcode.refused"] = count_all;
+        if (opcode_to_msgcounter[i] == MSG_OPCODE_OTHER) {
+            count_opcode_other += i;
+        }
+        for (uint8_t j = 0; j <= i; ++j) {
+            if (opcode_to_msgcounter[j] == MSG_OPCODE_OTHER) {
+                expect["opcode.other"] = count_opcode_other;
+            } else {
+                std::string code_text = Opcode(j).toText();
+                std::transform(code_text.begin(), code_text.end(),
+                               code_text.begin(), ::tolower);
+                expect["opcode."+code_text] = j;
+            }
+        }
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementRcode) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test all rcodes (NOERROR..BADVERS)
+    int count_all = 0, count_rcode_other = 0, count_ednsbadver = 0;
+    for (uint16_t i = Rcode::NOERROR().getCode(),
+                  e = Rcode::BADVERS().getCode();
+         i <= e;
+         ++i)
+    {
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestOpCode(Opcode::IQUERY());
+        msgattrs.setRequestTSIG(false, false);
+
+        response.setRcode(Rcode(i));
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::AAAA()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        for (uint16_t j = 0; j < i; ++j) {
+            // count up i times for i-th rcode to identify counters
+            counters.inc(msgattrs, response, true);
+            ++count_all;
+        }
+
+        expect.clear();
+        expect["opcode.iquery"] = count_all;
+        expect["request.v4"] = count_all;
+        expect["request.udp"] = count_all;
+        expect["request.edns0"] = count_all;
+        expect["request.dnssec_ok"] = count_all;
+        expect["request.tsig"] = 0;
+        expect["request.sig0"] = 0;
+        expect["request.badsig"] = 0;
+        expect["responses"] = count_all;
+        if (rcode_to_msgcounter[i] == MSG_RCODE_OTHER) {
+            count_rcode_other += i;
+        }
+        // "request.badednsver" counts for Rcode == BADVERS
+        if (rcode_to_msgcounter[i] == MSG_RCODE_BADVERS) {
+            count_ednsbadver += i;
+        }
+        expect["request.badednsver"] = count_ednsbadver;
+        for (uint16_t j = 0; j <= i; ++j) {
+            if (rcode_to_msgcounter[j] == MSG_RCODE_OTHER) {
+                expect["rcode.other"] = count_rcode_other;
+            } else {
+                std::string code_text = Rcode(j).toText();
+                std::transform(code_text.begin(), code_text.end(),
+                               code_text.begin(), ::tolower);
+                expect["rcode."+code_text] = j;
+            }
+        }
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementTruncated) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Test these patterns:
+    //      truncated
+    //     -----------
+    //      false
+    //      true
+    int count_truncated = 0;
+    for (int i = 0; i < 2; ++i) {
+        const bool is_truncated = i & 1;
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestOpCode(Opcode::IQUERY());
+        msgattrs.setRequestTSIG(false, false);
+        msgattrs.setResponseTruncated(is_truncated);
+
+        response.setRcode(Rcode::SERVFAIL());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::TXT()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+        counters.inc(msgattrs, response, true);
+
+        if (is_truncated) {
+            ++count_truncated;
+        }
+
+        expect.clear();
+        expect["opcode.iquery"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = i+1;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = i+1;
+        expect["rcode.servfail"] = i+1;
+        expect["response.truncated"] = count_truncated;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementQryAuthAnsAndNoAuthAns) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Opcode = QUERY, ANCOUNT = 0 (don't care), Rcode = SERVFAIL (don't care)
+    // Test these patterns:
+    //      AA flag
+    //     -----------------------
+    //      false -> QryNoAuthAns
+    //      true  -> QryAuthAns
+    int count_authans = 0, count_noauthans = 0;
+    for (int i = 0; i < 2; ++i) {
+        const bool is_aa_set = i & 1;
+        buildSkeletonMessage(msgattrs);
+        msgattrs.setRequestTSIG(false, false);
+
+        response.setRcode(Rcode::SERVFAIL());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::TXT()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+        if (is_aa_set) {
+            response.setHeaderFlag(Message::HEADERFLAG_AA);
+            ++count_authans;
+        } else {
+            ++count_noauthans;
+        }
+
+        counters.inc(msgattrs, response, true);
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = i+1;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = i+1;
+        expect["rcode.servfail"] = i+1;
+        expect["qryauthans"] = count_authans;
+        expect["qrynoauthans"] = count_noauthans;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementQrySuccess) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Opcode = QUERY, Rcode = NOERROR, ANCOUNT > 0
+    msgattrs.setRequestIPVersion(AF_INET);
+    msgattrs.setRequestTransportProtocol(IPPROTO_UDP);
+    msgattrs.setRequestOpCode(Opcode::QUERY());
+    msgattrs.setRequestEDNS0(true);
+    msgattrs.setRequestDO(true);
+    msgattrs.setRequestTSIG(false, false);
+
+    response.setRcode(Rcode::NOERROR());
+    response.addQuestion(Question(Name("example.com"),
+                                  RRClass::IN(), RRType::TXT()));
+    RRsetPtr answer_rrset(new RRset(Name("example.com"),
+                                    RRClass::IN(), RRType::TXT(),
+                                    RRTTL(3600)));
+    answer_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                              RRClass::IN(),
+                                              "Answer"));
+    response.addRRset(Message::SECTION_ANSWER, answer_rrset);
+    response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+    counters.inc(msgattrs, response, true);
+
+    expect.clear();
+    expect["opcode.query"] = 1;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["request.edns0"] = 1;
+    expect["request.dnssec_ok"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.noerror"] = 1;
+    expect["qrysuccess"] = 1;
+    // noauthans is also incremented
+    expect["qrynoauthans"] = 1;
+    checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                            expect);
+}
+
+TEST_F(CountersTest, incrementQryReferralAndNxrrset) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Opcode = QUERY, Rcode = NOERROR, ANCOUNT = 0
+    // Test these patterns:
+    //      AA flag
+    //     ----------------------
+    //      false -> QryReferral
+    //      true  -> QryNxrrset
+    int count_referral = 0, count_nxrrset = 0;
+    for (int i = 0; i < 2; ++i) {
+        const bool is_aa_set = i & 1;
+        msgattrs.setRequestIPVersion(AF_INET);
+        msgattrs.setRequestTransportProtocol(IPPROTO_UDP);
+        msgattrs.setRequestOpCode(Opcode::QUERY());
+        msgattrs.setRequestEDNS0(true);
+        msgattrs.setRequestDO(true);
+        msgattrs.setRequestTSIG(false, false);
+
+        response.setRcode(Rcode::NOERROR());
+        response.addQuestion(Question(Name("example.com"),
+                                      RRClass::IN(), RRType::TXT()));
+        response.setHeaderFlag(Message::HEADERFLAG_QR);
+        if (is_aa_set) {
+            response.setHeaderFlag(Message::HEADERFLAG_AA);
+            ++count_nxrrset;
+        } else {
+            ++count_referral;
+        }
+
+        counters.inc(msgattrs, response, true);
+
+        expect.clear();
+        expect["opcode.query"] = i+1;
+        expect["request.v4"] = i+1;
+        expect["request.udp"] = i+1;
+        expect["request.edns0"] = i+1;
+        expect["request.dnssec_ok"] = i+1;
+        expect["responses"] = i+1;
+        expect["rcode.noerror"] = i+1;
+        expect["qrynxrrset"] = count_nxrrset;
+        expect["qryreferral"] = count_referral;
+        // qryauthans or qrynoauthans is also incremented
+        expect["qryauthans"] = count_nxrrset;
+        expect["qrynoauthans"] = count_referral;
+        checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                                expect);
+    }
+}
+
+TEST_F(CountersTest, incrementAuthQryRej) {
+    Message response(Message::RENDER);
+    MessageAttributes msgattrs;
+    std::map<std::string, int> expect;
+
+    // Opcode = QUERY, Rcode = REFUSED, ANCOUNT = 0 (don't care)
+    msgattrs.setRequestIPVersion(AF_INET);
+    msgattrs.setRequestTransportProtocol(IPPROTO_UDP);
+    msgattrs.setRequestOpCode(Opcode::QUERY());
+    msgattrs.setRequestEDNS0(true);
+    msgattrs.setRequestDO(true);
+    msgattrs.setRequestTSIG(false, false);
+
+    response.setRcode(Rcode::REFUSED());
+    response.addQuestion(Question(Name("example.com"),
+                                  RRClass::IN(), RRType::TXT()));
+    response.setHeaderFlag(Message::HEADERFLAG_QR);
+
+    counters.inc(msgattrs, response, true);
+
+    expect.clear();
+    expect["opcode.query"] = 1;
+    expect["request.v4"] = 1;
+    expect["request.udp"] = 1;
+    expect["request.edns0"] = 1;
+    expect["request.dnssec_ok"] = 1;
+    expect["responses"] = 1;
+    expect["rcode.refused"] = 1;
+    expect["authqryrej"] = 1;
+    // noauthans is also incremented since AA bit is not set
+    expect["qrynoauthans"] = 1;
+    checkStatisticsCounters(counters.get()->get("zones")->get("_SERVER_"),
+                            expect);
+}
+
+int
+countTreeElements(const struct CounterSpec* tree) {
+    int count = 0;
+    for (int i = 0; tree[i].name != NULL; ++i) {
+        if (tree[i].sub_counters == NULL) {
+            ++count;
+        } else {
+            count += countTreeElements(tree[i].sub_counters);
+        }
+    }
+    return (count);
+}
+
+TEST(StatisticsItemsTest, MSGItemNamesCheck) {
+    EXPECT_EQ(MSG_COUNTER_TYPES, countTreeElements(msg_counter_tree));
+}
+
+}
diff --git a/src/bin/auth/tests/statistics_util.cc b/src/bin/auth/tests/statistics_util.cc
new file mode 100644
index 0000000..bb2cd5c
--- /dev/null
+++ b/src/bin/auth/tests/statistics_util.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2012  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 "statistics_util.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <map>
+
+namespace {
+void
+flatten(std::map<std::string, int>& flat_map, const std::string& prefix,
+        const isc::data::ConstElementPtr map_element)
+{
+    std::map<std::string, isc::data::ConstElementPtr> map =
+        map_element->mapValue();
+    for (std::map<std::string, isc::data::ConstElementPtr>::const_iterator
+             i = map.begin(), e = map.end();
+         i != e;
+         ++i)
+    {
+        switch (i->second->getType()) {
+            case isc::data::Element::map:
+                flatten(flat_map, i->first + ".", i->second);
+                break;
+            case isc::data::Element::integer:
+                flat_map[prefix + i->first] = i->second->intValue();
+                break;
+            default:
+                FAIL() << "Element Parse Error";
+        }
+    }
+}
+}
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+void
+checkStatisticsCounters(const isc::data::ConstElementPtr counters,
+                        const std::map<std::string, int>& expect)
+{
+    std::map<std::string, int> stats_map;
+    flatten(stats_map, "", counters);
+
+    for (std::map<std::string, int>::const_iterator
+            i = stats_map.begin(), e = stats_map.end();
+            i != e;
+            ++i)
+    {
+        const int value =
+            expect.find(i->first) == expect.end() ?
+                0 : expect.find(i->first)->second;
+        EXPECT_EQ(value, i->second) << "Expected counter "
+            << i->first << " = " << value << ", actual: "
+            << i->second;
+    }
+}
+
+} // end of unittest
+} // end of auth
+} // end of isc
diff --git a/src/bin/auth/tests/statistics_util.h b/src/bin/auth/tests/statistics_util.h
new file mode 100644
index 0000000..b01a016
--- /dev/null
+++ b/src/bin/auth/tests/statistics_util.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2012  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 __AUTH_STATISTICS_UTIL_H
+#define __AUTH_STATISTICS_UTIL_H 1
+
+#include <cc/data.h>
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+// Test if the counters has expected values specified in expect and the others
+// are zero.
+void
+checkStatisticsCounters(const isc::data::ConstElementPtr counters,
+                        const std::map<std::string, int>& expect);
+
+} // end of unittest
+} // end of auth
+} // end of isc
+
+#endif  // __AUTH_STATISTICS_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/auth/tests/testdata/Makefile.am b/src/bin/auth/tests/testdata/Makefile.am
index fed498a..ebde800 100644
--- a/src/bin/auth/tests/testdata/Makefile.am
+++ b/src/bin/auth/tests/testdata/Makefile.am
@@ -23,7 +23,6 @@ EXTRA_DIST += simpleresponse_fromWire.spec
 EXTRA_DIST += spec.spec
 
 EXTRA_DIST += example.com
-EXTRA_DIST += example.zone
 EXTRA_DIST += example.sqlite3
 
 EXTRA_DIST += example-base-inc.zone example-nsec3-inc.zone
diff --git a/src/bin/auth/tests/testdata/example-base-inc.zone b/src/bin/auth/tests/testdata/example-base-inc.zone
index bbcbef1..08fbf86 100644
--- a/src/bin/auth/tests/testdata/example-base-inc.zone
+++ b/src/bin/auth/tests/testdata/example-base-inc.zone
@@ -150,32 +150,32 @@ t.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 e
 ;; the best possible wildcard is below the "next domain" of the NSEC RR that
 ;; proves the NXDOMAIN, i.e.,
 ;; mx.example.com. (exist)
-;; (.no.example.com. (qname, NXDOMAIN)
-;; ).no.example.com. (exist)
+;; !.no.example.com. (qname, NXDOMAIN)
+;; &.no.example.com. (exist)
 ;; *.no.example.com. (best possible wildcard, not exist)
 ;var=no_txt
-\).no.example.com. 3600 IN AAAA 2001:db8::53
+&.no.example.com. 3600 IN AAAA 2001:db8::53
 ;; NSEC records.
 ;var=nsec_apex_txt
 example.com. 3600 IN NSEC cname.example.com. NS SOA NSEC RRSIG
 ;var=
 example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
 ;var=nsec_mx_txt
-mx.example.com. 3600 IN NSEC \).no.example.com. MX NSEC RRSIG
+mx.example.com. 3600 IN NSEC &.no.example.com. MX NSEC RRSIG
 
 ;var=
 mx.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
 
 ;var=nsec_no_txt
-\).no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG
+&.no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG
 
 ;var=
-\).no.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
+&.no.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
 
 ;; We'll also test the case where a single NSEC proves both NXDOMAIN and the
 ;; non existence of wildcard.  The following records will be used for that
 ;; test.
-;; ).no.example.com. (exist, whose NSEC proves everything)
+;; &.no.example.com. (exist, whose NSEC proves everything)
 ;; *.no.example.com. (best possible wildcard, not exist)
 ;; nx.no.example.com. (NXDOMAIN)
 ;; nz.no.example.com. (exist)
@@ -234,3 +234,8 @@ bad-delegation.example.com. 3600 IN NS ns.example.net.
 ;; or NSEC3 that proves it.
 ;var=nosec_delegation_txt
 nosec-delegation.example.com. 3600 IN NS ns.nosec.example.net.
+
+;; Setup for emulating insecure delegation that contain an empty name.
+;; the delegation itself isn't expected to be used directly in tests.
+;var=
+delegation.empty.example.com. 3600 IN NS ns.delegation.empty.example
diff --git a/src/bin/auth/tests/testdata/example-nsec3-inc.zone b/src/bin/auth/tests/testdata/example-nsec3-inc.zone
index 7742df0..d480ffe 100644
--- a/src/bin/auth/tests/testdata/example-nsec3-inc.zone
+++ b/src/bin/auth/tests/testdata/example-nsec3-inc.zone
@@ -1,4 +1,4 @@
-;; See query_testzone_data.txt for general notes.
+;; See example-base-inc.zone for general notes.
 
 ;; NSEC3PARAM.  This is needed for database-based data source to
 ;; signal the zone is NSEC3-signed
diff --git a/src/bin/bind10/.gitignore b/src/bin/bind10/.gitignore
index 2cf6b50..411e4fd 100644
--- a/src/bin/bind10/.gitignore
+++ b/src/bin/bind10/.gitignore
@@ -1,4 +1,6 @@
-/bind10
-/bind10_src.py
 /run_bind10.sh
+/bind10
 /bind10.8
+/b10-init
+/b10-init.8
+/init.py
diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am
index 86c6595..b2e9f05 100644
--- a/src/bin/bind10/Makefile.am
+++ b/src/bin/bind10/Makefile.am
@@ -1,29 +1,33 @@
 SUBDIRS = . tests
 
 sbin_SCRIPTS = bind10
-CLEANFILES = bind10 bind10_src.pyc
-CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/bind10_messages.py
-CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/bind10_messages.pyc
+pkglibexec_SCRIPTS = b10-init
+CLEANFILES = b10-init b10-init.pyc init.pyc
+CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/init_messages.py
+CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/init_messages.pyc
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
-nodist_pylogmessage_PYTHON = $(PYTHON_LOGMSGPKG_DIR)/work/bind10_messages.py
+nodist_pylogmessage_PYTHON = $(PYTHON_LOGMSGPKG_DIR)/work/init_messages.py
 pylogmessagedir = $(pyexecdir)/isc/log_messages/
 
 noinst_SCRIPTS = run_bind10.sh
 
 bind10dir = $(pkgdatadir)
-bind10_DATA = bob.spec
-EXTRA_DIST = bob.spec
+bind10_DATA = init.spec
+EXTRA_DIST = init.spec bind10.in
 
-man_MANS = bind10.8
-DISTCLEANFILES = $(man_MANS)
-EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes
+man_MANS = b10-init.8 bind10.8
+DISTCLEANFILES = $(man_MANS) bind10
+EXTRA_DIST += $(man_MANS) b10-init.xml bind10.xml init_messages.mes
 
 if GENERATE_DOCS
 
 bind10.8: bind10.xml
-	@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bind10.xml 
+	@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bind10.xml
+
+b10-init.8: b10-init.xml
+	@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-init.xml
 
 #dist-local-check-mans-enabled:
 #	@if grep "Man generation disabled" $(man_MANS) >/dev/null; then $(RM) $(man_MANS); fi
@@ -40,15 +44,15 @@ $(man_MANS):
 
 endif
 
-$(PYTHON_LOGMSGPKG_DIR)/work/bind10_messages.py : bind10_messages.mes
+$(PYTHON_LOGMSGPKG_DIR)/work/init_messages.py : init_messages.mes
 	$(top_builddir)/src/lib/log/compiler/message \
-	-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/bind10_messages.mes
+	-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/init_messages.mes
 
 # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
-bind10: bind10_src.py $(PYTHON_LOGMSGPKG_DIR)/work/bind10_messages.py
+b10-init: init.py $(PYTHON_LOGMSGPKG_DIR)/work/init_messages.py
 	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
 	       -e "s|@@LIBDIR@@|$(libdir)|" \
-	       -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bind10_src.py >$@
+	       -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" init.py >$@
 	chmod a+x $@
 
 pytest:
diff --git a/src/bin/bind10/README b/src/bin/bind10/README
index e1d2d89..d75c0cd 100644
--- a/src/bin/bind10/README
+++ b/src/bin/bind10/README
@@ -1,11 +1,12 @@
-This directory contains the source for the "Boss of Bind" program.
+This directory contains the source for the "b10-init" program, as well as
+the "bind10" script that runs it.
 
 Files:
   Makefile.am      - build information
   README           - this file
   TODO             - remaining development tasks for this program
   bind10.py.in     - used to make bind10.py with proper Python paths
-  bob.spec         - defines the options and commands
+  init.spec        - defines the options and commands
   run_bind10.sh.in - use to make run_bind10.sh with proper Python paths
 
 The "tests" directory contains unit tests for the application.
diff --git a/src/bin/bind10/b10-init.xml b/src/bin/bind10/b10-init.xml
new file mode 100644
index 0000000..de7832d
--- /dev/null
+++ b/src/bin/bind10/b10-init.xml
@@ -0,0 +1,519 @@
+<!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) 2010-2012  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>February 5, 2013</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-init</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-init</refname>
+    <refpurpose>BIND 10 Init process</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2010-2013</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-init</command>
+      <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
+      <arg><option>-i</option></arg>
+      <arg><option>-m <replaceable>file</replaceable></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>-w <replaceable>wait_time</replaceable></option></arg>
+      <arg><option>--clear-config</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-kill</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>
+      <arg><option>--wait <replaceable>wait_time</replaceable></option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>The <command>b10-init</command> daemon starts up other
+    BIND 10 required daemons.  It handles restarting of exiting
+    programs and also the shutdown of all managed daemons.</para>
+
+<!-- TODO: list what it starts here? -->
+
+<!-- TODO
+    <para>The configuration of the <command>b10-init</command> daemon
+    is defined in the TODO configuration file, as described in the
+    <citerefentry><refentrytitle>TODO</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    manual page.</para>
+-->
+
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>
+          <option>-c</option> <replaceable>config-filename</replaceable>,
+          <option>--config-file</option> <replaceable>config-filename</replaceable>
+        </term>
+        <listitem>
+          <para>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.
+          Defaults to <filename>b10-config.db</filename>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--clear-config</option>
+        </term>
+        <listitem>
+	  <para>
+	    This will create a backup of the existing configuration
+	    file, remove it and start
+	    <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+            with the default configuration.
+	    The name of the backup file can be found in the logs
+	    (<varname>CFGMGR_BACKED_UP_CONFIG_FILE</varname>).
+	    (It will append a number to the backup filename if a
+	    previous backup file exists.)
+
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <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.
+	  Currently only
+	  <citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+	  uses it to locate the configuration file, but the usage
+	  might be extended for other programs and other types of
+	  files.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-m</option> <replaceable>file</replaceable>,
+           <option>--msgq-socket-file</option> <replaceable>file</replaceable></term>
+
+        <listitem>
+          <para>The UNIX domain socket file for the
+	    <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+            daemon to use.
+            The default is
+            <filename>/usr/local/var/bind10/msg_socket</filename>.
+<!-- @localstatedir@/@PACKAGE_NAME@/msg_socket -->
+           </para>
+         </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-i</option>, <option>--no-kill</option></term>
+        <listitem>
+	  <para>When this option is passed, <command>b10-init</command>
+	  does not send SIGTERM and SIGKILL signals to modules during
+	  shutdown. (This option was introduced for use during
+	  testing.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-u</option> <replaceable>user</replaceable>, <option>--user</option> <replaceable>name</replaceable></term>
+<!-- TODO: example more detail. -->
+        <listitem>
+          <para>The username for <command>b10-init</command> to run as.
+            <command>b10-init</command> must be initially ran as the
+            root user to use this option.
+            The default is to run as the current user.</para>
+         </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--pid-file</option> <replaceable>filename</replaceable></term>
+        <listitem>
+          <para>If defined, the PID of the <command>b10-init</command> is stored
+             in this file.
+          </para>
+         </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--pretty-name <replaceable>name</replaceable></option></term>
+
+        <listitem>
+          <para>The name this process should have in tools like
+          <command>ps</command> or <command>top</command>. This
+          is handy if you have multiple versions/installations
+          of <command>b10-init</command>.
+<!-- TODO: only supported with setproctitle feature
+The default is the basename of ARG 0.
+-->
+</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v</option>, <option>--verbose</option></term>
+        <listitem>
+	  <para>Display more about what is going on for
+	  <command>b10-init</command> and its child processes.</para>
+<!-- TODO: not true about all children yet -->
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-w</option> <replaceable>wait_time</replaceable>, <option>--wait</option> <replaceable>wait_time</replaceable></term>
+        <listitem>
+	  <para>Sets the amount of time that BIND 10 will wait for
+	  the configuration manager (a key component of BIND 10)
+	  to initialize itself before abandoning the start up and
+	  terminating with an error.  The
+	  <replaceable>wait_time</replaceable> is specified in
+	  seconds and has a default value of 10.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+<!--
+TODO: configuration section
+-->
+
+  <refsect1>
+    <title>CONFIGURATION AND COMMANDS</title>
+
+    <para>
+      The configuration provides settings for components for
+      <command>b10-init</command> to manage under
+      <varname>/Init/components/</varname>.
+      The default elements are:
+    </para>
+
+    <itemizedlist>
+
+      <listitem>
+        <para> <varname>/Init/components/b10-cmdctl</varname> </para>
+      </listitem>
+
+      <listitem>
+        <para> <varname>/Init/components/b10-stats</varname> </para>
+      </listitem>
+
+    </itemizedlist>
+
+    <para>
+      (Note that the startup of <command>b10-sockcreator</command>,
+      <command>b10-cfgmgr</command>, and <command>b10-msgq</command>
+      is not configurable. They are hardcoded and <command>b10-init</command>
+      will not run without them.)
+    </para>
+
+    <para>
+      The named sets for components contain the following settings:
+    </para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><varname>address</varname></term>
+        <listitem>
+	  <para>The name used for communicating to it on the message
+	  bus.</para>
+<!-- NOTE: vorner said:
+These can be null, because the components are special ones, and
+the special class there already knows the address. It is (I hope)
+explained in the guide. I'd like to get rid of the special components
+sometime and I'd like it to teach to guess the address.
+-->
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>kind</varname></term>
+        <listitem>
+          <para>
+            This defines how required a component is.
+            The possible settings for <varname>kind</varname> are:
+            <varname>core</varname> (system won't start if it won't
+            start and <command>b10-init</command> will shutdown if
+            a <quote>core</quote> component crashes),
+            <varname>dispensable</varname> (<command>b10-init</command>
+            will restart failing component),
+            and
+	    <varname>needed</varname> (<command>b10-init</command>
+	    will shutdown if component won't initially start, but
+	    if crashes later, it will attempt to restart).
+            This setting is required.
+<!-- TODO: formatting -->
+          </para>
+        </listitem>
+      </varlistentry>
+
+<!--
+TODO: currently not used
+      <varlistentry>
+        <term> <varname>params</varname> </term>
+        <listitem>
+          <para>
+list
+</para>
+        </listitem>
+      </varlistentry>
+-->
+
+      <varlistentry>
+        <term> <varname>priority</varname> </term>
+        <listitem>
+          <para>This is an integer. <command>b10-init</command>
+            will start the components with largest priority numbers first.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+          <term> <varname>process</varname> </term>
+        <listitem>
+          <para>This is the filename of the executable to be started.
+            If not defined, then <command>b10-init</command> will
+            use the component name instead.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+          <term> <varname>special</varname> </term>
+        <listitem>
+          <para>
+            This defines if the component is started a special, hardcoded
+            way.
+<!--
+TODO: document this ... but maybe some of these will be removed
+once we get rid of some using switches for components?
+
+auth
+cfgmgr
+cmdctl
+msgq
+resolver
+sockcreator
+xfrin
+-->
+
+</para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+<!-- TODO: formating -->
+    <para>
+      The <varname>Init</varname> configuration commands are:
+    </para>
+
+<!-- TODO -->
+<!--
+    <para>
+      <command>drop_socket</command>
+      This is an internal command and not exposed to the administrator.
+    </para>
+-->
+
+<!-- TODO -->
+<!--
+    <para>
+      <command>get_socket</command>
+      This is an internal command and not exposed to the administrator.
+    </para>
+-->
+
+    <para>
+      <command>getstats</command> tells <command>b10-init</command>
+      to send its statistics data to the <command>b10-stats</command>
+      daemon.
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
+    <para>
+      <command>ping</command> is used to check the connection with the
+      <command>b10-init</command> daemon.
+      It returns the text <quote>pong</quote>.
+    </para>
+
+    <para>
+      <command>show_processes</command> lists the current processes
+      managed by <command>b10-init</command>.
+      The output is an array in JSON format containing the process
+      ID, the name for each and the address name used on each message bus.
+<!-- TODO: what is name? -->
+<!-- TODO: change to JSON object format? -->
+<!-- TODO: ticket #1406 -->
+    </para>
+
+    <para>
+      <command>shutdown</command> tells <command>b10-init</command>
+      to shutdown the BIND 10 servers.
+      It will tell each process it manages to shutdown and, when
+      complete, <command>b10-init</command> will exit.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>STATISTICS DATA</title>
+
+    <para>
+      The statistics data collected by the <command>b10-stats</command>
+      daemon for <quote>Init</quote> include:
+    </para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>boot_time</term>
+        <listitem><para>
+          The date and time that the <command>b10-init</command>
+          process started.
+          This is represented in ISO 8601 format.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+    <para><filename>sockcreator-XXXXXX/sockcreator</filename>
+    —
+    the Unix Domain socket located in a temporary file directory for
+    <command>b10-sockcreator</command>
+<!--    <citerefentry><refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum></citerefentry> -->
+    communication.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrout</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-stats-httpd</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+<!-- <citerefentry>
+        <refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>, -->
+
+  <refsect1 id='history'><title>HISTORY</title>
+    <para>The development of <command>b10-init</command>
+      was started in October 2009.
+      It was renamed and its configuration identifier changed
+      in February 2013.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>AUTHORS</title>
+    <para>
+      The <command>b10-init</command>
+      daemon was initially designed by Shane Kerr of ISC.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/bind10/bind10.in b/src/bin/bind10/bind10.in
new file mode 100755
index 0000000..88c45c9
--- /dev/null
+++ b/src/bin/bind10/bind10.in
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# We use this wrapper script both for production and in-source tests; in
+# the latter case B10_FROM_BUILD environment is expected to be defined.
+if test -n "${B10_FROM_BUILD}"; then
+	exec ${B10_FROM_BUILD}/src/bin/bind10/b10-init $*
+else
+	prefix=@prefix@
+	exec_prefix=@exec_prefix@
+	exec @libexecdir@/@PACKAGE@/b10-init $*
+fi
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index e32544a..16082f3 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "—">]>
 <!--
- - Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2013  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>April 12, 2012</date>
+    <date>February 5, 2013</date>
   </refentryinfo>
 
   <refmeta>
@@ -31,12 +31,12 @@
 
   <refnamediv>
     <refname>bind10</refname>
-    <refpurpose>BIND 10 boss process</refpurpose>
+    <refpurpose>BIND 10 start script</refpurpose>
   </refnamediv>
 
   <docinfo>
     <copyright>
-      <year>2010-2012</year>
+      <year>2013</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -44,468 +44,33 @@
   <refsynopsisdiv>
     <cmdsynopsis>
       <command>bind10</command>
-      <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
-      <arg><option>-i</option></arg>
-      <arg><option>-m <replaceable>file</replaceable></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>-w <replaceable>wait_time</replaceable></option></arg>
-      <arg><option>--clear-config</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-kill</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>
-      <arg><option>--wait <replaceable>wait_time</replaceable></option></arg>
+      <arg><option>options</option></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
     <title>DESCRIPTION</title>
 
-    <para>The <command>bind10</command> daemon starts up other
-    BIND 10 required daemons.  It handles restarting of exiting
-    programs and also the shutdown of all managed daemons.</para>
+    <para>The <command>bind10</command> script is a simple wrapper that
+    starts BIND 10 by running the <command>b10-init</command> daemon. All
+    options passed to <command>bind10</command> are directly passed on to
+    <command>b10-init</command>.</para>
 
-<!-- TODO: list what it starts here? -->
-
-<!-- TODO
-    <para>The configuration of the <command>bind10</command> daemon
-    is defined in the TODO configuration file, as described in the
-    <citerefentry><refentrytitle>TODO</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    manual page.</para>
--->
-
-  </refsect1>
-
-  <refsect1>
-    <title>ARGUMENTS</title>
-
-    <para>The arguments are as follows:</para>
-
-    <variablelist>
-
-      <varlistentry>
-        <term>
-          <option>-c</option> <replaceable>config-filename</replaceable>,
-          <option>--config-file</option> <replaceable>config-filename</replaceable>
-        </term>
-        <listitem>
-          <para>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.
-          Defaults to <filename>b10-config.db</filename>.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>
-          <option>--clear-config</option>
-        </term>
-        <listitem>
-	  <para>
-	    This will create a backup of the existing configuration
-	    file, remove it and start
-	    <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
-            with the default configuration.
-	    The name of the backup file can be found in the logs
-	    (<varname>CFGMGR_BACKED_UP_CONFIG_FILE</varname>).
-	    (It will append a number to the backup filename if a
-	    previous backup file exists.)
-
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>
-          <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.
-	  Currently only
-	  <citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-	  uses it to locate the configuration file, but the usage
-	  might be extended for other programs and other types of
-	  files.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-m</option> <replaceable>file</replaceable>,
-           <option>--msgq-socket-file</option> <replaceable>file</replaceable></term>
-
-        <listitem>
-          <para>The UNIX domain socket file for the
-	    <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-            daemon to use.
-            The default is
-            <filename>/usr/local/var/bind10/msg_socket</filename>.
-<!-- @localstatedir@/@PACKAGE_NAME@/msg_socket -->
-           </para>
-         </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-i</option>, <option>--no-kill</option></term>
-        <listitem>
-	  <para>When this option is passed, <command>bind10</command>
-	  does not send SIGTERM and SIGKILL signals to modules during
-	  shutdown. (This option was introduced for use during
-	  testing.)</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-u</option> <replaceable>user</replaceable>, <option>--user</option> <replaceable>name</replaceable></term>
-<!-- TODO: example more detail. -->
-        <listitem>
-          <para>The username for <command>bind10</command> to run as.
-            <command>bind10</command> must be initially ran as the
-            root user to use this option.
-            The default is to run as the current user.</para>
-         </listitem>
-      </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.
-          </para>
-         </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--pretty-name <replaceable>name</replaceable></option></term>
-
-        <listitem>
-          <para>The name this process should have in tools like
-          <command>ps</command> or <command>top</command>. This
-          is handy if you have multiple versions/installations
-          of <command>bind10</command>.
-<!-- TODO: only supported with setproctitle feature
-The default is the basename of ARG 0.
--->
-</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-v</option>, <option>--verbose</option></term>
-        <listitem>
-	  <para>Display more about what is going on for
-	  <command>bind10</command> and its child processes.</para>
-<!-- TODO: not true about all children yet -->
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-w</option> <replaceable>wait_time</replaceable>, <option>--wait</option> <replaceable>wait_time</replaceable></term>
-        <listitem>
-	  <para>Sets the amount of time that BIND 10 will wait for
-	  the configuration manager (a key component of BIND 10)
-	  to initialize itself before abandoning the start up and
-	  terminating with an error.  The
-	  <replaceable>wait_time</replaceable> is specified in
-	  seconds and has a default value of 10.
-          </para>
-        </listitem>
-      </varlistentry>
-
-    </variablelist>
-  </refsect1>
-
-<!--
-TODO: configuration section
--->
-
-  <refsect1>
-    <title>CONFIGURATION AND COMMANDS</title>
-
-    <para>
-      The configuration provides settings for components for
-      <command>bind10</command> to manage under
-      <varname>/Boss/components/</varname>.
-      The default elements are:
-    </para>
-
-    <itemizedlist>
-
-      <listitem>
-        <para> <varname>/Boss/components/b10-cmdctl</varname> </para>
-      </listitem>
-
-      <listitem>
-        <para> <varname>/Boss/components/b10-stats</varname> </para>
-      </listitem>
-
-    </itemizedlist>
-
-    <para>
-      (Note that the startup of <command>b10-sockcreator</command>,
-      <command>b10-cfgmgr</command>, and <command>b10-msgq</command>
-      is not configurable. They are hardcoded and <command>bind10</command>
-      will not run without them.)
-    </para>
-
-    <para>
-      The named sets for components contain the following settings:
-    </para>
-
-    <variablelist>
-
-      <varlistentry>
-        <term><varname>address</varname></term>
-        <listitem>
-	  <para>The name used for communicating to it on the message
-	  bus.</para>
-<!-- NOTE: vorner said:
-These can be null, because the components are special ones, and
-the special class there already knows the address. It is (I hope)
-explained in the guide. I'd like to get rid of the special components
-sometime and I'd like it to teach to guess the address.
--->
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>kind</varname></term>
-        <listitem>
-          <para>
-            This defines how required a component is.
-            The possible settings for <varname>kind</varname> are:
-            <varname>core</varname> (system won't start if it won't
-            start and <command>bind10</command> will shutdown if
-            a <quote>core</quote> component crashes),
-            <varname>dispensable</varname> (<command>bind10</command>
-            will restart failing component),
-            and
-	    <varname>needed</varname> (<command>bind10</command>
-	    will shutdown if component won't initially start, but
-	    if crashes later, it will attempt to restart).
-            This setting is required.
-<!-- TODO: formatting -->
-          </para>
-        </listitem>
-      </varlistentry>
-
-<!--
-TODO: currently not used
-      <varlistentry>
-        <term> <varname>params</varname> </term>
-        <listitem>
-          <para>
-list
-</para>
-        </listitem>
-      </varlistentry>
--->
-
-      <varlistentry>
-        <term> <varname>priority</varname> </term>
-        <listitem>
-          <para>This is an integer. <command>bind10</command>
-            will start the components with largest priority numbers first.
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-          <term> <varname>process</varname> </term>
-        <listitem>
-          <para>This is the filename of the executable to be started.
-            If not defined, then <command>bind10</command> will
-            use the component name instead.
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-          <term> <varname>special</varname> </term>
-        <listitem>
-          <para>
-            This defines if the component is started a special, hardcoded
-            way.
-<!--
-TODO: document this ... but maybe some of these will be removed
-once we get rid of some using switches for components?
-
-auth
-cfgmgr
-cmdctl
-msgq
-resolver
-sockcreator
-xfrin
--->
-
-</para>
-        </listitem>
-      </varlistentry>
-
-    </variablelist>
-
-<!-- TODO: formating -->
-    <para>
-      The <varname>Boss</varname> configuration commands are:
-    </para>
-<!-- TODO: let's just let bind10 be known as bind10 and not Boss -->
-
-<!-- TODO -->
-<!--
-    <para>
-      <command>drop_socket</command>
-      This is an internal command and not exposed to the administrator.
-    </para>
--->
-
-<!-- TODO -->
-<!--
-    <para>
-      <command>get_socket</command>
-      This is an internal command and not exposed to the administrator.
-    </para>
--->
-
-    <para>
-      <command>getstats</command> tells <command>bind10</command>
-      to send its statistics data to the <command>b10-stats</command>
-      daemon.
-      This is an internal command and not exposed to the administrator.
-<!-- not defined in spec -->
-    </para>
-
-    <para>
-      <command>ping</command> is used to check the connection with the
-      <command>bind10</command> daemon.
-      It returns the text <quote>pong</quote>.
-    </para>
-
-    <para>
-      <command>show_processes</command> lists the current processes
-      managed by <command>bind10</command>.
-      The output is an array in JSON format containing the process
-      ID, the name for each and the address name used on each message bus.
-<!-- TODO: what is name? -->
-<!-- TODO: change to JSON object format? -->
-<!-- TODO: ticket #1406 -->
-    </para>
-
-    <para>
-      <command>shutdown</command> tells <command>bind10</command>
-      to shutdown the BIND 10 servers.
-      It will tell each process it manages to shutdown and, when
-      complete, <command>bind10</command> will exit.
-    </para>
-
-  </refsect1>
-
-  <refsect1>
-    <title>STATISTICS DATA</title>
-
-    <para>
-      The statistics data collected by the <command>b10-stats</command>
-      daemon for <quote>Boss</quote> include:
-    </para>
-
-    <variablelist>
-
-      <varlistentry>
-        <term>boot_time</term>
-        <listitem><para>
-          The date and time that the <command>bind10</command>
-          process started.
-          This is represented in ISO 8601 format.
-        </para></listitem>
-      </varlistentry>
-
-    </variablelist>
-
-  </refsect1>
-
-  <refsect1>
-    <title>FILES</title>
-    <para><filename>sockcreator-XXXXXX/sockcreator</filename>
-    —
-    the Unix Domain socket located in a temporary file directory for
-    <command>b10-sockcreator</command>
-<!--    <citerefentry><refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum></citerefentry> -->
-    communication.
-    </para>
   </refsect1>
 
   <refsect1>
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
-        <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-xfrout</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>
-<!-- <citerefentry>
-        <refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>, -->
 
   <refsect1 id='history'><title>HISTORY</title>
-    <para>The development of <command>bind10</command>
-    was started in October 2009.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>AUTHORS</title>
-    <para>
-      The <command>bind10</command>
-      daemon was initially designed by Shane Kerr of ISC.
+    <para>The <command>bind10</command> script was added in February 2013.
     </para>
   </refsect1>
-</refentry><!--
- - Local variables:
- - mode: sgml
- - End:
--->
+
+</refentry>
diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes
deleted file mode 100644
index 9414ed6..0000000
--- a/src/bin/bind10/bind10_messages.mes
+++ /dev/null
@@ -1,327 +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.
-
-# No namespace declaration - these constants go in the global namespace
-# of the xfrin messages python module.
-
-% BIND10_CHECK_MSGQ_ALREADY_RUNNING checking if msgq is already running
-The boss process is starting up and will now check if the message bus
-daemon is already running. If so, it will not be able to start, as it
-needs a dedicated message bus.
-
-% BIND10_COMPONENT_FAILED component %1 (pid %2) failed: %3
-The process terminated, but the bind10 boss didn't expect it to, which means
-it must have failed.
-
-% BIND10_COMPONENT_RESTART component %1 is about to restart
-The named component failed previously and we will try to restart it to provide
-as flawless service as possible, but it should be investigated what happened,
-as it could happen again.
-
-% BIND10_COMPONENT_START component %1 is starting
-The named component is about to be started by the boss process.
-
-% BIND10_COMPONENT_START_EXCEPTION component %1 failed to start: %2
-An exception (mentioned in the message) happened during the startup of the
-named component. The componet is not considered started and further actions
-will be taken about it.
-
-% BIND10_COMPONENT_STOP component %1 is being stopped
-A component is about to be asked to stop willingly by the boss.
-
-% BIND10_COMPONENT_UNSATISFIED component %1 is required to run and failed
-A component failed for some reason (see previous messages). It is either a core
-component or needed component that was just started. In any case, the system
-can't continue without it and will terminate.
-
-% BIND10_CONFIGURATOR_BUILD building plan '%1' -> '%2'
-A debug message. This indicates that the configurator is building a plan
-how to change configuration from the older one to newer one. This does no
-real work yet, it just does the planning what needs to be done.
-
-% BIND10_CONFIGURATOR_PLAN_INTERRUPTED configurator plan interrupted, only %1 of %2 done
-There was an exception during some planned task. The plan will not continue and
-only some tasks of the plan were completed. The rest is aborted. The exception
-will be propagated.
-
-% BIND10_CONFIGURATOR_RECONFIGURE reconfiguring running components
-A different configuration of which components should be running is being
-installed. All components that are no longer needed will be stopped and
-newly introduced ones started. This happens at startup, when the configuration
-is read the first time, or when an operator changes configuration of the boss.
-
-% BIND10_CONFIGURATOR_RUN running plan of %1 tasks
-A debug message. The configurator is about to execute a plan of actions it
-computed previously.
-
-% BIND10_CONFIGURATOR_START bind10 component configurator is starting up
-The part that cares about starting and stopping the right component from the
-boss process is starting up. This happens only once at the startup of the
-boss process. It will start the basic set of processes now (the ones boss
-needs to read the configuration), the rest will be started after the
-configuration is known.
-
-% BIND10_CONFIGURATOR_STOP bind10 component configurator is shutting down
-The part that cares about starting and stopping processes in the boss is
-shutting down. All started components will be shut down now (more precisely,
-asked to terminate by their own, if they fail to comply, other parts of
-the boss process will try to force them).
-
-% BIND10_CONFIGURATOR_TASK performing task %1 on %2
-A debug message. The configurator is about to perform one task of the plan it
-is currently executing on the named component.
-
-% BIND10_CONNECTING_TO_CC_FAIL failed to connect to configuration/command channel; try -v to see output from msgq
-The boss process tried to connect to the communication channel for
-commands and configuration updates during initialization, but it
-failed.  This is a fatal startup error, and process will soon
-terminate after some cleanup.  There can be several reasons for the
-failure, but the most likely cause is that the msgq daemon failed to
-start, and the most likely cause of the msgq failure is that it
-doesn't have a permission to create a socket file for the
-communication.  To confirm that, you can see debug messages from msgq
-by starting BIND 10 with the -v command line option.  If it indicates
-permission problem for msgq, make sure the directory where the socket
-file is to be created is writable for the msgq process.  Note that if
-you specify the -u option to change process users, the directory must
-be writable for that user.
-
-% BIND10_INVALID_STATISTICS_DATA invalid specification of statistics data specified
-An error was encountered when the boss module specified
-statistics data which is invalid for the boss specification file.
-
-% BIND10_INVALID_USER invalid user: %1
-The boss process was started with the -u option, to drop root privileges
-and continue running as the specified user, but the user is unknown.
-
-% BIND10_KILLING_ALL_PROCESSES killing all started processes
-The boss module was not able to start every process it needed to start
-during startup, and will now kill the processes that did get started.
-
-% BIND10_LOST_SOCKET_CONSUMER consumer %1 of sockets disconnected, considering all its sockets closed
-A connection from one of the applications which requested a socket was
-closed. This means the application has terminated, so all the sockets it was
-using are now closed and bind10 process can release them as well, unless the
-same sockets are used by yet another application.
-
-% BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start
-There already appears to be a message bus daemon running. Either an
-old process was not shut down correctly, and needs to be killed, or
-another instance of BIND10, with the same msgq domain socket, is
-running, which needs to be stopped.
-
-% BIND10_MSGQ_DISAPPEARED msgq channel disappeared
-While listening on the message bus channel for messages, it suddenly
-disappeared. The msgq daemon may have died. This might lead to an
-inconsistent state of the system, and BIND 10 will now shut down.
-
-% BIND10_NO_SOCKET couldn't send a socket for token %1 because of error: %2
-An error occurred when the bind10 process was asked to send a socket file
-descriptor. The error is mentioned, most common reason is that the request
-is invalid and may not come from bind10 process at all.
-
-% BIND10_PROCESS_ENDED process %2 of %1 ended with status %3
-This indicates a process started previously terminated. The process id
-and component owning the process are indicated, as well as the exit code.
-This doesn't distinguish if the process was supposed to terminate or not.
-
-% BIND10_READING_BOSS_CONFIGURATION reading boss configuration
-The boss process is starting up, and will now process the initial
-configuration, as received from the configuration manager.
-
-% BIND10_RECEIVED_COMMAND received command: %1
-The boss module received a command and shall now process it. The command
-is printed.
-
-% BIND10_RECEIVED_NEW_CONFIGURATION received new configuration: %1
-The boss module received a configuration update and is going to apply
-it now. The new configuration is printed.
-
-% BIND10_RECEIVED_SIGNAL received signal %1
-The boss module received the given signal.
-
-% BIND10_RESTART_COMPONENT_SKIPPED Skipped restarting a component %1
-The boss module tried to restart a component after it failed (crashed)
-unexpectedly, but the boss then found that the component had been removed
-from its local configuration of components to run.  This is an unusual
-situation but can happen if the administrator removes the component from
-the configuration after the component's crash and before the restart time.
-The boss module simply skipped restarting that module, and the whole system
-went back to the expected state (except that the crash itself is likely
-to be a bug).
-
-% BIND10_RESURRECTED_PROCESS resurrected %1 (PID %2)
-The given process has been restarted successfully, and is now running
-with the given process id.
-
-% BIND10_RESURRECTING_PROCESS resurrecting dead %1 process...
-The given process has ended unexpectedly, and is now restarted.
-
-% BIND10_SELECT_ERROR error in select() call: %1
-There was a fatal error in the call to select(), used to see if a child
-process has ended or if there is a message on the message bus. This
-should not happen under normal circumstances and is considered fatal,
-so BIND 10 will now shut down. The specific error is printed.
-
-% BIND10_SEND_SIGKILL sending SIGKILL to %1 (PID %2)
-The boss module is sending a SIGKILL signal to the given process.
-
-% BIND10_SEND_SIGNAL_FAIL sending %1 to %2 (PID %3) failed: %4
-The boss module sent a single (either SIGTERM or SIGKILL) to a process,
-but it failed due to some system level error.  There are two major cases:
-the target process has already terminated but the boss module had sent
-the signal before it noticed the termination.  In this case an error
-message should indicate something like "no such process".  This can be
-safely ignored.  The other case is that the boss module doesn't have
-the privilege to send a signal to the process.  It can typically
-happen when the boss module started as a privileged process, spawned a
-subprocess, and then dropped the privilege.  It includes the case for
-the socket creator when the boss process runs with the -u command line
-option.  In this case, the boss module simply gives up to terminate
-the process explicitly because it's unlikely to succeed by keeping
-sending the signal.  Although the socket creator is implemented so
-that it will terminate automatically when the boss process exits
-(and that should be the case for any other future process running with
-a higher privilege), but it's recommended to check if there's any
-remaining BIND 10 process if this message is logged.  For all other
-cases, the boss module will keep sending the signal until it confirms
-all child processes terminate.  Although unlikely, this could prevent
-the boss module from exiting, just keeping sending the signals.  So,
-again, it's advisable to check if it really terminates when this
-message is logged.
-
-% BIND10_SEND_SIGTERM sending SIGTERM to %1 (PID %2)
-The boss module is sending a SIGTERM signal to the given process.
-
-% BIND10_SETGID setting GID to %1
-The boss switches the process group ID to the given value.  This happens
-when BIND 10 starts with the -u option, and the group ID will be set to
-that of the specified user.
-
-% BIND10_SETUID setting UID to %1
-The boss switches the user it runs as to the given UID.
-
-% BIND10_SHUTDOWN stopping the server
-The boss process received a command or signal telling it to shut down.
-It will send a shutdown command to each process. The processes that do
-not shut down will then receive a SIGTERM signal. If that doesn't work,
-it shall send SIGKILL signals to the processes still alive.
-
-% BIND10_SHUTDOWN_COMPLETE all processes ended, shutdown complete
-All child processes have been stopped, and the boss process will now
-stop itself.
-
-% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1
-The socket creator reported an error when creating a socket. But the function
-which failed is unknown (not one of 'S' for socket or 'B' for bind).
-
-% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1
-The boss requested a socket from the creator, but the answer is unknown. This
-looks like a programmer error.
-
-% BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator
-There should be more data from the socket creator, but it closed the socket.
-It probably crashed.
-
-% BIND10_SOCKCREATOR_INIT initializing socket creator parser
-The boss module initializes routines for parsing the socket creator
-protocol.
-
-% BIND10_SOCKCREATOR_KILL killing the socket creator
-The socket creator is being terminated the aggressive way, by sending it
-sigkill. This should not happen usually.
-
-% BIND10_SOCKCREATOR_TERMINATE terminating socket creator
-The boss module sends a request to terminate to the socket creator.
-
-% BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1
-Either sending or receiving data from the socket creator failed with the given
-error. The creator probably crashed or some serious OS-level problem happened,
-as the communication happens only on local host.
-
-% BIND10_SOCKET_CREATED successfully created socket %1
-The socket creator successfully created and sent a requested socket, it has
-the given file number.
-
-% BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3
-The socket creator failed to create the requested socket. It failed on the
-indicated OS API function with given error.
-
-% BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator
-The boss forwards a request for a socket to the socket creator.
-
-% BIND10_STARTED_CC started configuration/command session
-Debug message given when BIND 10 has successfully started the object that
-handles configuration and commands.
-
-% BIND10_STARTED_PROCESS started %1
-The given process has successfully been started.
-
-% BIND10_STARTED_PROCESS_PID started %1 (PID %2)
-The given process has successfully been started, and has the given PID.
-
-% BIND10_STARTING starting BIND10: %1
-Informational message on startup that shows the full version.
-
-% BIND10_STARTING_CC starting configuration/command session
-Informational message given when BIND 10 is starting the session object
-that handles configuration and commands.
-
-% BIND10_STARTING_PROCESS starting process %1
-The boss module is starting the given process.
-
-% BIND10_STARTING_PROCESS_PORT starting process %1 (to listen on port %2)
-The boss module is starting the given process, which will listen on the
-given port number.
-
-% BIND10_STARTING_PROCESS_PORT_ADDRESS starting process %1 (to listen on %2#%3)
-The boss module is starting the given process, which will listen on the
-given address and port number (written as <address>#<port>).
-
-% BIND10_STARTUP_COMPLETE BIND 10 started
-All modules have been successfully started, and BIND 10 is now running.
-
-% BIND10_STARTUP_ERROR error during startup: %1
-There was a fatal error when BIND10 was trying to start. The error is
-shown, and BIND10 will now shut down.
-
-% BIND10_STARTUP_UNEXPECTED_MESSAGE unrecognised startup message %1
-During the startup process, a number of messages are exchanged between the
-Boss process and the processes it starts.  This error is output when a
-message received by the Boss process is recognised as being of the
-correct format but is unexpected.  It may be that processes are starting
-of sequence.
-
-% BIND10_STARTUP_UNRECOGNISED_MESSAGE unrecognised startup message %1
-During the startup process, a number of messages are exchanged between the
-Boss process and the processes it starts.  This error is output when a
-message received by the Boss process is not recognised.
-
-% BIND10_STOP_PROCESS asking %1 to shut down
-The boss module is sending a shutdown command to the given module over
-the message channel.
-
-% BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited
-An unknown child process has exited. The PID is printed, but no further
-action will be taken by the boss process.
-
-% BIND10_WAIT_CFGMGR waiting for configuration manager process to initialize
-The configuration manager process is so critical to operation of BIND 10
-that after starting it, the Boss module will wait for it to initialize
-itself before continuing.  This debug message is produced during the
-wait and may be output zero or more times depending on how long it takes
-the configuration manager to start up.  The total length of time Boss
-will wait for the configuration manager before reporting an error is
-set with the command line --wait switch, which has a default value of
-ten seconds.
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
deleted file mode 100755
index 6fe5485..0000000
--- a/src/bin/bind10/bind10_src.py.in
+++ /dev/null
@@ -1,1316 +0,0 @@
-#!@PYTHON@
-
-# 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
-# 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 file implements the Boss of Bind (BoB, or bob) program.
-
-Its purpose is to start up the BIND 10 system, and then manage the
-processes, by starting and stopping processes, plus restarting
-processes that exit.
-
-To start the system, it first runs the c-channel program (msgq), then
-connects to that. It then runs the configuration manager, and reads
-its own configuration. Then it proceeds to starting other modules.
-
-The Python subprocess module is used for starting processes, but
-because this is not efficient for managing groups of processes,
-SIGCHLD signals are caught and processed using the signal module.
-
-Most of the logic is contained in the BoB class. However, since Python
-requires that signal processing happen in the main thread, we do
-signal handling outside of that class, in the code running for
-__main__.
-"""
-
-import sys; sys.path.append ('@@PYTHONPATH@@')
-import os
-
-# 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:
-    SPECFILE_LOCATION = os.environ["B10_FROM_SOURCE"] + "/src/bin/bind10/bob.spec"
-else:
-    PREFIX = "@prefix@"
-    DATAROOTDIR = "@datarootdir@"
-    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/bob.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
-
-import subprocess
-import signal
-import re
-import errno
-import time
-import select
-import random
-import socket
-from optparse import OptionParser, OptionValueError
-import io
-import pwd
-import posix
-import copy
-
-from bind10_config import LIBEXECPATH
-import bind10_config
-import isc.cc
-import isc.util.process
-import isc.net.parse
-import isc.log
-from isc.log_messages.bind10_messages import *
-import isc.bind10.component
-import isc.bind10.special_component
-import isc.bind10.socket_cache
-import libutil_io_python
-import tempfile
-
-isc.log.init("b10-boss", buffer=True)
-logger = isc.log.Logger("boss")
-
-# Pending system-wide debug level definitions, the ones we
-# use here are hardcoded for now
-DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
-DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
-
-# Messages sent over the unix domain socket to indicate if it is followed by a real socket
-CREATOR_SOCKET_OK = b"1\n"
-CREATOR_SOCKET_UNAVAILABLE = b"0\n"
-
-# RCodes of known exceptions for the get_token command
-CREATOR_SOCKET_ERROR = 2
-CREATOR_SHARE_ERROR = 3
-
-# Assign this process some longer name
-isc.util.process.rename(sys.argv[0])
-
-# This is the version that gets displayed to the user.
-# The VERSION string consists of the module name, the module version
-# number, and the overall BIND 10 version number (set in configure.ac).
-VERSION = "bind10 20110223 (BIND 10 @PACKAGE_VERSION@)"
-
-# This is for boot_time of Boss
-_BASETIME = time.gmtime()
-
-# Detailed error message commonly used on startup failure, possibly due to
-# permission issue regarding log lock file.  We dump verbose message because
-# it may not be clear exactly what to do if it simply says
-# "failed to open <filename>: permission denied"
-NOTE_ON_LOCK_FILE = """\
-TIP: if this is about permission error for a lock file, check if the directory
-of the file is writable for the user of the bind10 process; often you need
-to start bind10 as a super user.  Also, if you specify the -u option to
-change the user and group, the directory must be writable for the group,
-and the created lock file must be writable for that user. Finally, make sure
-the lock file is not left in the directly before restarting.
-"""
-
-class ProcessInfoError(Exception): pass
-
-class ChangeUserError(Exception):
-    '''Exception raised when setuid/setgid fails.
-
-    When raised, it's expected to be propagated via underlying component
-    management modules to the top level so that it will help provide useful
-    fatal error message.
-
-    '''
-    pass
-
-class ProcessInfo:
-    """Information about a process"""
-
-    dev_null = open(os.devnull, "w")
-
-    def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
-        self.name = name
-        self.args = args
-        self.env = env
-        self.dev_null_stdout = dev_null_stdout
-        self.dev_null_stderr = dev_null_stderr
-        self.process = None
-        self.pid = None
-
-    def _preexec_work(self):
-        """Function used before running a program that needs to run as a
-        different user."""
-        # First, put us into a separate process group so we don't get
-        # SIGINT signals on Ctrl-C (the boss will shut everthing down by
-        # other means).
-        os.setpgrp()
-
-    def _spawn(self):
-        if self.dev_null_stdout:
-            spawn_stdout = self.dev_null
-        else:
-            spawn_stdout = None
-        if self.dev_null_stderr:
-            spawn_stderr = self.dev_null
-        else:
-            spawn_stderr = None
-        # Environment variables for the child process will be a copy of those
-        # of the boss process with any additional specific variables given
-        # on construction (self.env).
-        spawn_env = copy.deepcopy(os.environ)
-        spawn_env.update(self.env)
-        spawn_env['PATH'] = LIBEXECPATH + ':' + spawn_env['PATH']
-        self.process = subprocess.Popen(self.args,
-                                        stdin=subprocess.PIPE,
-                                        stdout=spawn_stdout,
-                                        stderr=spawn_stderr,
-                                        close_fds=True,
-                                        env=spawn_env,
-                                        preexec_fn=self._preexec_work)
-        self.pid = self.process.pid
-
-    # spawn() and respawn() are the same for now, but in the future they
-    # may have different functionality
-    def spawn(self):
-        self._spawn()
-
-    def respawn(self):
-        self._spawn()
-
-class CChannelConnectError(Exception): pass
-
-class ProcessStartError(Exception): pass
-
-class BoB:
-    """Boss of BIND class."""
-
-    def __init__(self, msgq_socket_file=None, data_path=None,
-                 config_filename=None, clear_config=False,
-                 verbose=False, nokill=False, setuid=None, setgid=None,
-                 username=None, cmdctl_port=None, wait_time=10):
-        """
-            Initialize the Boss of BIND. This is a singleton (only one can run).
-
-            The msgq_socket_file specifies the UNIX domain socket file that the
-            msgq process listens on.  If verbose is True, then the boss reports
-            what it is doing.
-
-            Data path and config filename are passed through to config manager
-            (if provided) and specify the config file to be used.
-
-            The cmdctl_port is passed to cmdctl and specify on which port it
-            should listen.
-
-            wait_time controls the amount of time (in seconds) that Boss waits
-            for selected processes to initialize before continuing with the
-            initialization.  Currently this is only the configuration manager.
-        """
-        self.cc_session = None
-        self.ccs = None
-        self.curproc = None
-        self.msgq_socket_file = msgq_socket_file
-        self.component_config = {}
-        # Some time in future, it may happen that a single component has
-        # multple processes (like a pipeline-like component). If so happens,
-        # name "components" may be inapropriate. But as the code isn't probably
-        # completely ready for it, we leave it at components for now. We also
-        # want to support multiple instances of a single component. If it turns
-        # out that we'll have a single component with multiple same processes
-        # or if we start multiple components with the same configuration (we do
-        # this now, but it might change) is an open question.
-        self.components = {}
-        # Simply list of components that died and need to wait for a
-        # restart. Components manage their own restart schedule now
-        self.components_to_restart = []
-        self.runnable = False
-        self.__uid = setuid
-        self.__gid = setgid
-        self.username = username
-        self.verbose = verbose
-        self.nokill = nokill
-        self.data_path = data_path
-        self.config_filename = config_filename
-        self.clear_config = clear_config
-        self.cmdctl_port = cmdctl_port
-        self.wait_time = wait_time
-        self.msgq_timeout = 5
-
-        # _run_under_unittests is only meant to be used when testing. It
-        # bypasses execution of some code to help with testing.
-        self._run_under_unittests = False
-
-        self._component_configurator = isc.bind10.component.Configurator(self,
-            isc.bind10.special_component.get_specials())
-        # The priorities here make them start in the correct order. First
-        # the socket creator (which would drop root privileges by then),
-        # then message queue and after that the config manager (which uses
-        # the config manager)
-        self.__core_components = {
-            'sockcreator': {
-                'kind': 'core',
-                'special': 'sockcreator',
-                'priority': 200
-            },
-            'msgq': {
-                'kind': 'core',
-                'special': 'msgq',
-                'priority': 199
-            },
-            'cfgmgr': {
-                'kind': 'core',
-                'special': 'cfgmgr',
-                'priority': 198
-            }
-        }
-        self.__started = False
-        self.exitcode = 0
-
-        # If -v was set, enable full debug logging.
-        if self.verbose:
-            logger.set_severity("DEBUG", 99)
-        # This is set in init_socket_srv
-        self._socket_path = None
-        self._socket_cache = None
-        self._tmpdir = None
-        self._srv_socket = None
-        self._unix_sockets = {}
-
-    def __propagate_component_config(self, config):
-        comps = dict(config)
-        # Fill in the core components, so they stay alive
-        for comp in self.__core_components:
-            if comp in comps:
-                raise Exception(comp + " is core component managed by " +
-                                "bind10 boss, do not set it")
-            comps[comp] = self.__core_components[comp]
-        # Update the configuration
-        self._component_configurator.reconfigure(comps)
-
-    def change_user(self):
-        '''Change the user and group to those specified on construction.
-
-        This method is expected to be called by a component on initial
-        startup when the system is ready to switch the user and group
-        (i.e., once all components that need the privilege of the original
-        user have started).
-        '''
-        try:
-            if self.__gid is not None:
-                logger.info(BIND10_SETGID, self.__gid)
-                posix.setgid(self.__gid)
-        except Exception as ex:
-            raise ChangeUserError('failed to change group: ' + str(ex))
-
-        try:
-            if self.__uid is not None:
-                posix.setuid(self.__uid)
-                # We use one-shot logger after setuid here.  This will
-                # detect any permission issue regarding logging due to the
-                # result of setuid at the earliest opportunity.
-                isc.log.Logger("boss").info(BIND10_SETUID, self.__uid)
-        except Exception as ex:
-            raise ChangeUserError('failed to change user: ' + str(ex))
-
-    def config_handler(self, new_config):
-        # If this is initial update, don't do anything now, leave it to startup
-        if not self.runnable:
-            return
-        logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
-                     new_config)
-        try:
-            if 'components' in new_config:
-                self.__propagate_component_config(new_config['components'])
-            return isc.config.ccsession.create_answer(0)
-        except Exception as e:
-            return isc.config.ccsession.create_answer(1, str(e))
-
-    def get_processes(self):
-        pids = list(self.components.keys())
-        pids.sort()
-        process_list = [ ]
-        for pid in pids:
-            process_list.append([pid, self.components[pid].name(),
-                                 self.components[pid].address()])
-        return process_list
-
-    def _get_stats_data(self):
-        return { 'boot_time':
-                     time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
-                 }
-
-    def command_handler(self, command, args):
-        logger.debug(DBG_COMMANDS, BIND10_RECEIVED_COMMAND, command)
-        answer = isc.config.ccsession.create_answer(1, "command not implemented")
-        if type(command) != str:
-            answer = isc.config.ccsession.create_answer(1, "bad command")
-        else:
-            if command == "shutdown":
-                self.runnable = False
-                answer = isc.config.ccsession.create_answer(0)
-            elif command == "getstats":
-                answer = isc.config.ccsession.create_answer(
-                    0, self._get_stats_data())
-            elif command == "ping":
-                answer = isc.config.ccsession.create_answer(0, "pong")
-            elif command == "show_processes":
-                answer = isc.config.ccsession. \
-                    create_answer(0, self.get_processes())
-            elif command == "get_socket":
-                answer = self._get_socket(args)
-            elif command == "drop_socket":
-                if "token" not in args:
-                    answer = isc.config.ccsession. \
-                        create_answer(1, "Missing token parameter")
-                else:
-                    try:
-                        self._socket_cache.drop_socket(args["token"])
-                        answer = isc.config.ccsession.create_answer(0)
-                    except Exception as e:
-                        answer = isc.config.ccsession.create_answer(1, str(e))
-            else:
-                answer = isc.config.ccsession.create_answer(1,
-                                                            "Unknown command")
-        return answer
-
-    def kill_started_components(self):
-        """
-            Called as part of the exception handling when a process fails to
-            start, this runs through the list of started processes, killing
-            each one.  It then clears that list.
-        """
-        logger.info(BIND10_KILLING_ALL_PROCESSES)
-        self.__kill_children(True)
-        self.components = {}
-
-    def _read_bind10_config(self):
-        """
-            Reads the parameters associated with the BoB module itself.
-
-            This means the list of components we should start now.
-
-            This could easily be combined into start_all_processes, but
-            it stays because of historical reasons and because the tests
-            replace the method sometimes.
-        """
-        logger.info(BIND10_READING_BOSS_CONFIGURATION)
-
-        config_data = self.ccs.get_full_config()
-        self.__propagate_component_config(config_data['components'])
-
-    def log_starting(self, process, port = None, address = None):
-        """
-            A convenience function to output a "Starting xxx" message if the
-            logging is set to DEBUG with debuglevel DBG_PROCESS or higher.
-            Putting this into a separate method ensures
-            that the output form is consistent across all processes.
-
-            The process name (passed as the first argument) is put into
-            self.curproc, and is used to indicate which process failed to
-            start if there is an error (and is used in the "Started" message
-            on success).  The optional port and address information are
-            appended to the message (if present).
-        """
-        self.curproc = process
-        if port is None and address is None:
-            logger.info(BIND10_STARTING_PROCESS, self.curproc)
-        elif address is None:
-            logger.info(BIND10_STARTING_PROCESS_PORT, self.curproc,
-                        port)
-        else:
-            logger.info(BIND10_STARTING_PROCESS_PORT_ADDRESS,
-                        self.curproc, address, port)
-
-    def log_started(self, pid = None):
-        """
-            A convenience function to output a 'Started xxxx (PID yyyy)'
-            message.  As with starting_message(), this ensures a consistent
-            format.
-        """
-        if pid is None:
-            logger.debug(DBG_PROCESS, BIND10_STARTED_PROCESS, self.curproc)
-        else:
-            logger.debug(DBG_PROCESS, BIND10_STARTED_PROCESS_PID, self.curproc, pid)
-
-    def process_running(self, msg, who):
-        """
-            Some processes return a message to the Boss after they have
-            started to indicate that they are running.  The form of the
-            message is a dictionary with contents {"running:", "<process>"}.
-            This method checks the passed message and returns True if the
-            "who" process is contained in the message (so is presumably
-            running).  It returns False for all other conditions and will
-            log an error if appropriate.
-        """
-        if msg is not None:
-            try:
-                if msg["running"] == who:
-                    return True
-                else:
-                    logger.error(BIND10_STARTUP_UNEXPECTED_MESSAGE, msg)
-            except:
-                logger.error(BIND10_STARTUP_UNRECOGNISED_MESSAGE, msg)
-
-        return False
-
-    # The next few methods start the individual processes of BIND-10.  They
-    # are called via start_all_processes().  If any fail, an exception is
-    # raised which is caught by the caller of start_all_processes(); this kills
-    # processes started up to that point before terminating the program.
-
-    def _make_process_info(self, name, args, env,
-                           dev_null_stdout=False, dev_null_stderr=False):
-        """
-            Wrapper around ProcessInfo(), useful to override
-            ProcessInfo() creation during testing.
-        """
-        return ProcessInfo(name, args, env, dev_null_stdout, dev_null_stderr)
-
-    def start_msgq(self):
-        """
-            Start the message queue and connect to the command channel.
-        """
-        self.log_starting("b10-msgq")
-        msgq_proc = self._make_process_info("b10-msgq", ["b10-msgq"],
-                                            self.c_channel_env,
-                                            True, not self.verbose)
-        msgq_proc.spawn()
-        self.log_started(msgq_proc.pid)
-
-        # Now connect to the c-channel
-        cc_connect_start = time.time()
-        while self.cc_session is None:
-            # if we are run under unittests, break
-            if self._run_under_unittests:
-                break
-
-            # if we have been trying for "a while" give up
-            if (time.time() - cc_connect_start) > self.msgq_timeout:
-                logger.error(BIND10_CONNECTING_TO_CC_FAIL)
-                raise CChannelConnectError("Unable to connect to c-channel after 5 seconds")
-
-            # try to connect, and if we can't wait a short while
-            try:
-                self.cc_session = isc.cc.Session(self.msgq_socket_file)
-            except isc.cc.session.SessionError:
-                time.sleep(0.1)
-
-        # Subscribe to the message queue.  The only messages we expect to receive
-        # on this channel are once relating to process startup.
-        if self.cc_session is not None:
-            self.cc_session.group_subscribe("Boss")
-
-        return msgq_proc
-
-    def start_cfgmgr(self):
-        """
-            Starts the configuration manager process
-        """
-        self.log_starting("b10-cfgmgr")
-        args = ["b10-cfgmgr"]
-        if self.data_path is not None:
-            args.append("--data-path=" + self.data_path)
-        if self.config_filename is not None:
-            args.append("--config-filename=" + self.config_filename)
-        if self.clear_config:
-            args.append("--clear-config")
-        bind_cfgd = self._make_process_info("b10-cfgmgr", args,
-                                            self.c_channel_env)
-        bind_cfgd.spawn()
-        self.log_started(bind_cfgd.pid)
-
-        # Wait for the configuration manager to start up as
-        # subsequent initialization cannot proceed without it.  The
-        # time to wait can be set on the command line.
-        time_remaining = self.wait_time
-        msg, env = self.cc_session.group_recvmsg()
-        while time_remaining > 0 and not self.process_running(msg, "ConfigManager"):
-            logger.debug(DBG_PROCESS, BIND10_WAIT_CFGMGR)
-            time.sleep(1)
-            time_remaining = time_remaining - 1
-            msg, env = self.cc_session.group_recvmsg()
-
-        if not self.process_running(msg, "ConfigManager"):
-            raise ProcessStartError("Configuration manager process has not started")
-
-        return bind_cfgd
-
-    def start_ccsession(self, c_channel_env):
-        """
-            Start the CC Session
-
-            The argument c_channel_env is unused but is supplied to keep the
-            argument list the same for all start_xxx methods.
-
-            With regards to logging, note that as the CC session is not a
-            process, the log_starting/log_started methods are not used.
-        """
-        logger.info(BIND10_STARTING_CC)
-        self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION,
-                                      self.config_handler,
-                                      self.command_handler,
-                                      socket_file = self.msgq_socket_file)
-        self.ccs.start()
-        logger.debug(DBG_PROCESS, BIND10_STARTED_CC)
-
-    # A couple of utility methods for starting processes...
-
-    def start_process(self, name, args, c_channel_env, port=None, address=None):
-        """
-            Given a set of command arguments, start the process and output
-            appropriate log messages.  If the start is successful, the process
-            is added to the list of started processes.
-
-            The port and address arguments are for log messages only.
-        """
-        self.log_starting(name, port, address)
-        newproc = self._make_process_info(name, args, c_channel_env)
-        newproc.spawn()
-        self.log_started(newproc.pid)
-        return newproc
-
-    def register_process(self, pid, component):
-        """
-        Put another process into boss to watch over it.  When the process
-        dies, the component.failed() is called with the exit code.
-
-        It is expected the info is a isc.bind10.component.BaseComponent
-        subclass (or anything having the same interface).
-        """
-        self.components[pid] = component
-
-    def start_simple(self, name):
-        """
-            Most of the BIND-10 processes are started with the command:
-
-                <process-name> [-v]
-
-            ... where -v is appended if verbose is enabled.  This method
-            generates the arguments from the name and starts the process.
-
-            The port and address arguments are for log messages only.
-        """
-        # Set up the command arguments.
-        args = [name]
-        if self.verbose:
-            args += ['-v']
-
-        # ... and start the process
-        return self.start_process(name, args, self.c_channel_env)
-
-    # The next few methods start up the rest of the BIND-10 processes.
-    # Although many of these methods are little more than a call to
-    # start_simple, they are retained (a) for testing reasons and (b) as a place
-    # where modifications can be made if the process start-up sequence changes
-    # for a given process.
-
-    def start_auth(self):
-        """
-            Start the Authoritative server
-        """
-        authargs = ['b10-auth']
-        if self.verbose:
-            authargs += ['-v']
-
-        # ... and start
-        return self.start_process("b10-auth", authargs, self.c_channel_env)
-
-    def start_resolver(self):
-        """
-            Start the Resolver.  At present, all these arguments and switches
-            are pure speculation.  As with the auth daemon, they should be
-            read from the configuration database.
-        """
-        self.curproc = "b10-resolver"
-        # XXX: this must be read from the configuration manager in the future
-        resargs = ['b10-resolver']
-        if self.verbose:
-            resargs += ['-v']
-
-        # ... and start
-        return self.start_process("b10-resolver", resargs, self.c_channel_env)
-
-    def start_cmdctl(self):
-        """
-            Starts the command control process
-        """
-        args = ["b10-cmdctl"]
-        if self.cmdctl_port is not None:
-            args.append("--port=" + str(self.cmdctl_port))
-        if self.verbose:
-            args.append("-v")
-        return self.start_process("b10-cmdctl", args, self.c_channel_env,
-                                  self.cmdctl_port)
-
-    def start_all_components(self):
-        """
-            Starts up all the components.  Any exception generated during the
-            starting of the components is handled by the caller.
-        """
-        # Start the real core (sockcreator, msgq, cfgmgr)
-        self._component_configurator.startup(self.__core_components)
-
-        # Connect to the msgq. This is not a process, so it's not handled
-        # inside the configurator.
-        self.start_ccsession(self.c_channel_env)
-
-        # Extract the parameters associated with Bob.  This can only be
-        # done after the CC Session is started.  Note that the logging
-        # configuration may override the "-v" switch set on the command line.
-        self._read_bind10_config()
-
-        # TODO: Return the dropping of privileges
-
-    def startup(self):
-        """
-            Start the BoB instance.
-
-            Returns None if successful, otherwise an string describing the
-            problem.
-        """
-        # Try to connect to the c-channel daemon, to see if it is already
-        # running
-        c_channel_env = {}
-        if self.msgq_socket_file is not None:
-             c_channel_env["BIND10_MSGQ_SOCKET_FILE"] = self.msgq_socket_file
-        logger.debug(DBG_PROCESS, BIND10_CHECK_MSGQ_ALREADY_RUNNING)
-        try:
-            self.cc_session = isc.cc.Session(self.msgq_socket_file)
-            logger.fatal(BIND10_MSGQ_ALREADY_RUNNING)
-            return "b10-msgq already running, or socket file not cleaned , cannot start"
-        except isc.cc.session.SessionError:
-            # this is the case we want, where the msgq is not running
-            pass
-
-        # Start all components.  If any one fails to start, kill all started
-        # components and exit with an error indication.
-        try:
-            self.c_channel_env = c_channel_env
-            self.start_all_components()
-        except ChangeUserError as e:
-            self.kill_started_components()
-            return str(e) + '; ' + NOTE_ON_LOCK_FILE.replace('\n', ' ')
-        except Exception as e:
-            self.kill_started_components()
-            return "Unable to start " + self.curproc + ": " + str(e)
-
-        # Started successfully
-        self.runnable = True
-        self.__started = True
-        return None
-
-    def stop_process(self, process, recipient, pid):
-        """
-        Stop the given process, friendly-like. The process is the name it has
-        (in logs, etc), the recipient is the address on msgq. The pid is the
-        pid of the process (if we have multiple processes of the same name,
-        it might want to choose if it is for this one).
-        """
-        logger.info(BIND10_STOP_PROCESS, process)
-        self.cc_session.group_sendmsg(isc.config.ccsession.
-                                      create_command('shutdown', {'pid': pid}),
-                                      recipient, recipient)
-
-    def component_shutdown(self, exitcode=0):
-        """
-        Stop the Boss instance from a components' request. The exitcode
-        indicates the desired exit code.
-
-        If we did not start yet, it raises an exception, which is meant
-        to propagate through the component and configurator to the startup
-        routine and abort the startup immediately. If it is started up already,
-        we just mark it so we terminate soon.
-
-        It does set the exit code in both cases.
-        """
-        self.exitcode = exitcode
-        if not self.__started:
-            raise Exception("Component failed during startup");
-        else:
-            self.runnable = False
-
-    def shutdown(self):
-        """Stop the BoB instance."""
-        logger.info(BIND10_SHUTDOWN)
-        # If ccsession is still there, inform rest of the system this module
-        # is stopping. Since everything will be stopped shortly, this is not
-        # really necessary, but this is done to reflect that boss is also
-        # 'just' a module.
-        self.ccs.send_stopping()
-
-        # try using the BIND 10 request to stop
-        try:
-            self._component_configurator.shutdown()
-        except:
-            pass
-        # XXX: some delay probably useful... how much is uncertain
-        # I have changed the delay from 0.5 to 1, but sometime it's
-        # still not enough.
-        time.sleep(1)
-        self.reap_children()
-
-        # Send TERM and KILL signals to modules if we're not prevented
-        # from doing so
-        if not self.nokill:
-            # next try sending a SIGTERM
-            self.__kill_children(False)
-            # finally, send SIGKILL (unmaskable termination) until everybody
-            # dies
-            while self.components:
-                # XXX: some delay probably useful... how much is uncertain
-                time.sleep(0.1)
-                self.reap_children()
-                self.__kill_children(True)
-            logger.info(BIND10_SHUTDOWN_COMPLETE)
-
-    def __kill_children(self, forceful):
-        '''Terminate remaining subprocesses by sending a signal.
-
-        The forceful paramter will be passed Component.kill().
-        This is a dedicated subroutine of shutdown(), just to unify two
-        similar cases.
-
-        '''
-        logmsg = BIND10_SEND_SIGKILL if forceful else BIND10_SEND_SIGTERM
-        # We need to make a copy of values as the components may be modified
-        # in the loop.
-        for component in list(self.components.values()):
-            logger.info(logmsg, component.name(), component.pid())
-            try:
-                component.kill(forceful)
-            except OSError as ex:
-                # If kill() failed due to EPERM, it doesn't make sense to
-                # keep trying, so we just log the fact and forget that
-                # component.  Ignore other OSErrors (usually ESRCH because
-                # the child finally exited)
-                signame = "SIGKILL" if forceful else "SIGTERM"
-                logger.info(BIND10_SEND_SIGNAL_FAIL, signame,
-                            component.name(), component.pid(), ex)
-                if ex.errno == errno.EPERM:
-                    del self.components[component.pid()]
-
-    def _get_process_exit_status(self):
-        return os.waitpid(-1, os.WNOHANG)
-
-    def reap_children(self):
-        """Check to see if any of our child processes have exited,
-        and note this for later handling.
-        """
-        while True:
-            try:
-                (pid, exit_status) = self._get_process_exit_status()
-            except OSError as o:
-                if o.errno == errno.ECHILD:
-                    break
-                # XXX: should be impossible to get any other error here
-                raise
-            if pid == 0:
-                break
-            if pid in self.components:
-                # One of the components we know about.  Get information on it.
-                component = self.components.pop(pid)
-                logger.info(BIND10_PROCESS_ENDED, component.name(), pid,
-                            exit_status)
-                if component.is_running() and self.runnable:
-                    # Tell it it failed. But only if it matters (we are
-                    # not shutting down and the component considers itself
-                    # to be running.
-                    component_restarted = component.failed(exit_status);
-                    # if the process wants to be restarted, but not just yet,
-                    # it returns False
-                    if not component_restarted:
-                        self.components_to_restart.append(component)
-            else:
-                logger.info(BIND10_UNKNOWN_CHILD_PROCESS_ENDED, pid)
-
-    def restart_processes(self):
-        """
-            Restart any dead processes:
-
-            * Returns the time when the next process is ready to be restarted.
-            * If the server is shutting down, returns 0.
-            * If there are no processes, returns None.
-
-            The values returned can be safely passed into select() as the
-            timeout value.
-
-        """
-        if not self.runnable:
-            return 0
-        still_dead = []
-        # keep track of the first time we need to check this queue again,
-        # if at all
-        next_restart_time = None
-        now = time.time()
-        for component in self.components_to_restart:
-            # If the component was removed from the configurator between since
-            # scheduled to restart, just ignore it.  The object will just be
-            # dropped here.
-            if not self._component_configurator.has_component(component):
-                logger.info(BIND10_RESTART_COMPONENT_SKIPPED, component.name())
-            elif not component.restart(now):
-                still_dead.append(component)
-                if next_restart_time is None or\
-                   next_restart_time > component.get_restart_time():
-                    next_restart_time = component.get_restart_time()
-        self.components_to_restart = still_dead
-
-        return next_restart_time
-
-    def _get_socket(self, args):
-        """
-        Implementation of the get_socket CC command. It asks the cache
-        to provide the token and sends the information back.
-        """
-        try:
-            try:
-                addr = isc.net.parse.addr_parse(args['address'])
-                port = isc.net.parse.port_parse(args['port'])
-                protocol = args['protocol']
-                if protocol not in ['UDP', 'TCP']:
-                    raise ValueError("Protocol must be either UDP or TCP")
-                share_mode = args['share_mode']
-                if share_mode not in ['ANY', 'SAMEAPP', 'NO']:
-                    raise ValueError("Share mode must be one of ANY, SAMEAPP" +
-                                     " or NO")
-                share_name = args['share_name']
-            except KeyError as ke:
-                return \
-                    isc.config.ccsession.create_answer(1,
-                                                       "Missing parameter " +
-                                                       str(ke))
-
-            # FIXME: This call contains blocking IPC. It is expected to be
-            # short, but if it turns out to be problem, we'll need to do
-            # something about it.
-            token = self._socket_cache.get_token(protocol, addr, port,
-                                                 share_mode, share_name)
-            return isc.config.ccsession.create_answer(0, {
-                'token': token,
-                'path': self._socket_path
-            })
-        except isc.bind10.socket_cache.SocketError as e:
-            return isc.config.ccsession.create_answer(CREATOR_SOCKET_ERROR,
-                                                      str(e))
-        except isc.bind10.socket_cache.ShareError as e:
-            return isc.config.ccsession.create_answer(CREATOR_SHARE_ERROR,
-                                                      str(e))
-        except Exception as e:
-            return isc.config.ccsession.create_answer(1, str(e))
-
-    def socket_request_handler(self, token, unix_socket):
-        """
-        This function handles a token that comes over a unix_domain socket.
-        The function looks into the _socket_cache and sends the socket
-        identified by the token back over the unix_socket.
-        """
-        try:
-            token = str(token, 'ASCII') # Convert from bytes to str
-            fd = self._socket_cache.get_socket(token, unix_socket.fileno())
-            # FIXME: These two calls are blocking in their nature. An OS-level
-            # buffer is likely to be large enough to hold all these data, but
-            # if it wasn't and the remote application got stuck, we would have
-            # a problem. If there appear such problems, we should do something
-            # about it.
-            unix_socket.sendall(CREATOR_SOCKET_OK)
-            libutil_io_python.send_fd(unix_socket.fileno(), fd)
-        except Exception as e:
-            logger.info(BIND10_NO_SOCKET, token, e)
-            unix_socket.sendall(CREATOR_SOCKET_UNAVAILABLE)
-
-    def socket_consumer_dead(self, unix_socket):
-        """
-        This function handles when a unix_socket closes. This means all
-        sockets sent to it are to be considered closed. This function signals
-        so to the _socket_cache.
-        """
-        logger.info(BIND10_LOST_SOCKET_CONSUMER, unix_socket.fileno())
-        try:
-            self._socket_cache.drop_application(unix_socket.fileno())
-        except ValueError:
-            # This means the application holds no sockets. It's harmless, as it
-            # can happen in real life - for example, it requests a socket, but
-            # get_socket doesn't find it, so the application dies. It should be
-            # rare, though.
-            pass
-
-    def set_creator(self, creator):
-        """
-        Registeres a socket creator into the boss. The socket creator is not
-        used directly, but through a cache. The cache is created in this
-        method.
-
-        If called more than once, it raises a ValueError.
-        """
-        if self._socket_cache is not None:
-            raise ValueError("A creator was inserted previously")
-        self._socket_cache = isc.bind10.socket_cache.Cache(creator)
-
-    def init_socket_srv(self):
-        """
-        Creates and listens on a unix-domain socket to be able to send out
-        the sockets.
-
-        This method should be called after switching user, or the switched
-        applications won't be able to access the socket.
-        """
-        self._srv_socket = socket.socket(socket.AF_UNIX)
-        # We create a temporary directory somewhere safe and unique, to avoid
-        # the need to find the place ourself or bother users. Also, this
-        # secures the socket on some platforms, as it creates a private
-        # directory.
-        self._tmpdir = tempfile.mkdtemp(prefix='sockcreator-')
-        # Get the name
-        self._socket_path = os.path.join(self._tmpdir, "sockcreator")
-        # And bind the socket to the name
-        self._srv_socket.bind(self._socket_path)
-        self._srv_socket.listen(5)
-
-    def remove_socket_srv(self):
-        """
-        Closes and removes the listening socket and the directory where it
-        lives, as we created both.
-
-        It does nothing if the _srv_socket is not set (eg. it was not yet
-        initialized).
-        """
-        if self._srv_socket is not None:
-            self._srv_socket.close()
-            if os.path.exists(self._socket_path):
-                os.remove(self._socket_path)
-            if os.path.isdir(self._tmpdir):
-                os.rmdir(self._tmpdir)
-
-    def _srv_accept(self):
-        """
-        Accept a socket from the unix domain socket server and put it to the
-        others we care about.
-        """
-        (socket, conn) = self._srv_socket.accept()
-        self._unix_sockets[socket.fileno()] = (socket, b'')
-
-    def _socket_data(self, socket_fileno):
-        """
-        This is called when a socket identified by the socket_fileno needs
-        attention. We try to read data from there. If it is closed, we remove
-        it.
-        """
-        (sock, previous) = self._unix_sockets[socket_fileno]
-        while True:
-            try:
-                data = sock.recv(1, socket.MSG_DONTWAIT)
-            except socket.error as se:
-                # These two might be different on some systems
-                if se.errno == errno.EAGAIN or se.errno == errno.EWOULDBLOCK:
-                    # No more data now. Oh, well, just store what we have.
-                    self._unix_sockets[socket_fileno] = (sock, previous)
-                    return
-                else:
-                    data = b'' # Pretend it got closed
-            if len(data) == 0: # The socket got to it's end
-                del self._unix_sockets[socket_fileno]
-                self.socket_consumer_dead(sock)
-                sock.close()
-                return
-            else:
-                if data == b"\n":
-                    # Handle this token and clear it
-                    self.socket_request_handler(previous, sock)
-                    previous = b''
-                else:
-                    previous += data
-
-    def run(self, wakeup_fd):
-        """
-        The main loop, waiting for sockets, commands and dead processes.
-        Runs as long as the runnable is true.
-
-        The wakeup_fd descriptor is the read end of pipe where CHLD signal
-        handler writes.
-        """
-        ccs_fd = self.ccs.get_socket().fileno()
-        while self.runnable:
-            # clean up any processes that exited
-            self.reap_children()
-            next_restart = self.restart_processes()
-            if next_restart is None:
-                wait_time = None
-            else:
-                wait_time = max(next_restart - time.time(), 0)
-
-            # select() can raise EINTR when a signal arrives,
-            # even if they are resumable, so we have to catch
-            # the exception
-            try:
-                (rlist, wlist, xlist) = \
-                    select.select([wakeup_fd, ccs_fd,
-                                   self._srv_socket.fileno()] +
-                                   list(self._unix_sockets.keys()), [], [],
-                                  wait_time)
-            except select.error as err:
-                if err.args[0] == errno.EINTR:
-                    (rlist, wlist, xlist) = ([], [], [])
-                else:
-                    logger.fatal(BIND10_SELECT_ERROR, err)
-                    break
-
-            for fd in rlist + xlist:
-                if fd == ccs_fd:
-                    try:
-                        self.ccs.check_command()
-                    except isc.cc.session.ProtocolError:
-                        logger.fatal(BIND10_MSGQ_DISAPPEARED)
-                        self.runnable = False
-                        break
-                elif fd == wakeup_fd:
-                    os.read(wakeup_fd, 32)
-                elif fd == self._srv_socket.fileno():
-                    self._srv_accept()
-                elif fd in self._unix_sockets:
-                    self._socket_data(fd)
-
-# global variables, needed for signal handlers
-options = None
-boss_of_bind = None
-
-def reaper(signal_number, stack_frame):
-    """A child process has died (SIGCHLD received)."""
-    # don't do anything...
-    # the Python signal handler has been set up to write
-    # down a pipe, waking up our select() bit
-    pass
-
-def get_signame(signal_number):
-    """Return the symbolic name for a signal."""
-    for sig in dir(signal):
-        if sig.startswith("SIG") and sig[3].isalnum():
-            if getattr(signal, sig) == signal_number:
-                return sig
-    return "Unknown signal %d" % signal_number
-
-# XXX: perhaps register atexit() function and invoke that instead
-def fatal_signal(signal_number, stack_frame):
-    """We need to exit (SIGINT or SIGTERM received)."""
-    global options
-    global boss_of_bind
-    logger.info(BIND10_RECEIVED_SIGNAL, get_signame(signal_number))
-    signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-    boss_of_bind.runnable = False
-
-def process_rename(option, opt_str, value, parser):
-    """Function that renames the process if it is requested by a option."""
-    isc.util.process.rename(value)
-
-def parse_args(args=sys.argv[1:], Parser=OptionParser):
-    """
-    Function for parsing command line arguments. Returns the
-    options object from OptionParser.
-    """
-    parser = Parser(version=VERSION)
-    parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
-                      type="string", default=None,
-                      help="UNIX domain socket file the b10-msgq daemon will use")
-    parser.add_option("-i", "--no-kill", action="store_true", dest="nokill",
-                      default=False, help="do not send SIGTERM and SIGKILL signals to modules during shutdown")
-    parser.add_option("-u", "--user", dest="user", type="string", default=None,
-                      help="Change user after startup (must run as root)")
-    parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
-                      help="display more about what is going on")
-    parser.add_option("--pretty-name", type="string", action="callback",
-                      callback=process_rename,
-                      help="Set the process name (displayed in ps, top, ...)")
-    parser.add_option("-c", "--config-file", action="store",
-                      dest="config_file", default=None,
-                      help="Configuration database filename")
-    parser.add_option("--clear-config", action="store_true",
-                      dest="clear_config", default=False,
-                      help="Create backup of the configuration file and " +
-                           "start with a clean configuration")
-    parser.add_option("-p", "--data-path", dest="data_path",
-                      help="Directory to search for configuration files",
-                      default=None)
-    parser.add_option("--cmdctl-port", dest="cmdctl_port", type="int",
-                      default=None, help="Port of command control")
-    parser.add_option("--pid-file", dest="pid_file", type="string",
-                      default=None,
-                      help="file to dump the PID of the BIND 10 process")
-    parser.add_option("-w", "--wait", dest="wait_time", type="int",
-                      default=10, help="Time (in seconds) to wait for config manager to start up")
-
-    (options, args) = parser.parse_args(args)
-
-    if options.cmdctl_port is not None:
-        try:
-            isc.net.parse.port_parse(options.cmdctl_port)
-        except ValueError as e:
-            parser.error(e)
-
-    if args:
-        parser.print_help()
-        sys.exit(1)
-
-    return options
-
-def dump_pid(pid_file):
-    """
-    Dump the PID of the current process to the specified file.  If the given
-    file is None this function does nothing.  If the file already exists,
-    the existing content will be removed.  If a system error happens in
-    creating or writing to the file, the corresponding exception will be
-    propagated to the caller.
-    """
-    if pid_file is None:
-        return
-    f = open(pid_file, "w")
-    f.write('%d\n' % os.getpid())
-    f.close()
-
-def unlink_pid_file(pid_file):
-    """
-    Remove the given file, which is basically expected to be the PID file
-    created by dump_pid().  The specified may or may not exist; if it
-    doesn't this function does nothing.  Other system level errors in removing
-    the file will be propagated as the corresponding exception.
-    """
-    if pid_file is None:
-        return
-    try:
-        os.unlink(pid_file)
-    except OSError as error:
-        if error.errno is not errno.ENOENT:
-            raise
-
-def remove_lock_files():
-    """
-    Remove various lock files which were created by code such as in the
-    logger. This function should be called after BIND 10 shutdown.
-    """
-
-    lockfiles = ["logger_lockfile"]
-
-    lpath = bind10_config.DATA_PATH
-    if "B10_FROM_BUILD" in os.environ:
-        lpath = os.environ["B10_FROM_BUILD"]
-    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
-        lpath = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
-    if "B10_LOCKFILE_DIR_FROM_BUILD" in os.environ:
-        lpath = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"]
-
-    for f in lockfiles:
-        fname = lpath + '/' + f
-        if os.path.isfile(fname):
-            try:
-                os.unlink(fname)
-            except OSError as e:
-                # We catch and ignore permission related error on unlink.
-                # This can happen if bind10 started with -u, created a lock
-                # file as a privileged user, but the directory is not writable
-                # for the changed user.  This setup will cause immediate
-                # start failure, and we leave verbose error message including
-                # the leftover lock file, so it should be acceptable to ignore
-                # it (note that it doesn't make sense to log this event at
-                # this poitn)
-                if e.errno != errno.EPERM and e.errno != errno.EACCES:
-                    raise
-
-    return
-
-def main():
-    global options
-    global boss_of_bind
-    # Enforce line buffering on stdout, even when not a TTY
-    sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
-
-    options = parse_args()
-
-    # Announce startup.  Making this is the first log message.
-    try:
-        logger.info(BIND10_STARTING, VERSION)
-    except RuntimeError as e:
-        sys.stderr.write('ERROR: failed to write the initial log: %s\n' %
-                         str(e))
-        sys.stderr.write(NOTE_ON_LOCK_FILE)
-        sys.exit(1)
-
-    # Check user ID.
-    setuid = None
-    setgid = None
-    username = None
-    if options.user:
-        # Try getting information about the user, assuming UID passed.
-        try:
-            pw_ent = pwd.getpwuid(int(options.user))
-            setuid = pw_ent.pw_uid
-            setgid = pw_ent.pw_gid
-            username = pw_ent.pw_name
-        except ValueError:
-            pass
-        except KeyError:
-            pass
-
-        # Next try getting information about the user, assuming user name
-        # passed.
-        # If the information is both a valid user name and user number, we
-        # prefer the name because we try it second. A minor point, hopefully.
-        try:
-            pw_ent = pwd.getpwnam(options.user)
-            setuid = pw_ent.pw_uid
-            setgid = pw_ent.pw_gid
-            username = pw_ent.pw_name
-        except KeyError:
-            pass
-
-        if setuid is None:
-            logger.fatal(BIND10_INVALID_USER, options.user)
-            sys.exit(1)
-
-    # Create wakeup pipe for signal handlers
-    wakeup_pipe = os.pipe()
-    signal.set_wakeup_fd(wakeup_pipe[1])
-
-    # Set signal handlers for catching child termination, as well
-    # as our own demise.
-    signal.signal(signal.SIGCHLD, reaper)
-    signal.siginterrupt(signal.SIGCHLD, False)
-    signal.signal(signal.SIGINT, fatal_signal)
-    signal.signal(signal.SIGTERM, fatal_signal)
-
-    # Block SIGPIPE, as we don't want it to end this process
-    signal.signal(signal.SIGPIPE, signal.SIG_IGN)
-
-    try:
-        # Go bob!
-        boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
-                           options.config_file, options.clear_config,
-                           options.verbose, options.nokill,
-                           setuid, setgid, username, options.cmdctl_port,
-                           options.wait_time)
-        startup_result = boss_of_bind.startup()
-        if startup_result:
-            logger.fatal(BIND10_STARTUP_ERROR, startup_result)
-            sys.exit(1)
-        boss_of_bind.init_socket_srv()
-        logger.info(BIND10_STARTUP_COMPLETE)
-        dump_pid(options.pid_file)
-
-        # Let it run
-        boss_of_bind.run(wakeup_pipe[0])
-
-        # shutdown
-        signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-        boss_of_bind.shutdown()
-    finally:
-        # Clean up the filesystem
-        unlink_pid_file(options.pid_file)
-        remove_lock_files()
-        if boss_of_bind is not None:
-            boss_of_bind.remove_socket_srv()
-    sys.exit(boss_of_bind.exitcode)
-
-if __name__ == "__main__":
-    main()
diff --git a/src/bin/bind10/bob.spec b/src/bin/bind10/bob.spec
deleted file mode 100644
index 442d46f..0000000
--- a/src/bin/bind10/bob.spec
+++ /dev/null
@@ -1,92 +0,0 @@
-{
-  "module_spec": {
-    "module_name": "Boss",
-    "module_description": "Master process",
-    "config_data": [
-      {
-        "item_name": "components",
-        "item_type": "named_set",
-        "item_optional": false,
-        "item_default": {
-          "b10-stats": { "address": "Stats", "kind": "dispensable" },
-          "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
-        },
-        "named_set_item_spec": {
-          "item_name": "component",
-          "item_type": "map",
-          "item_optional": false,
-          "item_default": { },
-          "map_item_spec": [
-            {
-              "item_name": "special",
-              "item_optional": true,
-              "item_type": "string"
-            },
-            {
-              "item_name": "process",
-              "item_optional": true,
-              "item_type": "string"
-            },
-            {
-              "item_name": "kind",
-              "item_optional": false,
-              "item_type": "string",
-              "item_default": "dispensable"
-            },
-            {
-              "item_name": "address",
-              "item_optional": true,
-              "item_type": "string"
-            },
-            {
-              "item_name": "params",
-              "item_optional": true,
-              "item_type": "list",
-              "list_item_spec": {
-                "item_name": "param",
-                "item_optional": false,
-                "item_type": "string",
-                "item_default": ""
-              }
-            },
-            {
-              "item_name": "priority",
-              "item_optional": true,
-              "item_type": "integer"
-            }
-          ]
-        }
-      }
-    ],
-    "commands": [
-      {
-        "command_name": "shutdown",
-        "command_description": "Shut down BIND 10",
-        "command_args": []
-      },
-      {
-        "command_name": "ping",
-        "command_description": "Ping the boss process",
-        "command_args": []
-      },
-      {
-        "command_name": "show_processes",
-        "command_description": "List the running BIND 10 processes",
-        "command_args": []
-      }
-    ],
-    "statistics": [
-      {
-        "item_name": "boot_time",
-        "item_type": "string",
-        "item_optional": false,
-        "item_default": "1970-01-01T00:00:00Z",
-        "item_title": "Boot time",
-        "item_description": "A date time when bind10 process starts initially",
-        "item_format": "date-time"
-      }
-    ]
-  }
-}
-
-
diff --git a/src/bin/bind10/creatorapi.txt b/src/bin/bind10/creatorapi.txt
index c23d907..d3e67f4 100644
--- a/src/bin/bind10/creatorapi.txt
+++ b/src/bin/bind10/creatorapi.txt
@@ -1,7 +1,7 @@
 Socket creator API
 ==================
 
-This API is between Boss and other modules to allow them requesting of sockets.
+This API is between Init and other modules to allow them requesting of sockets.
 For simplicity, we will use the socket creator for all (even non-privileged)
 ports for now, but we should have some function where we can abstract it later.
 
@@ -25,12 +25,12 @@ It seems we are stuck with current msgq for a while and there's a chance the
 new replacement will not be able to send sockets inbound. So, we need another
 channel.
 
-The boss will create a unix-domain socket and listen on it. When something
+b10-init will create a unix-domain socket and listen on it. When something
 requests a socket over the command channel and the socket is created, some kind
 of token is returned to the application (which will represent the future
 socket). The application then connects to the unix-domain socket, sends the
-token over the connection (so Boss will know which socket to send there, in case
-multiple applications ask for sockets simultaneously) and Boss sends the socket
+token over the connection (so Init will know which socket to send there, in case
+multiple applications ask for sockets simultaneously) and Init sends the socket
 in return.
 
 In theory, we could send the requests directly over the unix-domain
@@ -48,8 +48,8 @@ socket, but it has two disadvantages:
 
 Caching of sockets
 ------------------
-To allow sending the same socket to multiple application, the Boss process will
-hold a cache. Each socket that is created and sent is kept open in Boss and
+To allow sending the same socket to multiple application, the Init process will
+hold a cache. Each socket that is created and sent is kept open in Init and
 preserved there as well. A reference count is kept with each of them.
 
 When another application asks for the same socket, it is simply sent from the
@@ -60,14 +60,14 @@ command channel), the reference count can be decreased without problems. But
 when the application terminates or crashes, we need to decrease it as well.
 There's a problem, since we don't know which command channel connection (eg.
 lname) belongs to which PID. Furthermore, the applications don't need to be
-started by boss.
+started by b10-init.
 
 There are two possibilities:
 * Let the msgq send messages about disconnected clients (eg. group message to
   some name). This one is better if we want to migrate to dbus, since dbus
   already has this capability as well as sending the sockets inbound (at least it
   seems so on unix) and we could get rid of the unix-domain socket completely.
-* Keep the unix-domain connections open forever. Boss can remember which socket
+* Keep the unix-domain connections open forever. Init can remember which socket
   was sent to which connection and when the connection closes (because the
   application crashed), it can drop all the references on the sockets. This
   seems easier to implement.
@@ -75,12 +75,12 @@ There are two possibilities:
 The commands
 ------------
 * Command to release a socket. This one would have single parameter, the token
-  used to get the socket. After this, boss would decrease its reference count
-  and if it drops to zero, close its own copy of the socket. This should be used
-  when the module stops using the socket (and after closes it). The
-  library could remember the file-descriptor to token mapping (for
-  common applications that don't request the same socket multiple
-  times in parallel).
+  used to get the socket. After this, b10-init would decrease its reference
+  count and if it drops to zero, close its own copy of the socket. This
+  should be used when the module stops using the socket (and after closes
+  it). The library could remember the file-descriptor to token mapping (for
+  common applications that don't request the same socket multiple times in
+  parallel).
 * Command to request a socket. It would have parameters to specify which socket
   (IP address, address family, port) and how to allow sharing. Sharing would be
   one of:
diff --git a/src/bin/bind10/init.py.in b/src/bin/bind10/init.py.in
new file mode 100755
index 0000000..f47de31
--- /dev/null
+++ b/src/bin/bind10/init.py.in
@@ -0,0 +1,1321 @@
+#!@PYTHON@
+
+# 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
+# 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 file implements the b10-init program.
+
+Its purpose is to start up the BIND 10 system, and then manage the
+processes, by starting and stopping processes, plus restarting
+processes that exit.
+
+To start the system, it first runs the c-channel program (msgq), then
+connects to that. It then runs the configuration manager, and reads
+its own configuration. Then it proceeds to starting other modules.
+
+The Python subprocess module is used for starting processes, but
+because this is not efficient for managing groups of processes,
+SIGCHLD signals are caught and processed using the signal module.
+
+Most of the logic is contained in the Init class. However, since Python
+requires that signal processing happen in the main thread, we do
+signal handling outside of that class, in the code running for
+__main__.
+"""
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import os
+
+# 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:
+    SPECFILE_LOCATION = os.environ["B10_FROM_SOURCE"] +\
+                        "/src/bin/bind10/init.spec"
+else:
+    PREFIX = "@prefix@"
+    DATAROOTDIR = "@datarootdir@"
+    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/init.spec"\
+                         .replace("${datarootdir}", DATAROOTDIR)\
+                         .replace("${prefix}", PREFIX)
+
+import subprocess
+import signal
+import re
+import errno
+import time
+import select
+import random
+import socket
+from optparse import OptionParser, OptionValueError
+import io
+import pwd
+import posix
+import copy
+
+from bind10_config import LIBEXECPATH
+import bind10_config
+import isc.cc
+import isc.util.process
+import isc.net.parse
+import isc.log
+import isc.config
+from isc.log_messages.init_messages import *
+import isc.bind10.component
+import isc.bind10.special_component
+import isc.bind10.socket_cache
+import libutil_io_python
+import tempfile
+
+isc.log.init("b10-init", buffer=True)
+logger = isc.log.Logger("init")
+
+# Pending system-wide debug level definitions, the ones we
+# use here are hardcoded for now
+DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
+DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
+
+# Messages sent over the unix domain socket to indicate if it is followed by a real socket
+CREATOR_SOCKET_OK = b"1\n"
+CREATOR_SOCKET_UNAVAILABLE = b"0\n"
+
+# RCodes of known exceptions for the get_token command
+CREATOR_SOCKET_ERROR = 2
+CREATOR_SHARE_ERROR = 3
+
+# Assign this process some longer name
+isc.util.process.rename()
+
+# This is the version that gets displayed to the user.
+# The VERSION string consists of the module name, the module version
+# number, and the overall BIND 10 version number (set in configure.ac).
+VERSION = "bind10 20110223 (BIND 10 @PACKAGE_VERSION@)"
+
+# This is for boot_time of Init
+_BASETIME = time.gmtime()
+
+# Detailed error message commonly used on startup failure, possibly due to
+# permission issue regarding log lock file.  We dump verbose message because
+# it may not be clear exactly what to do if it simply says
+# "failed to open <filename>: permission denied"
+NOTE_ON_LOCK_FILE = """\
+TIP: if this is about permission error for a lock file, check if the directory
+of the file is writable for the user of the bind10 process; often you need
+to start bind10 as a super user.  Also, if you specify the -u option to
+change the user and group, the directory must be writable for the group,
+and the created lock file must be writable for that user. Finally, make sure
+the lock file is not left in the directly before restarting.
+"""
+
+class ProcessInfoError(Exception): pass
+
+class ChangeUserError(Exception):
+    '''Exception raised when setuid/setgid fails.
+
+    When raised, it's expected to be propagated via underlying component
+    management modules to the top level so that it will help provide useful
+    fatal error message.
+
+    '''
+    pass
+
+class ProcessInfo:
+    """Information about a process"""
+
+    dev_null = open(os.devnull, "w")
+
+    def __init__(self, name, args, env={}, dev_null_stdout=False,
+                 dev_null_stderr=False):
+        self.name = name
+        self.args = args
+        self.env = env
+        self.dev_null_stdout = dev_null_stdout
+        self.dev_null_stderr = dev_null_stderr
+        self.process = None
+        self.pid = None
+
+    def _preexec_work(self):
+        """Function used before running a program that needs to run as a
+        different user."""
+        # First, put us into a separate process group so we don't get
+        # SIGINT signals on Ctrl-C (b10-init will shut everthing down by
+        # other means).
+        os.setpgrp()
+
+    def _spawn(self):
+        if self.dev_null_stdout:
+            spawn_stdout = self.dev_null
+        else:
+            spawn_stdout = None
+        if self.dev_null_stderr:
+            spawn_stderr = self.dev_null
+        else:
+            spawn_stderr = None
+        # Environment variables for the child process will be a copy of those
+        # of the b10-init process with any additional specific variables given
+        # on construction (self.env).
+        spawn_env = copy.deepcopy(os.environ)
+        spawn_env.update(self.env)
+        spawn_env['PATH'] = LIBEXECPATH + ':' + spawn_env['PATH']
+        self.process = subprocess.Popen(self.args,
+                                        stdin=subprocess.PIPE,
+                                        stdout=spawn_stdout,
+                                        stderr=spawn_stderr,
+                                        close_fds=True,
+                                        env=spawn_env,
+                                        preexec_fn=self._preexec_work)
+        self.pid = self.process.pid
+
+    # spawn() and respawn() are the same for now, but in the future they
+    # may have different functionality
+    def spawn(self):
+        self._spawn()
+
+    def respawn(self):
+        self._spawn()
+
+class CChannelConnectError(Exception): pass
+
+class ProcessStartError(Exception): pass
+
+class Init:
+    """Init of BIND class."""
+
+    def __init__(self, msgq_socket_file=None, data_path=None,
+                 config_filename=None, clear_config=False,
+                 verbose=False, nokill=False, setuid=None, setgid=None,
+                 username=None, cmdctl_port=None, wait_time=10):
+        """
+            Initialize the Init of BIND. This is a singleton (only one can run).
+
+            The msgq_socket_file specifies the UNIX domain socket file that the
+            msgq process listens on.  If verbose is True, then b10-init reports
+            what it is doing.
+
+            Data path and config filename are passed through to config manager
+            (if provided) and specify the config file to be used.
+
+            The cmdctl_port is passed to cmdctl and specify on which port it
+            should listen.
+
+            wait_time controls the amount of time (in seconds) that Init waits
+            for selected processes to initialize before continuing with the
+            initialization.  Currently this is only the configuration manager.
+        """
+        self.cc_session = None
+        self.ccs = None
+        self.curproc = None
+        self.msgq_socket_file = msgq_socket_file
+        self.component_config = {}
+        # Some time in future, it may happen that a single component has
+        # multple processes (like a pipeline-like component). If so happens,
+        # name "components" may be inapropriate. But as the code isn't probably
+        # completely ready for it, we leave it at components for now. We also
+        # want to support multiple instances of a single component. If it turns
+        # out that we'll have a single component with multiple same processes
+        # or if we start multiple components with the same configuration (we do
+        # this now, but it might change) is an open question.
+        self.components = {}
+        # Simply list of components that died and need to wait for a
+        # restart. Components manage their own restart schedule now
+        self.components_to_restart = []
+        self.runnable = False
+        self.__uid = setuid
+        self.__gid = setgid
+        self.username = username
+        self.verbose = verbose
+        self.nokill = nokill
+        self.data_path = data_path
+        self.config_filename = config_filename
+        self.clear_config = clear_config
+        self.cmdctl_port = cmdctl_port
+        self.wait_time = wait_time
+        self.msgq_timeout = 5
+
+        # _run_under_unittests is only meant to be used when testing. It
+        # bypasses execution of some code to help with testing.
+        self._run_under_unittests = False
+
+        self._component_configurator = isc.bind10.component.Configurator(self,
+            isc.bind10.special_component.get_specials())
+        # The priorities here make them start in the correct order. First
+        # the socket creator (which would drop root privileges by then),
+        # then message queue and after that the config manager (which uses
+        # the config manager)
+        self.__core_components = {
+            'sockcreator': {
+                'kind': 'core',
+                'special': 'sockcreator',
+                'priority': 200
+            },
+            'msgq': {
+                'kind': 'core',
+                'special': 'msgq',
+                'priority': 199
+            },
+            'cfgmgr': {
+                'kind': 'core',
+                'special': 'cfgmgr',
+                'priority': 198
+            }
+        }
+        self.__started = False
+        self.exitcode = 0
+
+        # If -v was set, enable full debug logging.
+        if self.verbose:
+            logger.set_severity("DEBUG", 99)
+        # This is set in init_socket_srv
+        self._socket_path = None
+        self._socket_cache = None
+        self._tmpdir = None
+        self._srv_socket = None
+        self._unix_sockets = {}
+
+    def __propagate_component_config(self, config):
+        comps = dict(config)
+        # Fill in the core components, so they stay alive
+        for comp in self.__core_components:
+            if comp in comps:
+                raise Exception(comp + " is core component managed by " +
+                                "b10-init, do not set it")
+            comps[comp] = self.__core_components[comp]
+        # Update the configuration
+        self._component_configurator.reconfigure(comps)
+
+    def change_user(self):
+        '''Change the user and group to those specified on construction.
+
+        This method is expected to be called by a component on initial
+        startup when the system is ready to switch the user and group
+        (i.e., once all components that need the privilege of the original
+        user have started).
+        '''
+        try:
+            if self.__gid is not None:
+                logger.info(BIND10_SETGID, self.__gid)
+                posix.setgid(self.__gid)
+        except Exception as ex:
+            raise ChangeUserError('failed to change group: ' + str(ex))
+
+        try:
+            if self.__uid is not None:
+                posix.setuid(self.__uid)
+                # We use one-shot logger after setuid here.  This will
+                # detect any permission issue regarding logging due to the
+                # result of setuid at the earliest opportunity.
+                isc.log.Logger("b10-init").info(BIND10_SETUID, self.__uid)
+        except Exception as ex:
+            raise ChangeUserError('failed to change user: ' + str(ex))
+
+    def config_handler(self, new_config):
+        # If this is initial update, don't do anything now, leave it to startup
+        if not self.runnable:
+            return
+        logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
+                     new_config)
+        try:
+            if 'components' in new_config:
+                self.__propagate_component_config(new_config['components'])
+            return isc.config.ccsession.create_answer(0)
+        except Exception as e:
+            return isc.config.ccsession.create_answer(1, str(e))
+
+    def get_processes(self):
+        pids = list(self.components.keys())
+        pids.sort()
+        process_list = [ ]
+        for pid in pids:
+            process_list.append([pid, self.components[pid].name(),
+                                 self.components[pid].address()])
+        return process_list
+
+    def _get_stats_data(self):
+        return { 'boot_time':
+                     time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
+                 }
+
+    def command_handler(self, command, args):
+        logger.debug(DBG_COMMANDS, BIND10_RECEIVED_COMMAND, command)
+        answer = isc.config.ccsession.create_answer(1, "command not implemented")
+        if type(command) != str:
+            answer = isc.config.ccsession.create_answer(1, "bad command")
+        else:
+            if command == "shutdown":
+                self.runnable = False
+                answer = isc.config.ccsession.create_answer(0)
+            elif command == "getstats":
+                answer = isc.config.ccsession.create_answer(
+                    0, self._get_stats_data())
+            elif command == "ping":
+                answer = isc.config.ccsession.create_answer(0, "pong")
+            elif command == "show_processes":
+                answer = isc.config.ccsession. \
+                    create_answer(0, self.get_processes())
+            elif command == "get_socket":
+                answer = self._get_socket(args)
+            elif command == "drop_socket":
+                if "token" not in args:
+                    answer = isc.config.ccsession. \
+                        create_answer(1, "Missing token parameter")
+                else:
+                    try:
+                        self._socket_cache.drop_socket(args["token"])
+                        answer = isc.config.ccsession.create_answer(0)
+                    except Exception as e:
+                        answer = isc.config.ccsession.create_answer(1, str(e))
+            else:
+                answer = isc.config.ccsession.create_answer(1,
+                                                            "Unknown command")
+        return answer
+
+    def kill_started_components(self):
+        """
+            Called as part of the exception handling when a process fails to
+            start, this runs through the list of started processes, killing
+            each one.  It then clears that list.
+        """
+        logger.info(BIND10_KILLING_ALL_PROCESSES)
+        self.__kill_children(True)
+        self.components = {}
+
+    def _read_bind10_config(self):
+        """
+            Reads the parameters associated with the Init module itself.
+
+            This means the list of components we should start now.
+
+            This could easily be combined into start_all_processes, but
+            it stays because of historical reasons and because the tests
+            replace the method sometimes.
+        """
+        logger.info(BIND10_READING_INIT_CONFIGURATION)
+
+        config_data = self.ccs.get_full_config()
+        self.__propagate_component_config(config_data['components'])
+
+    def log_starting(self, process, port = None, address = None):
+        """
+            A convenience function to output a "Starting xxx" message if the
+            logging is set to DEBUG with debuglevel DBG_PROCESS or higher.
+            Putting this into a separate method ensures
+            that the output form is consistent across all processes.
+
+            The process name (passed as the first argument) is put into
+            self.curproc, and is used to indicate which process failed to
+            start if there is an error (and is used in the "Started" message
+            on success).  The optional port and address information are
+            appended to the message (if present).
+        """
+        self.curproc = process
+        if port is None and address is None:
+            logger.info(BIND10_STARTING_PROCESS, self.curproc)
+        elif address is None:
+            logger.info(BIND10_STARTING_PROCESS_PORT, self.curproc,
+                        port)
+        else:
+            logger.info(BIND10_STARTING_PROCESS_PORT_ADDRESS,
+                        self.curproc, address, port)
+
+    def log_started(self, pid = None):
+        """
+            A convenience function to output a 'Started xxxx (PID yyyy)'
+            message.  As with starting_message(), this ensures a consistent
+            format.
+        """
+        if pid is None:
+            logger.debug(DBG_PROCESS, BIND10_STARTED_PROCESS, self.curproc)
+        else:
+            logger.debug(DBG_PROCESS, BIND10_STARTED_PROCESS_PID, self.curproc, pid)
+
+    def process_running(self, msg, who):
+        """
+            Some processes return a message to the Init after they have
+            started to indicate that they are running.  The form of the
+            message is a dictionary with contents {"running:", "<process>"}.
+            This method checks the passed message and returns True if the
+            "who" process is contained in the message (so is presumably
+            running).  It returns False for all other conditions and will
+            log an error if appropriate.
+        """
+        if msg is not None:
+            try:
+                if msg["running"] == who:
+                    return True
+                else:
+                    logger.error(BIND10_STARTUP_UNEXPECTED_MESSAGE, msg)
+            except:
+                logger.error(BIND10_STARTUP_UNRECOGNISED_MESSAGE, msg)
+
+        return False
+
+    # The next few methods start the individual processes of BIND-10.  They
+    # are called via start_all_processes().  If any fail, an exception is
+    # raised which is caught by the caller of start_all_processes(); this kills
+    # processes started up to that point before terminating the program.
+
+    def _make_process_info(self, name, args, env,
+                           dev_null_stdout=False, dev_null_stderr=False):
+        """
+            Wrapper around ProcessInfo(), useful to override
+            ProcessInfo() creation during testing.
+        """
+        return ProcessInfo(name, args, env, dev_null_stdout, dev_null_stderr)
+
+    def start_msgq(self):
+        """
+            Start the message queue and connect to the command channel.
+        """
+        self.log_starting("b10-msgq")
+        msgq_proc = self._make_process_info("b10-msgq", ["b10-msgq"],
+                                            self.c_channel_env,
+                                            True, not self.verbose)
+        msgq_proc.spawn()
+        self.log_started(msgq_proc.pid)
+
+        # Now connect to the c-channel
+        cc_connect_start = time.time()
+        while self.cc_session is None:
+            # if we are run under unittests, break
+            if self._run_under_unittests:
+                break
+
+            # if we have been trying for "a while" give up
+            if (time.time() - cc_connect_start) > self.msgq_timeout:
+                if msgq_proc.process:
+                    msgq_proc.process.kill()
+                logger.error(BIND10_CONNECTING_TO_CC_FAIL)
+                raise CChannelConnectError("Unable to connect to c-channel after 5 seconds")
+
+            # try to connect, and if we can't wait a short while
+            try:
+                self.cc_session = isc.cc.Session(self.msgq_socket_file)
+            except isc.cc.session.SessionError:
+                time.sleep(0.1)
+
+        # Subscribe to the message queue.  The only messages we expect to receive
+        # on this channel are once relating to process startup.
+        if self.cc_session is not None:
+            self.cc_session.group_subscribe("Init")
+
+        return msgq_proc
+
+    def start_cfgmgr(self):
+        """
+            Starts the configuration manager process
+        """
+        self.log_starting("b10-cfgmgr")
+        args = ["b10-cfgmgr"]
+        if self.data_path is not None:
+            args.append("--data-path=" + self.data_path)
+        if self.config_filename is not None:
+            args.append("--config-filename=" + self.config_filename)
+        if self.clear_config:
+            args.append("--clear-config")
+        bind_cfgd = self._make_process_info("b10-cfgmgr", args,
+                                            self.c_channel_env)
+        bind_cfgd.spawn()
+        self.log_started(bind_cfgd.pid)
+
+        # Wait for the configuration manager to start up as
+        # subsequent initialization cannot proceed without it.  The
+        # time to wait can be set on the command line.
+        time_remaining = self.wait_time
+        msg, env = self.cc_session.group_recvmsg()
+        while time_remaining > 0 and not self.process_running(msg, "ConfigManager"):
+            logger.debug(DBG_PROCESS, BIND10_WAIT_CFGMGR)
+            time.sleep(1)
+            time_remaining = time_remaining - 1
+            msg, env = self.cc_session.group_recvmsg()
+
+        if not self.process_running(msg, "ConfigManager"):
+            raise ProcessStartError("Configuration manager process has not started")
+
+        return bind_cfgd
+
+    def start_ccsession(self, c_channel_env):
+        """
+            Start the CC Session
+
+            The argument c_channel_env is unused but is supplied to keep the
+            argument list the same for all start_xxx methods.
+
+            With regards to logging, note that as the CC session is not a
+            process, the log_starting/log_started methods are not used.
+        """
+        logger.info(BIND10_STARTING_CC)
+        self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+                                      self.config_handler,
+                                      self.command_handler,
+                                      socket_file = self.msgq_socket_file)
+        self.ccs.start()
+        logger.debug(DBG_PROCESS, BIND10_STARTED_CC)
+
+    # A couple of utility methods for starting processes...
+
+    def start_process(self, name, args, c_channel_env, port=None, address=None):
+        """
+            Given a set of command arguments, start the process and output
+            appropriate log messages.  If the start is successful, the process
+            is added to the list of started processes.
+
+            The port and address arguments are for log messages only.
+        """
+        self.log_starting(name, port, address)
+        newproc = self._make_process_info(name, args, c_channel_env)
+        newproc.spawn()
+        self.log_started(newproc.pid)
+        return newproc
+
+    def register_process(self, pid, component):
+        """
+        Put another process into b10-init to watch over it.  When the process
+        dies, the component.failed() is called with the exit code.
+
+        It is expected the info is a isc.bind10.component.BaseComponent
+        subclass (or anything having the same interface).
+        """
+        self.components[pid] = component
+
+    def start_simple(self, name):
+        """
+            Most of the BIND-10 processes are started with the command:
+
+                <process-name> [-v]
+
+            ... where -v is appended if verbose is enabled.  This method
+            generates the arguments from the name and starts the process.
+
+            The port and address arguments are for log messages only.
+        """
+        # Set up the command arguments.
+        args = [name]
+        if self.verbose:
+            args += ['-v']
+
+        # ... and start the process
+        return self.start_process(name, args, self.c_channel_env)
+
+    # The next few methods start up the rest of the BIND-10 processes.
+    # Although many of these methods are little more than a call to
+    # start_simple, they are retained (a) for testing reasons and (b) as a place
+    # where modifications can be made if the process start-up sequence changes
+    # for a given process.
+
+    def start_auth(self):
+        """
+            Start the Authoritative server
+        """
+        authargs = ['b10-auth']
+        if self.verbose:
+            authargs += ['-v']
+
+        # ... and start
+        return self.start_process("b10-auth", authargs, self.c_channel_env)
+
+    def start_resolver(self):
+        """
+            Start the Resolver.  At present, all these arguments and switches
+            are pure speculation.  As with the auth daemon, they should be
+            read from the configuration database.
+        """
+        self.curproc = "b10-resolver"
+        # XXX: this must be read from the configuration manager in the future
+        resargs = ['b10-resolver']
+        if self.verbose:
+            resargs += ['-v']
+
+        # ... and start
+        return self.start_process("b10-resolver", resargs, self.c_channel_env)
+
+    def start_cmdctl(self):
+        """
+            Starts the command control process
+        """
+        args = ["b10-cmdctl"]
+        if self.cmdctl_port is not None:
+            args.append("--port=" + str(self.cmdctl_port))
+        if self.verbose:
+            args.append("-v")
+        return self.start_process("b10-cmdctl", args, self.c_channel_env,
+                                  self.cmdctl_port)
+
+    def start_all_components(self):
+        """
+            Starts up all the components.  Any exception generated during the
+            starting of the components is handled by the caller.
+        """
+        # Start the real core (sockcreator, msgq, cfgmgr)
+        self._component_configurator.startup(self.__core_components)
+
+        # Connect to the msgq. This is not a process, so it's not handled
+        # inside the configurator.
+        self.start_ccsession(self.c_channel_env)
+
+        # Extract the parameters associated with Init.  This can only be
+        # done after the CC Session is started.  Note that the logging
+        # configuration may override the "-v" switch set on the command line.
+        self._read_bind10_config()
+
+        # TODO: Return the dropping of privileges
+
+    def startup(self):
+        """
+            Start the Init instance.
+
+            Returns None if successful, otherwise an string describing the
+            problem.
+        """
+        # Try to connect to the c-channel daemon, to see if it is already
+        # running
+        c_channel_env = {}
+        if self.msgq_socket_file is not None:
+             c_channel_env["BIND10_MSGQ_SOCKET_FILE"] = self.msgq_socket_file
+        logger.debug(DBG_PROCESS, BIND10_CHECK_MSGQ_ALREADY_RUNNING)
+        try:
+            self.cc_session = isc.cc.Session(self.msgq_socket_file)
+            logger.fatal(BIND10_MSGQ_ALREADY_RUNNING)
+            return "b10-msgq already running, or socket file not cleaned , cannot start"
+        except isc.cc.session.SessionError:
+            # this is the case we want, where the msgq is not running
+            pass
+
+        # Start all components.  If any one fails to start, kill all started
+        # components and exit with an error indication.
+        try:
+            self.c_channel_env = c_channel_env
+            self.start_all_components()
+        except ChangeUserError as e:
+            self.kill_started_components()
+            return str(e) + '; ' + NOTE_ON_LOCK_FILE.replace('\n', ' ')
+        except Exception as e:
+            self.kill_started_components()
+            return "Unable to start " + self.curproc + ": " + str(e)
+
+        # Started successfully
+        self.runnable = True
+        self.__started = True
+        return None
+
+    def stop_process(self, process, recipient, pid):
+        """
+        Stop the given process, friendly-like. The process is the name it has
+        (in logs, etc), the recipient is the address on msgq. The pid is the
+        pid of the process (if we have multiple processes of the same name,
+        it might want to choose if it is for this one).
+        """
+        logger.info(BIND10_STOP_PROCESS, process)
+        self.cc_session.group_sendmsg(isc.config.ccsession.
+                                      create_command('shutdown', {'pid': pid}),
+                                      recipient, recipient)
+
+    def component_shutdown(self, exitcode=0):
+        """
+        Stop the Init instance from a components' request. The exitcode
+        indicates the desired exit code.
+
+        If we did not start yet, it raises an exception, which is meant
+        to propagate through the component and configurator to the startup
+        routine and abort the startup immediately. If it is started up already,
+        we just mark it so we terminate soon.
+
+        It does set the exit code in both cases.
+        """
+        self.exitcode = exitcode
+        if not self.__started:
+            raise Exception("Component failed during startup");
+        else:
+            self.runnable = False
+
+    def shutdown(self):
+        """Stop the Init instance."""
+        logger.info(BIND10_SHUTDOWN)
+        # If ccsession is still there, inform rest of the system this module
+        # is stopping. Since everything will be stopped shortly, this is not
+        # really necessary, but this is done to reflect that b10-init is also
+        # 'just' a module.
+        self.ccs.send_stopping()
+
+        # try using the BIND 10 request to stop
+        try:
+            self._component_configurator.shutdown()
+        except:
+            pass
+        # XXX: some delay probably useful... how much is uncertain
+        # I have changed the delay from 0.5 to 1, but sometime it's
+        # still not enough.
+        time.sleep(1)
+        self.reap_children()
+
+        # Send TERM and KILL signals to modules if we're not prevented
+        # from doing so
+        if not self.nokill:
+            # next try sending a SIGTERM
+            self.__kill_children(False)
+            # finally, send SIGKILL (unmaskable termination) until everybody
+            # dies
+            while self.components:
+                # XXX: some delay probably useful... how much is uncertain
+                time.sleep(0.1)
+                self.reap_children()
+                self.__kill_children(True)
+            logger.info(BIND10_SHUTDOWN_COMPLETE)
+
+    def __kill_children(self, forceful):
+        '''Terminate remaining subprocesses by sending a signal.
+
+        The forceful paramter will be passed Component.kill().
+        This is a dedicated subroutine of shutdown(), just to unify two
+        similar cases.
+
+        '''
+        logmsg = BIND10_SEND_SIGKILL if forceful else BIND10_SEND_SIGTERM
+        # We need to make a copy of values as the components may be modified
+        # in the loop.
+        for component in list(self.components.values()):
+            logger.info(logmsg, component.name(), component.pid())
+            try:
+                component.kill(forceful)
+            except OSError as ex:
+                # If kill() failed due to EPERM, it doesn't make sense to
+                # keep trying, so we just log the fact and forget that
+                # component.  Ignore other OSErrors (usually ESRCH because
+                # the child finally exited)
+                signame = "SIGKILL" if forceful else "SIGTERM"
+                logger.info(BIND10_SEND_SIGNAL_FAIL, signame,
+                            component.name(), component.pid(), ex)
+                if ex.errno == errno.EPERM:
+                    del self.components[component.pid()]
+
+    def _get_process_exit_status(self):
+        return os.waitpid(-1, os.WNOHANG)
+
+    def reap_children(self):
+        """Check to see if any of our child processes have exited,
+        and note this for later handling.
+        """
+        while True:
+            try:
+                (pid, exit_status) = self._get_process_exit_status()
+            except OSError as o:
+                if o.errno == errno.ECHILD:
+                    break
+                # XXX: should be impossible to get any other error here
+                raise
+            if pid == 0:
+                break
+            if pid in self.components:
+                # One of the components we know about.  Get information on it.
+                component = self.components.pop(pid)
+                logger.info(BIND10_PROCESS_ENDED, component.name(), pid,
+                            exit_status)
+                if component.is_running() and self.runnable:
+                    # Tell it it failed. But only if it matters (we are
+                    # not shutting down and the component considers itself
+                    # to be running.
+                    component_restarted = component.failed(exit_status);
+                    # if the process wants to be restarted, but not just yet,
+                    # it returns False
+                    if not component_restarted:
+                        self.components_to_restart.append(component)
+            else:
+                logger.info(BIND10_UNKNOWN_CHILD_PROCESS_ENDED, pid)
+
+    def restart_processes(self):
+        """
+            Restart any dead processes:
+
+            * Returns the time when the next process is ready to be restarted.
+            * If the server is shutting down, returns 0.
+            * If there are no processes, returns None.
+
+            The values returned can be safely passed into select() as the
+            timeout value.
+
+        """
+        if not self.runnable:
+            return 0
+        still_dead = []
+        # keep track of the first time we need to check this queue again,
+        # if at all
+        next_restart_time = None
+        now = time.time()
+        for component in self.components_to_restart:
+            # If the component was removed from the configurator between since
+            # scheduled to restart, just ignore it.  The object will just be
+            # dropped here.
+            if not self._component_configurator.has_component(component):
+                logger.info(BIND10_RESTART_COMPONENT_SKIPPED, component.name())
+            elif not component.restart(now):
+                still_dead.append(component)
+                if next_restart_time is None or\
+                   next_restart_time > component.get_restart_time():
+                    next_restart_time = component.get_restart_time()
+        self.components_to_restart = still_dead
+
+        return next_restart_time
+
+    def _get_socket(self, args):
+        """
+        Implementation of the get_socket CC command. It asks the cache
+        to provide the token and sends the information back.
+        """
+        try:
+            try:
+                addr = isc.net.parse.addr_parse(args['address'])
+                port = isc.net.parse.port_parse(args['port'])
+                protocol = args['protocol']
+                if protocol not in ['UDP', 'TCP']:
+                    raise ValueError("Protocol must be either UDP or TCP")
+                share_mode = args['share_mode']
+                if share_mode not in ['ANY', 'SAMEAPP', 'NO']:
+                    raise ValueError("Share mode must be one of ANY, SAMEAPP" +
+                                     " or NO")
+                share_name = args['share_name']
+            except KeyError as ke:
+                return \
+                    isc.config.ccsession.create_answer(1,
+                                                       "Missing parameter " +
+                                                       str(ke))
+
+            # FIXME: This call contains blocking IPC. It is expected to be
+            # short, but if it turns out to be problem, we'll need to do
+            # something about it.
+            token = self._socket_cache.get_token(protocol, addr, port,
+                                                 share_mode, share_name)
+            return isc.config.ccsession.create_answer(0, {
+                'token': token,
+                'path': self._socket_path
+            })
+        except isc.bind10.socket_cache.SocketError as e:
+            return isc.config.ccsession.create_answer(CREATOR_SOCKET_ERROR,
+                                                      str(e))
+        except isc.bind10.socket_cache.ShareError as e:
+            return isc.config.ccsession.create_answer(CREATOR_SHARE_ERROR,
+                                                      str(e))
+        except Exception as e:
+            return isc.config.ccsession.create_answer(1, str(e))
+
+    def socket_request_handler(self, token, unix_socket):
+        """
+        This function handles a token that comes over a unix_domain socket.
+        The function looks into the _socket_cache and sends the socket
+        identified by the token back over the unix_socket.
+        """
+        try:
+            token = str(token, 'ASCII') # Convert from bytes to str
+            fd = self._socket_cache.get_socket(token, unix_socket.fileno())
+            # FIXME: These two calls are blocking in their nature. An OS-level
+            # buffer is likely to be large enough to hold all these data, but
+            # if it wasn't and the remote application got stuck, we would have
+            # a problem. If there appear such problems, we should do something
+            # about it.
+            unix_socket.sendall(CREATOR_SOCKET_OK)
+            libutil_io_python.send_fd(unix_socket.fileno(), fd)
+        except Exception as e:
+            logger.info(BIND10_NO_SOCKET, token, e)
+            unix_socket.sendall(CREATOR_SOCKET_UNAVAILABLE)
+
+    def socket_consumer_dead(self, unix_socket):
+        """
+        This function handles when a unix_socket closes. This means all
+        sockets sent to it are to be considered closed. This function signals
+        so to the _socket_cache.
+        """
+        logger.info(BIND10_LOST_SOCKET_CONSUMER, unix_socket.fileno())
+        try:
+            self._socket_cache.drop_application(unix_socket.fileno())
+        except ValueError:
+            # This means the application holds no sockets. It's harmless, as it
+            # can happen in real life - for example, it requests a socket, but
+            # get_socket doesn't find it, so the application dies. It should be
+            # rare, though.
+            pass
+
+    def set_creator(self, creator):
+        """
+        Registeres a socket creator into the b10-init. The socket creator is not
+        used directly, but through a cache. The cache is created in this
+        method.
+
+        If called more than once, it raises a ValueError.
+        """
+        if self._socket_cache is not None:
+            raise ValueError("A creator was inserted previously")
+        self._socket_cache = isc.bind10.socket_cache.Cache(creator)
+
+    def init_socket_srv(self):
+        """
+        Creates and listens on a unix-domain socket to be able to send out
+        the sockets.
+
+        This method should be called after switching user, or the switched
+        applications won't be able to access the socket.
+        """
+        self._srv_socket = socket.socket(socket.AF_UNIX)
+        # We create a temporary directory somewhere safe and unique, to avoid
+        # the need to find the place ourself or bother users. Also, this
+        # secures the socket on some platforms, as it creates a private
+        # directory.
+        self._tmpdir = tempfile.mkdtemp(prefix='sockcreator-')
+        # Get the name
+        self._socket_path = os.path.join(self._tmpdir, "sockcreator")
+        # And bind the socket to the name
+        self._srv_socket.bind(self._socket_path)
+        self._srv_socket.listen(5)
+
+    def remove_socket_srv(self):
+        """
+        Closes and removes the listening socket and the directory where it
+        lives, as we created both.
+
+        It does nothing if the _srv_socket is not set (eg. it was not yet
+        initialized).
+        """
+        if self._srv_socket is not None:
+            self._srv_socket.close()
+            if os.path.exists(self._socket_path):
+                os.remove(self._socket_path)
+            if os.path.isdir(self._tmpdir):
+                os.rmdir(self._tmpdir)
+
+    def _srv_accept(self):
+        """
+        Accept a socket from the unix domain socket server and put it to the
+        others we care about.
+        """
+        (socket, conn) = self._srv_socket.accept()
+        self._unix_sockets[socket.fileno()] = (socket, b'')
+
+    def _socket_data(self, socket_fileno):
+        """
+        This is called when a socket identified by the socket_fileno needs
+        attention. We try to read data from there. If it is closed, we remove
+        it.
+        """
+        (sock, previous) = self._unix_sockets[socket_fileno]
+        while True:
+            try:
+                data = sock.recv(1, socket.MSG_DONTWAIT)
+            except socket.error as se:
+                # These two might be different on some systems
+                if se.errno == errno.EAGAIN or se.errno == errno.EWOULDBLOCK:
+                    # No more data now. Oh, well, just store what we have.
+                    self._unix_sockets[socket_fileno] = (sock, previous)
+                    return
+                else:
+                    data = b'' # Pretend it got closed
+            if len(data) == 0: # The socket got to it's end
+                del self._unix_sockets[socket_fileno]
+                self.socket_consumer_dead(sock)
+                sock.close()
+                return
+            else:
+                if data == b"\n":
+                    # Handle this token and clear it
+                    self.socket_request_handler(previous, sock)
+                    previous = b''
+                else:
+                    previous += data
+
+    def run(self, wakeup_fd):
+        """
+        The main loop, waiting for sockets, commands and dead processes.
+        Runs as long as the runnable is true.
+
+        The wakeup_fd descriptor is the read end of pipe where CHLD signal
+        handler writes.
+        """
+        ccs_fd = self.ccs.get_socket().fileno()
+        while self.runnable:
+            # clean up any processes that exited
+            self.reap_children()
+            next_restart = self.restart_processes()
+            if next_restart is None:
+                wait_time = None
+            else:
+                wait_time = max(next_restart - time.time(), 0)
+
+            # select() can raise EINTR when a signal arrives,
+            # even if they are resumable, so we have to catch
+            # the exception
+            try:
+                (rlist, wlist, xlist) = \
+                    select.select([wakeup_fd, ccs_fd,
+                                   self._srv_socket.fileno()] +
+                                   list(self._unix_sockets.keys()), [], [],
+                                  wait_time)
+            except select.error as err:
+                if err.args[0] == errno.EINTR:
+                    (rlist, wlist, xlist) = ([], [], [])
+                else:
+                    logger.fatal(BIND10_SELECT_ERROR, err)
+                    break
+
+            for fd in rlist + xlist:
+                if fd == ccs_fd:
+                    try:
+                        self.ccs.check_command()
+                    except isc.cc.session.ProtocolError:
+                        logger.fatal(BIND10_MSGQ_DISAPPEARED)
+                        self.runnable = False
+                        break
+                elif fd == wakeup_fd:
+                    os.read(wakeup_fd, 32)
+                elif fd == self._srv_socket.fileno():
+                    self._srv_accept()
+                elif fd in self._unix_sockets:
+                    self._socket_data(fd)
+
+# global variables, needed for signal handlers
+options = None
+b10_init = None
+
+def reaper(signal_number, stack_frame):
+    """A child process has died (SIGCHLD received)."""
+    # don't do anything...
+    # the Python signal handler has been set up to write
+    # down a pipe, waking up our select() bit
+    pass
+
+def get_signame(signal_number):
+    """Return the symbolic name for a signal."""
+    for sig in dir(signal):
+        if sig.startswith("SIG") and sig[3].isalnum():
+            if getattr(signal, sig) == signal_number:
+                return sig
+    return "Unknown signal %d" % signal_number
+
+# XXX: perhaps register atexit() function and invoke that instead
+def fatal_signal(signal_number, stack_frame):
+    """We need to exit (SIGINT or SIGTERM received)."""
+    global options
+    global b10_init
+    logger.info(BIND10_RECEIVED_SIGNAL, get_signame(signal_number))
+    signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+    b10_init.runnable = False
+
+def process_rename(option, opt_str, value, parser):
+    """Function that renames the process if it is requested by a option."""
+    isc.util.process.rename(value)
+
+def parse_args(args=sys.argv[1:], Parser=OptionParser):
+    """
+    Function for parsing command line arguments. Returns the
+    options object from OptionParser.
+    """
+    parser = Parser(version=VERSION)
+    parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
+                      type="string", default=None,
+                      help="UNIX domain socket file the b10-msgq daemon will use")
+    parser.add_option("-i", "--no-kill", action="store_true", dest="nokill",
+                      default=False, help="do not send SIGTERM and SIGKILL signals to modules during shutdown")
+    parser.add_option("-u", "--user", dest="user", type="string", default=None,
+                      help="Change user after startup (must run as root)")
+    parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+                      help="display more about what is going on")
+    parser.add_option("--pretty-name", type="string", action="callback",
+                      callback=process_rename,
+                      help="Set the process name (displayed in ps, top, ...)")
+    parser.add_option("-c", "--config-file", action="store",
+                      dest="config_file", default=None,
+                      help="Configuration database filename")
+    parser.add_option("--clear-config", action="store_true",
+                      dest="clear_config", default=False,
+                      help="Create backup of the configuration file and " +
+                           "start with a clean configuration")
+    parser.add_option("-p", "--data-path", dest="data_path",
+                      help="Directory to search for configuration files",
+                      default=None)
+    parser.add_option("--cmdctl-port", dest="cmdctl_port", type="int",
+                      default=None, help="Port of command control")
+    parser.add_option("--pid-file", dest="pid_file", type="string",
+                      default=None,
+                      help="file to dump the PID of the BIND 10 process")
+    parser.add_option("-w", "--wait", dest="wait_time", type="int",
+                      default=10, help="Time (in seconds) to wait for config manager to start up")
+
+    (options, args) = parser.parse_args(args)
+
+    if options.cmdctl_port is not None:
+        try:
+            isc.net.parse.port_parse(options.cmdctl_port)
+        except ValueError as e:
+            parser.error(e)
+
+    if args:
+        parser.print_help()
+        sys.exit(1)
+
+    return options
+
+def dump_pid(pid_file):
+    """
+    Dump the PID of the current process to the specified file.  If the given
+    file is None this function does nothing.  If the file already exists,
+    the existing content will be removed.  If a system error happens in
+    creating or writing to the file, the corresponding exception will be
+    propagated to the caller.
+    """
+    if pid_file is None:
+        return
+    f = open(pid_file, "w")
+    f.write('%d\n' % os.getpid())
+    f.close()
+
+def unlink_pid_file(pid_file):
+    """
+    Remove the given file, which is basically expected to be the PID file
+    created by dump_pid().  The specified may or may not exist; if it
+    doesn't this function does nothing.  Other system level errors in removing
+    the file will be propagated as the corresponding exception.
+    """
+    if pid_file is None:
+        return
+    try:
+        os.unlink(pid_file)
+    except OSError as error:
+        if error.errno is not errno.ENOENT:
+            raise
+
+def remove_lock_files():
+    """
+    Remove various lock files which were created by code such as in the
+    logger. This function should be called after BIND 10 shutdown.
+    """
+
+    lockfiles = ["logger_lockfile"]
+
+    lpath = bind10_config.DATA_PATH
+    if "B10_FROM_BUILD" in os.environ:
+        lpath = os.environ["B10_FROM_BUILD"]
+    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+        lpath = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+    if "B10_LOCKFILE_DIR_FROM_BUILD" in os.environ:
+        lpath = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"]
+
+    for f in lockfiles:
+        fname = lpath + '/' + f
+        if os.path.isfile(fname):
+            try:
+                os.unlink(fname)
+            except OSError as e:
+                # We catch and ignore permission related error on unlink.
+                # This can happen if bind10 started with -u, created a lock
+                # file as a privileged user, but the directory is not writable
+                # for the changed user.  This setup will cause immediate
+                # start failure, and we leave verbose error message including
+                # the leftover lock file, so it should be acceptable to ignore
+                # it (note that it doesn't make sense to log this event at
+                # this poitn)
+                if e.errno != errno.EPERM and e.errno != errno.EACCES:
+                    raise
+
+    return
+
+def main():
+    global options
+    global b10_init
+    # Enforce line buffering on stdout, even when not a TTY
+    sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
+
+    options = parse_args()
+
+    # Announce startup.  Making this is the first log message.
+    try:
+        logger.info(BIND10_STARTING, VERSION)
+    except RuntimeError as e:
+        sys.stderr.write('ERROR: failed to write the initial log: %s\n' %
+                         str(e))
+        sys.stderr.write(NOTE_ON_LOCK_FILE)
+        sys.exit(1)
+
+    # Check user ID.
+    setuid = None
+    setgid = None
+    username = None
+    if options.user:
+        # Try getting information about the user, assuming UID passed.
+        try:
+            pw_ent = pwd.getpwuid(int(options.user))
+            setuid = pw_ent.pw_uid
+            setgid = pw_ent.pw_gid
+            username = pw_ent.pw_name
+        except ValueError:
+            pass
+        except KeyError:
+            pass
+
+        # Next try getting information about the user, assuming user name
+        # passed.
+        # If the information is both a valid user name and user number, we
+        # prefer the name because we try it second. A minor point, hopefully.
+        try:
+            pw_ent = pwd.getpwnam(options.user)
+            setuid = pw_ent.pw_uid
+            setgid = pw_ent.pw_gid
+            username = pw_ent.pw_name
+        except KeyError:
+            pass
+
+        if setuid is None:
+            logger.fatal(BIND10_INVALID_USER, options.user)
+            sys.exit(1)
+
+    # Create wakeup pipe for signal handlers
+    wakeup_pipe = os.pipe()
+    signal.set_wakeup_fd(wakeup_pipe[1])
+
+    # Set signal handlers for catching child termination, as well
+    # as our own demise.
+    signal.signal(signal.SIGCHLD, reaper)
+    signal.siginterrupt(signal.SIGCHLD, False)
+    signal.signal(signal.SIGINT, fatal_signal)
+    signal.signal(signal.SIGTERM, fatal_signal)
+
+    # Block SIGPIPE, as we don't want it to end this process
+    signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+
+    try:
+        b10_init = Init(options.msgq_socket_file, options.data_path,
+                        options.config_file, options.clear_config,
+                        options.verbose, options.nokill,
+                        setuid, setgid, username, options.cmdctl_port,
+                        options.wait_time)
+        startup_result = b10_init.startup()
+        if startup_result:
+            logger.fatal(BIND10_STARTUP_ERROR, startup_result)
+            sys.exit(1)
+        b10_init.init_socket_srv()
+        logger.info(BIND10_STARTUP_COMPLETE)
+        dump_pid(options.pid_file)
+
+        # Let it run
+        b10_init.run(wakeup_pipe[0])
+
+        # shutdown
+        signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+        b10_init.shutdown()
+    finally:
+        # Clean up the filesystem
+        unlink_pid_file(options.pid_file)
+        remove_lock_files()
+        if b10_init is not None:
+            b10_init.remove_socket_srv()
+    sys.exit(b10_init.exitcode)
+
+if __name__ == "__main__":
+    main()
diff --git a/src/bin/bind10/init.spec b/src/bin/bind10/init.spec
new file mode 100644
index 0000000..62c6f09
--- /dev/null
+++ b/src/bin/bind10/init.spec
@@ -0,0 +1,92 @@
+{
+  "module_spec": {
+    "module_name": "Init",
+    "module_description": "Init process",
+    "config_data": [
+      {
+        "item_name": "components",
+        "item_type": "named_set",
+        "item_optional": false,
+        "item_default": {
+          "b10-stats": { "address": "Stats", "kind": "dispensable" },
+          "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+        },
+        "named_set_item_spec": {
+          "item_name": "component",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": { },
+          "map_item_spec": [
+            {
+              "item_name": "special",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "process",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "kind",
+              "item_optional": false,
+              "item_type": "string",
+              "item_default": "dispensable"
+            },
+            {
+              "item_name": "address",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "params",
+              "item_optional": true,
+              "item_type": "list",
+              "list_item_spec": {
+                "item_name": "param",
+                "item_optional": false,
+                "item_type": "string",
+                "item_default": ""
+              }
+            },
+            {
+              "item_name": "priority",
+              "item_optional": true,
+              "item_type": "integer"
+            }
+          ]
+        }
+      }
+    ],
+    "commands": [
+      {
+        "command_name": "shutdown",
+        "command_description": "Shut down BIND 10",
+        "command_args": []
+      },
+      {
+        "command_name": "ping",
+        "command_description": "Ping the b10-init process",
+        "command_args": []
+      },
+      {
+        "command_name": "show_processes",
+        "command_description": "List the running BIND 10 processes",
+        "command_args": []
+      }
+    ],
+    "statistics": [
+      {
+        "item_name": "boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "Boot time",
+        "item_description": "A date time when bind10 process starts initially",
+        "item_format": "date-time"
+      }
+    ]
+  }
+}
+
+
diff --git a/src/bin/bind10/init_messages.mes b/src/bin/bind10/init_messages.mes
new file mode 100644
index 0000000..9cdb7ef
--- /dev/null
+++ b/src/bin/bind10/init_messages.mes
@@ -0,0 +1,327 @@
+# 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.
+
+# No namespace declaration - these constants go in the global namespace
+# of the xfrin messages python module.
+
+% BIND10_CHECK_MSGQ_ALREADY_RUNNING checking if msgq is already running
+The b10-init process is starting up and will now check if the message bus
+daemon is already running. If so, it will not be able to start, as it
+needs a dedicated message bus.
+
+% BIND10_COMPONENT_FAILED component %1 (pid %2) failed: %3
+The process terminated, but b10-init didn't expect it to, which means
+it must have failed.
+
+% BIND10_COMPONENT_RESTART component %1 is about to restart
+The named component failed previously and we will try to restart it to provide
+as flawless service as possible, but it should be investigated what happened,
+as it could happen again.
+
+% BIND10_COMPONENT_START component %1 is starting
+The named component is about to be started by the b10-init process.
+
+% BIND10_COMPONENT_START_EXCEPTION component %1 failed to start: %2
+An exception (mentioned in the message) happened during the startup of the
+named component. The componet is not considered started and further actions
+will be taken about it.
+
+% BIND10_COMPONENT_STOP component %1 is being stopped
+A component is about to be asked to stop willingly by the b10-init.
+
+% BIND10_COMPONENT_UNSATISFIED component %1 is required to run and failed
+A component failed for some reason (see previous messages). It is either a core
+component or needed component that was just started. In any case, the system
+can't continue without it and will terminate.
+
+% BIND10_CONFIGURATOR_BUILD building plan '%1' -> '%2'
+A debug message. This indicates that the configurator is building a plan
+how to change configuration from the older one to newer one. This does no
+real work yet, it just does the planning what needs to be done.
+
+% BIND10_CONFIGURATOR_PLAN_INTERRUPTED configurator plan interrupted, only %1 of %2 done
+There was an exception during some planned task. The plan will not continue and
+only some tasks of the plan were completed. The rest is aborted. The exception
+will be propagated.
+
+% BIND10_CONFIGURATOR_RECONFIGURE reconfiguring running components
+A different configuration of which components should be running is being
+installed. All components that are no longer needed will be stopped and
+newly introduced ones started. This happens at startup, when the configuration
+is read the first time, or when an operator changes configuration of the b10-init.
+
+% BIND10_CONFIGURATOR_RUN running plan of %1 tasks
+A debug message. The configurator is about to execute a plan of actions it
+computed previously.
+
+% BIND10_CONFIGURATOR_START bind10 component configurator is starting up
+The part that cares about starting and stopping the right component from
+the b10-init process is starting up. This happens only once at the startup
+of the b10-init process. It will start the basic set of processes now (the
+ones b10-init needs to read the configuration), the rest will be started
+after the configuration is known.
+
+% BIND10_CONFIGURATOR_STOP bind10 component configurator is shutting down
+The part that cares about starting and stopping processes in the b10-init is
+shutting down. All started components will be shut down now (more precisely,
+asked to terminate by their own, if they fail to comply, other parts of
+the b10-init process will try to force them).
+
+% BIND10_CONFIGURATOR_TASK performing task %1 on %2
+A debug message. The configurator is about to perform one task of the plan it
+is currently executing on the named component.
+
+% BIND10_CONNECTING_TO_CC_FAIL failed to connect to configuration/command channel; try -v to see output from msgq
+The b10-init process tried to connect to the communication channel for
+commands and configuration updates during initialization, but it
+failed.  This is a fatal startup error, and process will soon
+terminate after some cleanup.  There can be several reasons for the
+failure, but the most likely cause is that the msgq daemon failed to
+start, and the most likely cause of the msgq failure is that it
+doesn't have a permission to create a socket file for the
+communication.  To confirm that, you can see debug messages from msgq
+by starting BIND 10 with the -v command line option.  If it indicates
+permission problem for msgq, make sure the directory where the socket
+file is to be created is writable for the msgq process.  Note that if
+you specify the -u option to change process users, the directory must
+be writable for that user.
+
+% BIND10_INVALID_STATISTICS_DATA invalid specification of statistics data specified
+An error was encountered when the b10-init module specified
+statistics data which is invalid for the b10-init specification file.
+
+% BIND10_INVALID_USER invalid user: %1
+The b10-init process was started with the -u option, to drop root privileges
+and continue running as the specified user, but the user is unknown.
+
+% BIND10_KILLING_ALL_PROCESSES killing all started processes
+The b10-init module was not able to start every process it needed to start
+during startup, and will now kill the processes that did get started.
+
+% BIND10_LOST_SOCKET_CONSUMER consumer %1 of sockets disconnected, considering all its sockets closed
+A connection from one of the applications which requested a socket was
+closed. This means the application has terminated, so all the sockets it was
+using are now closed and bind10 process can release them as well, unless the
+same sockets are used by yet another application.
+
+% BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start
+There already appears to be a message bus daemon running. Either an
+old process was not shut down correctly, and needs to be killed, or
+another instance of BIND10, with the same msgq domain socket, is
+running, which needs to be stopped.
+
+% BIND10_MSGQ_DISAPPEARED msgq channel disappeared
+While listening on the message bus channel for messages, it suddenly
+disappeared. The msgq daemon may have died. This might lead to an
+inconsistent state of the system, and BIND 10 will now shut down.
+
+% BIND10_NO_SOCKET couldn't send a socket for token %1 because of error: %2
+An error occurred when the bind10 process was asked to send a socket file
+descriptor. The error is mentioned, most common reason is that the request
+is invalid and may not come from bind10 process at all.
+
+% BIND10_PROCESS_ENDED process %2 of %1 ended with status %3
+This indicates a process started previously terminated. The process id
+and component owning the process are indicated, as well as the exit code.
+This doesn't distinguish if the process was supposed to terminate or not.
+
+% BIND10_READING_INIT_CONFIGURATION reading b10-init configuration
+The b10-init process is starting up, and will now process the initial
+configuration, as received from the configuration manager.
+
+% BIND10_RECEIVED_COMMAND received command: %1
+The b10-init module received a command and shall now process it. The command
+is printed.
+
+% BIND10_RECEIVED_NEW_CONFIGURATION received new configuration: %1
+The b10-init module received a configuration update and is going to apply
+it now. The new configuration is printed.
+
+% BIND10_RECEIVED_SIGNAL received signal %1
+The b10-init module received the given signal.
+
+% BIND10_RESTART_COMPONENT_SKIPPED Skipped restarting a component %1
+The b10-init module tried to restart a component after it failed (crashed)
+unexpectedly, but the b10-init then found that the component had been removed
+from its local configuration of components to run.  This is an unusual
+situation but can happen if the administrator removes the component from
+the configuration after the component's crash and before the restart time.
+The b10-init module simply skipped restarting that module, and the whole system
+went back to the expected state (except that the crash itself is likely
+to be a bug).
+
+% BIND10_RESURRECTED_PROCESS resurrected %1 (PID %2)
+The given process has been restarted successfully, and is now running
+with the given process id.
+
+% BIND10_RESURRECTING_PROCESS resurrecting dead %1 process...
+The given process has ended unexpectedly, and is now restarted.
+
+% BIND10_SELECT_ERROR error in select() call: %1
+There was a fatal error in the call to select(), used to see if a child
+process has ended or if there is a message on the message bus. This
+should not happen under normal circumstances and is considered fatal,
+so BIND 10 will now shut down. The specific error is printed.
+
+% BIND10_SEND_SIGKILL sending SIGKILL to %1 (PID %2)
+The b10-init module is sending a SIGKILL signal to the given process.
+
+% BIND10_SEND_SIGNAL_FAIL sending %1 to %2 (PID %3) failed: %4
+The b10-init module sent a single (either SIGTERM or SIGKILL) to a process,
+but it failed due to some system level error.  There are two major cases:
+the target process has already terminated but the b10-init module had sent
+the signal before it noticed the termination.  In this case an error
+message should indicate something like "no such process".  This can be
+safely ignored.  The other case is that the b10-init module doesn't have
+the privilege to send a signal to the process.  It can typically
+happen when the b10-init module started as a privileged process, spawned a
+subprocess, and then dropped the privilege.  It includes the case for
+the socket creator when the b10-init process runs with the -u command line
+option.  In this case, the b10-init module simply gives up to terminate
+the process explicitly because it's unlikely to succeed by keeping
+sending the signal.  Although the socket creator is implemented so
+that it will terminate automatically when the b10-init process exits
+(and that should be the case for any other future process running with
+a higher privilege), but it's recommended to check if there's any
+remaining BIND 10 process if this message is logged.  For all other
+cases, the b10-init module will keep sending the signal until it confirms
+all child processes terminate.  Although unlikely, this could prevent
+the b10-init module from exiting, just keeping sending the signals.  So,
+again, it's advisable to check if it really terminates when this
+message is logged.
+
+% BIND10_SEND_SIGTERM sending SIGTERM to %1 (PID %2)
+The b10-init module is sending a SIGTERM signal to the given process.
+
+% BIND10_SETGID setting GID to %1
+The b10-init switches the process group ID to the given value.  This happens
+when BIND 10 starts with the -u option, and the group ID will be set to
+that of the specified user.
+
+% BIND10_SETUID setting UID to %1
+The b10-init switches the user it runs as to the given UID.
+
+% BIND10_SHUTDOWN stopping the server
+The b10-init process received a command or signal telling it to shut down.
+It will send a shutdown command to each process. The processes that do
+not shut down will then receive a SIGTERM signal. If that doesn't work,
+it shall send SIGKILL signals to the processes still alive.
+
+% BIND10_SHUTDOWN_COMPLETE all processes ended, shutdown complete
+All child processes have been stopped, and the b10-init process will now
+stop itself.
+
+% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1
+The socket creator reported an error when creating a socket. But the function
+which failed is unknown (not one of 'S' for socket or 'B' for bind).
+
+% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1
+The b10-init requested a socket from the creator, but the answer is unknown. This
+looks like a programmer error.
+
+% BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator
+There should be more data from the socket creator, but it closed the socket.
+It probably crashed.
+
+% BIND10_SOCKCREATOR_INIT initializing socket creator parser
+The b10-init module initializes routines for parsing the socket creator
+protocol.
+
+% BIND10_SOCKCREATOR_KILL killing the socket creator
+The socket creator is being terminated the aggressive way, by sending it
+sigkill. This should not happen usually.
+
+% BIND10_SOCKCREATOR_TERMINATE terminating socket creator
+The b10-init module sends a request to terminate to the socket creator.
+
+% BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1
+Either sending or receiving data from the socket creator failed with the given
+error. The creator probably crashed or some serious OS-level problem happened,
+as the communication happens only on local host.
+
+% BIND10_SOCKET_CREATED successfully created socket %1
+The socket creator successfully created and sent a requested socket, it has
+the given file number.
+
+% BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3
+The socket creator failed to create the requested socket. It failed on the
+indicated OS API function with given error.
+
+% BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator
+The b10-init forwards a request for a socket to the socket creator.
+
+% BIND10_STARTED_CC started configuration/command session
+Debug message given when BIND 10 has successfully started the object that
+handles configuration and commands.
+
+% BIND10_STARTED_PROCESS started %1
+The given process has successfully been started.
+
+% BIND10_STARTED_PROCESS_PID started %1 (PID %2)
+The given process has successfully been started, and has the given PID.
+
+% BIND10_STARTING starting BIND10: %1
+Informational message on startup that shows the full version.
+
+% BIND10_STARTING_CC starting configuration/command session
+Informational message given when BIND 10 is starting the session object
+that handles configuration and commands.
+
+% BIND10_STARTING_PROCESS starting process %1
+The b10-init module is starting the given process.
+
+% BIND10_STARTING_PROCESS_PORT starting process %1 (to listen on port %2)
+The b10-init module is starting the given process, which will listen on the
+given port number.
+
+% BIND10_STARTING_PROCESS_PORT_ADDRESS starting process %1 (to listen on %2#%3)
+The b10-init module is starting the given process, which will listen on the
+given address and port number (written as <address>#<port>).
+
+% BIND10_STARTUP_COMPLETE BIND 10 started
+All modules have been successfully started, and BIND 10 is now running.
+
+% BIND10_STARTUP_ERROR error during startup: %1
+There was a fatal error when BIND10 was trying to start. The error is
+shown, and BIND10 will now shut down.
+
+% BIND10_STARTUP_UNEXPECTED_MESSAGE unrecognised startup message %1
+During the startup process, a number of messages are exchanged between the
+Init process and the processes it starts.  This error is output when a
+message received by the Init process is recognised as being of the
+correct format but is unexpected.  It may be that processes are starting
+of sequence.
+
+% BIND10_STARTUP_UNRECOGNISED_MESSAGE unrecognised startup message %1
+During the startup process, a number of messages are exchanged between the
+Init process and the processes it starts.  This error is output when a
+message received by the Init process is not recognised.
+
+% BIND10_STOP_PROCESS asking %1 to shut down
+The b10-init module is sending a shutdown command to the given module over
+the message channel.
+
+% BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited
+An unknown child process has exited. The PID is printed, but no further
+action will be taken by the b10-init process.
+
+% BIND10_WAIT_CFGMGR waiting for configuration manager process to initialize
+The configuration manager process is so critical to operation of BIND 10
+that after starting it, the Init module will wait for it to initialize
+itself before continuing.  This debug message is produced during the
+wait and may be output zero or more times depending on how long it takes
+the configuration manager to start up.  The total length of time Init
+will wait for the configuration manager before reporting an error is
+set with the command line --wait switch, which has a default value of
+ten seconds.
diff --git a/src/bin/bind10/run_bind10.sh.in b/src/bin/bind10/run_bind10.sh.in
index 17d2c53..bb00e23 100755
--- a/src/bin/bind10/run_bind10.sh.in
+++ b/src/bin/bind10/run_bind10.sh.in
@@ -23,7 +23,7 @@ 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:@abs_top_builddir@/src/bin/ddns:@abs_top_builddir@/src/bin/dhcp6:@abs_top_builddir@/src/bin/sockcreator:$PATH
 export PATH
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
@@ -45,5 +45,5 @@ export B10_FROM_BUILD
 BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
 export BIND10_MSGQ_SOCKET_FILE
 
-exec ${PYTHON_EXEC} -O ${BIND10_PATH}/bind10 "$@"
+exec ${BIND10_PATH}/b10-init "$@"
 
diff --git a/src/bin/bind10/tests/.gitignore b/src/bin/bind10/tests/.gitignore
index 5e54716..575a4c5 100644
--- a/src/bin/bind10/tests/.gitignore
+++ b/src/bin/bind10/tests/.gitignore
@@ -1 +1 @@
-/bind10_test.py
+/init_test.py
diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am
index a5e3fab..6d59dbd 100644
--- a/src/bin/bind10/tests/Makefile.am
+++ b/src/bin/bind10/tests/Makefile.am
@@ -1,7 +1,7 @@
 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
+PYTESTS = init_test.py
 noinst_SCRIPTS = $(PYTESTS)
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/bind10/tests/args_test.py b/src/bin/bind10/tests/args_test.py
index 93a7cea..c08343b 100644
--- a/src/bin/bind10/tests/args_test.py
+++ b/src/bin/bind10/tests/args_test.py
@@ -1,5 +1,20 @@
+# Copyright (C) 2010,2013  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 program tests the boss process to make sure that it runs while
+This program tests the b10-init process to make sure that it runs while
 dropping permissions. It must be run as a user that can set permission.
 """
 import unittest
@@ -17,69 +32,69 @@ SUID_USER="shane"
 BIND10_EXE="../run_bind10.sh"
 TIMEOUT=3
 
-class TestBossArgs(unittest.TestCase):
-    def _waitForString(self, bob, s):
+class TestInitArgs(unittest.TestCase):
+    def _waitForString(self, init, s):
         found_string = False
         start_time = time.time()
         while time.time() < start_time + TIMEOUT:
-            (r,w,x) = select.select((bob.stdout,), (), (), TIMEOUT) 
-            if bob.stdout in r:
-                s = bob.stdout.readline()
+            (r,w,x) = select.select((init.stdout,), (), (), TIMEOUT)
+            if init.stdout in r:
+                s = init.stdout.readline()
                 if s == '':
                     break
-                if s.startswith(s): 
+                if s.startswith(s):
                     found_string = True
                     break
         return found_string
 
     def testNoArgs(self):
         """Run bind10 without any arguments"""
-        bob = subprocess.Popen(args=(BIND10_EXE,),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        started_ok = self._waitForString(bob, '[bind10] BIND 10 started')
+        init = subprocess.Popen(args=(BIND10_EXE,),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        started_ok = self._waitForString(init, '[bind10] BIND 10 started')
         time.sleep(0.1)
-        bob.terminate()
-        bob.wait()
+        init.terminate()
+        init.wait()
         self.assertTrue(started_ok)
 
     def testBadOption(self):
         """Run bind10 with a bogus option"""
-        bob = subprocess.Popen(args=(BIND10_EXE, "--badoption"),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        failed = self._waitForString(bob, 'bind10: error: no such option: --badoption')
+        init = subprocess.Popen(args=(BIND10_EXE, "--badoption"),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(init, 'bind10: error: no such option: --badoption')
         time.sleep(0.1)
-        bob.terminate()
-        self.assertTrue(bob.wait() == 2)
+        init.terminate()
+        self.assertTrue(init.wait() == 2)
         self.assertTrue(failed)
 
     def testArgument(self):
         """Run bind10 with an argument (this is not allowed)"""
-        bob = subprocess.Popen(args=(BIND10_EXE, "argument"),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        failed = self._waitForString(bob, 'Usage: bind10 [options]')
+        init = subprocess.Popen(args=(BIND10_EXE, "argument"),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(init, 'Usage: bind10 [options]')
         time.sleep(0.1)
-        bob.terminate()
-        self.assertTrue(bob.wait() == 1)
+        init.terminate()
+        self.assertTrue(init.wait() == 1)
         self.assertTrue(failed)
 
     def testBadUser(self):
         """Run bind10 with a bogus user"""
-        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "bogus_user"),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        failed = self._waitForString(bob, "bind10: invalid user: 'bogus_user'")
+        init = subprocess.Popen(args=(BIND10_EXE, "-u", "bogus_user"),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(init, "bind10: invalid user: 'bogus_user'")
         time.sleep(0.1)
-        bob.terminate()
-        self.assertTrue(bob.wait() == 1)
+        init.terminate()
+        self.assertTrue(init.wait() == 1)
         self.assertTrue(failed)
 
     def testBadUid(self):
         """Run bind10 with a bogus user ID"""
-        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "999999999"),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        failed = self._waitForString(bob, "bind10: invalid user: '999999999'")
+        init = subprocess.Popen(args=(BIND10_EXE, "-u", "999999999"),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(init, "bind10: invalid user: '999999999'")
         time.sleep(0.1)
-        bob.terminate()
-        self.assertTrue(bob.wait() == 1)
+        init.terminate()
+        self.assertTrue(init.wait() == 1)
         self.assertTrue(failed)
 
     def testFailSetUser(self):
@@ -90,12 +105,12 @@ class TestBossArgs(unittest.TestCase):
         if os.getuid() == 0:
             self.skipTest("test must not be run as root (uid is 0)")
         # XXX: we depend on the "nobody" user
-        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "nobody"),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        failed = self._waitForString(bob, "[bind10] Error on startup: Unable to start b10-msgq; Unable to change to user nobody")
+        init = subprocess.Popen(args=(BIND10_EXE, "-u", "nobody"),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(init, "[bind10] Error on startup: Unable to start b10-msgq; Unable to change to user nobody")
         time.sleep(0.1)
-        bob.terminate()
-        self.assertTrue(bob.wait() == 1)
+        init.terminate()
+        self.assertTrue(init.wait() == 1)
         self.assertTrue(failed)
 
     def testSetUser(self):
@@ -108,9 +123,9 @@ class TestBossArgs(unittest.TestCase):
         if os.geteuid() != 0:
             self.skipTest("test must run as root (euid is not 0)")
 
-        bob = subprocess.Popen(args=(BIND10_EXE, "-u", SUID_USER),
-                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        started_ok = self._waitForString(bob, '[bind10] BIND 10 started')
+        init = subprocess.Popen(args=(BIND10_EXE, "-u", SUID_USER),
+                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        started_ok = self._waitForString(init, '[bind10] BIND 10 started')
         self.assertTrue(started_ok)
         ps = subprocess.Popen(args=("ps", "axo", "user,pid"),
                               stdout=subprocess.PIPE)
@@ -120,22 +135,22 @@ class TestBossArgs(unittest.TestCase):
             s = ps.stdout.readline()
             if s == '': break
             (user, pid) = s.split()
-            if int(pid) == bob.pid:
+            if int(pid) == init.pid:
                 ps_user = user.decode()
                 break
         self.assertTrue(ps_user is not None)
         self.assertTrue(ps_user == SUID_USER)
         time.sleep(0.1)
-        bob.terminate()
-        x = bob.wait()
-        self.assertTrue(bob.wait() == 0)
+        init.terminate()
+        x = init.wait()
+        self.assertTrue(init.wait() == 0)
 
     def testPrettyName(self):
         """Try the --pretty-name option."""
-        CMD_PRETTY_NAME = b'bob-name-test'
-        bob = subprocess.Popen(args=(BIND10_EXE, '--pretty-name',
+        CMD_PRETTY_NAME = b'init-name-test'
+        init = subprocess.Popen(args=(BIND10_EXE, '--pretty-name',
             CMD_PRETTY_NAME), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        started_ok = self._waitForString(bob, '[bind10] BIND 10 started')
+        started_ok = self._waitForString(init, '[bind10] BIND 10 started')
         self.assertTrue(started_ok)
         ps = subprocess.Popen(args=("ps", "axo", "pid,comm"),
                               stdout=subprocess.PIPE)
@@ -145,13 +160,13 @@ class TestBossArgs(unittest.TestCase):
             s = ps.stdout.readline()
             if s == '': break
             (pid,comm) = s.split(None, 1)
-            if int(pid) == bob.pid:
+            if int(pid) == init.pid:
                 command = comm
                 break
         self.assertEqual(command, CMD_PRETTY_NAME + b'\n')
         time.sleep(0.1)
-        bob.terminate()
-        bob.wait()
+        init.terminate()
+        init.wait()
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
deleted file mode 100644
index ccfa831..0000000
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ /dev/null
@@ -1,2422 +0,0 @@
-# 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.
-
-# Most of the time, we omit the "bind10_src" for brevity. Sometimes,
-# we want to be explicit about what we do, like when hijacking a library
-# call used by the bind10_src.
-from bind10_src import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file, _BASETIME
-import bind10_src
-
-# XXX: environment tests are currently disabled, due to the preprocessor
-#      setup that we have now complicating the environment
-
-import unittest
-import sys
-import os
-import os.path
-import copy
-import signal
-import socket
-from isc.net.addr import IPAddr
-import time
-import isc
-import isc.log
-import isc.bind10.socket_cache
-import errno
-import random
-
-from isc.testutils.parse_args import TestOptParser, OptsError
-from isc.testutils.ccsession_mock import MockModuleCCSession
-
-class TestProcessInfo(unittest.TestCase):
-    def setUp(self):
-        # redirect stdout to a pipe so we can check that our
-        # process spawning is doing the right thing with stdout
-        self.old_stdout = os.dup(sys.stdout.fileno())
-        self.pipes = os.pipe()
-        os.dup2(self.pipes[1], sys.stdout.fileno())
-        os.close(self.pipes[1])
-        # note that we use dup2() to restore the original stdout
-        # to the main program ASAP in each test... this prevents
-        # hangs reading from the child process (as the pipe is only
-        # open in the child), and also insures nice pretty output
-
-    def tearDown(self):
-        # clean up our stdout munging
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        os.close(self.pipes[0])
-
-    def test_init(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
-        pi.spawn()
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        self.assertEqual(pi.name, 'Test Process')
-        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
-        self.assertEqual(pi.dev_null_stdout, False)
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        self.assertNotEqual(pi.process, None)
-        self.assertTrue(type(pi.pid) is int)
-
-#    def test_setting_env(self):
-#        pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
-#        os.dup2(self.old_stdout, sys.stdout.fileno())
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
-#                                   'FOO': 'BAR' })
-
-    def test_setting_null_stdout(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
-                         dev_null_stdout=True)
-        pi.spawn()
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        self.assertEqual(pi.dev_null_stdout, True)
-        self.assertEqual(os.read(self.pipes[0], 100), b"")
-
-    def test_respawn(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
-        pi.spawn()
-        # wait for old process to work...
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        # respawn it
-        old_pid = pi.pid
-        pi.respawn()
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        # make sure the new one started properly
-        self.assertEqual(pi.name, 'Test Process')
-        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
-        self.assertEqual(pi.dev_null_stdout, False)
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        self.assertNotEqual(pi.process, None)
-        self.assertTrue(type(pi.pid) is int)
-        self.assertNotEqual(pi.pid, old_pid)
-
-class TestCacheCommands(unittest.TestCase):
-    """
-    Test methods of boss related to the socket cache and socket handling.
-    """
-    def setUp(self):
-        """
-        Prepare the boss for some tests.
-
-        Also prepare some variables we need.
-        """
-        self.__boss = BoB()
-        # Fake the cache here so we can pretend it is us and hijack the
-        # calls to its methods.
-        self.__boss._socket_cache = self
-        self.__boss._socket_path = '/socket/path'
-        self.__raise_exception = None
-        self.__socket_args = {
-            "port": 53,
-            "address": "::",
-            "protocol": "UDP",
-            "share_mode": "ANY",
-            "share_name": "app"
-        }
-        # What was and wasn't called.
-        self.__drop_app_called = None
-        self.__get_socket_called = None
-        self.__send_fd_called = None
-        self.__get_token_called = None
-        self.__drop_socket_called = None
-        bind10_src.libutil_io_python.send_fd = self.__send_fd
-
-    def __send_fd(self, to, socket):
-        """
-        A function to hook the send_fd in the bind10_src.
-        """
-        self.__send_fd_called = (to, socket)
-
-    class FalseSocket:
-        """
-        A socket where we can fake methods we need instead of having a real
-        socket.
-        """
-        def __init__(self):
-            self.send = b""
-        def fileno(self):
-            """
-            The file number. Used for identifying the remote application.
-            """
-            return 42
-
-        def sendall(self, data):
-            """
-            Adds data to the self.send.
-            """
-            self.send += data
-
-    def drop_application(self, application):
-        """
-        Part of pretending to be the cache. Logs the parameter to
-        self.__drop_app_called.
-
-        In the case self.__raise_exception is set, the exception there
-        is raised instead.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__drop_app_called = application
-
-    def test_consumer_dead(self):
-        """
-        Test that it calls the drop_application method of the cache.
-        """
-        self.__boss.socket_consumer_dead(self.FalseSocket())
-        self.assertEqual(42, self.__drop_app_called)
-
-    def test_consumer_dead_invalid(self):
-        """
-        Test that it doesn't crash in case the application is not known to
-        the cache, the boss doesn't crash, as this actually can happen in
-        practice.
-        """
-        self.__raise_exception = ValueError("This application is unknown")
-        # This doesn't crash
-        self.__boss.socket_consumer_dead(self.FalseSocket())
-
-    def get_socket(self, token, application):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the call is logged
-        into __get_socket_called and a number is returned.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__get_socket_called = (token, application)
-        return 13
-
-    def test_request_handler(self):
-        """
-        Test that a request for socket is forwarded and the socket is sent
-        back, if it returns a socket.
-        """
-        socket = self.FalseSocket()
-        # An exception from the cache
-        self.__raise_exception = ValueError("Test value error")
-        self.__boss.socket_request_handler(b"token", socket)
-        # It was called, but it threw, so it is not noted here
-        self.assertIsNone(self.__get_socket_called)
-        self.assertEqual(b"0\n", socket.send)
-        # It should not have sent any socket.
-        self.assertIsNone(self.__send_fd_called)
-        # Now prepare a valid scenario
-        self.__raise_exception = None
-        socket.send = b""
-        self.__boss.socket_request_handler(b"token", socket)
-        self.assertEqual(b"1\n", socket.send)
-        self.assertEqual((42, 13), self.__send_fd_called)
-        self.assertEqual(("token", 42), self.__get_socket_called)
-
-    def get_token(self, protocol, address, port, share_mode, share_name):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the parameters are
-        logged into __get_token_called and a token is returned.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__get_token_called = (protocol, address, port, share_mode,
-                                   share_name)
-        return "token"
-
-    def test_get_socket_ok(self):
-        """
-        Test the successful scenario of getting a socket.
-        """
-        result = self.__boss._get_socket(self.__socket_args)
-        [code, answer] = result['result']
-        self.assertEqual(0, code)
-        self.assertEqual({
-            'token': 'token',
-            'path': '/socket/path'
-        }, answer)
-        addr = self.__get_token_called[1]
-        self.assertTrue(isinstance(addr, IPAddr))
-        self.assertEqual("::", str(addr))
-        self.assertEqual(("UDP", addr, 53, "ANY", "app"),
-                         self.__get_token_called)
-
-    def test_get_socket_error(self):
-        """
-        Test that bad inputs are handled correctly, etc.
-        """
-        def check_code(code, args):
-            """
-            Pass the args there and check if it returns success or not.
-
-            The rest is not tested, as it is already checked in the
-            test_get_socket_ok.
-            """
-            [rcode, ranswer] = self.__boss._get_socket(args)['result']
-            self.assertEqual(code, rcode)
-            if code != 0:
-                # This should be an error message. The exact formatting
-                # is unknown, but we check it is string at least
-                self.assertTrue(isinstance(ranswer, str))
-
-        def mod_args(name, value):
-            """
-            Override a parameter in the args.
-            """
-            result = dict(self.__socket_args)
-            result[name] = value
-            return result
-
-        # Port too large
-        check_code(1, mod_args('port', 65536))
-        # Not numeric address
-        check_code(1, mod_args('address', 'example.org.'))
-        # Some bad values of enum-like params
-        check_code(1, mod_args('protocol', 'BAD PROTO'))
-        check_code(1, mod_args('share_mode', 'BAD SHARE'))
-        # Check missing parameters
-        for param in self.__socket_args.keys():
-            args = dict(self.__socket_args)
-            del args[param]
-            check_code(1, args)
-        # These are OK values for the enum-like parameters
-        # The ones from test_get_socket_ok are not tested here
-        check_code(0, mod_args('protocol', 'TCP'))
-        check_code(0, mod_args('share_mode', 'SAMEAPP'))
-        check_code(0, mod_args('share_mode', 'NO'))
-        # If an exception is raised from within the cache, it is converted
-        # to an error, not propagated
-        self.__raise_exception = Exception("Test exception")
-        check_code(1, self.__socket_args)
-        # The special "expected" exceptions
-        self.__raise_exception = \
-            isc.bind10.socket_cache.ShareError("Not shared")
-        check_code(3, self.__socket_args)
-        self.__raise_exception = \
-            isc.bind10.socket_cache.SocketError("Not shared", 13)
-        check_code(2, self.__socket_args)
-
-    def drop_socket(self, token):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the parameter is stored
-        in __drop_socket_called.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__drop_socket_called = token
-
-    def test_drop_socket(self):
-        """
-        Check the drop_socket command. It should directly call the method
-        on the cache. Exceptions should be translated to error messages.
-        """
-        # This should be OK and just propagated to the call.
-        self.assertEqual({"result": [0]},
-                         self.__boss.command_handler("drop_socket",
-                                                     {"token": "token"}))
-        self.assertEqual("token", self.__drop_socket_called)
-        self.__drop_socket_called = None
-        # Missing parameter
-        self.assertEqual({"result": [1, "Missing token parameter"]},
-                         self.__boss.command_handler("drop_socket", {}))
-        self.assertIsNone(self.__drop_socket_called)
-        # An exception is raised from within the cache
-        self.__raise_exception = ValueError("Test error")
-        self.assertEqual({"result": [1, "Test error"]},
-                         self.__boss.command_handler("drop_socket",
-                         {"token": "token"}))
-
-
-class TestBoB(unittest.TestCase):
-    def setUp(self):
-        # Save original values that may be tweaked in some tests
-        self.__orig_setgid = bind10_src.posix.setgid
-        self.__orig_setuid = bind10_src.posix.setuid
-        self.__orig_logger_class = isc.log.Logger
-
-    def tearDown(self):
-        # Restore original values saved in setUp()
-        bind10_src.posix.setgid = self.__orig_setgid
-        bind10_src.posix.setuid = self.__orig_setuid
-        isc.log.Logger = self.__orig_logger_class
-
-    def test_init(self):
-        bob = BoB()
-        self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.msgq_socket_file, None)
-        self.assertEqual(bob.cc_session, None)
-        self.assertEqual(bob.ccs, None)
-        self.assertEqual(bob.components, {})
-        self.assertEqual(bob.runnable, False)
-        self.assertEqual(bob.username, None)
-        self.assertIsNone(bob._socket_cache)
-
-    def __setgid(self, gid):
-        self.__gid_set = gid
-
-    def __setuid(self, uid):
-        self.__uid_set = uid
-
-    def test_change_user(self):
-        bind10_src.posix.setgid = self.__setgid
-        bind10_src.posix.setuid = self.__setuid
-
-        self.__gid_set = None
-        self.__uid_set = None
-        bob = BoB()
-        bob.change_user()
-        # No gid/uid set in boss, nothing called.
-        self.assertIsNone(self.__gid_set)
-        self.assertIsNone(self.__uid_set)
-
-        BoB(setuid=42, setgid=4200).change_user()
-        # This time, it get's called
-        self.assertEqual(4200, self.__gid_set)
-        self.assertEqual(42, self.__uid_set)
-
-        def raising_set_xid(gid_or_uid):
-            ex = OSError()
-            ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
-            raise ex
-
-        # Let setgid raise an exception
-        bind10_src.posix.setgid = raising_set_xid
-        bind10_src.posix.setuid = self.__setuid
-        self.assertRaises(bind10_src.ChangeUserError,
-                          BoB(setuid=42, setgid=4200).change_user)
-
-        # Let setuid raise an exception
-        bind10_src.posix.setgid = self.__setgid
-        bind10_src.posix.setuid = raising_set_xid
-        self.assertRaises(bind10_src.ChangeUserError,
-                          BoB(setuid=42, setgid=4200).change_user)
-
-        # Let initial log output after setuid raise an exception
-        bind10_src.posix.setgid = self.__setgid
-        bind10_src.posix.setuid = self.__setuid
-        isc.log.Logger = raising_set_xid
-        self.assertRaises(bind10_src.ChangeUserError,
-                          BoB(setuid=42, setgid=4200).change_user)
-
-    def test_set_creator(self):
-        """
-        Test the call to set_creator. First time, the cache is created
-        with the passed creator. The next time, it throws an exception.
-        """
-        bob = BoB()
-        # The cache doesn't use it at start, so just create an empty class
-        class Creator: pass
-        creator = Creator()
-        bob.set_creator(creator)
-        self.assertTrue(isinstance(bob._socket_cache,
-                        isc.bind10.socket_cache.Cache))
-        self.assertEqual(creator, bob._socket_cache._creator)
-        self.assertRaises(ValueError, bob.set_creator, creator)
-
-    def test_socket_srv(self):
-        """Tests init_socket_srv() and remove_socket_srv() work as expected."""
-        bob = BoB()
-
-        self.assertIsNone(bob._srv_socket)
-        self.assertIsNone(bob._tmpdir)
-        self.assertIsNone(bob._socket_path)
-
-        bob.init_socket_srv()
-
-        self.assertIsNotNone(bob._srv_socket)
-        self.assertNotEqual(-1, bob._srv_socket.fileno())
-        self.assertEqual(os.path.join(bob._tmpdir, 'sockcreator'),
-                         bob._srv_socket.getsockname())
-
-        self.assertIsNotNone(bob._tmpdir)
-        self.assertTrue(os.path.isdir(bob._tmpdir))
-        self.assertIsNotNone(bob._socket_path)
-        self.assertTrue(os.path.exists(bob._socket_path))
-
-        # Check that it's possible to connect to the socket file (this
-        # only works if the socket file exists and the server listens on
-        # it).
-        s = socket.socket(socket.AF_UNIX)
-        try:
-            s.connect(bob._socket_path)
-            can_connect = True
-            s.close()
-        except socket.error as e:
-            can_connect = False
-
-        self.assertTrue(can_connect)
-
-        bob.remove_socket_srv()
-
-        self.assertEqual(-1, bob._srv_socket.fileno())
-        self.assertFalse(os.path.exists(bob._socket_path))
-        self.assertFalse(os.path.isdir(bob._tmpdir))
-
-        # These should not fail either:
-
-        # second call
-        bob.remove_socket_srv()
-
-        bob._srv_socket = None
-        bob.remove_socket_srv()
-
-    def test_init_alternate_socket(self):
-        bob = BoB("alt_socket_file")
-        self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
-        self.assertEqual(bob.cc_session, None)
-        self.assertEqual(bob.ccs, None)
-        self.assertEqual(bob.components, {})
-        self.assertEqual(bob.runnable, False)
-        self.assertEqual(bob.username, None)
-
-    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
-        class DummyModuleCCSession():
-            module_spec = isc.config.module_spec.ModuleSpec({
-                    "module_name": "Boss",
-                    "statistics": [
-                        {
-                            "item_name": "boot_time",
-                            "item_type": "string",
-                            "item_optional": False,
-                            "item_default": "1970-01-01T00:00:00Z",
-                            "item_title": "Boot time",
-                            "item_description": "A date time when bind10 process starts initially",
-                            "item_format": "date-time"
-                            }
-                        ]
-                    })
-            def get_module_spec(self):
-                return self.module_spec
-        bob = BoB()
-        bob.verbose = True
-        bob.cc_session = DummySession()
-        bob.ccs = DummyModuleCCSession()
-        # 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)
-        # "getstats" command
-        self.assertEqual(bob.command_handler("getstats", None),
-                         isc.config.ccsession.create_answer(0,
-                            { '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"))
-
-        # Fake the get_token of cache and test the command works
-        bob._socket_path = '/socket/path'
-        class cache:
-            def get_token(self, protocol, addr, port, share_mode, share_name):
-                return str(addr) + ':' + str(port)
-        bob._socket_cache = cache()
-        args = {
-            "port": 53,
-            "address": "0.0.0.0",
-            "protocol": "UDP",
-            "share_mode": "ANY",
-            "share_name": "app"
-        }
-        # at all and this is the easiest way to check.
-        self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
-                                         'path': '/socket/path'}]},
-                         bob.command_handler("get_socket", args))
-        # The drop_socket is not tested here, but in TestCacheCommands.
-        # It needs the cache mocks to be in place and they are there.
-
-    def test_stop_process(self):
-        """
-        Test checking the stop_process method sends the right message over
-        the message bus.
-        """
-        class DummySession():
-            def group_sendmsg(self, msg, group, instance="*"):
-                (self.msg, self.group, self.instance) = (msg, group, instance)
-        bob = BoB()
-        bob.cc_session = DummySession()
-        bob.stop_process('process', 'address', 42)
-        self.assertEqual('address', bob.cc_session.group)
-        self.assertEqual('address', bob.cc_session.instance)
-        self.assertEqual({'command': ['shutdown', {'pid': 42}]},
-                         bob.cc_session.msg)
-
-# Mock class for testing BoB's usage of ProcessInfo
-class MockProcessInfo:
-    def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
-        self.name = name
-        self.args = args
-        self.env = env
-        self.dev_null_stdout = dev_null_stdout
-        self.dev_null_stderr = dev_null_stderr
-        self.process = None
-        self.pid = None
-
-    def spawn(self):
-        # set some pid (only used for testing that it is not None anymore)
-        self.pid = 42147
-
-# Class for testing the BoB without actually starting processes.
-# This is used for testing the start/stop components routines and
-# the BoB commands.
-#
-# Testing that external processes start is outside the scope
-# of the unit test, by overriding the process start methods we can check
-# that the right processes are started depending on the configuration
-# options.
-class MockBob(BoB):
-    def __init__(self):
-        BoB.__init__(self)
-
-        # Set flags as to which of the overridden methods has been run.
-        self.msgq = False
-        self.cfgmgr = False
-        self.ccsession = False
-        self.auth = False
-        self.resolver = False
-        self.xfrout = False
-        self.xfrin = False
-        self.zonemgr = False
-        self.stats = False
-        self.stats_httpd = False
-        self.cmdctl = False
-        self.dhcp6 = False
-        self.dhcp4 = False
-        self.c_channel_env = {}
-        self.components = { }
-        self.creator = False
-        self.get_process_exit_status_called = False
-
-        class MockSockCreator(isc.bind10.component.Component):
-            def __init__(self, process, boss, kind, address=None, params=None):
-                isc.bind10.component.Component.__init__(self, process, boss,
-                                                        kind, 'SockCreator')
-                self._start_func = boss.start_creator
-
-        specials = isc.bind10.special_component.get_specials()
-        specials['sockcreator'] = MockSockCreator
-        self._component_configurator = \
-            isc.bind10.component.Configurator(self, specials)
-
-    def start_creator(self):
-        self.creator = True
-        procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
-        procinfo.pid = 1
-        return procinfo
-
-    def _read_bind10_config(self):
-        # Configuration options are set directly
-        pass
-
-    def start_msgq(self):
-        self.msgq = True
-        procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
-        procinfo.pid = 2
-        return procinfo
-
-    def start_ccsession(self, c_channel_env):
-        # this is not a process, don't have to do anything with procinfo
-        self.ccsession = True
-
-    def start_cfgmgr(self):
-        self.cfgmgr = True
-        procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
-        procinfo.pid = 3
-        return procinfo
-
-    def start_auth(self):
-        self.auth = True
-        procinfo = ProcessInfo('b10-auth', ['/bin/false'])
-        procinfo.pid = 5
-        return procinfo
-
-    def start_resolver(self):
-        self.resolver = True
-        procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
-        procinfo.pid = 6
-        return procinfo
-
-    def start_simple(self, name):
-        procmap = { 'b10-zonemgr': self.start_zonemgr,
-                    'b10-stats': self.start_stats,
-                    'b10-stats-httpd': self.start_stats_httpd,
-                    'b10-cmdctl': self.start_cmdctl,
-                    'b10-dhcp6': self.start_dhcp6,
-                    'b10-dhcp4': self.start_dhcp4,
-                    'b10-xfrin': self.start_xfrin,
-                    'b10-xfrout': self.start_xfrout }
-        return procmap[name]()
-
-    def start_xfrout(self):
-        self.xfrout = True
-        procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
-        procinfo.pid = 7
-        return procinfo
-
-    def start_xfrin(self):
-        self.xfrin = True
-        procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
-        procinfo.pid = 8
-        return procinfo
-
-    def start_zonemgr(self):
-        self.zonemgr = True
-        procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
-        procinfo.pid = 9
-        return procinfo
-
-    def start_stats(self):
-        self.stats = True
-        procinfo = ProcessInfo('b10-stats', ['/bin/false'])
-        procinfo.pid = 10
-        return procinfo
-
-    def start_stats_httpd(self):
-        self.stats_httpd = True
-        procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
-        procinfo.pid = 11
-        return procinfo
-
-    def start_cmdctl(self):
-        self.cmdctl = True
-        procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
-        procinfo.pid = 12
-        return procinfo
-
-    def start_dhcp6(self):
-        self.dhcp6 = True
-        procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
-        procinfo.pid = 13
-        return procinfo
-
-    def start_dhcp4(self):
-        self.dhcp4 = True
-        procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
-        procinfo.pid = 14
-        return procinfo
-
-    def stop_process(self, process, recipient, pid):
-        procmap = { 'b10-auth': self.stop_auth,
-                    'b10-resolver': self.stop_resolver,
-                    'b10-xfrout': self.stop_xfrout,
-                    'b10-xfrin': self.stop_xfrin,
-                    'b10-zonemgr': self.stop_zonemgr,
-                    'b10-stats': self.stop_stats,
-                    'b10-stats-httpd': self.stop_stats_httpd,
-                    'b10-cmdctl': self.stop_cmdctl }
-        procmap[process]()
-
-    # Some functions to pretend we stop processes, use by stop_process
-    def stop_msgq(self):
-        if self.msgq:
-            del self.components[2]
-        self.msgq = False
-
-    def stop_cfgmgr(self):
-        if self.cfgmgr:
-            del self.components[3]
-        self.cfgmgr = False
-
-    def stop_auth(self):
-        if self.auth:
-            del self.components[5]
-        self.auth = False
-
-    def stop_resolver(self):
-        if self.resolver:
-            del self.components[6]
-        self.resolver = False
-
-    def stop_xfrout(self):
-        if self.xfrout:
-            del self.components[7]
-        self.xfrout = False
-
-    def stop_xfrin(self):
-        if self.xfrin:
-            del self.components[8]
-        self.xfrin = False
-
-    def stop_zonemgr(self):
-        if self.zonemgr:
-            del self.components[9]
-        self.zonemgr = False
-
-    def stop_stats(self):
-        if self.stats:
-            del self.components[10]
-        self.stats = False
-
-    def stop_stats_httpd(self):
-        if self.stats_httpd:
-            del self.components[11]
-        self.stats_httpd = False
-
-    def stop_cmdctl(self):
-        if self.cmdctl:
-            del self.components[12]
-        self.cmdctl = False
-
-    def _get_process_exit_status(self):
-        if self.get_process_exit_status_called:
-            return (0, 0)
-        self.get_process_exit_status_called = True
-        return (53, 0)
-
-    def _get_process_exit_status_unknown_pid(self):
-        if self.get_process_exit_status_called:
-            return (0, 0)
-        self.get_process_exit_status_called = True
-        return (42, 0)
-
-    def _get_process_exit_status_raises_oserror_echild(self):
-        raise OSError(errno.ECHILD, 'Mock error')
-
-    def _get_process_exit_status_raises_oserror_other(self):
-        raise OSError(0, 'Mock error')
-
-    def _get_process_exit_status_raises_other(self):
-        raise Exception('Mock error')
-
-    def _make_mock_process_info(self, name, args, c_channel_env,
-                                dev_null_stdout=False, dev_null_stderr=False):
-        return MockProcessInfo(name, args, c_channel_env,
-                               dev_null_stdout, dev_null_stderr)
-
-class MockBobSimple(BoB):
-    def __init__(self):
-        BoB.__init__(self)
-        # Set which process has been started
-        self.started_process_name = None
-        self.started_process_args = None
-        self.started_process_env = None
-
-    def _make_mock_process_info(self, name, args, c_channel_env,
-                                dev_null_stdout=False, dev_null_stderr=False):
-        return MockProcessInfo(name, args, c_channel_env,
-                               dev_null_stdout, dev_null_stderr)
-
-    def start_process(self, name, args, c_channel_env, port=None,
-                      address=None):
-        self.started_process_name = name
-        self.started_process_args = args
-        self.started_process_env = c_channel_env
-        return None
-
-class TestStartStopProcessesBob(unittest.TestCase):
-    """
-    Check that the start_all_components method starts the right combination
-    of components and that the right components are started and stopped
-    according to changes in configuration.
-    """
-    def check_environment_unchanged(self):
-        # Check whether the environment has not been changed
-        self.assertEqual(original_os_environ, os.environ)
-
-    def check_started(self, bob, core, auth, resolver):
-        """
-        Check that the right sets of services are started. The ones that
-        should be running are specified by the core, auth and resolver parameters
-        (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
-        and -zonemgr).
-        """
-        self.assertEqual(bob.msgq, core)
-        self.assertEqual(bob.cfgmgr, core)
-        self.assertEqual(bob.ccsession, core)
-        self.assertEqual(bob.creator, core)
-        self.assertEqual(bob.auth, auth)
-        self.assertEqual(bob.resolver, resolver)
-        self.assertEqual(bob.xfrout, auth)
-        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)
-        self.check_environment_unchanged()
-
-    def check_preconditions(self, bob):
-        self.check_started(bob, False, False, False)
-
-    def check_started_none(self, bob):
-        """
-        Check that the situation is according to configuration where no servers
-        should be started. Some components still need to be running.
-        """
-        self.check_started(bob, True, False, False)
-        self.check_environment_unchanged()
-
-    def check_started_both(self, bob):
-        """
-        Check the situation is according to configuration where both servers
-        (auth and resolver) are enabled.
-        """
-        self.check_started(bob, True, True, True)
-        self.check_environment_unchanged()
-
-    def check_started_auth(self, bob):
-        """
-        Check the set of components needed to run auth only is started.
-        """
-        self.check_started(bob, True, True, False)
-        self.check_environment_unchanged()
-
-    def check_started_resolver(self, bob):
-        """
-        Check the set of components needed to run resolver only is started.
-        """
-        self.check_started(bob, True, False, True)
-        self.check_environment_unchanged()
-
-    def check_started_dhcp(self, bob, v4, v6):
-        """
-        Check if proper combinations of DHCPv4 and DHCpv6 can be started
-        """
-        self.assertEqual(v4, bob.dhcp4)
-        self.assertEqual(v6, bob.dhcp6)
-        self.check_environment_unchanged()
-
-    def construct_config(self, start_auth, start_resolver):
-        # The things that are common, not turned on an off
-        config = {}
-        config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
-        config['b10-stats-httpd'] = { 'kind': 'dispensable',
-                                      'address': 'StatsHttpd' }
-        config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
-        if start_auth:
-            config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
-            config['b10-xfrout'] = { 'kind': 'dispensable',
-                                     'address': 'Xfrout' }
-            config['b10-xfrin'] = { 'kind': 'dispensable',
-                                    'address': 'Xfrin' }
-            config['b10-zonemgr'] = { 'kind': 'dispensable',
-                                      'address': 'Zonemgr' }
-        if start_resolver:
-            config['b10-resolver'] = { 'kind': 'needed',
-                                       'special': 'resolver' }
-        return {'components': config}
-
-    def config_start_init(self, start_auth, start_resolver):
-        """
-        Test the configuration is loaded at the startup.
-        """
-        bob = MockBob()
-        config = self.construct_config(start_auth, start_resolver)
-        class CC:
-            def get_full_config(self):
-                return config
-        # Provide the fake CC with data
-        bob.ccs = CC()
-        # And make sure it's not overwritten
-        def start_ccsession():
-            bob.ccsession = True
-        bob.start_ccsession = lambda _: start_ccsession()
-        # We need to return the original _read_bind10_config
-        bob._read_bind10_config = lambda: BoB._read_bind10_config(bob)
-        bob.start_all_components()
-        self.check_started(bob, True, start_auth, start_resolver)
-        self.check_environment_unchanged()
-
-    def test_start_none(self):
-        self.config_start_init(False, False)
-
-    def test_start_resolver(self):
-        self.config_start_init(False, True)
-
-    def test_start_auth(self):
-        self.config_start_init(True, False)
-
-    def test_start_both(self):
-        self.config_start_init(True, True)
-
-    def test_config_start(self):
-        """
-        Test that the configuration starts and stops components according
-        to configuration changes.
-        """
-
-        # Create BoB and ensure correct initialization
-        bob = MockBob()
-        self.check_preconditions(bob)
-
-        bob.start_all_components()
-        bob.runnable = True
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_none(bob)
-
-        # Enable both at once
-        bob.config_handler(self.construct_config(True, True))
-        self.check_started_both(bob)
-
-        # Not touched by empty change
-        bob.config_handler({})
-        self.check_started_both(bob)
-
-        # Not touched by change to the same configuration
-        bob.config_handler(self.construct_config(True, True))
-        self.check_started_both(bob)
-
-        # Turn them both off again
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_none(bob)
-
-        # Not touched by empty change
-        bob.config_handler({})
-        self.check_started_none(bob)
-
-        # Not touched by change to the same configuration
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_none(bob)
-
-        # Start and stop auth separately
-        bob.config_handler(self.construct_config(True, False))
-        self.check_started_auth(bob)
-
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_none(bob)
-
-        # Start and stop resolver separately
-        bob.config_handler(self.construct_config(False, True))
-        self.check_started_resolver(bob)
-
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_none(bob)
-
-        # Alternate
-        bob.config_handler(self.construct_config(True, False))
-        self.check_started_auth(bob)
-
-        bob.config_handler(self.construct_config(False, True))
-        self.check_started_resolver(bob)
-
-        bob.config_handler(self.construct_config(True, False))
-        self.check_started_auth(bob)
-
-    def test_config_start_once(self):
-        """
-        Tests that a component is started only once.
-        """
-        # Create BoB and ensure correct initialization
-        bob = MockBob()
-        self.check_preconditions(bob)
-
-        bob.start_all_components()
-
-        bob.runnable = True
-        bob.config_handler(self.construct_config(True, True))
-        self.check_started_both(bob)
-
-        bob.start_auth = lambda: self.fail("Started auth again")
-        bob.start_xfrout = lambda: self.fail("Started xfrout again")
-        bob.start_xfrin = lambda: self.fail("Started xfrin again")
-        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        bob.start_resolver = lambda: self.fail("Started resolver again")
-
-        # Send again we want to start them. Should not do it, as they are.
-        bob.config_handler(self.construct_config(True, True))
-
-    def test_config_not_started_early(self):
-        """
-        Test that components are not started by the config handler before
-        startup.
-        """
-        bob = MockBob()
-        self.check_preconditions(bob)
-
-        bob.start_auth = lambda: self.fail("Started auth again")
-        bob.start_xfrout = lambda: self.fail("Started xfrout again")
-        bob.start_xfrin = lambda: self.fail("Started xfrin again")
-        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        bob.start_resolver = lambda: self.fail("Started resolver again")
-
-        bob.config_handler({'start_auth': True, 'start_resolver': True})
-
-    # Checks that DHCP (v4 and v6) components are started when expected
-    def test_start_dhcp(self):
-
-        # Create BoB and ensure correct initialization
-        bob = MockBob()
-        self.check_preconditions(bob)
-
-        bob.start_all_components()
-        bob.config_handler(self.construct_config(False, False))
-        self.check_started_dhcp(bob, False, False)
-
-    def test_start_dhcp_v6only(self):
-        # Create BoB and ensure correct initialization
-        bob = MockBob()
-        self.check_preconditions(bob)
-        # v6 only enabled
-        bob.start_all_components()
-        bob.runnable = True
-        bob._BoB_started = True
-        config = self.construct_config(False, False)
-        config['components']['b10-dhcp6'] = { 'kind': 'needed',
-                                              'address': 'Dhcp6' }
-        bob.config_handler(config)
-        self.check_started_dhcp(bob, False, True)
-
-        # uncomment when dhcpv4 becomes implemented
-        # v4 only enabled
-        #bob.cfg_start_dhcp6 = False
-        #bob.cfg_start_dhcp4 = True
-        #self.check_started_dhcp(bob, True, False)
-
-        # both v4 and v6 enabled
-        #bob.cfg_start_dhcp6 = True
-        #bob.cfg_start_dhcp4 = True
-        #self.check_started_dhcp(bob, True, True)
-
-class MockComponent:
-    def __init__(self, name, pid, address=None):
-        self.name = lambda: name
-        self.pid = lambda: pid
-        self.address = lambda: address
-        self.restarted = False
-        self.forceful = False
-        self.running = True
-        self.has_failed = False
-
-    def get_restart_time(self):
-        return 0                # arbitrary dummy value
-
-    def restart(self, now):
-        self.restarted = True
-        return True
-
-    def is_running(self):
-        return self.running
-
-    def failed(self, status):
-        return self.has_failed
-
-    def kill(self, forceful):
-        self.forceful = forceful
-
-class TestBossCmd(unittest.TestCase):
-    def test_ping(self):
-        """
-        Confirm simple ping command works.
-        """
-        bob = MockBob()
-        answer = bob.command_handler("ping", None)
-        self.assertEqual(answer, {'result': [0, 'pong']})
-
-    def test_show_processes_empty(self):
-        """
-        Confirm getting a list of processes works.
-        """
-        bob = MockBob()
-        answer = bob.command_handler("show_processes", None)
-        self.assertEqual(answer, {'result': [0, []]})
-
-    def test_show_processes(self):
-        """
-        Confirm getting a list of processes works.
-        """
-        bob = MockBob()
-        bob.register_process(1, MockComponent('first', 1))
-        bob.register_process(2, MockComponent('second', 2, 'Second'))
-        answer = bob.command_handler("show_processes", None)
-        processes = [[1, 'first', None],
-                     [2, 'second', 'Second']]
-        self.assertEqual(answer, {'result': [0, processes]})
-
-class TestParseArgs(unittest.TestCase):
-    """
-    This tests parsing of arguments of the bind10 master process.
-    """
-    #TODO: Write tests for the original parsing, bad options, etc.
-    def test_no_opts(self):
-        """
-        Test correct default values when no options are passed.
-        """
-        options = parse_args([], TestOptParser)
-        self.assertEqual(None, options.data_path)
-        self.assertEqual(None, options.config_file)
-        self.assertEqual(None, options.cmdctl_port)
-
-    def test_data_path(self):
-        """
-        Test it can parse the data path.
-        """
-        self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--data-path'],
-                          TestOptParser)
-        options = parse_args(['-p', '/data/path'], TestOptParser)
-        self.assertEqual('/data/path', options.data_path)
-        options = parse_args(['--data-path=/data/path'], TestOptParser)
-        self.assertEqual('/data/path', options.data_path)
-
-    def test_config_filename(self):
-        """
-        Test it can parse the config switch.
-        """
-        self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--config-file'],
-                          TestOptParser)
-        options = parse_args(['-c', 'config-file'], TestOptParser)
-        self.assertEqual('config-file', options.config_file)
-        options = parse_args(['--config-file=config-file'], TestOptParser)
-        self.assertEqual('config-file', options.config_file)
-
-    def test_clear_config(self):
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.clear_config)
-        options = parse_args(['--clear-config'], TestOptParser)
-        self.assertEqual(True, options.clear_config)
-
-    def test_nokill(self):
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.nokill)
-        options = parse_args(['--no-kill'], TestOptParser)
-        self.assertEqual(True, options.nokill)
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.nokill)
-        options = parse_args(['-i'], TestOptParser)
-        self.assertEqual(True, options.nokill)
-
-    def test_cmdctl_port(self):
-        """
-        Test it can parse the command control port.
-        """
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
-                                                TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
-                                                TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
-                          TestOptParser)
-        options = parse_args(['--cmdctl-port=1234'], TestOptParser)
-        self.assertEqual(1234, options.cmdctl_port)
-
-class TestPIDFile(unittest.TestCase):
-    def setUp(self):
-        self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
-        if os.path.exists(self.pid_file):
-            os.unlink(self.pid_file)
-
-    def tearDown(self):
-        if os.path.exists(self.pid_file):
-            os.unlink(self.pid_file)
-
-    def check_pid_file(self):
-        # dump PID to the file, and confirm the content is correct
-        dump_pid(self.pid_file)
-        my_pid = os.getpid()
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(my_pid, int(f.read()))
-
-    def test_dump_pid(self):
-        self.check_pid_file()
-
-        # make sure any existing content will be removed
-        with open(self.pid_file, "w") as f:
-            f.write('dummy data\n')
-        self.check_pid_file()
-
-    def test_unlink_pid_file_notexist(self):
-        dummy_data = 'dummy_data\n'
-
-        with open(self.pid_file, "w") as f:
-            f.write(dummy_data)
-
-        unlink_pid_file("no_such_pid_file")
-
-        # the file specified for unlink_pid_file doesn't exist,
-        # and the original content of the file should be intact.
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(dummy_data, f.read())
-
-    def test_dump_pid_with_none(self):
-        # Check the behavior of dump_pid() and unlink_pid_file() with None.
-        # This should be no-op.
-        dump_pid(None)
-        self.assertFalse(os.path.exists(self.pid_file))
-
-        dummy_data = 'dummy_data\n'
-
-        with open(self.pid_file, "w") as f:
-            f.write(dummy_data)
-
-        unlink_pid_file(None)
-
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(dummy_data, f.read())
-
-    def test_dump_pid_failure(self):
-        # the attempt to open file will fail, which should result in exception.
-        self.assertRaises(IOError, dump_pid,
-                          'nonexistent_dir' + os.sep + 'bind10.pid')
-
-class TestBossComponents(unittest.TestCase):
-    """
-    Test the boss propagates component configuration properly to the
-    component configurator and acts sane.
-    """
-    def setUp(self):
-        self.__param = None
-        self.__called = False
-        self.__compconfig = {
-            'comp': {
-                'kind': 'needed',
-                'process': 'cat'
-            }
-        }
-        self._tmp_time = None
-        self._tmp_sleep = None
-        self._tmp_module_cc_session = None
-        self._tmp_cc_session = None
-
-    def tearDown(self):
-        if self._tmp_time is not None:
-            time.time = self._tmp_time
-        if self._tmp_sleep is not None:
-            time.sleep = self._tmp_sleep
-        if self._tmp_module_cc_session is not None:
-            isc.config.ModuleCCSession = self._tmp_module_cc_session
-        if self._tmp_cc_session is not None:
-            isc.cc.Session = self._tmp_cc_session
-
-    def __unary_hook(self, param):
-        """
-        A hook function that stores the parameter for later examination.
-        """
-        self.__param = param
-
-    def __nullary_hook(self):
-        """
-        A hook function that notes down it was called.
-        """
-        self.__called = True
-
-    def __check_core(self, config):
-        """
-        A function checking that the config contains parts for the valid
-        core component configuration.
-        """
-        self.assertIsNotNone(config)
-        for component in ['sockcreator', 'msgq', 'cfgmgr']:
-            self.assertTrue(component in config)
-            self.assertEqual(component, config[component]['special'])
-            self.assertEqual('core', config[component]['kind'])
-
-    def __check_extended(self, config):
-        """
-        This checks that the config contains the core and one more component.
-        """
-        self.__check_core(config)
-        self.assertTrue('comp' in config)
-        self.assertEqual('cat', config['comp']['process'])
-        self.assertEqual('needed', config['comp']['kind'])
-        self.assertEqual(4, len(config))
-
-    def test_correct_run(self):
-        """
-        Test the situation when we run in usual scenario, nothing fails,
-        we just start, reconfigure and then stop peacefully.
-        """
-        bob = MockBob()
-        # Start it
-        orig = bob._component_configurator.startup
-        bob._component_configurator.startup = self.__unary_hook
-        bob.start_all_components()
-        bob._component_configurator.startup = orig
-        self.__check_core(self.__param)
-        self.assertEqual(3, len(self.__param))
-
-        # Reconfigure it
-        self.__param = None
-        orig = bob._component_configurator.reconfigure
-        bob._component_configurator.reconfigure = self.__unary_hook
-        # Otherwise it does not work
-        bob.runnable = True
-        bob.config_handler({'components': self.__compconfig})
-        self.__check_extended(self.__param)
-        currconfig = self.__param
-        # If we reconfigure it, but it does not contain the components part,
-        # nothing is called
-        bob.config_handler({})
-        self.assertEqual(self.__param, currconfig)
-        self.__param = None
-        bob._component_configurator.reconfigure = orig
-        # Check a configuration that messes up the core components is rejected.
-        compconf = dict(self.__compconfig)
-        compconf['msgq'] = { 'process': 'echo' }
-        result = bob.config_handler({'components': compconf})
-        # Check it rejected it
-        self.assertEqual(1, result['result'][0])
-
-        # We can't call shutdown, that one relies on the stuff in main
-        # We check somewhere else that the shutdown is actually called
-        # from there (the test_kills).
-
-    def __real_test_kill(self, nokill=False, ex_on_kill=None):
-        """
-        Helper function that does the actual kill functionality testing.
-        """
-        bob = MockBob()
-        bob.nokill = nokill
-
-        killed = []
-        class ImmortalComponent:
-            """
-            An immortal component. It does not stop when it is told so
-            (anyway it is not told so). It does not die if it is killed
-            the first time. It dies only when killed forcefully.
-            """
-            def __init__(self):
-                # number of kill() calls, preventing infinite loop.
-                self.__call_count = 0
-
-            def kill(self, forceful=False):
-                self.__call_count += 1
-                if self.__call_count > 2:
-                    raise Exception('Too many calls to ImmortalComponent.kill')
-
-                killed.append(forceful)
-                if ex_on_kill is not None:
-                    # If exception is given by the test, raise it here.
-                    # In the case of ESRCH, the process should have gone
-                    # somehow, so we clear the components.
-                    if ex_on_kill.errno == errno.ESRCH:
-                        bob.components = {}
-                    raise ex_on_kill
-                if forceful:
-                    bob.components = {}
-            def pid(self):
-                return 1
-            def name(self):
-                return "Immortal"
-        bob.components = {}
-        bob.register_process(1, ImmortalComponent())
-
-        # While at it, we check the configurator shutdown is actually called
-        orig = bob._component_configurator.shutdown
-        bob._component_configurator.shutdown = self.__nullary_hook
-        self.__called = False
-
-        bob.ccs = MockModuleCCSession()
-        self.assertFalse(bob.ccs.stopped)
-
-        bob.shutdown()
-
-        self.assertTrue(bob.ccs.stopped)
-
-        # Here, killed is an array where False is added if SIGTERM
-        # should be sent, or True if SIGKILL should be sent, in order in
-        # which they're sent.
-        if nokill:
-            self.assertEqual([], killed)
-        else:
-            if ex_on_kill is not None:
-                self.assertEqual([False], killed)
-            else:
-                self.assertEqual([False, True], killed)
-
-        self.assertTrue(self.__called)
-
-        bob._component_configurator.shutdown = orig
-
-    def test_kills(self):
-        """
-        Test that the boss kills components which don't want to stop.
-        """
-        self.__real_test_kill()
-
-    def test_kill_fail(self):
-        """Test cases where kill() results in an exception due to OS error.
-
-        The behavior should be different for EPERM, so we test two cases.
-
-        """
-
-        ex = OSError()
-        ex.errno, ex.strerror = errno.ESRCH, 'No such process'
-        self.__real_test_kill(ex_on_kill=ex)
-
-        ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
-        self.__real_test_kill(ex_on_kill=ex)
-
-    def test_nokill(self):
-        """
-        Test that the boss *doesn't* kill components which don't want to
-        stop, when asked not to (by passing the --no-kill option which
-        sets bob.nokill to True).
-        """
-        self.__real_test_kill(True)
-
-    def test_component_shutdown(self):
-        """
-        Test the component_shutdown sets all variables accordingly.
-        """
-        bob = MockBob()
-        self.assertRaises(Exception, bob.component_shutdown, 1)
-        self.assertEqual(1, bob.exitcode)
-        bob._BoB__started = True
-        bob.component_shutdown(2)
-        self.assertEqual(2, bob.exitcode)
-        self.assertFalse(bob.runnable)
-
-    def test_init_config(self):
-        """
-        Test initial configuration is loaded.
-        """
-        bob = MockBob()
-        # Start it
-        bob._component_configurator.reconfigure = self.__unary_hook
-        # We need to return the original read_bind10_config
-        bob._read_bind10_config = lambda: BoB._read_bind10_config(bob)
-        # And provide a session to read the data from
-        class CC:
-            pass
-        bob.ccs = CC()
-        bob.ccs.get_full_config = lambda: {'components': self.__compconfig}
-        bob.start_all_components()
-        self.__check_extended(self.__param)
-
-    def __setup_restart(self, bob, component):
-        '''Common procedure for restarting a component used below.'''
-        bob.components_to_restart = { component }
-        component.restarted = False
-        bob.restart_processes()
-
-    def test_restart_processes(self):
-        '''Check some behavior on restarting processes.'''
-        bob = MockBob()
-        bob.runnable = True
-        component = MockComponent('test', 53)
-
-        # A component to be restarted will actually be restarted iff it's
-        # in the configurator's configuration.
-        # We bruteforce the configurator internal below; ugly, but the easiest
-        # way for the test.
-        bob._component_configurator._components['test'] = (None, component)
-        self.__setup_restart(bob, component)
-        self.assertTrue(component.restarted)
-        self.assertNotIn(component, bob.components_to_restart)
-
-        # Remove the component from the configuration.  It won't be restarted
-        # even if scheduled, nor will remain in the to-be-restarted list.
-        del bob._component_configurator._components['test']
-        self.__setup_restart(bob, component)
-        self.assertFalse(component.restarted)
-        self.assertNotIn(component, bob.components_to_restart)
-
-    def test_get_processes(self):
-        '''Test that procsses are returned correctly, sorted by pid.'''
-        bob = MockBob()
-
-        pids = list(range(0, 20))
-        random.shuffle(pids)
-
-        for i in range(0, 20):
-            pid = pids[i]
-            component = MockComponent('test' + str(pid), pid,
-                                      'Test' + str(pid))
-            bob.components[pid] = component
-
-        process_list = bob.get_processes()
-        self.assertEqual(20, len(process_list))
-
-        last_pid = -1
-        for process in process_list:
-            pid = process[0]
-            self.assertLessEqual(last_pid, pid)
-            last_pid = pid
-            self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
-                             process)
-
-    def _test_reap_children_helper(self, runnable, is_running, failed):
-        '''Construct a BoB instance, set various data in it according to
-        passed args and check if the component was added to the list of
-        components to restart.'''
-        bob = MockBob()
-        bob.runnable = runnable
-
-        component = MockComponent('test', 53)
-        component.running = is_running
-        component.has_failed = failed
-        bob.components[53] = component
-
-        self.assertNotIn(component, bob.components_to_restart)
-
-        bob.reap_children()
-
-        if runnable and is_running and not failed:
-            self.assertIn(component, bob.components_to_restart)
-        else:
-            self.assertEqual([], bob.components_to_restart)
-
-    def test_reap_children(self):
-        '''Test that children are queued to be restarted when they ask for it.'''
-        # test various combinations of 3 booleans
-        # (BoB.runnable, component.is_running(), component.failed())
-        self._test_reap_children_helper(False, False, False)
-        self._test_reap_children_helper(False, False, True)
-        self._test_reap_children_helper(False, True,  False)
-        self._test_reap_children_helper(False, True,  True)
-        self._test_reap_children_helper(True,  False, False)
-        self._test_reap_children_helper(True,  False, True)
-        self._test_reap_children_helper(True,  True,  False)
-        self._test_reap_children_helper(True,  True,  True)
-
-        # setup for more tests below
-        bob = MockBob()
-        bob.runnable = True
-        component = MockComponent('test', 53)
-        bob.components[53] = component
-
-        # case where the returned pid is unknown to us. nothing should
-        # happpen then.
-        bob.get_process_exit_status_called = False
-        bob._get_process_exit_status = bob._get_process_exit_status_unknown_pid
-        bob.components_to_restart = []
-        # this should do nothing as the pid is unknown
-        bob.reap_children()
-        self.assertEqual([], bob.components_to_restart)
-
-        # case where bob._get_process_exit_status() raises OSError with
-        # errno.ECHILD
-        bob._get_process_exit_status = \
-            bob._get_process_exit_status_raises_oserror_echild
-        bob.components_to_restart = []
-        # this should catch and handle the OSError
-        bob.reap_children()
-        self.assertEqual([], bob.components_to_restart)
-
-        # case where bob._get_process_exit_status() raises OSError with
-        # errno other than ECHILD
-        bob._get_process_exit_status = \
-            bob._get_process_exit_status_raises_oserror_other
-        with self.assertRaises(OSError):
-            bob.reap_children()
-
-        # case where bob._get_process_exit_status() raises something
-        # other than OSError
-        bob._get_process_exit_status = \
-            bob._get_process_exit_status_raises_other
-        with self.assertRaises(Exception):
-            bob.reap_children()
-
-    def test_kill_started_components(self):
-        '''Test that started components are killed.'''
-        bob = MockBob()
-
-        component = MockComponent('test', 53, 'Test')
-        bob.components[53] = component
-
-        self.assertEqual([[53, 'test', 'Test']], bob.get_processes())
-        bob.kill_started_components()
-        self.assertEqual([], bob.get_processes())
-        self.assertTrue(component.forceful)
-
-    def _start_msgq_helper(self, bob, verbose):
-        bob.verbose = verbose
-        pi = bob.start_msgq()
-        self.assertEqual('b10-msgq', pi.name)
-        self.assertEqual(['b10-msgq'], pi.args)
-        self.assertTrue(pi.dev_null_stdout)
-        self.assertEqual(pi.dev_null_stderr, not verbose)
-        self.assertEqual({'FOO': 'an env string'}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_start_msgq(self):
-        '''Test that b10-msgq is started.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {'FOO': 'an env string'}
-        bob._run_under_unittests = True
-
-        # use the MockProcessInfo creator
-        bob._make_process_info = bob._make_mock_process_info
-
-        # non-verbose case
-        self._start_msgq_helper(bob, False)
-
-        # verbose case
-        self._start_msgq_helper(bob, True)
-
-    def test_start_msgq_timeout(self):
-        '''Test that b10-msgq startup attempts connections several times
-        and times out eventually.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {}
-        # set the timeout to an arbitrary pre-determined value (which
-        # code below depends on)
-        bob.msgq_timeout = 1
-        bob._run_under_unittests = False
-
-        # use the MockProcessInfo creator
-        bob._make_process_info = bob._make_mock_process_info
-
-        global attempts
-        global tsec
-        attempts = 0
-        tsec = 0
-        self._tmp_time = time.time
-        self._tmp_sleep = time.sleep
-        def _my_time():
-            global attempts
-            global tsec
-            attempts += 1
-            return tsec
-        def _my_sleep(nsec):
-            global tsec
-            tsec += nsec
-        time.time = _my_time
-        time.sleep = _my_sleep
-
-        global cc_sub
-        cc_sub = None
-        class DummySessionAlwaysFails():
-            def __init__(self, socket_file):
-                raise isc.cc.session.SessionError('Connection fails')
-            def group_subscribe(self, s):
-                global cc_sub
-                cc_sub = s
-
-        isc.cc.Session = DummySessionAlwaysFails
-
-        with self.assertRaises(bind10_src.CChannelConnectError):
-            # An exception will be thrown here when it eventually times
-            # out.
-            pi = bob.start_msgq()
-
-        # time.time() should be called 12 times within the while loop:
-        # starting from 0, and 11 more times from 0.1 to 1.1. There's
-        # another call to time.time() outside the loop, which makes it
-        # 13.
-        self.assertEqual(attempts, 13)
-
-        # group_subscribe() should not have been called here.
-        self.assertIsNone(cc_sub)
-
-        global cc_socket_file
-        cc_socket_file = None
-        cc_sub = None
-        class DummySession():
-            def __init__(self, socket_file):
-                global cc_socket_file
-                cc_socket_file = socket_file
-            def group_subscribe(self, s):
-                global cc_sub
-                cc_sub = s
-
-        isc.cc.Session = DummySession
-
-        # reset values
-        attempts = 0
-        tsec = 0
-
-        pi = bob.start_msgq()
-
-        # just one attempt, but 2 calls to time.time()
-        self.assertEqual(attempts, 2)
-
-        self.assertEqual(cc_socket_file, bob.msgq_socket_file)
-        self.assertEqual(cc_sub, 'Boss')
-
-        # isc.cc.Session, time.time() and time.sleep() are restored
-        # during tearDown().
-
-    def _start_cfgmgr_helper(self, bob, data_path, filename, clear_config):
-        expect_args = ['b10-cfgmgr']
-        if data_path is not None:
-            bob.data_path = data_path
-            expect_args.append('--data-path=' + data_path)
-        if filename is not None:
-            bob.config_filename = filename
-            expect_args.append('--config-filename=' + filename)
-        if clear_config:
-            bob.clear_config = clear_config
-            expect_args.append('--clear-config')
-
-        pi = bob.start_cfgmgr()
-        self.assertEqual('b10-cfgmgr', pi.name)
-        self.assertEqual(expect_args, pi.args)
-        self.assertEqual({'TESTENV': 'A test string'}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_start_cfgmgr(self):
-        '''Test that b10-cfgmgr is started.'''
-        class DummySession():
-            def __init__(self):
-                self._tries = 0
-            def group_recvmsg(self):
-                self._tries += 1
-                # return running on the 3rd try onwards
-                if self._tries >= 3:
-                    return ({'running': 'ConfigManager'}, None)
-                else:
-                    return ({}, None)
-
-        bob = MockBobSimple()
-        bob.c_channel_env = {'TESTENV': 'A test string'}
-        bob.cc_session = DummySession()
-        bob.wait_time = 5
-
-        # use the MockProcessInfo creator
-        bob._make_process_info = bob._make_mock_process_info
-
-        global attempts
-        attempts = 0
-        self._tmp_sleep = time.sleep
-        def _my_sleep(nsec):
-            global attempts
-            attempts += 1
-        time.sleep = _my_sleep
-
-        # defaults
-        self._start_cfgmgr_helper(bob, None, None, False)
-
-        # check that 2 attempts were made. on the 3rd attempt,
-        # process_running() returns that ConfigManager is running.
-        self.assertEqual(attempts, 2)
-
-        # data_path is specified
-        self._start_cfgmgr_helper(bob, '/var/lib/test', None, False)
-
-        # config_filename is specified. Because `bob` is not
-        # reconstructed, data_path is retained from the last call to
-        # _start_cfgmgr_helper().
-        self._start_cfgmgr_helper(bob, '/var/lib/test', 'foo.cfg', False)
-
-        # clear_config is specified. Because `bob` is not reconstructed,
-        # data_path and config_filename are retained from the last call
-        # to _start_cfgmgr_helper().
-        self._start_cfgmgr_helper(bob, '/var/lib/test', 'foo.cfg', True)
-
-    def test_start_cfgmgr_timeout(self):
-        '''Test that b10-cfgmgr startup attempts connections several times
-        and times out eventually.'''
-        class DummySession():
-            def group_recvmsg(self):
-                return (None, None)
-        bob = MockBobSimple()
-        bob.c_channel_env = {}
-        bob.cc_session = DummySession()
-        # set wait_time to an arbitrary pre-determined value (which code
-        # below depends on)
-        bob.wait_time = 2
-
-        # use the MockProcessInfo creator
-        bob._make_process_info = bob._make_mock_process_info
-
-        global attempts
-        attempts = 0
-        self._tmp_sleep = time.sleep
-        def _my_sleep(nsec):
-            global attempts
-            attempts += 1
-        time.sleep = _my_sleep
-
-        # We just check that an exception was thrown, and that several
-        # attempts were made to connect.
-        with self.assertRaises(bind10_src.ProcessStartError):
-            pi = bob.start_cfgmgr()
-
-        # 2 seconds of attempts every 1 second should result in 2 attempts
-        self.assertEqual(attempts, 2)
-
-        # time.sleep() is restored during tearDown().
-
-    def test_start_ccsession(self):
-        '''Test that CC session is started.'''
-        class DummySession():
-            def __init__(self, specfile, config_handler, command_handler,
-                         socket_file):
-                self.specfile = specfile
-                self.config_handler = config_handler
-                self.command_handler = command_handler
-                self.socket_file = socket_file
-                self.started = False
-            def start(self):
-                self.started = True
-        bob = MockBobSimple()
-        self._tmp_module_cc_session = isc.config.ModuleCCSession
-        isc.config.ModuleCCSession = DummySession
-
-        bob.start_ccsession({})
-        self.assertEqual(bind10_src.SPECFILE_LOCATION, bob.ccs.specfile)
-        self.assertEqual(bob.config_handler, bob.ccs.config_handler)
-        self.assertEqual(bob.command_handler, bob.ccs.command_handler)
-        self.assertEqual(bob.msgq_socket_file, bob.ccs.socket_file)
-        self.assertTrue(bob.ccs.started)
-
-        # isc.config.ModuleCCSession is restored during tearDown().
-
-    def test_start_process(self):
-        '''Test that processes can be started.'''
-        bob = MockBob()
-
-        # use the MockProcessInfo creator
-        bob._make_process_info = bob._make_mock_process_info
-
-        pi = bob.start_process('Test Process', ['/bin/true'], {})
-        self.assertEqual('Test Process', pi.name)
-        self.assertEqual(['/bin/true'], pi.args)
-        self.assertEqual({}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_register_process(self):
-        '''Test that processes can be registered with BoB.'''
-        bob = MockBob()
-        component = MockComponent('test', 53, 'Test')
-
-        self.assertFalse(53 in bob.components)
-        bob.register_process(53, component)
-        self.assertTrue(53 in bob.components)
-        self.assertEqual(bob.components[53].name(), 'test')
-        self.assertEqual(bob.components[53].pid(), 53)
-        self.assertEqual(bob.components[53].address(), 'Test')
-
-    def _start_simple_helper(self, bob, verbose):
-        bob.verbose = verbose
-
-        args = ['/bin/true']
-        if verbose:
-            args.append('-v')
-
-        bob.start_simple('/bin/true')
-        self.assertEqual('/bin/true', bob.started_process_name)
-        self.assertEqual(args, bob.started_process_args)
-        self.assertEqual({'TESTENV': 'A test string'}, bob.started_process_env)
-
-    def test_start_simple(self):
-        '''Test simple process startup.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {'TESTENV': 'A test string'}
-
-        # non-verbose case
-        self._start_simple_helper(bob, False)
-
-        # verbose case
-        self._start_simple_helper(bob, True)
-
-    def _start_auth_helper(self, bob, verbose):
-        bob.verbose = verbose
-
-        args = ['b10-auth']
-        if verbose:
-            args.append('-v')
-
-        bob.start_auth()
-        self.assertEqual('b10-auth', bob.started_process_name)
-        self.assertEqual(args, bob.started_process_args)
-        self.assertEqual({'FOO': 'an env string'}, bob.started_process_env)
-
-    def test_start_auth(self):
-        '''Test that b10-auth is started.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {'FOO': 'an env string'}
-
-        # non-verbose case
-        self._start_auth_helper(bob, False)
-
-        # verbose case
-        self._start_auth_helper(bob, True)
-
-    def _start_resolver_helper(self, bob, verbose):
-        bob.verbose = verbose
-
-        args = ['b10-resolver']
-        if verbose:
-            args.append('-v')
-
-        bob.start_resolver()
-        self.assertEqual('b10-resolver', bob.started_process_name)
-        self.assertEqual(args, bob.started_process_args)
-        self.assertEqual({'BAR': 'an env string'}, bob.started_process_env)
-
-    def test_start_resolver(self):
-        '''Test that b10-resolver is started.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {'BAR': 'an env string'}
-
-        # non-verbose case
-        self._start_resolver_helper(bob, False)
-
-        # verbose case
-        self._start_resolver_helper(bob, True)
-
-    def _start_cmdctl_helper(self, bob, verbose, port = None):
-        bob.verbose = verbose
-
-        args = ['b10-cmdctl']
-
-        if port is not None:
-            bob.cmdctl_port = port
-            args.append('--port=9353')
-
-        if verbose:
-            args.append('-v')
-
-        bob.start_cmdctl()
-        self.assertEqual('b10-cmdctl', bob.started_process_name)
-        self.assertEqual(args, bob.started_process_args)
-        self.assertEqual({'BAZ': 'an env string'}, bob.started_process_env)
-
-    def test_start_cmdctl(self):
-        '''Test that b10-cmdctl is started.'''
-        bob = MockBobSimple()
-        bob.c_channel_env = {'BAZ': 'an env string'}
-
-        # non-verbose case
-        self._start_cmdctl_helper(bob, False)
-
-        # verbose case
-        self._start_cmdctl_helper(bob, True)
-
-        # with port, non-verbose case
-        self._start_cmdctl_helper(bob, False, 9353)
-
-        # with port, verbose case
-        self._start_cmdctl_helper(bob, True, 9353)
-
-    def test_socket_data(self):
-        '''Test that BoB._socket_data works as expected.'''
-        class MockSock:
-            def __init__(self, fd, throw):
-                self.fd = fd
-                self.throw = throw
-                self.buf = b'Hello World.\nYou are so nice today.\nXX'
-                self.i = 0
-
-            def recv(self, bufsize, flags = 0):
-                if bufsize != 1:
-                    raise Exception('bufsize != 1')
-                if flags != socket.MSG_DONTWAIT:
-                    raise Exception('flags != socket.MSG_DONTWAIT')
-                # after 15 recv()s, throw a socket.error with EAGAIN to
-                # get _socket_data() to save back what's been read. The
-                # number 15 is arbitrarily chosen, but the checks then
-                # depend on this being 15, i.e., if you adjust this
-                # number, you may have to adjust the checks below too.
-                if self.throw and self.i > 15:
-                    raise socket.error(errno.EAGAIN, 'Try again')
-                if self.i >= len(self.buf):
-                    return b'';
-                t = self.i
-                self.i += 1
-                return self.buf[t:t+1]
-
-            def close(self):
-                return
-
-        class MockBobSocketData(BoB):
-            def __init__(self, throw):
-                self._unix_sockets = {42: (MockSock(42, throw), b'')}
-                self.requests = []
-                self.dead = []
-
-            def socket_request_handler(self, previous, sock):
-                self.requests.append({sock.fd: previous})
-
-            def socket_consumer_dead(self, sock):
-                self.dead.append(sock.fd)
-
-        # Case where we get data every time we call recv()
-        bob = MockBobSocketData(False)
-        bob._socket_data(42)
-        self.assertEqual(bob.requests,
-                         [{42: b'Hello World.'},
-                          {42: b'You are so nice today.'}])
-        self.assertEqual(bob.dead, [42])
-        self.assertEqual({}, bob._unix_sockets)
-
-        # Case where socket.recv() raises EAGAIN. In this case, the
-        # routine is supposed to save what it has back to
-        # BoB._unix_sockets.
-        bob = MockBobSocketData(True)
-        bob._socket_data(42)
-        self.assertEqual(bob.requests, [{42: b'Hello World.'}])
-        self.assertFalse(bob.dead)
-        self.assertEqual(len(bob._unix_sockets), 1)
-        self.assertEqual(bob._unix_sockets[42][1], b'You')
-
-    def test_startup(self):
-        '''Test that BoB.startup() handles failures properly.'''
-        class MockBobStartup(BoB):
-            def __init__(self, throw):
-                self.throw = throw
-                self.started = False
-                self.killed = False
-                self.msgq_socket_file = None
-                self.curproc = 'myproc'
-                self.runnable = False
-
-            def start_all_components(self):
-                self.started = True
-                if self.throw is True:
-                    raise Exception('Assume starting components has failed.')
-                elif self.throw:
-                    raise self.throw
-
-            def kill_started_components(self):
-                self.killed = True
-
-        class DummySession():
-            def __init__(self, socket_file):
-                raise isc.cc.session.SessionError('This is the expected case.')
-
-        class DummySessionSocketExists():
-            def __init__(self, socket_file):
-                # simulate that connect passes
-                return
-
-        isc.cc.Session = DummySession
-
-        # All is well case, where all components are started
-        # successfully. We check that the actual call to
-        # start_all_components() is made, and BoB.runnable is true.
-        bob = MockBobStartup(False)
-        r = bob.startup()
-        self.assertIsNone(r)
-        self.assertTrue(bob.started)
-        self.assertFalse(bob.killed)
-        self.assertTrue(bob.runnable)
-        self.assertEqual({}, bob.c_channel_env)
-
-        # Case where starting components fails. We check that
-        # kill_started_components() is called right after, and
-        # BoB.runnable is not modified.
-        bob = MockBobStartup(True)
-        r = bob.startup()
-        # r contains an error message
-        self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
-        self.assertTrue(bob.started)
-        self.assertTrue(bob.killed)
-        self.assertFalse(bob.runnable)
-        self.assertEqual({}, bob.c_channel_env)
-
-        # Check if msgq_socket_file is carried over
-        bob = MockBobStartup(False)
-        bob.msgq_socket_file = 'foo'
-        r = bob.startup()
-        self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'}, bob.c_channel_env)
-
-        # Check failure of changing user results in a different message
-        bob = MockBobStartup(bind10_src.ChangeUserError('failed to chusr'))
-        r = bob.startup()
-        self.assertIn('failed to chusr', r)
-        self.assertTrue(bob.killed)
-
-        # Check the case when socket file already exists
-        isc.cc.Session = DummySessionSocketExists
-        bob = MockBobStartup(False)
-        r = bob.startup()
-        self.assertIn('already running', r)
-
-        # isc.cc.Session is restored during tearDown().
-
-class SocketSrvTest(unittest.TestCase):
-    """
-    This tests some methods of boss related to the unix domain sockets used
-    to transfer other sockets to applications.
-    """
-    def setUp(self):
-        """
-        Create the boss to test, testdata and backup some functions.
-        """
-        self.__boss = BoB()
-        self.__select_backup = bind10_src.select.select
-        self.__select_called = None
-        self.__socket_data_called = None
-        self.__consumer_dead_called = None
-        self.__socket_request_handler_called = None
-
-    def tearDown(self):
-        """
-        Restore functions.
-        """
-        bind10_src.select.select = self.__select_backup
-
-    class __FalseSocket:
-        """
-        A mock socket for the select and accept and stuff like that.
-        """
-        def __init__(self, owner, fileno=42):
-            self.__owner = owner
-            self.__fileno = fileno
-            self.data = None
-            self.closed = False
-
-        def fileno(self):
-            return self.__fileno
-
-        def accept(self):
-            return (self.__class__(self.__owner, 13), "/path/to/socket")
-
-        def recv(self, bufsize, flags=0):
-            self.__owner.assertEqual(1, bufsize)
-            self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
-            if isinstance(self.data, socket.error):
-                raise self.data
-            elif self.data is not None:
-                if len(self.data):
-                    result = self.data[0:1]
-                    self.data = self.data[1:]
-                    return result
-                else:
-                    raise socket.error(errno.EAGAIN, "Would block")
-            else:
-                return b''
-
-        def close(self):
-            self.closed = True
-
-    class __CCS:
-        """
-        A mock CCS, just to provide the socket file number.
-        """
-        class __Socket:
-            def fileno(self):
-                return 1
-        def get_socket(self):
-            return self.__Socket()
-
-    def __select_accept(self, r, w, x, t):
-        self.__select_called = (r, w, x, t)
-        return ([42], [], [])
-
-    def __select_data(self, r, w, x, t):
-        self.__select_called = (r, w, x, t)
-        return ([13], [], [])
-
-    def __accept(self):
-        """
-        Hijact the accept method of the boss.
-
-        Notes down it was called and stops the boss.
-        """
-        self.__accept_called = True
-        self.__boss.runnable = False
-
-    def test_srv_accept_called(self):
-        """
-        Test that the _srv_accept method of boss is called when the listening
-        socket is readable.
-        """
-        self.__boss.runnable = True
-        self.__boss._srv_socket = self.__FalseSocket(self)
-        self.__boss._srv_accept = self.__accept
-        self.__boss.ccs = self.__CCS()
-        bind10_src.select.select = self.__select_accept
-        self.__boss.run(2)
-        # It called the accept
-        self.assertTrue(self.__accept_called)
-        # And the select had the right parameters
-        self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
-
-    def test_srv_accept(self):
-        """
-        Test how the _srv_accept method works.
-        """
-        self.__boss._srv_socket = self.__FalseSocket(self)
-        self.__boss._srv_accept()
-        # After we accepted, a new socket is added there
-        socket = self.__boss._unix_sockets[13][0]
-        # The socket is properly stored there
-        self.assertTrue(isinstance(socket, self.__FalseSocket))
-        # And the buffer (yet empty) is there
-        self.assertEqual({13: (socket, b'')}, self.__boss._unix_sockets)
-
-    def __socket_data(self, socket):
-        self.__boss.runnable = False
-        self.__socket_data_called = socket
-
-    def test_socket_data(self):
-        """
-        Test that a socket that wants attention gets it.
-        """
-        self.__boss._srv_socket = self.__FalseSocket(self)
-        self.__boss._socket_data = self.__socket_data
-        self.__boss.ccs = self.__CCS()
-        self.__boss._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
-        self.__boss.runnable = True
-        bind10_src.select.select = self.__select_data
-        self.__boss.run(2)
-        self.assertEqual(13, self.__socket_data_called)
-        self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
-
-    def __prepare_data(self, data):
-        socket = self.__FalseSocket(self, 13)
-        self.__boss._unix_sockets = {13: (socket, b'')}
-        socket.data = data
-        self.__boss.socket_consumer_dead = self.__consumer_dead
-        self.__boss.socket_request_handler = self.__socket_request_handler
-        return socket
-
-    def __consumer_dead(self, socket):
-        self.__consumer_dead_called = socket
-
-    def __socket_request_handler(self, token, socket):
-        self.__socket_request_handler_called = (token, socket)
-
-    def test_socket_closed(self):
-        """
-        Test that a socket is removed and the socket_consumer_dead is called
-        when it is closed.
-        """
-        socket = self.__prepare_data(None)
-        self.__boss._socket_data(13)
-        self.assertEqual(socket, self.__consumer_dead_called)
-        self.assertEqual({}, self.__boss._unix_sockets)
-        self.assertTrue(socket.closed)
-
-    def test_socket_short(self):
-        """
-        Test that if there's not enough data to get the whole socket, it is
-        kept there, but nothing is called.
-        """
-        socket = self.__prepare_data(b'tok')
-        self.__boss._socket_data(13)
-        self.assertEqual({13: (socket, b'tok')}, self.__boss._unix_sockets)
-        self.assertFalse(socket.closed)
-        self.assertIsNone(self.__consumer_dead_called)
-        self.assertIsNone(self.__socket_request_handler_called)
-
-    def test_socket_continue(self):
-        """
-        Test that we call the token handling function when the whole token
-        comes. This test pretends to continue reading where the previous one
-        stopped.
-        """
-        socket = self.__prepare_data(b"en\nanothe")
-        # The data to finish
-        self.__boss._unix_sockets[13] = (socket, b'tok')
-        self.__boss._socket_data(13)
-        self.assertEqual({13: (socket, b'anothe')}, self.__boss._unix_sockets)
-        self.assertFalse(socket.closed)
-        self.assertIsNone(self.__consumer_dead_called)
-        self.assertEqual((b'token', socket),
-                         self.__socket_request_handler_called)
-
-    def test_broken_socket(self):
-        """
-        If the socket raises an exception during the read other than EAGAIN,
-        it is broken and we remove it.
-        """
-        sock = self.__prepare_data(socket.error(errno.ENOMEM,
-            "There's more memory available, but not for you"))
-        self.__boss._socket_data(13)
-        self.assertEqual(sock, self.__consumer_dead_called)
-        self.assertEqual({}, self.__boss._unix_sockets)
-        self.assertTrue(sock.closed)
-
-class TestFunctions(unittest.TestCase):
-    def setUp(self):
-        self.lockfile_testpath = \
-            "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
-        self.assertFalse(os.path.exists(self.lockfile_testpath))
-        os.mkdir(self.lockfile_testpath)
-        self.assertTrue(os.path.isdir(self.lockfile_testpath))
-        self.__isfile_orig = bind10_src.os.path.isfile
-        self.__unlink_orig = bind10_src.os.unlink
-
-    def tearDown(self):
-        os.rmdir(self.lockfile_testpath)
-        self.assertFalse(os.path.isdir(self.lockfile_testpath))
-        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
-        bind10_src.os.path.isfile = self.__isfile_orig
-        bind10_src.os.unlink = self.__unlink_orig
-
-    def test_remove_lock_files(self):
-        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
-
-        # create lockfiles for the testcase
-        lockfiles = ["logger_lockfile"]
-        for f in lockfiles:
-            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
-            self.assertFalse(os.path.exists(fname))
-            open(fname, "w").close()
-            self.assertTrue(os.path.isfile(fname))
-
-        # first call should clear up all the lockfiles
-        bind10_src.remove_lock_files()
-
-        # check if the lockfiles exist
-        for f in lockfiles:
-            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
-            self.assertFalse(os.path.isfile(fname))
-
-        # second call should not assert anyway
-        bind10_src.remove_lock_files()
-
-    def test_remove_lock_files_fail(self):
-        # Permission error on unlink is ignored; other exceptions are really
-        # unexpected and propagated.
-        def __raising_unlink(unused, ex):
-            raise ex
-
-        bind10_src.os.path.isfile = lambda _: True
-        os_error = OSError()
-        bind10_src.os.unlink = lambda f: __raising_unlink(f, os_error)
-
-        os_error.errno = errno.EPERM
-        bind10_src.remove_lock_files() # no disruption
-
-        os_error.errno = errno.EACCES
-        bind10_src.remove_lock_files() # no disruption
-
-        os_error.errno = errno.ENOENT
-        self.assertRaises(OSError, bind10_src.remove_lock_files)
-
-        bind10_src.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
-        self.assertRaises(Exception, bind10_src.remove_lock_files)
-
-    def test_get_signame(self):
-        # just test with some samples
-        signame = bind10_src.get_signame(signal.SIGTERM)
-        self.assertEqual('SIGTERM', signame)
-        signame = bind10_src.get_signame(signal.SIGKILL)
-        self.assertEqual('SIGKILL', signame)
-        # 59426 is hopefully an unused signal on most platforms
-        signame = bind10_src.get_signame(59426)
-        self.assertEqual('Unknown signal 59426', signame)
-
-    def test_fatal_signal(self):
-        self.assertIsNone(bind10_src.boss_of_bind)
-        bind10_src.boss_of_bind = BoB()
-        bind10_src.boss_of_bind.runnable = True
-        bind10_src.fatal_signal(signal.SIGTERM, None)
-        # Now, runnable must be False
-        self.assertFalse(bind10_src.boss_of_bind.runnable)
-        bind10_src.boss_of_bind = None
-
-if __name__ == '__main__':
-    # store os.environ for test_unchanged_environment
-    original_os_environ = copy.deepcopy(os.environ)
-    isc.log.resetUnitTestRootLogger()
-    unittest.main()
diff --git a/src/bin/bind10/tests/init_test.py.in b/src/bin/bind10/tests/init_test.py.in
new file mode 100644
index 0000000..9a591ef
--- /dev/null
+++ b/src/bin/bind10/tests/init_test.py.in
@@ -0,0 +1,2426 @@
+# 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.
+
+# Most of the time, we omit the "init" for brevity. Sometimes,
+# we want to be explicit about what we do, like when hijacking a library
+# call used by the b10-init.
+from init import Init, ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+import init
+
+# XXX: environment tests are currently disabled, due to the preprocessor
+#      setup that we have now complicating the environment
+
+import unittest
+import sys
+import os
+import os.path
+import copy
+import signal
+import socket
+from isc.net.addr import IPAddr
+import time
+import isc.log
+import isc.config
+import isc.bind10.socket_cache
+import errno
+import random
+
+from isc.testutils.parse_args import TestOptParser, OptsError
+from isc.testutils.ccsession_mock import MockModuleCCSession
+
+class TestProcessInfo(unittest.TestCase):
+    def setUp(self):
+        # redirect stdout to a pipe so we can check that our
+        # process spawning is doing the right thing with stdout
+        self.old_stdout = os.dup(sys.stdout.fileno())
+        self.pipes = os.pipe()
+        os.dup2(self.pipes[1], sys.stdout.fileno())
+        os.close(self.pipes[1])
+        # note that we use dup2() to restore the original stdout
+        # to the main program ASAP in each test... this prevents
+        # hangs reading from the child process (as the pipe is only
+        # open in the child), and also insures nice pretty output
+
+    def tearDown(self):
+        # clean up our stdout munging
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        os.close(self.pipes[0])
+
+    def test_init(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+        pi.spawn()
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        self.assertEqual(pi.name, 'Test Process')
+        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+        self.assertEqual(pi.dev_null_stdout, False)
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        self.assertNotEqual(pi.process, None)
+        self.assertTrue(type(pi.pid) is int)
+
+#    def test_setting_env(self):
+#        pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
+#        os.dup2(self.old_stdout, sys.stdout.fileno())
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
+#                                   'FOO': 'BAR' })
+
+    def test_setting_null_stdout(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
+                         dev_null_stdout=True)
+        pi.spawn()
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        self.assertEqual(pi.dev_null_stdout, True)
+        self.assertEqual(os.read(self.pipes[0], 100), b"")
+
+    def test_respawn(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+        pi.spawn()
+        # wait for old process to work...
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        # respawn it
+        old_pid = pi.pid
+        pi.respawn()
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        # make sure the new one started properly
+        self.assertEqual(pi.name, 'Test Process')
+        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+        self.assertEqual(pi.dev_null_stdout, False)
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        self.assertNotEqual(pi.process, None)
+        self.assertTrue(type(pi.pid) is int)
+        self.assertNotEqual(pi.pid, old_pid)
+
+class TestCacheCommands(unittest.TestCase):
+    """
+    Test methods of b10-init related to the socket cache and socket handling.
+    """
+    def setUp(self):
+        """
+        Prepare b10-init for some tests.
+
+        Also prepare some variables we need.
+        """
+        self.__b10_init = Init()
+        # Fake the cache here so we can pretend it is us and hijack the
+        # calls to its methods.
+        self.__b10_init._socket_cache = self
+        self.__b10_init._socket_path = '/socket/path'
+        self.__raise_exception = None
+        self.__socket_args = {
+            "port": 53,
+            "address": "::",
+            "protocol": "UDP",
+            "share_mode": "ANY",
+            "share_name": "app"
+        }
+        # What was and wasn't called.
+        self.__drop_app_called = None
+        self.__get_socket_called = None
+        self.__send_fd_called = None
+        self.__get_token_called = None
+        self.__drop_socket_called = None
+        init.libutil_io_python.send_fd = self.__send_fd
+
+    def __send_fd(self, to, socket):
+        """
+        A function to hook the send_fd in the b10-init.
+        """
+        self.__send_fd_called = (to, socket)
+
+    class FalseSocket:
+        """
+        A socket where we can fake methods we need instead of having a real
+        socket.
+        """
+        def __init__(self):
+            self.send = b""
+        def fileno(self):
+            """
+            The file number. Used for identifying the remote application.
+            """
+            return 42
+
+        def sendall(self, data):
+            """
+            Adds data to the self.send.
+            """
+            self.send += data
+
+    def drop_application(self, application):
+        """
+        Part of pretending to be the cache. Logs the parameter to
+        self.__drop_app_called.
+
+        In the case self.__raise_exception is set, the exception there
+        is raised instead.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__drop_app_called = application
+
+    def test_consumer_dead(self):
+        """
+        Test that it calls the drop_application method of the cache.
+        """
+        self.__b10_init.socket_consumer_dead(self.FalseSocket())
+        self.assertEqual(42, self.__drop_app_called)
+
+    def test_consumer_dead_invalid(self):
+        """
+        Test that it doesn't crash in case the application is not known to
+        the cache, the b10_init doesn't crash, as this actually can happen in
+        practice.
+        """
+        self.__raise_exception = ValueError("This application is unknown")
+        # This doesn't crash
+        self.__b10_init.socket_consumer_dead(self.FalseSocket())
+
+    def get_socket(self, token, application):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the call is logged
+        into __get_socket_called and a number is returned.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__get_socket_called = (token, application)
+        return 13
+
+    def test_request_handler(self):
+        """
+        Test that a request for socket is forwarded and the socket is sent
+        back, if it returns a socket.
+        """
+        socket = self.FalseSocket()
+        # An exception from the cache
+        self.__raise_exception = ValueError("Test value error")
+        self.__b10_init.socket_request_handler(b"token", socket)
+        # It was called, but it threw, so it is not noted here
+        self.assertIsNone(self.__get_socket_called)
+        self.assertEqual(b"0\n", socket.send)
+        # It should not have sent any socket.
+        self.assertIsNone(self.__send_fd_called)
+        # Now prepare a valid scenario
+        self.__raise_exception = None
+        socket.send = b""
+        self.__b10_init.socket_request_handler(b"token", socket)
+        self.assertEqual(b"1\n", socket.send)
+        self.assertEqual((42, 13), self.__send_fd_called)
+        self.assertEqual(("token", 42), self.__get_socket_called)
+
+    def get_token(self, protocol, address, port, share_mode, share_name):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the parameters are
+        logged into __get_token_called and a token is returned.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__get_token_called = (protocol, address, port, share_mode,
+                                   share_name)
+        return "token"
+
+    def test_get_socket_ok(self):
+        """
+        Test the successful scenario of getting a socket.
+        """
+        result = self.__b10_init._get_socket(self.__socket_args)
+        [code, answer] = result['result']
+        self.assertEqual(0, code)
+        self.assertEqual({
+            'token': 'token',
+            'path': '/socket/path'
+        }, answer)
+        addr = self.__get_token_called[1]
+        self.assertTrue(isinstance(addr, IPAddr))
+        self.assertEqual("::", str(addr))
+        self.assertEqual(("UDP", addr, 53, "ANY", "app"),
+                         self.__get_token_called)
+
+    def test_get_socket_error(self):
+        """
+        Test that bad inputs are handled correctly, etc.
+        """
+        def check_code(code, args):
+            """
+            Pass the args there and check if it returns success or not.
+
+            The rest is not tested, as it is already checked in the
+            test_get_socket_ok.
+            """
+            [rcode, ranswer] = self.__b10_init._get_socket(args)['result']
+            self.assertEqual(code, rcode)
+            if code != 0:
+                # This should be an error message. The exact formatting
+                # is unknown, but we check it is string at least
+                self.assertTrue(isinstance(ranswer, str))
+
+        def mod_args(name, value):
+            """
+            Override a parameter in the args.
+            """
+            result = dict(self.__socket_args)
+            result[name] = value
+            return result
+
+        # Port too large
+        check_code(1, mod_args('port', 65536))
+        # Not numeric address
+        check_code(1, mod_args('address', 'example.org.'))
+        # Some bad values of enum-like params
+        check_code(1, mod_args('protocol', 'BAD PROTO'))
+        check_code(1, mod_args('share_mode', 'BAD SHARE'))
+        # Check missing parameters
+        for param in self.__socket_args.keys():
+            args = dict(self.__socket_args)
+            del args[param]
+            check_code(1, args)
+        # These are OK values for the enum-like parameters
+        # The ones from test_get_socket_ok are not tested here
+        check_code(0, mod_args('protocol', 'TCP'))
+        check_code(0, mod_args('share_mode', 'SAMEAPP'))
+        check_code(0, mod_args('share_mode', 'NO'))
+        # If an exception is raised from within the cache, it is converted
+        # to an error, not propagated
+        self.__raise_exception = Exception("Test exception")
+        check_code(1, self.__socket_args)
+        # The special "expected" exceptions
+        self.__raise_exception = \
+            isc.bind10.socket_cache.ShareError("Not shared")
+        check_code(3, self.__socket_args)
+        self.__raise_exception = \
+            isc.bind10.socket_cache.SocketError("Not shared", 13)
+        check_code(2, self.__socket_args)
+
+    def drop_socket(self, token):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the parameter is stored
+        in __drop_socket_called.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__drop_socket_called = token
+
+    def test_drop_socket(self):
+        """
+        Check the drop_socket command. It should directly call the method
+        on the cache. Exceptions should be translated to error messages.
+        """
+        # This should be OK and just propagated to the call.
+        self.assertEqual({"result": [0]},
+                         self.__b10_init.command_handler("drop_socket",
+                                                         {"token": "token"}))
+        self.assertEqual("token", self.__drop_socket_called)
+        self.__drop_socket_called = None
+        # Missing parameter
+        self.assertEqual({"result": [1, "Missing token parameter"]},
+                         self.__b10_init.command_handler("drop_socket", {}))
+        self.assertIsNone(self.__drop_socket_called)
+        # An exception is raised from within the cache
+        self.__raise_exception = ValueError("Test error")
+        self.assertEqual({"result": [1, "Test error"]},
+                         self.__b10_init.command_handler("drop_socket",
+                         {"token": "token"}))
+
+
+class TestInit(unittest.TestCase):
+    def setUp(self):
+        # Save original values that may be tweaked in some tests
+        self.__orig_setgid = init.posix.setgid
+        self.__orig_setuid = init.posix.setuid
+        self.__orig_logger_class = isc.log.Logger
+
+    def tearDown(self):
+        # Restore original values saved in setUp()
+        init.posix.setgid = self.__orig_setgid
+        init.posix.setuid = self.__orig_setuid
+        isc.log.Logger = self.__orig_logger_class
+
+    def test_init(self):
+        b10_init = Init()
+        self.assertEqual(b10_init.verbose, False)
+        self.assertEqual(b10_init.msgq_socket_file, None)
+        self.assertEqual(b10_init.cc_session, None)
+        self.assertEqual(b10_init.ccs, None)
+        self.assertEqual(b10_init.components, {})
+        self.assertEqual(b10_init.runnable, False)
+        self.assertEqual(b10_init.username, None)
+        self.assertIsNone(b10_init._socket_cache)
+
+    def __setgid(self, gid):
+        self.__gid_set = gid
+
+    def __setuid(self, uid):
+        self.__uid_set = uid
+
+    def test_change_user(self):
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = self.__setuid
+
+        self.__gid_set = None
+        self.__uid_set = None
+        b10_init = Init()
+        b10_init.change_user()
+        # No gid/uid set in init, nothing called.
+        self.assertIsNone(self.__gid_set)
+        self.assertIsNone(self.__uid_set)
+
+        Init(setuid=42, setgid=4200).change_user()
+        # This time, it get's called
+        self.assertEqual(4200, self.__gid_set)
+        self.assertEqual(42, self.__uid_set)
+
+        def raising_set_xid(gid_or_uid):
+            ex = OSError()
+            ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+            raise ex
+
+        # Let setgid raise an exception
+        init.posix.setgid = raising_set_xid
+        init.posix.setuid = self.__setuid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+        # Let setuid raise an exception
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = raising_set_xid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+        # Let initial log output after setuid raise an exception
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = self.__setuid
+        isc.log.Logger = raising_set_xid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+    def test_set_creator(self):
+        """
+        Test the call to set_creator. First time, the cache is created
+        with the passed creator. The next time, it throws an exception.
+        """
+        init = Init()
+        # The cache doesn't use it at start, so just create an empty class
+        class Creator: pass
+        creator = Creator()
+        init.set_creator(creator)
+        self.assertTrue(isinstance(init._socket_cache,
+                        isc.bind10.socket_cache.Cache))
+        self.assertEqual(creator, init._socket_cache._creator)
+        self.assertRaises(ValueError, init.set_creator, creator)
+
+    def test_socket_srv(self):
+        """Tests init_socket_srv() and remove_socket_srv() work as expected."""
+        init = Init()
+
+        self.assertIsNone(init._srv_socket)
+        self.assertIsNone(init._tmpdir)
+        self.assertIsNone(init._socket_path)
+
+        init.init_socket_srv()
+
+        self.assertIsNotNone(init._srv_socket)
+        self.assertNotEqual(-1, init._srv_socket.fileno())
+        self.assertEqual(os.path.join(init._tmpdir, 'sockcreator'),
+                         init._srv_socket.getsockname())
+
+        self.assertIsNotNone(init._tmpdir)
+        self.assertTrue(os.path.isdir(init._tmpdir))
+        self.assertIsNotNone(init._socket_path)
+        self.assertTrue(os.path.exists(init._socket_path))
+
+        # Check that it's possible to connect to the socket file (this
+        # only works if the socket file exists and the server listens on
+        # it).
+        s = socket.socket(socket.AF_UNIX)
+        try:
+            s.connect(init._socket_path)
+            can_connect = True
+            s.close()
+        except socket.error as e:
+            can_connect = False
+
+        self.assertTrue(can_connect)
+
+        init.remove_socket_srv()
+
+        self.assertEqual(-1, init._srv_socket.fileno())
+        self.assertFalse(os.path.exists(init._socket_path))
+        self.assertFalse(os.path.isdir(init._tmpdir))
+
+        # These should not fail either:
+
+        # second call
+        init.remove_socket_srv()
+
+        init._srv_socket = None
+        init.remove_socket_srv()
+
+    def test_init_alternate_socket(self):
+        init = Init("alt_socket_file")
+        self.assertEqual(init.verbose, False)
+        self.assertEqual(init.msgq_socket_file, "alt_socket_file")
+        self.assertEqual(init.cc_session, None)
+        self.assertEqual(init.ccs, None)
+        self.assertEqual(init.components, {})
+        self.assertEqual(init.runnable, False)
+        self.assertEqual(init.username, None)
+
+    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
+        class DummyModuleCCSession():
+            module_spec = isc.config.module_spec.ModuleSpec({
+                    "module_name": "Init",
+                    "statistics": [
+                        {
+                            "item_name": "boot_time",
+                            "item_type": "string",
+                            "item_optional": False,
+                            "item_default": "1970-01-01T00:00:00Z",
+                            "item_title": "Boot time",
+                            "item_description": "A date time when bind10 process starts initially",
+                            "item_format": "date-time"
+                            }
+                        ]
+                    })
+            def get_module_spec(self):
+                return self.module_spec
+        init = Init()
+        init.verbose = True
+        init.cc_session = DummySession()
+        init.ccs = DummyModuleCCSession()
+        # a bad command
+        self.assertEqual(init.command_handler(-1, None),
+                         isc.config.ccsession.create_answer(1, "bad command"))
+        # "shutdown" command
+        self.assertEqual(init.command_handler("shutdown", None),
+                         isc.config.ccsession.create_answer(0))
+        self.assertFalse(init.runnable)
+        # "getstats" command
+        self.assertEqual(init.command_handler("getstats", None),
+                         isc.config.ccsession.create_answer(0,
+                            { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
+        # "ping" command
+        self.assertEqual(init.command_handler("ping", None),
+                         isc.config.ccsession.create_answer(0, "pong"))
+        # "show_processes" command
+        self.assertEqual(init.command_handler("show_processes", None),
+                         isc.config.ccsession.create_answer(0,
+                                                            init.get_processes()))
+        # an unknown command
+        self.assertEqual(init.command_handler("__UNKNOWN__", None),
+                         isc.config.ccsession.create_answer(1, "Unknown command"))
+
+        # Fake the get_token of cache and test the command works
+        init._socket_path = '/socket/path'
+        class cache:
+            def get_token(self, protocol, addr, port, share_mode, share_name):
+                return str(addr) + ':' + str(port)
+        init._socket_cache = cache()
+        args = {
+            "port": 53,
+            "address": "0.0.0.0",
+            "protocol": "UDP",
+            "share_mode": "ANY",
+            "share_name": "app"
+        }
+        # at all and this is the easiest way to check.
+        self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
+                                         'path': '/socket/path'}]},
+                         init.command_handler("get_socket", args))
+        # The drop_socket is not tested here, but in TestCacheCommands.
+        # It needs the cache mocks to be in place and they are there.
+
+    def test_stop_process(self):
+        """
+        Test checking the stop_process method sends the right message over
+        the message bus.
+        """
+        class DummySession():
+            def group_sendmsg(self, msg, group, instance="*"):
+                (self.msg, self.group, self.instance) = (msg, group, instance)
+        init = Init()
+        init.cc_session = DummySession()
+        init.stop_process('process', 'address', 42)
+        self.assertEqual('address', init.cc_session.group)
+        self.assertEqual('address', init.cc_session.instance)
+        self.assertEqual({'command': ['shutdown', {'pid': 42}]},
+                         init.cc_session.msg)
+
+# Mock class for testing Init's usage of ProcessInfo
+class MockProcessInfo:
+    def __init__(self, name, args, env={}, dev_null_stdout=False,
+                 dev_null_stderr=False):
+        self.name = name
+        self.args = args
+        self.env = env
+        self.dev_null_stdout = dev_null_stdout
+        self.dev_null_stderr = dev_null_stderr
+        self.process = None
+        self.pid = None
+
+    def spawn(self):
+        # set some pid (only used for testing that it is not None anymore)
+        self.pid = 42147
+
+# Class for testing the Init without actually starting processes.
+# This is used for testing the start/stop components routines and
+# the Init commands.
+#
+# Testing that external processes start is outside the scope
+# of the unit test, by overriding the process start methods we can check
+# that the right processes are started depending on the configuration
+# options.
+class MockInit(Init):
+    def __init__(self):
+        Init.__init__(self)
+
+        # Set flags as to which of the overridden methods has been run.
+        self.msgq = False
+        self.cfgmgr = False
+        self.ccsession = False
+        self.auth = False
+        self.resolver = False
+        self.xfrout = False
+        self.xfrin = False
+        self.zonemgr = False
+        self.stats = False
+        self.stats_httpd = False
+        self.cmdctl = False
+        self.dhcp6 = False
+        self.dhcp4 = False
+        self.c_channel_env = {}
+        self.components = { }
+        self.creator = False
+        self.get_process_exit_status_called = False
+
+        class MockSockCreator(isc.bind10.component.Component):
+            def __init__(self, process, b10_init, kind, address=None,
+                         params=None):
+                isc.bind10.component.Component.__init__(self, process,
+                                                        b10_init, kind,
+                                                        'SockCreator')
+                self._start_func = b10_init.start_creator
+
+        specials = isc.bind10.special_component.get_specials()
+        specials['sockcreator'] = MockSockCreator
+        self._component_configurator = \
+            isc.bind10.component.Configurator(self, specials)
+
+    def start_creator(self):
+        self.creator = True
+        procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
+        procinfo.pid = 1
+        return procinfo
+
+    def _read_bind10_config(self):
+        # Configuration options are set directly
+        pass
+
+    def start_msgq(self):
+        self.msgq = True
+        procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
+        procinfo.pid = 2
+        return procinfo
+
+    def start_ccsession(self, c_channel_env):
+        # this is not a process, don't have to do anything with procinfo
+        self.ccsession = True
+
+    def start_cfgmgr(self):
+        self.cfgmgr = True
+        procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
+        procinfo.pid = 3
+        return procinfo
+
+    def start_auth(self):
+        self.auth = True
+        procinfo = ProcessInfo('b10-auth', ['/bin/false'])
+        procinfo.pid = 5
+        return procinfo
+
+    def start_resolver(self):
+        self.resolver = True
+        procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
+        procinfo.pid = 6
+        return procinfo
+
+    def start_simple(self, name):
+        procmap = { 'b10-zonemgr': self.start_zonemgr,
+                    'b10-stats': self.start_stats,
+                    'b10-stats-httpd': self.start_stats_httpd,
+                    'b10-cmdctl': self.start_cmdctl,
+                    'b10-dhcp6': self.start_dhcp6,
+                    'b10-dhcp4': self.start_dhcp4,
+                    'b10-xfrin': self.start_xfrin,
+                    'b10-xfrout': self.start_xfrout }
+        return procmap[name]()
+
+    def start_xfrout(self):
+        self.xfrout = True
+        procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
+        procinfo.pid = 7
+        return procinfo
+
+    def start_xfrin(self):
+        self.xfrin = True
+        procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
+        procinfo.pid = 8
+        return procinfo
+
+    def start_zonemgr(self):
+        self.zonemgr = True
+        procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
+        procinfo.pid = 9
+        return procinfo
+
+    def start_stats(self):
+        self.stats = True
+        procinfo = ProcessInfo('b10-stats', ['/bin/false'])
+        procinfo.pid = 10
+        return procinfo
+
+    def start_stats_httpd(self):
+        self.stats_httpd = True
+        procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+        procinfo.pid = 11
+        return procinfo
+
+    def start_cmdctl(self):
+        self.cmdctl = True
+        procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
+        procinfo.pid = 12
+        return procinfo
+
+    def start_dhcp6(self):
+        self.dhcp6 = True
+        procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
+        procinfo.pid = 13
+        return procinfo
+
+    def start_dhcp4(self):
+        self.dhcp4 = True
+        procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
+        procinfo.pid = 14
+        return procinfo
+
+    def stop_process(self, process, recipient, pid):
+        procmap = { 'b10-auth': self.stop_auth,
+                    'b10-resolver': self.stop_resolver,
+                    'b10-xfrout': self.stop_xfrout,
+                    'b10-xfrin': self.stop_xfrin,
+                    'b10-zonemgr': self.stop_zonemgr,
+                    'b10-stats': self.stop_stats,
+                    'b10-stats-httpd': self.stop_stats_httpd,
+                    'b10-cmdctl': self.stop_cmdctl }
+        procmap[process]()
+
+    # Some functions to pretend we stop processes, use by stop_process
+    def stop_msgq(self):
+        if self.msgq:
+            del self.components[2]
+        self.msgq = False
+
+    def stop_cfgmgr(self):
+        if self.cfgmgr:
+            del self.components[3]
+        self.cfgmgr = False
+
+    def stop_auth(self):
+        if self.auth:
+            del self.components[5]
+        self.auth = False
+
+    def stop_resolver(self):
+        if self.resolver:
+            del self.components[6]
+        self.resolver = False
+
+    def stop_xfrout(self):
+        if self.xfrout:
+            del self.components[7]
+        self.xfrout = False
+
+    def stop_xfrin(self):
+        if self.xfrin:
+            del self.components[8]
+        self.xfrin = False
+
+    def stop_zonemgr(self):
+        if self.zonemgr:
+            del self.components[9]
+        self.zonemgr = False
+
+    def stop_stats(self):
+        if self.stats:
+            del self.components[10]
+        self.stats = False
+
+    def stop_stats_httpd(self):
+        if self.stats_httpd:
+            del self.components[11]
+        self.stats_httpd = False
+
+    def stop_cmdctl(self):
+        if self.cmdctl:
+            del self.components[12]
+        self.cmdctl = False
+
+    def _get_process_exit_status(self):
+        if self.get_process_exit_status_called:
+            return (0, 0)
+        self.get_process_exit_status_called = True
+        return (53, 0)
+
+    def _get_process_exit_status_unknown_pid(self):
+        if self.get_process_exit_status_called:
+            return (0, 0)
+        self.get_process_exit_status_called = True
+        return (42, 0)
+
+    def _get_process_exit_status_raises_oserror_echild(self):
+        raise OSError(errno.ECHILD, 'Mock error')
+
+    def _get_process_exit_status_raises_oserror_other(self):
+        raise OSError(0, 'Mock error')
+
+    def _get_process_exit_status_raises_other(self):
+        raise Exception('Mock error')
+
+    def _make_mock_process_info(self, name, args, c_channel_env,
+                                dev_null_stdout=False, dev_null_stderr=False):
+        return MockProcessInfo(name, args, c_channel_env,
+                               dev_null_stdout, dev_null_stderr)
+
+class MockInitSimple(Init):
+    def __init__(self):
+        Init.__init__(self)
+        # Set which process has been started
+        self.started_process_name = None
+        self.started_process_args = None
+        self.started_process_env = None
+
+    def _make_mock_process_info(self, name, args, c_channel_env,
+                                dev_null_stdout=False, dev_null_stderr=False):
+        return MockProcessInfo(name, args, c_channel_env,
+                               dev_null_stdout, dev_null_stderr)
+
+    def start_process(self, name, args, c_channel_env, port=None,
+                      address=None):
+        self.started_process_name = name
+        self.started_process_args = args
+        self.started_process_env = c_channel_env
+        return None
+
+class TestStartStopProcessesInit(unittest.TestCase):
+    """
+    Check that the start_all_components method starts the right combination
+    of components and that the right components are started and stopped
+    according to changes in configuration.
+    """
+    def check_environment_unchanged(self):
+        # Check whether the environment has not been changed
+        self.assertEqual(original_os_environ, os.environ)
+
+    def check_started(self, init, core, auth, resolver):
+        """
+        Check that the right sets of services are started. The ones that
+        should be running are specified by the core, auth and resolver parameters
+        (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
+        and -zonemgr).
+        """
+        self.assertEqual(init.msgq, core)
+        self.assertEqual(init.cfgmgr, core)
+        self.assertEqual(init.ccsession, core)
+        self.assertEqual(init.creator, core)
+        self.assertEqual(init.auth, auth)
+        self.assertEqual(init.resolver, resolver)
+        self.assertEqual(init.xfrout, auth)
+        self.assertEqual(init.xfrin, auth)
+        self.assertEqual(init.zonemgr, auth)
+        self.assertEqual(init.stats, core)
+        self.assertEqual(init.stats_httpd, core)
+        self.assertEqual(init.cmdctl, core)
+        self.check_environment_unchanged()
+
+    def check_preconditions(self, init):
+        self.check_started(init, False, False, False)
+
+    def check_started_none(self, init):
+        """
+        Check that the situation is according to configuration where no servers
+        should be started. Some components still need to be running.
+        """
+        self.check_started(init, True, False, False)
+        self.check_environment_unchanged()
+
+    def check_started_both(self, init):
+        """
+        Check the situation is according to configuration where both servers
+        (auth and resolver) are enabled.
+        """
+        self.check_started(init, True, True, True)
+        self.check_environment_unchanged()
+
+    def check_started_auth(self, init):
+        """
+        Check the set of components needed to run auth only is started.
+        """
+        self.check_started(init, True, True, False)
+        self.check_environment_unchanged()
+
+    def check_started_resolver(self, init):
+        """
+        Check the set of components needed to run resolver only is started.
+        """
+        self.check_started(init, True, False, True)
+        self.check_environment_unchanged()
+
+    def check_started_dhcp(self, init, v4, v6):
+        """
+        Check if proper combinations of DHCPv4 and DHCpv6 can be started
+        """
+        self.assertEqual(v4, init.dhcp4)
+        self.assertEqual(v6, init.dhcp6)
+        self.check_environment_unchanged()
+
+    def construct_config(self, start_auth, start_resolver):
+        # The things that are common, not turned on an off
+        config = {}
+        config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
+        config['b10-stats-httpd'] = { 'kind': 'dispensable',
+                                      'address': 'StatsHttpd' }
+        config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
+        if start_auth:
+            config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
+            config['b10-xfrout'] = { 'kind': 'dispensable',
+                                     'address': 'Xfrout' }
+            config['b10-xfrin'] = { 'kind': 'dispensable',
+                                    'address': 'Xfrin' }
+            config['b10-zonemgr'] = { 'kind': 'dispensable',
+                                      'address': 'Zonemgr' }
+        if start_resolver:
+            config['b10-resolver'] = { 'kind': 'needed',
+                                       'special': 'resolver' }
+        return {'components': config}
+
+    def config_start_init(self, start_auth, start_resolver):
+        """
+        Test the configuration is loaded at the startup.
+        """
+        init = MockInit()
+        config = self.construct_config(start_auth, start_resolver)
+        class CC:
+            def get_full_config(self):
+                return config
+        # Provide the fake CC with data
+        init.ccs = CC()
+        # And make sure it's not overwritten
+        def start_ccsession():
+            init.ccsession = True
+        init.start_ccsession = lambda _: start_ccsession()
+        # We need to return the original _read_bind10_config
+        init._read_bind10_config = lambda: Init._read_bind10_config(init)
+        init.start_all_components()
+        self.check_started(init, True, start_auth, start_resolver)
+        self.check_environment_unchanged()
+
+    def test_start_none(self):
+        self.config_start_init(False, False)
+
+    def test_start_resolver(self):
+        self.config_start_init(False, True)
+
+    def test_start_auth(self):
+        self.config_start_init(True, False)
+
+    def test_start_both(self):
+        self.config_start_init(True, True)
+
+    def test_config_start(self):
+        """
+        Test that the configuration starts and stops components according
+        to configuration changes.
+        """
+
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+        init.runnable = True
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Enable both at once
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        # Not touched by empty change
+        init.config_handler({})
+        self.check_started_both(init)
+
+        # Not touched by change to the same configuration
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        # Turn them both off again
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Not touched by empty change
+        init.config_handler({})
+        self.check_started_none(init)
+
+        # Not touched by change to the same configuration
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Start and stop auth separately
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Start and stop resolver separately
+        init.config_handler(self.construct_config(False, True))
+        self.check_started_resolver(init)
+
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Alternate
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+        init.config_handler(self.construct_config(False, True))
+        self.check_started_resolver(init)
+
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+    def test_config_start_once(self):
+        """
+        Tests that a component is started only once.
+        """
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+
+        init.runnable = True
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        init.start_auth = lambda: self.fail("Started auth again")
+        init.start_xfrout = lambda: self.fail("Started xfrout again")
+        init.start_xfrin = lambda: self.fail("Started xfrin again")
+        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        init.start_resolver = lambda: self.fail("Started resolver again")
+
+        # Send again we want to start them. Should not do it, as they are.
+        init.config_handler(self.construct_config(True, True))
+
+    def test_config_not_started_early(self):
+        """
+        Test that components are not started by the config handler before
+        startup.
+        """
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_auth = lambda: self.fail("Started auth again")
+        init.start_xfrout = lambda: self.fail("Started xfrout again")
+        init.start_xfrin = lambda: self.fail("Started xfrin again")
+        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        init.start_resolver = lambda: self.fail("Started resolver again")
+
+        init.config_handler({'start_auth': True, 'start_resolver': True})
+
+    # Checks that DHCP (v4 and v6) components are started when expected
+    def test_start_dhcp(self):
+
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_dhcp(init, False, False)
+
+    def test_start_dhcp_v6only(self):
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+        # v6 only enabled
+        init.start_all_components()
+        init.runnable = True
+        init._Init_started = True
+        config = self.construct_config(False, False)
+        config['components']['b10-dhcp6'] = { 'kind': 'needed',
+                                              'address': 'Dhcp6' }
+        init.config_handler(config)
+        self.check_started_dhcp(init, False, True)
+
+        # uncomment when dhcpv4 becomes implemented
+        # v4 only enabled
+        #init.cfg_start_dhcp6 = False
+        #init.cfg_start_dhcp4 = True
+        #self.check_started_dhcp(init, True, False)
+
+        # both v4 and v6 enabled
+        #init.cfg_start_dhcp6 = True
+        #init.cfg_start_dhcp4 = True
+        #self.check_started_dhcp(init, True, True)
+
+class MockComponent:
+    def __init__(self, name, pid, address=None):
+        self.name = lambda: name
+        self.pid = lambda: pid
+        self.address = lambda: address
+        self.restarted = False
+        self.forceful = False
+        self.running = True
+        self.has_failed = False
+
+    def get_restart_time(self):
+        return 0                # arbitrary dummy value
+
+    def restart(self, now):
+        self.restarted = True
+        return True
+
+    def is_running(self):
+        return self.running
+
+    def failed(self, status):
+        return self.has_failed
+
+    def kill(self, forceful):
+        self.forceful = forceful
+
+class TestInitCmd(unittest.TestCase):
+    def test_ping(self):
+        """
+        Confirm simple ping command works.
+        """
+        init = MockInit()
+        answer = init.command_handler("ping", None)
+        self.assertEqual(answer, {'result': [0, 'pong']})
+
+    def test_show_processes_empty(self):
+        """
+        Confirm getting a list of processes works.
+        """
+        init = MockInit()
+        answer = init.command_handler("show_processes", None)
+        self.assertEqual(answer, {'result': [0, []]})
+
+    def test_show_processes(self):
+        """
+        Confirm getting a list of processes works.
+        """
+        init = MockInit()
+        init.register_process(1, MockComponent('first', 1))
+        init.register_process(2, MockComponent('second', 2, 'Second'))
+        answer = init.command_handler("show_processes", None)
+        processes = [[1, 'first', None],
+                     [2, 'second', 'Second']]
+        self.assertEqual(answer, {'result': [0, processes]})
+
+class TestParseArgs(unittest.TestCase):
+    """
+    This tests parsing of arguments of the bind10 master process.
+    """
+    #TODO: Write tests for the original parsing, bad options, etc.
+    def test_no_opts(self):
+        """
+        Test correct default values when no options are passed.
+        """
+        options = parse_args([], TestOptParser)
+        self.assertEqual(None, options.data_path)
+        self.assertEqual(None, options.config_file)
+        self.assertEqual(None, options.cmdctl_port)
+
+    def test_data_path(self):
+        """
+        Test it can parse the data path.
+        """
+        self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--data-path'],
+                          TestOptParser)
+        options = parse_args(['-p', '/data/path'], TestOptParser)
+        self.assertEqual('/data/path', options.data_path)
+        options = parse_args(['--data-path=/data/path'], TestOptParser)
+        self.assertEqual('/data/path', options.data_path)
+
+    def test_config_filename(self):
+        """
+        Test it can parse the config switch.
+        """
+        self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--config-file'],
+                          TestOptParser)
+        options = parse_args(['-c', 'config-file'], TestOptParser)
+        self.assertEqual('config-file', options.config_file)
+        options = parse_args(['--config-file=config-file'], TestOptParser)
+        self.assertEqual('config-file', options.config_file)
+
+    def test_clear_config(self):
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.clear_config)
+        options = parse_args(['--clear-config'], TestOptParser)
+        self.assertEqual(True, options.clear_config)
+
+    def test_nokill(self):
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.nokill)
+        options = parse_args(['--no-kill'], TestOptParser)
+        self.assertEqual(True, options.nokill)
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.nokill)
+        options = parse_args(['-i'], TestOptParser)
+        self.assertEqual(True, options.nokill)
+
+    def test_cmdctl_port(self):
+        """
+        Test it can parse the command control port.
+        """
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
+                                                TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
+                                                TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
+                          TestOptParser)
+        options = parse_args(['--cmdctl-port=1234'], TestOptParser)
+        self.assertEqual(1234, options.cmdctl_port)
+
+class TestPIDFile(unittest.TestCase):
+    def setUp(self):
+        self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
+        if os.path.exists(self.pid_file):
+            os.unlink(self.pid_file)
+
+    def tearDown(self):
+        if os.path.exists(self.pid_file):
+            os.unlink(self.pid_file)
+
+    def check_pid_file(self):
+        # dump PID to the file, and confirm the content is correct
+        dump_pid(self.pid_file)
+        my_pid = os.getpid()
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(my_pid, int(f.read()))
+
+    def test_dump_pid(self):
+        self.check_pid_file()
+
+        # make sure any existing content will be removed
+        with open(self.pid_file, "w") as f:
+            f.write('dummy data\n')
+        self.check_pid_file()
+
+    def test_unlink_pid_file_notexist(self):
+        dummy_data = 'dummy_data\n'
+
+        with open(self.pid_file, "w") as f:
+            f.write(dummy_data)
+
+        unlink_pid_file("no_such_pid_file")
+
+        # the file specified for unlink_pid_file doesn't exist,
+        # and the original content of the file should be intact.
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(dummy_data, f.read())
+
+    def test_dump_pid_with_none(self):
+        # Check the behavior of dump_pid() and unlink_pid_file() with None.
+        # This should be no-op.
+        dump_pid(None)
+        self.assertFalse(os.path.exists(self.pid_file))
+
+        dummy_data = 'dummy_data\n'
+
+        with open(self.pid_file, "w") as f:
+            f.write(dummy_data)
+
+        unlink_pid_file(None)
+
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(dummy_data, f.read())
+
+    def test_dump_pid_failure(self):
+        # the attempt to open file will fail, which should result in exception.
+        self.assertRaises(IOError, dump_pid,
+                          'nonexistent_dir' + os.sep + 'bind10.pid')
+
+class TestInitComponents(unittest.TestCase):
+    """
+    Test b10-init propagates component configuration properly to the
+    component configurator and acts sane.
+    """
+    def setUp(self):
+        self.__param = None
+        self.__called = False
+        self.__compconfig = {
+            'comp': {
+                'kind': 'needed',
+                'process': 'cat'
+            }
+        }
+        self._tmp_time = None
+        self._tmp_sleep = None
+        self._tmp_module_cc_session = None
+        self._tmp_cc_session = None
+
+    def tearDown(self):
+        if self._tmp_time is not None:
+            time.time = self._tmp_time
+        if self._tmp_sleep is not None:
+            time.sleep = self._tmp_sleep
+        if self._tmp_module_cc_session is not None:
+            isc.config.ModuleCCSession = self._tmp_module_cc_session
+        if self._tmp_cc_session is not None:
+            isc.cc.Session = self._tmp_cc_session
+
+    def __unary_hook(self, param):
+        """
+        A hook function that stores the parameter for later examination.
+        """
+        self.__param = param
+
+    def __nullary_hook(self):
+        """
+        A hook function that notes down it was called.
+        """
+        self.__called = True
+
+    def __check_core(self, config):
+        """
+        A function checking that the config contains parts for the valid
+        core component configuration.
+        """
+        self.assertIsNotNone(config)
+        for component in ['sockcreator', 'msgq', 'cfgmgr']:
+            self.assertTrue(component in config)
+            self.assertEqual(component, config[component]['special'])
+            self.assertEqual('core', config[component]['kind'])
+
+    def __check_extended(self, config):
+        """
+        This checks that the config contains the core and one more component.
+        """
+        self.__check_core(config)
+        self.assertTrue('comp' in config)
+        self.assertEqual('cat', config['comp']['process'])
+        self.assertEqual('needed', config['comp']['kind'])
+        self.assertEqual(4, len(config))
+
+    def test_correct_run(self):
+        """
+        Test the situation when we run in usual scenario, nothing fails,
+        we just start, reconfigure and then stop peacefully.
+        """
+        init = MockInit()
+        # Start it
+        orig = init._component_configurator.startup
+        init._component_configurator.startup = self.__unary_hook
+        init.start_all_components()
+        init._component_configurator.startup = orig
+        self.__check_core(self.__param)
+        self.assertEqual(3, len(self.__param))
+
+        # Reconfigure it
+        self.__param = None
+        orig = init._component_configurator.reconfigure
+        init._component_configurator.reconfigure = self.__unary_hook
+        # Otherwise it does not work
+        init.runnable = True
+        init.config_handler({'components': self.__compconfig})
+        self.__check_extended(self.__param)
+        currconfig = self.__param
+        # If we reconfigure it, but it does not contain the components part,
+        # nothing is called
+        init.config_handler({})
+        self.assertEqual(self.__param, currconfig)
+        self.__param = None
+        init._component_configurator.reconfigure = orig
+        # Check a configuration that messes up the core components is rejected.
+        compconf = dict(self.__compconfig)
+        compconf['msgq'] = { 'process': 'echo' }
+        result = init.config_handler({'components': compconf})
+        # Check it rejected it
+        self.assertEqual(1, result['result'][0])
+
+        # We can't call shutdown, that one relies on the stuff in main
+        # We check somewhere else that the shutdown is actually called
+        # from there (the test_kills).
+
+    def __real_test_kill(self, nokill=False, ex_on_kill=None):
+        """
+        Helper function that does the actual kill functionality testing.
+        """
+        init = MockInit()
+        init.nokill = nokill
+
+        killed = []
+        class ImmortalComponent:
+            """
+            An immortal component. It does not stop when it is told so
+            (anyway it is not told so). It does not die if it is killed
+            the first time. It dies only when killed forcefully.
+            """
+            def __init__(self):
+                # number of kill() calls, preventing infinite loop.
+                self.__call_count = 0
+
+            def kill(self, forceful=False):
+                self.__call_count += 1
+                if self.__call_count > 2:
+                    raise Exception('Too many calls to ImmortalComponent.kill')
+
+                killed.append(forceful)
+                if ex_on_kill is not None:
+                    # If exception is given by the test, raise it here.
+                    # In the case of ESRCH, the process should have gone
+                    # somehow, so we clear the components.
+                    if ex_on_kill.errno == errno.ESRCH:
+                        init.components = {}
+                    raise ex_on_kill
+                if forceful:
+                    init.components = {}
+            def pid(self):
+                return 1
+            def name(self):
+                return "Immortal"
+        init.components = {}
+        init.register_process(1, ImmortalComponent())
+
+        # While at it, we check the configurator shutdown is actually called
+        orig = init._component_configurator.shutdown
+        init._component_configurator.shutdown = self.__nullary_hook
+        self.__called = False
+
+        init.ccs = MockModuleCCSession()
+        self.assertFalse(init.ccs.stopped)
+
+        init.shutdown()
+
+        self.assertTrue(init.ccs.stopped)
+
+        # Here, killed is an array where False is added if SIGTERM
+        # should be sent, or True if SIGKILL should be sent, in order in
+        # which they're sent.
+        if nokill:
+            self.assertEqual([], killed)
+        else:
+            if ex_on_kill is not None:
+                self.assertEqual([False], killed)
+            else:
+                self.assertEqual([False, True], killed)
+
+        self.assertTrue(self.__called)
+
+        init._component_configurator.shutdown = orig
+
+    def test_kills(self):
+        """
+        Test that b10-init kills components which don't want to stop.
+        """
+        self.__real_test_kill()
+
+    def test_kill_fail(self):
+        """Test cases where kill() results in an exception due to OS error.
+
+        The behavior should be different for EPERM, so we test two cases.
+
+        """
+
+        ex = OSError()
+        ex.errno, ex.strerror = errno.ESRCH, 'No such process'
+        self.__real_test_kill(ex_on_kill=ex)
+
+        ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+        self.__real_test_kill(ex_on_kill=ex)
+
+    def test_nokill(self):
+        """
+        Test that b10-init *doesn't* kill components which don't want to
+        stop, when asked not to (by passing the --no-kill option which
+        sets init.nokill to True).
+        """
+        self.__real_test_kill(True)
+
+    def test_component_shutdown(self):
+        """
+        Test the component_shutdown sets all variables accordingly.
+        """
+        init = MockInit()
+        self.assertRaises(Exception, init.component_shutdown, 1)
+        self.assertEqual(1, init.exitcode)
+        init._Init__started = True
+        init.component_shutdown(2)
+        self.assertEqual(2, init.exitcode)
+        self.assertFalse(init.runnable)
+
+    def test_init_config(self):
+        """
+        Test initial configuration is loaded.
+        """
+        init = MockInit()
+        # Start it
+        init._component_configurator.reconfigure = self.__unary_hook
+        # We need to return the original read_bind10_config
+        init._read_bind10_config = lambda: Init._read_bind10_config(init)
+        # And provide a session to read the data from
+        class CC:
+            pass
+        init.ccs = CC()
+        init.ccs.get_full_config = lambda: {'components': self.__compconfig}
+        init.start_all_components()
+        self.__check_extended(self.__param)
+
+    def __setup_restart(self, init, component):
+        '''Common procedure for restarting a component used below.'''
+        init.components_to_restart = { component }
+        component.restarted = False
+        init.restart_processes()
+
+    def test_restart_processes(self):
+        '''Check some behavior on restarting processes.'''
+        init = MockInit()
+        init.runnable = True
+        component = MockComponent('test', 53)
+
+        # A component to be restarted will actually be restarted iff it's
+        # in the configurator's configuration.
+        # We bruteforce the configurator internal below; ugly, but the easiest
+        # way for the test.
+        init._component_configurator._components['test'] = (None, component)
+        self.__setup_restart(init, component)
+        self.assertTrue(component.restarted)
+        self.assertNotIn(component, init.components_to_restart)
+
+        # Remove the component from the configuration.  It won't be restarted
+        # even if scheduled, nor will remain in the to-be-restarted list.
+        del init._component_configurator._components['test']
+        self.__setup_restart(init, component)
+        self.assertFalse(component.restarted)
+        self.assertNotIn(component, init.components_to_restart)
+
+    def test_get_processes(self):
+        '''Test that procsses are returned correctly, sorted by pid.'''
+        init = MockInit()
+
+        pids = list(range(0, 20))
+        random.shuffle(pids)
+
+        for i in range(0, 20):
+            pid = pids[i]
+            component = MockComponent('test' + str(pid), pid,
+                                      'Test' + str(pid))
+            init.components[pid] = component
+
+        process_list = init.get_processes()
+        self.assertEqual(20, len(process_list))
+
+        last_pid = -1
+        for process in process_list:
+            pid = process[0]
+            self.assertLessEqual(last_pid, pid)
+            last_pid = pid
+            self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
+                             process)
+
+    def _test_reap_children_helper(self, runnable, is_running, failed):
+        '''Construct a Init instance, set various data in it according to
+        passed args and check if the component was added to the list of
+        components to restart.'''
+        init = MockInit()
+        init.runnable = runnable
+
+        component = MockComponent('test', 53)
+        component.running = is_running
+        component.has_failed = failed
+        init.components[53] = component
+
+        self.assertNotIn(component, init.components_to_restart)
+
+        init.reap_children()
+
+        if runnable and is_running and not failed:
+            self.assertIn(component, init.components_to_restart)
+        else:
+            self.assertEqual([], init.components_to_restart)
+
+    def test_reap_children(self):
+        '''Test that children are queued to be restarted when they ask for it.'''
+        # test various combinations of 3 booleans
+        # (Init.runnable, component.is_running(), component.failed())
+        self._test_reap_children_helper(False, False, False)
+        self._test_reap_children_helper(False, False, True)
+        self._test_reap_children_helper(False, True,  False)
+        self._test_reap_children_helper(False, True,  True)
+        self._test_reap_children_helper(True,  False, False)
+        self._test_reap_children_helper(True,  False, True)
+        self._test_reap_children_helper(True,  True,  False)
+        self._test_reap_children_helper(True,  True,  True)
+
+        # setup for more tests below
+        init = MockInit()
+        init.runnable = True
+        component = MockComponent('test', 53)
+        init.components[53] = component
+
+        # case where the returned pid is unknown to us. nothing should
+        # happpen then.
+        init.get_process_exit_status_called = False
+        init._get_process_exit_status = init._get_process_exit_status_unknown_pid
+        init.components_to_restart = []
+        # this should do nothing as the pid is unknown
+        init.reap_children()
+        self.assertEqual([], init.components_to_restart)
+
+        # case where init._get_process_exit_status() raises OSError with
+        # errno.ECHILD
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_oserror_echild
+        init.components_to_restart = []
+        # this should catch and handle the OSError
+        init.reap_children()
+        self.assertEqual([], init.components_to_restart)
+
+        # case where init._get_process_exit_status() raises OSError with
+        # errno other than ECHILD
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_oserror_other
+        with self.assertRaises(OSError):
+            init.reap_children()
+
+        # case where init._get_process_exit_status() raises something
+        # other than OSError
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_other
+        with self.assertRaises(Exception):
+            init.reap_children()
+
+    def test_kill_started_components(self):
+        '''Test that started components are killed.'''
+        init = MockInit()
+
+        component = MockComponent('test', 53, 'Test')
+        init.components[53] = component
+
+        self.assertEqual([[53, 'test', 'Test']], init.get_processes())
+        init.kill_started_components()
+        self.assertEqual([], init.get_processes())
+        self.assertTrue(component.forceful)
+
+    def _start_msgq_helper(self, init, verbose):
+        init.verbose = verbose
+        pi = init.start_msgq()
+        self.assertEqual('b10-msgq', pi.name)
+        self.assertEqual(['b10-msgq'], pi.args)
+        self.assertTrue(pi.dev_null_stdout)
+        self.assertEqual(pi.dev_null_stderr, not verbose)
+        self.assertEqual({'FOO': 'an env string'}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_start_msgq(self):
+        '''Test that b10-msgq is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'FOO': 'an env string'}
+        init._run_under_unittests = True
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        # non-verbose case
+        self._start_msgq_helper(init, False)
+
+        # verbose case
+        self._start_msgq_helper(init, True)
+
+    def test_start_msgq_timeout(self):
+        '''Test that b10-msgq startup attempts connections several times
+        and times out eventually.'''
+        b10_init = MockInitSimple()
+        b10_init.c_channel_env = {}
+        # set the timeout to an arbitrary pre-determined value (which
+        # code below depends on)
+        b10_init.msgq_timeout = 1
+        b10_init._run_under_unittests = False
+
+        # use the MockProcessInfo creator
+        b10_init._make_process_info = b10_init._make_mock_process_info
+
+        global attempts
+        global tsec
+        attempts = 0
+        tsec = 0
+        self._tmp_time = time.time
+        self._tmp_sleep = time.sleep
+        def _my_time():
+            global attempts
+            global tsec
+            attempts += 1
+            return tsec
+        def _my_sleep(nsec):
+            global tsec
+            tsec += nsec
+        time.time = _my_time
+        time.sleep = _my_sleep
+
+        global cc_sub
+        cc_sub = None
+        class DummySessionAlwaysFails():
+            def __init__(self, socket_file):
+                raise isc.cc.session.SessionError('Connection fails')
+            def group_subscribe(self, s):
+                global cc_sub
+                cc_sub = s
+
+        isc.cc.Session = DummySessionAlwaysFails
+
+        with self.assertRaises(init.CChannelConnectError):
+            # An exception will be thrown here when it eventually times
+            # out.
+            pi = b10_init.start_msgq()
+
+        # time.time() should be called 12 times within the while loop:
+        # starting from 0, and 11 more times from 0.1 to 1.1. There's
+        # another call to time.time() outside the loop, which makes it
+        # 13.
+        self.assertEqual(attempts, 13)
+
+        # group_subscribe() should not have been called here.
+        self.assertIsNone(cc_sub)
+
+        global cc_socket_file
+        cc_socket_file = None
+        cc_sub = None
+        class DummySession():
+            def __init__(self, socket_file):
+                global cc_socket_file
+                cc_socket_file = socket_file
+            def group_subscribe(self, s):
+                global cc_sub
+                cc_sub = s
+
+        isc.cc.Session = DummySession
+
+        # reset values
+        attempts = 0
+        tsec = 0
+
+        pi = b10_init.start_msgq()
+
+        # just one attempt, but 2 calls to time.time()
+        self.assertEqual(attempts, 2)
+
+        self.assertEqual(cc_socket_file, b10_init.msgq_socket_file)
+        self.assertEqual(cc_sub, 'Init')
+
+        # isc.cc.Session, time.time() and time.sleep() are restored
+        # during tearDown().
+
+    def _start_cfgmgr_helper(self, init, data_path, filename, clear_config):
+        expect_args = ['b10-cfgmgr']
+        if data_path is not None:
+            init.data_path = data_path
+            expect_args.append('--data-path=' + data_path)
+        if filename is not None:
+            init.config_filename = filename
+            expect_args.append('--config-filename=' + filename)
+        if clear_config:
+            init.clear_config = clear_config
+            expect_args.append('--clear-config')
+
+        pi = init.start_cfgmgr()
+        self.assertEqual('b10-cfgmgr', pi.name)
+        self.assertEqual(expect_args, pi.args)
+        self.assertEqual({'TESTENV': 'A test string'}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_start_cfgmgr(self):
+        '''Test that b10-cfgmgr is started.'''
+        class DummySession():
+            def __init__(self):
+                self._tries = 0
+            def group_recvmsg(self):
+                self._tries += 1
+                # return running on the 3rd try onwards
+                if self._tries >= 3:
+                    return ({'running': 'ConfigManager'}, None)
+                else:
+                    return ({}, None)
+
+        init = MockInitSimple()
+        init.c_channel_env = {'TESTENV': 'A test string'}
+        init.cc_session = DummySession()
+        init.wait_time = 5
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        global attempts
+        attempts = 0
+        self._tmp_sleep = time.sleep
+        def _my_sleep(nsec):
+            global attempts
+            attempts += 1
+        time.sleep = _my_sleep
+
+        # defaults
+        self._start_cfgmgr_helper(init, None, None, False)
+
+        # check that 2 attempts were made. on the 3rd attempt,
+        # process_running() returns that ConfigManager is running.
+        self.assertEqual(attempts, 2)
+
+        # data_path is specified
+        self._start_cfgmgr_helper(init, '/var/lib/test', None, False)
+
+        # config_filename is specified. Because `init` is not
+        # reconstructed, data_path is retained from the last call to
+        # _start_cfgmgr_helper().
+        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', False)
+
+        # clear_config is specified. Because `init` is not reconstructed,
+        # data_path and config_filename are retained from the last call
+        # to _start_cfgmgr_helper().
+        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', True)
+
+    def test_start_cfgmgr_timeout(self):
+        '''Test that b10-cfgmgr startup attempts connections several times
+        and times out eventually.'''
+        class DummySession():
+            def group_recvmsg(self):
+                return (None, None)
+        b10_init = MockInitSimple()
+        b10_init.c_channel_env = {}
+        b10_init.cc_session = DummySession()
+        # set wait_time to an arbitrary pre-determined value (which code
+        # below depends on)
+        b10_init.wait_time = 2
+
+        # use the MockProcessInfo creator
+        b10_init._make_process_info = b10_init._make_mock_process_info
+
+        global attempts
+        attempts = 0
+        self._tmp_sleep = time.sleep
+        def _my_sleep(nsec):
+            global attempts
+            attempts += 1
+        time.sleep = _my_sleep
+
+        # We just check that an exception was thrown, and that several
+        # attempts were made to connect.
+        with self.assertRaises(init.ProcessStartError):
+            pi = b10_init.start_cfgmgr()
+
+        # 2 seconds of attempts every 1 second should result in 2 attempts
+        self.assertEqual(attempts, 2)
+
+        # time.sleep() is restored during tearDown().
+
+    def test_start_ccsession(self):
+        '''Test that CC session is started.'''
+        class DummySession():
+            def __init__(self, specfile, config_handler, command_handler,
+                         socket_file):
+                self.specfile = specfile
+                self.config_handler = config_handler
+                self.command_handler = command_handler
+                self.socket_file = socket_file
+                self.started = False
+            def start(self):
+                self.started = True
+        b10_init = MockInitSimple()
+        self._tmp_module_cc_session = isc.config.ModuleCCSession
+        isc.config.ModuleCCSession = DummySession
+
+        b10_init.start_ccsession({})
+        self.assertEqual(init.SPECFILE_LOCATION, b10_init.ccs.specfile)
+        self.assertEqual(b10_init.config_handler, b10_init.ccs.config_handler)
+        self.assertEqual(b10_init.command_handler,
+                         b10_init.ccs.command_handler)
+        self.assertEqual(b10_init.msgq_socket_file, b10_init.ccs.socket_file)
+        self.assertTrue(b10_init.ccs.started)
+
+        # isc.config.ModuleCCSession is restored during tearDown().
+
+    def test_start_process(self):
+        '''Test that processes can be started.'''
+        init = MockInit()
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        pi = init.start_process('Test Process', ['/bin/true'], {})
+        self.assertEqual('Test Process', pi.name)
+        self.assertEqual(['/bin/true'], pi.args)
+        self.assertEqual({}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_register_process(self):
+        '''Test that processes can be registered with Init.'''
+        init = MockInit()
+        component = MockComponent('test', 53, 'Test')
+
+        self.assertFalse(53 in init.components)
+        init.register_process(53, component)
+        self.assertTrue(53 in init.components)
+        self.assertEqual(init.components[53].name(), 'test')
+        self.assertEqual(init.components[53].pid(), 53)
+        self.assertEqual(init.components[53].address(), 'Test')
+
+    def _start_simple_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['/bin/true']
+        if verbose:
+            args.append('-v')
+
+        init.start_simple('/bin/true')
+        self.assertEqual('/bin/true', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'TESTENV': 'A test string'}, init.started_process_env)
+
+    def test_start_simple(self):
+        '''Test simple process startup.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'TESTENV': 'A test string'}
+
+        # non-verbose case
+        self._start_simple_helper(init, False)
+
+        # verbose case
+        self._start_simple_helper(init, True)
+
+    def _start_auth_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['b10-auth']
+        if verbose:
+            args.append('-v')
+
+        init.start_auth()
+        self.assertEqual('b10-auth', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'FOO': 'an env string'}, init.started_process_env)
+
+    def test_start_auth(self):
+        '''Test that b10-auth is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'FOO': 'an env string'}
+
+        # non-verbose case
+        self._start_auth_helper(init, False)
+
+        # verbose case
+        self._start_auth_helper(init, True)
+
+    def _start_resolver_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['b10-resolver']
+        if verbose:
+            args.append('-v')
+
+        init.start_resolver()
+        self.assertEqual('b10-resolver', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'BAR': 'an env string'}, init.started_process_env)
+
+    def test_start_resolver(self):
+        '''Test that b10-resolver is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'BAR': 'an env string'}
+
+        # non-verbose case
+        self._start_resolver_helper(init, False)
+
+        # verbose case
+        self._start_resolver_helper(init, True)
+
+    def _start_cmdctl_helper(self, init, verbose, port = None):
+        init.verbose = verbose
+
+        args = ['b10-cmdctl']
+
+        if port is not None:
+            init.cmdctl_port = port
+            args.append('--port=9353')
+
+        if verbose:
+            args.append('-v')
+
+        init.start_cmdctl()
+        self.assertEqual('b10-cmdctl', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'BAZ': 'an env string'}, init.started_process_env)
+
+    def test_start_cmdctl(self):
+        '''Test that b10-cmdctl is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'BAZ': 'an env string'}
+
+        # non-verbose case
+        self._start_cmdctl_helper(init, False)
+
+        # verbose case
+        self._start_cmdctl_helper(init, True)
+
+        # with port, non-verbose case
+        self._start_cmdctl_helper(init, False, 9353)
+
+        # with port, verbose case
+        self._start_cmdctl_helper(init, True, 9353)
+
+    def test_socket_data(self):
+        '''Test that Init._socket_data works as expected.'''
+        class MockSock:
+            def __init__(self, fd, throw):
+                self.fd = fd
+                self.throw = throw
+                self.buf = b'Hello World.\nYou are so nice today.\nXX'
+                self.i = 0
+
+            def recv(self, bufsize, flags = 0):
+                if bufsize != 1:
+                    raise Exception('bufsize != 1')
+                if flags != socket.MSG_DONTWAIT:
+                    raise Exception('flags != socket.MSG_DONTWAIT')
+                # after 15 recv()s, throw a socket.error with EAGAIN to
+                # get _socket_data() to save back what's been read. The
+                # number 15 is arbitrarily chosen, but the checks then
+                # depend on this being 15, i.e., if you adjust this
+                # number, you may have to adjust the checks below too.
+                if self.throw and self.i > 15:
+                    raise socket.error(errno.EAGAIN, 'Try again')
+                if self.i >= len(self.buf):
+                    return b'';
+                t = self.i
+                self.i += 1
+                return self.buf[t:t+1]
+
+            def close(self):
+                return
+
+        class MockInitSocketData(Init):
+            def __init__(self, throw):
+                self._unix_sockets = {42: (MockSock(42, throw), b'')}
+                self.requests = []
+                self.dead = []
+
+            def socket_request_handler(self, previous, sock):
+                self.requests.append({sock.fd: previous})
+
+            def socket_consumer_dead(self, sock):
+                self.dead.append(sock.fd)
+
+        # Case where we get data every time we call recv()
+        init = MockInitSocketData(False)
+        init._socket_data(42)
+        self.assertEqual(init.requests,
+                         [{42: b'Hello World.'},
+                          {42: b'You are so nice today.'}])
+        self.assertEqual(init.dead, [42])
+        self.assertEqual({}, init._unix_sockets)
+
+        # Case where socket.recv() raises EAGAIN. In this case, the
+        # routine is supposed to save what it has back to
+        # Init._unix_sockets.
+        init = MockInitSocketData(True)
+        init._socket_data(42)
+        self.assertEqual(init.requests, [{42: b'Hello World.'}])
+        self.assertFalse(init.dead)
+        self.assertEqual(len(init._unix_sockets), 1)
+        self.assertEqual(init._unix_sockets[42][1], b'You')
+
+    def test_startup(self):
+        '''Test that Init.startup() handles failures properly.'''
+        class MockInitStartup(Init):
+            def __init__(self, throw):
+                self.throw = throw
+                self.started = False
+                self.killed = False
+                self.msgq_socket_file = None
+                self.curproc = 'myproc'
+                self.runnable = False
+
+            def start_all_components(self):
+                self.started = True
+                if self.throw is True:
+                    raise Exception('Assume starting components has failed.')
+                elif self.throw:
+                    raise self.throw
+
+            def kill_started_components(self):
+                self.killed = True
+
+        class DummySession():
+            def __init__(self, socket_file):
+                raise isc.cc.session.SessionError('This is the expected case.')
+
+        class DummySessionSocketExists():
+            def __init__(self, socket_file):
+                # simulate that connect passes
+                return
+
+        isc.cc.Session = DummySession
+
+        # All is well case, where all components are started
+        # successfully. We check that the actual call to
+        # start_all_components() is made, and Init.runnable is true.
+        b10_init = MockInitStartup(False)
+        r = b10_init.startup()
+        self.assertIsNone(r)
+        self.assertTrue(b10_init.started)
+        self.assertFalse(b10_init.killed)
+        self.assertTrue(b10_init.runnable)
+        self.assertEqual({}, b10_init.c_channel_env)
+
+        # Case where starting components fails. We check that
+        # kill_started_components() is called right after, and
+        # Init.runnable is not modified.
+        b10_init = MockInitStartup(True)
+        r = b10_init.startup()
+        # r contains an error message
+        self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
+        self.assertTrue(b10_init.started)
+        self.assertTrue(b10_init.killed)
+        self.assertFalse(b10_init.runnable)
+        self.assertEqual({}, b10_init.c_channel_env)
+
+        # Check if msgq_socket_file is carried over
+        b10_init = MockInitStartup(False)
+        b10_init.msgq_socket_file = 'foo'
+        r = b10_init.startup()
+        self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'},
+                         b10_init.c_channel_env)
+
+        # Check failure of changing user results in a different message
+        b10_init = MockInitStartup(init.ChangeUserError('failed to chusr'))
+        r = b10_init.startup()
+        self.assertIn('failed to chusr', r)
+        self.assertTrue(b10_init.killed)
+
+        # Check the case when socket file already exists
+        isc.cc.Session = DummySessionSocketExists
+        b10_init = MockInitStartup(False)
+        r = b10_init.startup()
+        self.assertIn('already running', r)
+
+        # isc.cc.Session is restored during tearDown().
+
+class SocketSrvTest(unittest.TestCase):
+    """
+    This tests some methods of b10-init related to the unix domain sockets
+    used to transfer other sockets to applications.
+    """
+    def setUp(self):
+        """
+        Create the b10-init to test, testdata and backup some functions.
+        """
+        self.__b10_init = Init()
+        self.__select_backup = init.select.select
+        self.__select_called = None
+        self.__socket_data_called = None
+        self.__consumer_dead_called = None
+        self.__socket_request_handler_called = None
+
+    def tearDown(self):
+        """
+        Restore functions.
+        """
+        init.select.select = self.__select_backup
+
+    class __FalseSocket:
+        """
+        A mock socket for the select and accept and stuff like that.
+        """
+        def __init__(self, owner, fileno=42):
+            self.__owner = owner
+            self.__fileno = fileno
+            self.data = None
+            self.closed = False
+
+        def fileno(self):
+            return self.__fileno
+
+        def accept(self):
+            return (self.__class__(self.__owner, 13), "/path/to/socket")
+
+        def recv(self, bufsize, flags=0):
+            self.__owner.assertEqual(1, bufsize)
+            self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
+            if isinstance(self.data, socket.error):
+                raise self.data
+            elif self.data is not None:
+                if len(self.data):
+                    result = self.data[0:1]
+                    self.data = self.data[1:]
+                    return result
+                else:
+                    raise socket.error(errno.EAGAIN, "Would block")
+            else:
+                return b''
+
+        def close(self):
+            self.closed = True
+
+    class __CCS:
+        """
+        A mock CCS, just to provide the socket file number.
+        """
+        class __Socket:
+            def fileno(self):
+                return 1
+        def get_socket(self):
+            return self.__Socket()
+
+    def __select_accept(self, r, w, x, t):
+        self.__select_called = (r, w, x, t)
+        return ([42], [], [])
+
+    def __select_data(self, r, w, x, t):
+        self.__select_called = (r, w, x, t)
+        return ([13], [], [])
+
+    def __accept(self):
+        """
+        Hijack the accept method of the b10-init.
+
+        Notes down it was called and stops b10-init.
+        """
+        self.__accept_called = True
+        self.__b10_init.runnable = False
+
+    def test_srv_accept_called(self):
+        """
+        Test that the _srv_accept method of b10-init is called when the
+        listening socket is readable.
+        """
+        self.__b10_init.runnable = True
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._srv_accept = self.__accept
+        self.__b10_init.ccs = self.__CCS()
+        init.select.select = self.__select_accept
+        self.__b10_init.run(2)
+        # It called the accept
+        self.assertTrue(self.__accept_called)
+        # And the select had the right parameters
+        self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
+
+    def test_srv_accept(self):
+        """
+        Test how the _srv_accept method works.
+        """
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._srv_accept()
+        # After we accepted, a new socket is added there
+        socket = self.__b10_init._unix_sockets[13][0]
+        # The socket is properly stored there
+        self.assertTrue(isinstance(socket, self.__FalseSocket))
+        # And the buffer (yet empty) is there
+        self.assertEqual({13: (socket, b'')}, self.__b10_init._unix_sockets)
+
+    def __socket_data(self, socket):
+        self.__b10_init.runnable = False
+        self.__socket_data_called = socket
+
+    def test_socket_data(self):
+        """
+        Test that a socket that wants attention gets it.
+        """
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._socket_data = self.__socket_data
+        self.__b10_init.ccs = self.__CCS()
+        self.__b10_init._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
+        self.__b10_init.runnable = True
+        init.select.select = self.__select_data
+        self.__b10_init.run(2)
+        self.assertEqual(13, self.__socket_data_called)
+        self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
+
+    def __prepare_data(self, data):
+        socket = self.__FalseSocket(self, 13)
+        self.__b10_init._unix_sockets = {13: (socket, b'')}
+        socket.data = data
+        self.__b10_init.socket_consumer_dead = self.__consumer_dead
+        self.__b10_init.socket_request_handler = self.__socket_request_handler
+        return socket
+
+    def __consumer_dead(self, socket):
+        self.__consumer_dead_called = socket
+
+    def __socket_request_handler(self, token, socket):
+        self.__socket_request_handler_called = (token, socket)
+
+    def test_socket_closed(self):
+        """
+        Test that a socket is removed and the socket_consumer_dead is called
+        when it is closed.
+        """
+        socket = self.__prepare_data(None)
+        self.__b10_init._socket_data(13)
+        self.assertEqual(socket, self.__consumer_dead_called)
+        self.assertEqual({}, self.__b10_init._unix_sockets)
+        self.assertTrue(socket.closed)
+
+    def test_socket_short(self):
+        """
+        Test that if there's not enough data to get the whole socket, it is
+        kept there, but nothing is called.
+        """
+        socket = self.__prepare_data(b'tok')
+        self.__b10_init._socket_data(13)
+        self.assertEqual({13: (socket, b'tok')}, self.__b10_init._unix_sockets)
+        self.assertFalse(socket.closed)
+        self.assertIsNone(self.__consumer_dead_called)
+        self.assertIsNone(self.__socket_request_handler_called)
+
+    def test_socket_continue(self):
+        """
+        Test that we call the token handling function when the whole token
+        comes. This test pretends to continue reading where the previous one
+        stopped.
+        """
+        socket = self.__prepare_data(b"en\nanothe")
+        # The data to finish
+        self.__b10_init._unix_sockets[13] = (socket, b'tok')
+        self.__b10_init._socket_data(13)
+        self.assertEqual({13: (socket, b'anothe')}, self.__b10_init._unix_sockets)
+        self.assertFalse(socket.closed)
+        self.assertIsNone(self.__consumer_dead_called)
+        self.assertEqual((b'token', socket),
+                         self.__socket_request_handler_called)
+
+    def test_broken_socket(self):
+        """
+        If the socket raises an exception during the read other than EAGAIN,
+        it is broken and we remove it.
+        """
+        sock = self.__prepare_data(socket.error(errno.ENOMEM,
+            "There's more memory available, but not for you"))
+        self.__b10_init._socket_data(13)
+        self.assertEqual(sock, self.__consumer_dead_called)
+        self.assertEqual({}, self.__b10_init._unix_sockets)
+        self.assertTrue(sock.closed)
+
+class TestFunctions(unittest.TestCase):
+    def setUp(self):
+        self.lockfile_testpath = \
+            "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
+        self.assertFalse(os.path.exists(self.lockfile_testpath))
+        os.mkdir(self.lockfile_testpath)
+        self.assertTrue(os.path.isdir(self.lockfile_testpath))
+        self.__isfile_orig = init.os.path.isfile
+        self.__unlink_orig = init.os.unlink
+
+    def tearDown(self):
+        os.rmdir(self.lockfile_testpath)
+        self.assertFalse(os.path.isdir(self.lockfile_testpath))
+        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
+        init.os.path.isfile = self.__isfile_orig
+        init.os.unlink = self.__unlink_orig
+
+    def test_remove_lock_files(self):
+        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
+
+        # create lockfiles for the testcase
+        lockfiles = ["logger_lockfile"]
+        for f in lockfiles:
+            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+            self.assertFalse(os.path.exists(fname))
+            open(fname, "w").close()
+            self.assertTrue(os.path.isfile(fname))
+
+        # first call should clear up all the lockfiles
+        init.remove_lock_files()
+
+        # check if the lockfiles exist
+        for f in lockfiles:
+            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+            self.assertFalse(os.path.isfile(fname))
+
+        # second call should not assert anyway
+        init.remove_lock_files()
+
+    def test_remove_lock_files_fail(self):
+        # Permission error on unlink is ignored; other exceptions are really
+        # unexpected and propagated.
+        def __raising_unlink(unused, ex):
+            raise ex
+
+        init.os.path.isfile = lambda _: True
+        os_error = OSError()
+        init.os.unlink = lambda f: __raising_unlink(f, os_error)
+
+        os_error.errno = errno.EPERM
+        init.remove_lock_files() # no disruption
+
+        os_error.errno = errno.EACCES
+        init.remove_lock_files() # no disruption
+
+        os_error.errno = errno.ENOENT
+        self.assertRaises(OSError, init.remove_lock_files)
+
+        init.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
+        self.assertRaises(Exception, init.remove_lock_files)
+
+    def test_get_signame(self):
+        # just test with some samples
+        signame = init.get_signame(signal.SIGTERM)
+        self.assertEqual('SIGTERM', signame)
+        signame = init.get_signame(signal.SIGKILL)
+        self.assertEqual('SIGKILL', signame)
+        # 59426 is hopefully an unused signal on most platforms
+        signame = init.get_signame(59426)
+        self.assertEqual('Unknown signal 59426', signame)
+
+    def test_fatal_signal(self):
+        self.assertIsNone(init.b10_init)
+        init.b10_init = Init()
+        init.b10_init.runnable = True
+        init.fatal_signal(signal.SIGTERM, None)
+        # Now, runnable must be False
+        self.assertFalse(init.b10_init.runnable)
+        init.b10_init = None
+
+if __name__ == '__main__':
+    # store os.environ for test_unchanged_environment
+    original_os_environ = copy.deepcopy(os.environ)
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()
diff --git a/src/bin/bindctl/bindcmd.py b/src/bin/bindctl/bindcmd.py
index 7c2b2af..f382e2a 100644
--- a/src/bin/bindctl/bindcmd.py
+++ b/src/bin/bindctl/bindcmd.py
@@ -25,7 +25,7 @@ from bindctl.moduleinfo import *
 from bindctl.cmdparse import BindCmdParser
 from bindctl import command_sets
 from xml.dom import minidom
-import isc
+import isc.config
 import isc.cc.data
 import http.client
 import json
@@ -39,6 +39,7 @@ import csv
 import pwd
 import getpass
 import copy
+import errno
 
 try:
     from collections import OrderedDict
@@ -123,6 +124,11 @@ class BindCmdInterpreter(Cmd):
             self.csv_file_dir = pwd.getpwnam(getpass.getuser()).pw_dir + \
                 os.sep + '.bind10' + os.sep
 
+    def _print(self, *args):
+        '''Simple wrapper around calls to print that can be overridden in
+           unit tests.'''
+        print(*args)
+
     def _get_session_id(self):
         '''Generate one session id for the connection. '''
         rand = os.urandom(16)
@@ -150,19 +156,19 @@ WARNING: Python readline module isn't available, so the command line editor
                 return 1
 
             self.cmdloop()
-            print('\nExit from bindctl')
+            self._print('\nExit from bindctl')
             return 0
         except FailToLogin as err:
             # error already printed when this was raised, ignoring
             return 1
         except KeyboardInterrupt:
-            print('\nExit from bindctl')
+            self._print('\nExit from bindctl')
             return 0
         except socket.error as err:
-            print('Failed to send request, the connection is closed')
+            self._print('Failed to send request, the connection is closed')
             return 1
         except http.client.CannotSendRequest:
-            print('Can not send request, the connection is busy')
+            self._print('Can not send request, the connection is busy')
             return 1
 
     def _get_saved_user_info(self, dir, file_name):
@@ -181,7 +187,8 @@ WARNING: Python readline module isn't available, so the command line editor
             for row in users_info:
                 users.append([row[0], row[1]])
         except (IOError, IndexError) as err:
-            print("Error reading saved username and password from %s%s: %s" % (dir, file_name, err))
+            self._print("Error reading saved username and password "
+                        "from %s%s: %s" % (dir, file_name, err))
         finally:
             if csvfile:
                 csvfile.close()
@@ -201,12 +208,48 @@ WARNING: Python readline module isn't available, so the command line editor
             writer.writerow([username, passwd])
             csvfile.close()
         except IOError as err:
-            print("Error saving user information:", err)
-            print("user info file name: %s%s" % (dir, file_name))
+            self._print("Error saving user information:", err)
+            self._print("user info file name: %s%s" % (dir, file_name))
             return False
 
         return True
 
+    def __print_check_ssl_msg(self):
+        self._print("Please check the logs of b10-cmdctl, there may "
+                    "be a problem accepting SSL connections, such "
+                    "as a permission problem on the server "
+                    "certificate file.")
+
+    def _try_login(self, username, password):
+        '''
+        Attempts to log in to cmdctl by sending a POST with
+        the given username and password.
+        On success of the POST (mind, not the login, only the network
+        operation), returns a tuple (response, data).
+        On failure, raises a FailToLogin exception, and prints some
+        information on the failure.
+        This call is essentially 'private', but made 'protected' for
+        easier testing.
+        '''
+        param = {'username': username, 'password' : password}
+        try:
+            response = self.send_POST('/login', param)
+            data = response.read().decode()
+            # return here (will raise error after try block)
+            return (response, data)
+        except ssl.SSLError as err:
+            self._print("SSL error while sending login information: ", err)
+            if err.errno == ssl.SSL_ERROR_EOF:
+                self.__print_check_ssl_msg()
+        except socket.error as err:
+            self._print("Socket error while sending login information: ", err)
+            # An SSL setup error can also bubble up as a plain CONNRESET...
+            # (on some systems it usually does)
+            if err.errno == errno.ECONNRESET:
+                self.__print_check_ssl_msg()
+            pass
+        raise FailToLogin()
+
     def login_to_cmdctl(self):
         '''Login to cmdctl with the username and password given by
         the user. After the login is sucessful, the username and
@@ -217,41 +260,30 @@ WARNING: Python readline module isn't available, so the command line editor
         # Look at existing username/password combinations and try to log in
         users = self._get_saved_user_info(self.csv_file_dir, CSV_FILE_NAME)
         for row in users:
-            param = {'username': row[0], 'password' : row[1]}
-            try:
-                response = self.send_POST('/login', param)
-                data = response.read().decode()
-            except socket.error as err:
-                print("Socket error while sending login information:", err)
-                raise FailToLogin()
+            response, data = self._try_login(row[0], row[1])
 
             if response.status == http.client.OK:
                 # Is interactive?
                 if sys.stdin.isatty():
-                    print(data + ' login as ' + row[0])
+                    self._print(data + ' login as ' + row[0])
                 return True
 
         # No valid logins were found, prompt the user for a username/password
         count = 0
-        print('No stored password file found, please see sections '
+        self._print('No stored password file found, please see sections '
               '"Configuration specification for b10-cmdctl" and "bindctl '
               'command-line options" of the BIND 10 guide.')
         while True:
             count = count + 1
             if count > 3:
-                print("Too many authentication failures")
+                self._print("Too many authentication failures")
                 return False
 
             username = input("Username: ")
             passwd = getpass.getpass()
-            param = {'username': username, 'password' : passwd}
-            try:
-                response = self.send_POST('/login', param)
-                data = response.read().decode()
-                print(data)
-            except socket.error as err:
-                print("Socket error while sending login information:", err)
-                raise FailToLogin()
+
+            response, data = self._try_login(username, passwd)
+            self._print(data)
 
             if response.status == http.client.OK:
                 self._save_user_info(username, passwd, self.csv_file_dir,
@@ -449,25 +481,26 @@ WARNING: Python readline module isn't available, so the command line editor
         pass
 
     def do_help(self, name):
-        print(CONST_BINDCTL_HELP)
+        self._print(CONST_BINDCTL_HELP)
         for k in self.modules.values():
             n = k.get_name()
             if len(n) >= CONST_BINDCTL_HELP_INDENT_WIDTH:
-                print("    %s" % n)
-                print(textwrap.fill(k.get_desc(),
-                      initial_indent="            ",
-                      subsequent_indent="    " +
-                      " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
-                      width=70))
+                self._print("    %s" % n)
+                self._print(textwrap.fill(k.get_desc(),
+                            initial_indent="            ",
+                            subsequent_indent="    " +
+                            " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
+                            width=70))
             else:
-                print(textwrap.fill("%s%s%s" %
-                    (k.get_name(),
-                     " "*(CONST_BINDCTL_HELP_INDENT_WIDTH - len(k.get_name())),
-                     k.get_desc()),
-                    initial_indent="    ",
-                    subsequent_indent="    " +
-                    " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
-                    width=70))
+                self._print(textwrap.fill("%s%s%s" %
+                            (k.get_name(),
+                            " "*(CONST_BINDCTL_HELP_INDENT_WIDTH -
+                                 len(k.get_name())),
+                            k.get_desc()),
+                            initial_indent="    ",
+                            subsequent_indent="    " +
+                            " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
+                            width=70))
 
     def onecmd(self, line):
         if line == 'EOF' or line.lower() == "quit":
@@ -642,20 +675,20 @@ WARNING: Python readline module isn't available, so the command line editor
             self._validate_cmd(cmd)
             self._handle_cmd(cmd)
         except (IOError, http.client.HTTPException) as err:
-            print('Error: ', err)
+            self._print('Error: ', err)
         except BindCtlException as err:
-            print("Error! ", err)
+            self._print("Error! ", err)
             self._print_correct_usage(err)
         except isc.cc.data.DataTypeError as err:
-            print("Error! ", err)
+            self._print("Error! ", err)
         except isc.cc.data.DataTypeError as dte:
-            print("Error: " + str(dte))
+            self._print("Error: " + str(dte))
         except isc.cc.data.DataNotFoundError as dnfe:
-            print("Error: " + str(dnfe))
+            self._print("Error: " + str(dnfe))
         except isc.cc.data.DataAlreadyPresentError as dape:
-            print("Error: " + str(dape))
+            self._print("Error: " + str(dape))
         except KeyError as ke:
-            print("Error: missing " + str(ke))
+            self._print("Error: missing " + str(ke))
 
     def _print_correct_usage(self, ept):
         if isinstance(ept, CmdUnknownModuleSyntaxError):
@@ -704,7 +737,8 @@ WARNING: Python readline module isn't available, so the command line editor
             module_name = identifier.split('/')[1]
             if module_name != "" and (self.config_data is None or \
                not self.config_data.have_specification(module_name)):
-                print("Error: Module '" + module_name + "' unknown or not running")
+                self._print("Error: Module '" + module_name +
+                            "' unknown or not running")
                 return
 
         if cmd.command == "show":
@@ -718,7 +752,9 @@ WARNING: Python readline module isn't available, so the command line editor
                     #identifier
                     identifier += cmd.params['argument']
                 else:
-                    print("Error: unknown argument " + cmd.params['argument'] + ", or multiple identifiers given")
+                    self._print("Error: unknown argument " +
+                                cmd.params['argument'] +
+                                ", or multiple identifiers given")
                     return
             values = self.config_data.get_value_maps(identifier, show_all)
             for value_map in values:
@@ -746,13 +782,14 @@ WARNING: Python readline module isn't available, so the command line editor
                     line += "(default)"
                 if value_map['modified']:
                     line += "(modified)"
-                print(line)
+                self._print(line)
         elif cmd.command == "show_json":
             if identifier == "":
-                print("Need at least the module to show the configuration in JSON format")
+                self._print("Need at least the module to show the "
+                            "configuration in JSON format")
             else:
                 data, default = self.config_data.get_value(identifier)
-                print(json.dumps(data))
+                self._print(json.dumps(data))
         elif cmd.command == "add":
             self.config_data.add_value(identifier,
                                        cmd.params.get('value_or_name'),
@@ -764,7 +801,7 @@ WARNING: Python readline module isn't available, so the command line editor
                 self.config_data.remove_value(identifier, None)
         elif cmd.command == "set":
             if 'identifier' not in cmd.params:
-                print("Error: missing identifier or value")
+                self._print("Error: missing identifier or value")
             else:
                 parsed_value = None
                 try:
@@ -781,9 +818,9 @@ WARNING: Python readline module isn't available, so the command line editor
             try:
                 self.config_data.commit()
             except isc.config.ModuleCCSessionError as mcse:
-                print(str(mcse))
+                self._print(str(mcse))
         elif cmd.command == "diff":
-            print(self.config_data.get_local_changes())
+            self._print(self.config_data.get_local_changes())
         elif cmd.command == "go":
             self.go(identifier)
 
@@ -803,7 +840,7 @@ WARNING: Python readline module isn't available, so the command line editor
         # check if exists, if not, revert and error
         v,d = self.config_data.get_value(new_location)
         if v is None:
-            print("Error: " + identifier + " not found")
+            self._print("Error: " + identifier + " not found")
             return
 
         self.location = new_location
@@ -818,7 +855,7 @@ WARNING: Python readline module isn't available, so the command line editor
                 with open(command.params['filename']) as command_file:
                     commands = command_file.readlines()
             except IOError as ioe:
-                print("Error: " + str(ioe))
+                self._print("Error: " + str(ioe))
                 return
         elif command_sets.has_command_set(command.command):
             commands = command_sets.get_commands(command.command)
@@ -836,7 +873,7 @@ WARNING: Python readline module isn't available, so the command line editor
     def __show_execute_commands(self, commands):
         '''Prints the command list without executing them'''
         for line in commands:
-            print(line.strip())
+            self._print(line.strip())
 
     def __apply_execute_commands(self, commands):
         '''Applies the configuration commands from the given iterator.
@@ -857,18 +894,19 @@ WARNING: Python readline module isn't available, so the command line editor
             for line in commands:
                 line = line.strip()
                 if verbose:
-                    print(line)
+                    self._print(line)
                 if line.startswith('#') or len(line) == 0:
                     continue
                 elif line.startswith('!'):
                     if re.match('^!echo ', line, re.I) and len(line) > 6:
-                        print(line[6:])
+                        self._print(line[6:])
                     elif re.match('^!verbose\s+on\s*$', line, re.I):
                         verbose = True
                     elif re.match('^!verbose\s+off$', line, re.I):
                         verbose = False
                     else:
-                        print("Warning: ignoring unknown directive: " + line)
+                        self._print("Warning: ignoring unknown directive: " +
+                                    line)
                 else:
                     cmd = BindCmdParser(line)
                     self._validate_cmd(cmd)
@@ -879,12 +917,12 @@ WARNING: Python readline module isn't available, so the command line editor
                 isc.cc.data.DataNotFoundError,
                 isc.cc.data.DataAlreadyPresentError,
                 KeyError) as err:
-            print('Error: ', err)
-            print()
-            print('Depending on the contents of the script, and which')
-            print('commands it has called, there can be committed and')
-            print('local changes. It is advised to check your settings,')
-            print('and revert local changes with "config revert".')
+            self._print('Error: ', err)
+            self._print()
+            self._print('Depending on the contents of the script, and which')
+            self._print('commands it has called, there can be committed and')
+            self._print('local changes. It is advised to check your settings')
+            self._print(', and revert local changes with "config revert".')
 
     def apply_cmd(self, cmd):
         '''Handles a general module command'''
@@ -898,6 +936,7 @@ WARNING: Python readline module isn't available, so the command line editor
         # The reply is a string containing JSON data,
         # parse it, then prettyprint
         if data != "" and data != "{}":
-            print(json.dumps(json.loads(data), sort_keys=True, indent=4))
+            self._print(json.dumps(json.loads(data), sort_keys=True,
+                                   indent=4))
 
 
diff --git a/src/bin/bindctl/bindctl.xml b/src/bin/bindctl/bindctl.xml
index 3993739..426c478 100644
--- a/src/bin/bindctl/bindctl.xml
+++ b/src/bin/bindctl/bindctl.xml
@@ -218,7 +218,7 @@
        <command>config</command> for Configuration commands.
 <!-- TODO: or is config from the cfgmgr module? -->
        Additional modules may be available, such as
-       <command>Boss</command>, <command>Xfrin</command>, and
+       <command>Init</command>, <command>Xfrin</command>, and
        <command>Auth</command>.
      </para>
 
@@ -305,16 +305,13 @@ configuration location.
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
-        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
-        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
diff --git a/src/bin/bindctl/bindctl_main.py.in b/src/bin/bindctl/bindctl_main.py.in
index 546ecc0..875b06e 100755
--- a/src/bin/bindctl/bindctl_main.py.in
+++ b/src/bin/bindctl/bindctl_main.py.in
@@ -34,7 +34,7 @@ isc.util.process.rename()
 # number, and the overall BIND 10 version number (set in configure.ac).
 VERSION = "bindctl 20110217 (BIND 10 @PACKAGE_VERSION@)"
 
-DEFAULT_IDENTIFIER_DESC = "The identifier specifies the config item. Child elements are separated with the '/' character. List indices can be specified with '[i]', where i is an integer specifying the index, starting with 0. Examples: 'Boss/start_auth', 'Recurse/listen_on[0]/address'. If no identifier is given, shows the item at the current location."
+DEFAULT_IDENTIFIER_DESC = "The identifier specifies the config item. Child elements are separated with the '/' character. List indices can be specified with '[i]', where i is an integer specifying the index, starting with 0. Examples: 'Init/start_auth', 'Auth/listen_on[0]/address'. If no identifier is given, shows the item at the current location."
 
 def prepare_config_commands(tool):
     '''Prepare fixed commands for local configuration editing'''
diff --git a/src/bin/bindctl/command_sets.py b/src/bin/bindctl/command_sets.py
index c001ec8..b146c38 100644
--- a/src/bin/bindctl/command_sets.py
+++ b/src/bin/bindctl/command_sets.py
@@ -35,21 +35,21 @@ command_sets = {
         'commands':
             [
             '!echo adding Authoritative server component',
-            'config add /Boss/components b10-auth',
-            'config set /Boss/components/b10-auth/kind needed',
-            'config set /Boss/components/b10-auth/special auth',
+            'config add /Init/components b10-auth',
+            'config set /Init/components/b10-auth/kind needed',
+            'config set /Init/components/b10-auth/special auth',
             '!echo adding Xfrin component',
-            'config add /Boss/components b10-xfrin',
-            'config set /Boss/components/b10-xfrin/address Xfrin',
-            'config set /Boss/components/b10-xfrin/kind dispensable',
+            'config add /Init/components b10-xfrin',
+            'config set /Init/components/b10-xfrin/address Xfrin',
+            'config set /Init/components/b10-xfrin/kind dispensable',
             '!echo adding Xfrout component',
-            'config add /Boss/components b10-xfrout',
-            'config set /Boss/components/b10-xfrout/address Xfrout',
-            'config set /Boss/components/b10-xfrout/kind dispensable',
+            'config add /Init/components b10-xfrout',
+            'config set /Init/components/b10-xfrout/address Xfrout',
+            'config set /Init/components/b10-xfrout/kind dispensable',
             '!echo adding Zone Manager component',
-            'config add /Boss/components b10-zonemgr',
-            'config set /Boss/components/b10-zonemgr/address Zonemgr',
-            'config set /Boss/components/b10-zonemgr/kind dispensable',
+            'config add /Init/components b10-zonemgr',
+            'config set /Init/components/b10-zonemgr/address Zonemgr',
+            'config set /Init/components/b10-zonemgr/kind dispensable',
             '!echo Components added. Please enter "config commit" to',
             '!echo finalize initial setup and run the components.'
             ]
diff --git a/src/bin/bindctl/mycollections.py b/src/bin/bindctl/mycollections.py
index 824ef21..42279bd 100644
--- a/src/bin/bindctl/mycollections.py
+++ b/src/bin/bindctl/mycollections.py
@@ -1,3 +1,18 @@
+# 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.
+
 from collections import MutableMapping
 
 class OrderedDict(dict, MutableMapping):
diff --git a/src/bin/bindctl/run_bindctl.sh.in b/src/bin/bindctl/run_bindctl.sh.in
index f4cc40c..97e9250 100755
--- a/src/bin/bindctl/run_bindctl.sh.in
+++ b/src/bin/bindctl/run_bindctl.sh.in
@@ -20,7 +20,7 @@ export PYTHON_EXEC
 
 BINDCTL_PATH=@abs_top_builddir@/src/bin/bindctl
 
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/bindctl/tests/bindctl_test.py b/src/bin/bindctl/tests/bindctl_test.py
index 5c6aeb2..0ec9b58 100644
--- a/src/bin/bindctl/tests/bindctl_test.py
+++ b/src/bin/bindctl/tests/bindctl_test.py
@@ -18,11 +18,14 @@ import unittest
 import isc.cc.data
 import os
 import io
+import errno
 import sys
 import socket
+import ssl
 import http.client
 import pwd
 import getpass
+import re
 from optparse import OptionParser
 from isc.config.config_data import ConfigData, MultiConfigData
 from isc.config.module_spec import ModuleSpec
@@ -335,6 +338,8 @@ class TestConfigCommands(unittest.TestCase):
         self.tool.add_module_info(mod_info)
         self.tool.config_data = FakeCCSession()
         self.stdout_backup = sys.stdout
+        self.printed_messages = []
+        self.tool._print = self.store_print
 
     def test_precmd(self):
         def update_all_modules_info():
@@ -347,6 +352,111 @@ class TestConfigCommands(unittest.TestCase):
         precmd('EOF')
         self.assertRaises(socket.error, precmd, 'continue')
 
+    def store_print(self, *args):
+        '''Method to override _print in BindCmdInterpreter.
+           Instead of printing the values, appends the argument tuple
+           to the list in self.printed_messages'''
+        self.printed_messages.append(" ".join(map(str, args)))
+
+    def __check_printed_message(self, expected_message, printed_message):
+        self.assertIsNotNone(re.match(expected_message, printed_message),
+                             "Printed message '" + printed_message +
+                             "' does not match '" + expected_message + "'")
+
+    def __check_printed_messages(self, expected_messages):
+        '''Helper test function to check the printed messages against a list
+           of regexps'''
+        self.assertEqual(len(expected_messages), len(self.printed_messages))
+        for _ in map(self.__check_printed_message,
+                     expected_messages,
+                     self.printed_messages):
+            pass
+
+    def test_try_login(self):
+        # Make sure __try_login raises the correct exception
+        # upon failure of either send_POST or the read() on the
+        # response
+
+        orig_send_POST = self.tool.send_POST
+        expected_printed_messages = []
+        try:
+            def send_POST_raiseImmediately(self, params):
+                raise socket.error("test error")
+
+            self.tool.send_POST = send_POST_raiseImmediately
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'Socket error while sending login information:  test error')
+            self.__check_printed_messages(expected_printed_messages)
+
+            def create_send_POST_raiseOnRead(exception):
+                '''Create a replacement send_POST() method that raises
+                   the given exception when read() is called on the value
+                   returned from send_POST()'''
+                def send_POST_raiseOnRead(self, params):
+                    class MyResponse:
+                        def read(self):
+                            raise exception
+                    return MyResponse()
+                return send_POST_raiseOnRead
+
+            # basic socket error
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(socket.error("read error"))
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'Socket error while sending login information:  read error')
+            self.__check_printed_messages(expected_printed_messages)
+
+            # connection reset
+            exc = socket.error("connection reset")
+            exc.errno = errno.ECONNRESET
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'Socket error while sending login information:  '
+                'connection reset')
+            expected_printed_messages.append(
+                'Please check the logs of b10-cmdctl, there may be a '
+                'problem accepting SSL connections, such as a permission '
+                'problem on the server certificate file.'
+            )
+            self.__check_printed_messages(expected_printed_messages)
+
+            # 'normal' SSL error
+            exc = ssl.SSLError()
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'SSL error while sending login information:  .*')
+            self.__check_printed_messages(expected_printed_messages)
+
+            # 'EOF' SSL error
+            exc = ssl.SSLError()
+            exc.errno = ssl.SSL_ERROR_EOF
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'SSL error while sending login information: .*')
+            expected_printed_messages.append(
+                'Please check the logs of b10-cmdctl, there may be a '
+                'problem accepting SSL connections, such as a permission '
+                'problem on the server certificate file.'
+            )
+            self.__check_printed_messages(expected_printed_messages)
+
+            # any other exception should be passed through
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(ImportError())
+            self.assertRaises(ImportError, self.tool._try_login, "foo", "bar")
+            self.__check_printed_messages(expected_printed_messages)
+
+        finally:
+            self.tool.send_POST = orig_send_POST
+
     def test_run(self):
         def login_to_cmdctl():
             return True
@@ -360,29 +470,22 @@ class TestConfigCommands(unittest.TestCase):
         self.tool.conn.sock = FakeSocket()
         self.tool.conn.sock.close()
 
-        # validate log message for socket.err
-        socket_err_output = io.StringIO()
-        sys.stdout = socket_err_output
         self.assertEqual(1, self.tool.run())
 
         # First few lines may be some kind of heading, or a warning that
         # Python readline is unavailable, so we do a sub-string check.
         self.assertIn("Failed to send request, the connection is closed",
-                      socket_err_output.getvalue())
-
-        socket_err_output.close()
+                      self.printed_messages)
+        self.assertEqual(1, len(self.printed_messages))
 
         # validate log message for http.client.CannotSendRequest
-        cannot_send_output = io.StringIO()
-        sys.stdout = cannot_send_output
         self.assertEqual(1, self.tool.run())
 
         # First few lines may be some kind of heading, or a warning that
         # Python readline is unavailable, so we do a sub-string check.
         self.assertIn("Can not send request, the connection is busy",
-                      cannot_send_output.getvalue())
-
-        cannot_send_output.close()
+                      self.printed_messages)
+        self.assertEqual(2, len(self.printed_messages))
 
     def test_apply_cfg_command_int(self):
         self.tool.location = '/'
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 315e3c5..06b9b0f 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -115,7 +115,7 @@ def main():
         cm.read_config()
         for ppath in PLUGIN_PATHS:
             load_plugins(ppath, cm)
-        cm.notify_boss()
+        cm.notify_b10_init()
         cm.run()
     except SessionError as se:
         logger.fatal(CFGMGR_CC_SESSION_ERROR, se)
diff --git a/src/bin/cfgmgr/b10-cfgmgr.xml b/src/bin/cfgmgr/b10-cfgmgr.xml
index d8688f9..78dde76 100644
--- a/src/bin/cfgmgr/b10-cfgmgr.xml
+++ b/src/bin/cfgmgr/b10-cfgmgr.xml
@@ -65,7 +65,7 @@
       The <command>bindctl</command> can be used to talk to this
       configuration manager via a <command>b10-cmdctl</command> connection.
     </para>
-     
+
 <!-- TODO: briefly explain why both msqg channel and cmdctl communication -->
     <para>
       This daemon communicates over a <command>b10-msgq</command> C-Channel
@@ -148,7 +148,13 @@
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
-        <refentrytitle>msgq</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>.
+      <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>.
     </para>
   </refsect1>
diff --git a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
index 351e8bf..02b48bd 100644
--- a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
+++ b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
@@ -27,7 +27,7 @@ class MyConfigManager:
     def __init__(self, path, filename, session=None, rename_config_file=False):
         self._path = path
         self.read_config_called = False
-        self.notify_boss_called = False
+        self.notify_b10_init_called = False
         self.run_called = False
         self.write_config_called = False
         self.rename_config_called = False
@@ -37,8 +37,8 @@ class MyConfigManager:
     def read_config(self):
         self.read_config_called = True
 
-    def notify_boss(self):
-        self.notify_boss_called = True
+    def notify_b10_init(self):
+        self.notify_b10_init_called = True
 
     def run(self):
         self.run_called = True
@@ -89,7 +89,7 @@ class TestConfigManagerStartup(unittest.TestCase):
         b.load_plugins = orig_load
 
         self.assertTrue(b.cm.read_config_called)
-        self.assertTrue(b.cm.notify_boss_called)
+        self.assertTrue(b.cm.notify_b10_init_called)
         self.assertTrue(b.cm.run_called)
         self.assertTrue(self.loaded_plugins)
         # if there are no changes, config is not written
diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am
index bfc13af..8cadf89 100644
--- a/src/bin/cmdctl/Makefile.am
+++ b/src/bin/cmdctl/Makefile.am
@@ -11,17 +11,12 @@ pylogmessagedir = $(pyexecdir)/isc/log_messages/
 
 b10_cmdctldir = $(pkgdatadir)
 
-# NOTE: this will overwrite on install
-# So these generic copies are placed in share/bind10 instead of to etc
-# Admin or packageer will need to put into place manually.
+USERSFILES = cmdctl-accounts.csv
+CERTFILES = cmdctl-keyfile.pem cmdctl-certfile.pem
 
-CMDCTL_CONFIGURATIONS = cmdctl-accounts.csv
-CMDCTL_CONFIGURATIONS += cmdctl-keyfile.pem cmdctl-certfile.pem
+b10_cmdctl_DATA = cmdctl.spec
 
-b10_cmdctl_DATA = $(CMDCTL_CONFIGURATIONS)
-b10_cmdctl_DATA += cmdctl.spec
-
-EXTRA_DIST = $(CMDCTL_CONFIGURATIONS)
+EXTRA_DIST = $(USERSFILES)
 
 CLEANFILES= b10-cmdctl cmdctl.pyc cmdctl.spec
 CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py
@@ -55,7 +50,7 @@ $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py : cmdctl_messages.mes
 	-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/cmdctl_messages.mes
 
 # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
-b10-cmdctl: cmdctl.py $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py
+b10-cmdctl: cmdctl.py $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py $(CERTFILES)
 	$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@
 	chmod a+x $@
 
@@ -76,7 +71,7 @@ if INSTALL_CONFIGURATIONS
 # because these file will contain sensitive information.
 install-data-local:
 	$(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
-	for f in $(CMDCTL_CONFIGURATIONS) ; do	\
+	for f in $(CERTFILES) ; do	\
 	  if test ! -f $(DESTDIR)$(sysconfdir)/@PACKAGE@/$$f; then	\
 	    ${INSTALL} -m 640 $(srcdir)/$$f $(DESTDIR)$(sysconfdir)/@PACKAGE@/ ;	\
 	  fi ;	\
diff --git a/src/bin/cmdctl/b10-certgen.xml b/src/bin/cmdctl/b10-certgen.xml
index 5ac8783..d7fe100 100644
--- a/src/bin/cmdctl/b10-certgen.xml
+++ b/src/bin/cmdctl/b10-certgen.xml
@@ -172,6 +172,9 @@
       <citerefentry>
         <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
+      </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>
diff --git a/src/bin/cmdctl/b10-cmdctl.xml b/src/bin/cmdctl/b10-cmdctl.xml
index 4b1b32f..871265c 100644
--- a/src/bin/cmdctl/b10-cmdctl.xml
+++ b/src/bin/cmdctl/b10-cmdctl.xml
@@ -78,7 +78,7 @@
 
   <refsect1>
     <title>OPTIONS</title>
-    
+
     <para>The arguments are as follows:</para>
 
     <variablelist>
@@ -175,7 +175,7 @@
       <command>shutdown</command> exits <command>b10-cmdctl</command>.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the b10-init process may restart this service
       if configured.)
     </para>
 
@@ -209,6 +209,9 @@
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/cmdctl/cmdctl.py.in b/src/bin/cmdctl/cmdctl.py.in
index 52af54a..457873b 100755
--- a/src/bin/cmdctl/cmdctl.py.in
+++ b/src/bin/cmdctl/cmdctl.py.in
@@ -82,6 +82,18 @@ SPECFILE_LOCATION = SPECFILE_PATH + os.sep + "cmdctl.spec"
 class CmdctlException(Exception):
     pass
 
+def check_file(file_name):
+    # TODO: Check contents of certificate file
+    if not os.path.exists(file_name):
+        raise CmdctlException("'%s' does not exist" % file_name)
+
+    if not os.path.isfile(file_name):
+        raise CmdctlException("'%s' is not a file" % file_name)
+
+    if not os.access(file_name, os.R_OK):
+        raise CmdctlException("'%s' is not readable" % file_name)
+
+
 class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
     '''https connection request handler.
     Currently only GET and POST are supported.  '''
@@ -153,7 +165,6 @@ class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
         self.end_headers()
         self.wfile.write(json.dumps(reply).encode())
 
-
     def _handle_login(self):
         if self._is_user_logged_in():
             return http.client.OK, ["user has already login"]
@@ -278,12 +289,14 @@ class CommandControl():
             if key == 'version':
                 continue
             elif key in ['key_file', 'cert_file']:
-                #TODO, only check whether the file exist,
-                # further check need to be done: eg. whether
-                # the private/certificate is valid.
+                # TODO: we only check whether the file exist, is a
+                # file, and is readable; but further check need to be done:
+                # eg. whether the private/certificate is valid.
                 path = new_config[key]
-                if not os.path.exists(path):
-                    errstr = "the file doesn't exist: " + path
+                try:
+                    check_file(path)
+                except CmdctlException as cce:
+                    errstr = str(cce)
             elif key == 'accounts_file':
                 errstr = self._accounts_file_check(new_config[key])
             else:
@@ -326,7 +339,7 @@ class CommandControl():
                     self.modules_spec[args[0]] = args[1]
 
         elif command == ccsession.COMMAND_SHUTDOWN:
-            #When cmdctl get 'shutdown' command from boss,
+            #When cmdctl get 'shutdown' command from b10-init,
             #shutdown the outer httpserver.
             self._module_cc.send_stopping()
             self._httpserver.shutdown()
@@ -416,8 +429,13 @@ class CommandControl():
             # Process the command sent to cmdctl directly.
             answer = self.command_handler(command_name, params)
         else:
+            # FIXME: Due to the fact that we use a separate session
+            # from the module one (due to threads and blocking), and
+            # because the plain cc session does not have the high-level
+            # rpc-call method, we use the low-level way and create the
+            # command ourselves.
             msg = ccsession.create_command(command_name, params)
-            seq = self._cc.group_sendmsg(msg, module_name)
+            seq = self._cc.group_sendmsg(msg, module_name, want_answer=True)
             logger.debug(DBG_CMDCTL_MESSAGING, CMDCTL_COMMAND_SENT,
                          command_name, module_name)
             #TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
@@ -524,27 +542,27 @@ class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
         self.user_sessions[session_id] = time.time()
 
     def _check_key_and_cert(self, key, cert):
-        # TODO, check the content of key/certificate file
-        if not os.path.exists(key):
-            raise CmdctlException("key file '%s' doesn't exist " % key)
-
-        if not os.path.exists(cert):
-            raise CmdctlException("certificate file '%s' doesn't exist " % cert)
+        check_file(key)
+        check_file(cert);
 
     def _wrap_socket_in_ssl_context(self, sock, key, cert):
         try:
             self._check_key_and_cert(key, cert)
             ssl_sock = ssl.wrap_socket(sock,
-                                      server_side = True,
-                                      certfile = cert,
-                                      keyfile = key,
-                                      ssl_version = ssl.PROTOCOL_SSLv23)
+                                       server_side=True,
+                                       certfile=cert,
+                                       keyfile=key,
+                                       ssl_version=ssl.PROTOCOL_SSLv23)
+            # Return here (if control leaves this blocks it will raise an
+            # error)
             return ssl_sock
-        except (ssl.SSLError, CmdctlException) as err :
+        except ssl.SSLError as err:
             logger.error(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
-            self.close_request(sock)
-            # raise socket error to finish the request
-            raise socket.error
+        except (CmdctlException, IOError) as cce:
+            logger.error(CMDCTL_SSL_SETUP_FAILURE_READING_CERT, cce)
+        self.close_request(sock)
+        # raise socket error to finish the request
+        raise socket.error
 
     def get_request(self):
         '''Get client request socket and wrap it in SSL context. '''
@@ -637,4 +655,6 @@ if __name__ == '__main__':
     if httpd:
         httpd.shutdown()
 
+    logger.info(CMDCTL_EXITING)
+
     sys.exit(result)
diff --git a/src/bin/cmdctl/cmdctl_messages.mes b/src/bin/cmdctl/cmdctl_messages.mes
index a3371b9..32afce3 100644
--- a/src/bin/cmdctl/cmdctl_messages.mes
+++ b/src/bin/cmdctl/cmdctl_messages.mes
@@ -43,6 +43,9 @@ specific error is printed in the message.
 This debug message indicates that the given command has been sent to
 the given module.
 
+% CMDCTL_EXITING exiting
+The b10-cmdctl daemon is exiting.
+
 % CMDCTL_NO_SUCH_USER username not found in user database: %1
 A login attempt was made to b10-cmdctl, but the username was not known.
 Users can be added with the tool b10-cmdctl-usermgr.
@@ -58,6 +61,13 @@ with the tool b10-cmdctl-usermgr.
 This debug message indicates that the given command is being sent to
 the given module.
 
+% CMDCTL_SSL_SETUP_FAILURE_READING_CERT failed to read certificate or key: %1
+The b10-cmdctl daemon is unable to read either the certificate file or
+the private key file, and is therefore unable to accept any SSL connections.
+The specific error is printed in the message.
+The administrator should solve the issue with the files, or recreate them
+with the b10-certgen tool.
+
 % CMDCTL_SSL_SETUP_FAILURE_USER_DENIED failed to create an SSL connection (user denied): %1
 The user was denied because the SSL connection could not successfully
 be set up. The specific error is given in the log message. Possible
diff --git a/src/bin/cmdctl/run_b10-cmdctl.sh.in b/src/bin/cmdctl/run_b10-cmdctl.sh.in
index 7e63249..7dcf1d5 100644
--- a/src/bin/cmdctl/run_b10-cmdctl.sh.in
+++ b/src/bin/cmdctl/run_b10-cmdctl.sh.in
@@ -19,7 +19,7 @@ PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
 export PYTHON_EXEC
 
 CMD_CTRLD_PATH=@abs_top_builddir@/src/bin/cmdctl
-PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/cmdctl/tests/Makefile.am b/src/bin/cmdctl/tests/Makefile.am
index 6d8f282..74b801a 100644
--- a/src/bin/cmdctl/tests/Makefile.am
+++ b/src/bin/cmdctl/tests/Makefile.am
@@ -25,7 +25,7 @@ endif
 	echo Running test: $$pytest ; \
 	$(LIBRARY_PATH_PLACEHOLDER) \
 	PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_builddir)/src/bin/cmdctl \
-	CMDCTL_SPEC_PATH=$(abs_top_builddir)/src/bin/cmdctl \
+	CMDCTL_BUILD_PATH=$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
 	B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir) \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
diff --git a/src/bin/cmdctl/tests/cmdctl_test.py b/src/bin/cmdctl/tests/cmdctl_test.py
index 856adf1..ee44f45 100644
--- a/src/bin/cmdctl/tests/cmdctl_test.py
+++ b/src/bin/cmdctl/tests/cmdctl_test.py
@@ -17,17 +17,18 @@
 import unittest
 import socket
 import tempfile
+import stat
 import sys
 from cmdctl import *
 import isc.log
 
-SPEC_FILE_PATH = '..' + os.sep
-if 'CMDCTL_SPEC_PATH' in os.environ:
-    SPEC_FILE_PATH = os.environ['CMDCTL_SPEC_PATH'] + os.sep
+assert 'CMDCTL_SRC_PATH' in os.environ,\
+       "Please run this test with 'make check'"
+SRC_FILE_PATH = os.environ['CMDCTL_SRC_PATH'] + os.sep
 
-SRC_FILE_PATH = '..' + os.sep
-if 'CMDCTL_SRC_PATH' in os.environ:
-    SRC_FILE_PATH = os.environ['CMDCTL_SRC_PATH'] + os.sep
+assert 'CMDCTL_BUILD_PATH' in os.environ,\
+       "Please run this test with 'make check'"
+BUILD_FILE_PATH = os.environ['CMDCTL_BUILD_PATH'] + os.sep
 
 # Rewrite the class for unittest.
 class MySecureHTTPRequestHandler(SecureHTTPRequestHandler):
@@ -36,7 +37,7 @@ class MySecureHTTPRequestHandler(SecureHTTPRequestHandler):
 
     def send_response(self, rcode):
         self.rcode = rcode
-    
+
     def end_headers(self):
         pass
 
@@ -51,13 +52,13 @@ class MySecureHTTPRequestHandler(SecureHTTPRequestHandler):
         super().do_POST()
         self.wfile.close()
         os.remove('tmp.file')
-    
+
 
 class FakeSecureHTTPServer(SecureHTTPServer):
     def __init__(self):
         self.user_sessions = {}
         self.cmdctl = FakeCommandControlForTestRequestHandler()
-        self._verbose = True 
+        self._verbose = True
         self._user_infos = {}
         self.idle_timeout = 1200
         self._lock = threading.Lock()
@@ -71,6 +72,17 @@ class FakeCommandControlForTestRequestHandler(CommandControl):
     def send_command(self, mod, cmd, param):
         return 0, {}
 
+# context to temporarily make a file unreadable
+class UnreadableFile:
+    def __init__(self, file_name):
+        self.file_name = file_name
+        self.orig_mode = os.stat(file_name).st_mode
+
+    def __enter__(self):
+        os.chmod(self.file_name, self.orig_mode & ~stat.S_IRUSR)
+
+    def __exit__(self, type, value, traceback):
+        os.chmod(self.file_name, self.orig_mode)
 
 class TestSecureHTTPRequestHandler(unittest.TestCase):
     def setUp(self):
@@ -97,7 +109,7 @@ class TestSecureHTTPRequestHandler(unittest.TestCase):
         self.handler.path = '/abc'
         mod, cmd = self.handler._parse_request_path()
         self.assertTrue((mod == 'abc') and (cmd == None))
-        
+
         self.handler.path = '/abc/edf'
         mod, cmd = self.handler._parse_request_path()
         self.assertTrue((mod == 'abc') and (cmd == 'edf'))
@@ -125,20 +137,20 @@ class TestSecureHTTPRequestHandler(unittest.TestCase):
 
     def test_do_GET(self):
         self.handler.do_GET()
-        self.assertEqual(self.handler.rcode, http.client.BAD_REQUEST)    
-        
+        self.assertEqual(self.handler.rcode, http.client.BAD_REQUEST)
+
     def test_do_GET_1(self):
         self.handler.headers['cookie'] = 12345
         self.handler.do_GET()
-        self.assertEqual(self.handler.rcode, http.client.UNAUTHORIZED)    
+        self.assertEqual(self.handler.rcode, http.client.UNAUTHORIZED)
 
     def test_do_GET_2(self):
         self.handler.headers['cookie'] = 12345
         self.handler.server.user_sessions[12345] = time.time() + 1000000
         self.handler.path = '/how/are'
         self.handler.do_GET()
-        self.assertEqual(self.handler.rcode, http.client.NO_CONTENT)    
-    
+        self.assertEqual(self.handler.rcode, http.client.NO_CONTENT)
+
     def test_do_GET_3(self):
         self.handler.headers['cookie'] = 12346
         self.handler.server.user_sessions[12346] = time.time() + 1000000
@@ -146,8 +158,8 @@ class TestSecureHTTPRequestHandler(unittest.TestCase):
         for path in path_vec:
             self.handler.path = '/' + path
             self.handler.do_GET()
-            self.assertEqual(self.handler.rcode, http.client.OK)    
-    
+            self.assertEqual(self.handler.rcode, http.client.OK)
+
     def test_user_logged_in(self):
         self.handler.server.user_sessions = {}
         self.handler.session_id = 12345
@@ -243,8 +255,8 @@ class TestSecureHTTPRequestHandler(unittest.TestCase):
         self.assertEqual(http.client.BAD_REQUEST, rcode)
 
     def _gen_module_spec(self):
-        spec = { 'commands': [ 
-                  { 'command_name' :'command', 
+        spec = { 'commands': [
+                  { 'command_name' :'command',
                     'command_args': [ {
                             'item_name' : 'param1',
                             'item_type' : 'integer',
@@ -253,9 +265,9 @@ class TestSecureHTTPRequestHandler(unittest.TestCase):
                            } ],
                     'command_description' : 'cmd description'
                   }
-                ] 
+                ]
                }
-        
+
         return spec
 
     def test_handle_post_request_2(self):
@@ -290,13 +302,13 @@ class MyCommandControl(CommandControl):
         return {}
 
     def _setup_session(self):
-        spec_file = SPEC_FILE_PATH + 'cmdctl.spec'
+        spec_file = BUILD_FILE_PATH + 'cmdctl.spec'
         module_spec = isc.config.module_spec_from_file(spec_file)
         config = isc.config.config_data.ConfigData(module_spec)
         self._module_name = 'Cmdctl'
         self._cmdctl_config_data = config.get_full_config()
 
-    def _handle_msg_from_msgq(self): 
+    def _handle_msg_from_msgq(self):
         pass
 
 class TestCommandControl(unittest.TestCase):
@@ -305,7 +317,7 @@ class TestCommandControl(unittest.TestCase):
         self.old_stdout = sys.stdout
         sys.stdout = open(os.devnull, 'w')
         self.cmdctl = MyCommandControl(None, True)
-   
+
     def tearDown(self):
         sys.stdout.close()
         sys.stdout = self.old_stdout
@@ -320,7 +332,7 @@ class TestCommandControl(unittest.TestCase):
         old_env = os.environ
         if 'B10_FROM_SOURCE' in os.environ:
             del os.environ['B10_FROM_SOURCE']
-        self.cmdctl.get_cmdctl_config_data() 
+        self.cmdctl.get_cmdctl_config_data()
         self._check_config(self.cmdctl)
         os.environ = old_env
 
@@ -328,7 +340,7 @@ class TestCommandControl(unittest.TestCase):
         os.environ['B10_FROM_SOURCE'] = '../'
         self._check_config(self.cmdctl)
         os.environ = old_env
-    
+
     def test_parse_command_result(self):
         self.assertEqual({}, self.cmdctl._parse_command_result(1, {'error' : 1}))
         self.assertEqual({'a': 1}, self.cmdctl._parse_command_result(0, {'a' : 1}))
@@ -391,13 +403,13 @@ class TestCommandControl(unittest.TestCase):
         os.environ = old_env
 
         answer = self.cmdctl.config_handler({'key_file': '/user/non-exist_folder'})
-        self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+        self._check_answer(answer, 1, "'/user/non-exist_folder' does not exist")
 
         answer = self.cmdctl.config_handler({'cert_file': '/user/non-exist_folder'})
-        self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+        self._check_answer(answer, 1, "'/user/non-exist_folder' does not exist")
 
         answer = self.cmdctl.config_handler({'accounts_file': '/user/non-exist_folder'})
-        self._check_answer(answer, 1, 
+        self._check_answer(answer, 1,
                 "Invalid accounts file: [Errno 2] No such file or directory: '/user/non-exist_folder'")
 
         # Test with invalid accounts file
@@ -409,7 +421,7 @@ class TestCommandControl(unittest.TestCase):
         answer = self.cmdctl.config_handler({'accounts_file': file_name})
         self._check_answer(answer, 1, "Invalid accounts file: list index out of range")
         os.remove(file_name)
-    
+
     def test_send_command(self):
         rcode, value = self.cmdctl.send_command('Cmdctl', 'print_settings', None)
         self.assertEqual(rcode, 0)
@@ -424,7 +436,7 @@ class TestSecureHTTPServer(unittest.TestCase):
         self.old_stderr = sys.stderr
         sys.stdout = open(os.devnull, 'w')
         sys.stderr = sys.stdout
-        self.server = MySecureHTTPServer(('localhost', 8080), 
+        self.server = MySecureHTTPServer(('localhost', 8080),
                                          MySecureHTTPRequestHandler,
                                          MyCommandControl, verbose=True)
 
@@ -458,32 +470,90 @@ class TestSecureHTTPServer(unittest.TestCase):
         self.assertEqual(1, len(self.server._user_infos))
         self.assertTrue('root' in self.server._user_infos)
 
+    def test_check_file(self):
+        # Just some file that we know exists
+        file_name = BUILD_FILE_PATH + 'cmdctl-keyfile.pem'
+        check_file(file_name)
+        with UnreadableFile(file_name):
+            self.assertRaises(CmdctlException, check_file, file_name)
+        self.assertRaises(CmdctlException, check_file, '/local/not-exist')
+        self.assertRaises(CmdctlException, check_file, '/')
+
+
     def test_check_key_and_cert(self):
+        keyfile = BUILD_FILE_PATH + 'cmdctl-keyfile.pem'
+        certfile = BUILD_FILE_PATH + 'cmdctl-certfile.pem'
+
+        # no exists
+        self.assertRaises(CmdctlException, self.server._check_key_and_cert,
+                          keyfile, '/local/not-exist')
+        self.assertRaises(CmdctlException, self.server._check_key_and_cert,
+                         '/local/not-exist', certfile)
+
+        # not a file
+        self.assertRaises(CmdctlException, self.server._check_key_and_cert,
+                          keyfile, '/')
         self.assertRaises(CmdctlException, self.server._check_key_and_cert,
-                         '/local/not-exist', 'cmdctl-keyfile.pem')
+                         '/', certfile)
 
-        self.server._check_key_and_cert(SRC_FILE_PATH + 'cmdctl-keyfile.pem',
-                                        SRC_FILE_PATH + 'cmdctl-certfile.pem')
+        # no read permission
+        with UnreadableFile(certfile):
+            self.assertRaises(CmdctlException,
+                              self.server._check_key_and_cert,
+                              keyfile, certfile)
+
+        with UnreadableFile(keyfile):
+            self.assertRaises(CmdctlException,
+                              self.server._check_key_and_cert,
+                              keyfile, certfile)
+
+        # All OK (also happens to check the context code above works)
+        self.server._check_key_and_cert(keyfile, certfile)
 
     def test_wrap_sock_in_ssl_context(self):
         sock = socket.socket()
-        self.assertRaises(socket.error, 
+
+        # Bad files should result in a socket.error raised by our own
+        # code in the basic file checks
+        self.assertRaises(socket.error,
                           self.server._wrap_socket_in_ssl_context,
-                          sock, 
-                          '../cmdctl-keyfile',
-                          '../cmdctl-certfile')
+                          sock,
+                          'no_such_file', 'no_such_file')
 
+        # Using a non-certificate file would cause an SSLError, which
+        # is caught by our code which then raises a basic socket.error
+        self.assertRaises(socket.error,
+                          self.server._wrap_socket_in_ssl_context,
+                          sock,
+                          BUILD_FILE_PATH + 'cmdctl.py',
+                          BUILD_FILE_PATH + 'cmdctl-certfile.pem')
+
+        # Should succeed
         sock1 = socket.socket()
-        self.server._wrap_socket_in_ssl_context(sock1, 
-                          SRC_FILE_PATH + 'cmdctl-keyfile.pem',
-                          SRC_FILE_PATH + 'cmdctl-certfile.pem')
+        ssl_sock = self.server._wrap_socket_in_ssl_context(sock1,
+                                   BUILD_FILE_PATH + 'cmdctl-keyfile.pem',
+                                   BUILD_FILE_PATH + 'cmdctl-certfile.pem')
+        self.assertTrue(isinstance(ssl_sock, ssl.SSLSocket))
+
+        # wrap_socket can also raise IOError, which should be caught and
+        # handled like the other errors.
+        # Force this by temporarily disabling our own file checks
+        orig_check_func = self.server._check_key_and_cert
+        try:
+            self.server._check_key_and_cert = lambda x,y: None
+            self.assertRaises(socket.error,
+                              self.server._wrap_socket_in_ssl_context,
+                              sock,
+                              'no_such_file', 'no_such_file')
+        finally:
+            self.server._check_key_and_cert = orig_check_func
 
 class TestFuncNotInClass(unittest.TestCase):
     def test_check_port(self):
-        self.assertRaises(OptionValueError, check_port, None, 'port', -1, None)        
-        self.assertRaises(OptionValueError, check_port, None, 'port', 65536, None)        
-        self.assertRaises(OptionValueError, check_addr, None, 'ipstr', 'a.b.d', None)        
-        self.assertRaises(OptionValueError, check_addr, None, 'ipstr', '1::0:a.b', None)        
+        self.assertRaises(OptionValueError, check_port, None, 'port', -1, None)
+        self.assertRaises(OptionValueError, check_port, None, 'port', 65536, None)
+        self.assertRaises(OptionValueError, check_addr, None, 'ipstr', 'a.b.d', None)
+        self.assertRaises(OptionValueError, check_addr, None, 'ipstr', '1::0:a.b', None)
 
 
 if __name__== "__main__":
diff --git a/src/bin/dbutil/b10-dbutil.xml b/src/bin/dbutil/b10-dbutil.xml
index 752b8a8..c93d060 100644
--- a/src/bin/dbutil/b10-dbutil.xml
+++ b/src/bin/dbutil/b10-dbutil.xml
@@ -93,7 +93,7 @@
       file.  It has the same name, with ".backup" appended to it.  If a
       file of that name already exists, the file will have the suffix
       ".backup-1".  If that exists, the file will be suffixed ".backup-2",
-      and so on). Exit status is 0 if the upgrade is either succesful or
+      and so on). Exit status is 0 if the upgrade is either successful or
       aborted by the user, and non-zero if there is an error.
     </para>
 
diff --git a/src/bin/dbutil/dbutil.py.in b/src/bin/dbutil/dbutil.py.in
index a844484..7a1469c 100755
--- a/src/bin/dbutil/dbutil.py.in
+++ b/src/bin/dbutil/dbutil.py.in
@@ -200,10 +200,16 @@ UPGRADES = [
             "CREATE INDEX nsec3_byhash_and_rdtype ON nsec3 " +
                 "(hash, rdtype)"
         ]
+    },
+
+    {'from': (2, 1), 'to': (2, 2),
+        'statements': [
+            "CREATE INDEX records_byrname_and_rdtype ON records (rname, rdtype)"
+        ]
     }
 
 # To extend this, leave the above statements in place and add another
-# dictionary to the list.  The "from" version should be (2, 1), the "to"
+# dictionary to the list.  The "from" version should be (2, 2), the "to"
 # version whatever the version the update is to, and the SQL statements are
 # the statements required to perform the upgrade.  This way, the upgrade
 # program will be able to upgrade both a V1.0 and a V2.0 database.
diff --git a/src/bin/dbutil/run_dbutil.sh.in b/src/bin/dbutil/run_dbutil.sh.in
index fea7482..8ec5668 100755
--- a/src/bin/dbutil/run_dbutil.sh.in
+++ b/src/bin/dbutil/run_dbutil.sh.in
@@ -20,7 +20,10 @@ export PYTHON_EXEC
 
 DBUTIL_PATH=@abs_top_builddir@/src/bin/dbutil
 
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
+# Note: lib/dns/python/.libs is necessary because __init__.py of isc package
+# automatically imports isc.datasrc, which then requires the DNS loadable
+# module.  #2145 should eliminate the need for it.
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/dbutil/tests/dbutil_test.sh.in b/src/bin/dbutil/tests/dbutil_test.sh.in
index d60f186..4bc9f85 100755
--- a/src/bin/dbutil/tests/dbutil_test.sh.in
+++ b/src/bin/dbutil/tests/dbutil_test.sh.in
@@ -165,7 +165,7 @@ upgrade_ok_test() {
     if [ $? -eq 0 ]
     then
         # Compare schema with the reference
-        get_schema $testdata/v2_1.sqlite3
+        get_schema $testdata/v2_2.sqlite3
         expected_schema=$db_schema
         get_schema $tempfile
         actual_schema=$db_schema
@@ -177,7 +177,7 @@ upgrade_ok_test() {
         fi
 
         # Check the version is set correctly
-        check_version $tempfile "V2.1"
+        check_version $tempfile "V2.2"
 
         # Check that a backup was made
         check_backup $1 $2
@@ -303,26 +303,32 @@ check_version_fail() {
 
 rm -f $tempfile $backupfile
 
-# Test 1 - check that the utility fails if the database does not exist
-echo "1.1. Non-existent database - check"
+# This is the section number that is echoed during tests. It is
+# incremented when each section is run.
+sec=0
+
+# Test: check that the utility fails if the database does not exist
+sec=`expr $sec + 1`
+echo $sec".1. Non-existent database - check"
 ${SHELL} ../run_dbutil.sh --check $tempfile
 failzero $?
 check_no_backup $tempfile $backupfile
 
-echo "1.2. Non-existent database - upgrade"
+echo $sec".2. Non-existent database - upgrade"
 ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
 check_no_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
 
-# Test 2 - should fail to check an empty file and fail to upgrade it
-echo "2.1. Database is an empty file - check"
+# Test: should fail to check an empty file and fail to upgrade it
+sec=`expr $sec + 1`
+echo $sec".1. Database is an empty file - check"
 touch $tempfile
 check_version_fail $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-echo "2.2. Database is an empty file - upgrade"
+echo $sec".2. Database is an empty file - upgrade"
 touch $tempfile
 ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
@@ -330,13 +336,13 @@ failzero $?
 check_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-
-echo "3.1. Database is not an SQLite file - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is not an SQLite file - check"
 echo "This is not an sqlite3 database" > $tempfile
 check_version_fail $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-echo "3.2. Database is not an SQLite file - upgrade"
+echo $sec".2. Database is not an SQLite file - upgrade"
 echo "This is not an sqlite3 database" > $tempfile
 ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
@@ -345,81 +351,113 @@ check_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "4.1. Database is an SQLite3 file without the schema table - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is an SQLite3 file without the schema table - check"
 check_version_fail $testdata/no_schema.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
-echo "4.1. Database is an SQLite3 file without the schema table - upgrade"
+echo $sec".1. Database is an SQLite3 file without the schema table - upgrade"
 upgrade_fail_test $testdata/no_schema.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "5.1. Database is an old V1 database - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is an old V1 database - check"
 check_version $testdata/old_v1.sqlite3 "V1.0"
 check_no_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-echo "5.2. Database is an old V1 database - upgrade"
+echo $sec".2. Database is an old V1 database - upgrade"
 upgrade_ok_test $testdata/old_v1.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "6.1. Database is new V1 database - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is new V1 database - check"
 check_version $testdata/new_v1.sqlite3 "V1.0"
 check_no_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-echo "6.2. Database is a new V1 database - upgrade"
+echo $sec".2. Database is a new V1 database - upgrade"
 upgrade_ok_test $testdata/new_v1.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "7.1. Database is V2.0 database - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is V2.0 database - check"
 check_version $testdata/v2_0.sqlite3 "V2.0"
 check_no_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
 
-echo "7.2. Database is a V2.0 database - upgrade"
+echo $sec".2. Database is a V2.0 database - upgrade"
 upgrade_ok_test $testdata/v2_0.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "8.1. Database is V2.0 database with empty schema table - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is V2.1 database - check"
+check_version $testdata/v2_1.sqlite3 "V2.1"
+check_no_backup $tempfile $backupfile
+rm -f $tempfile $backupfile
+
+echo $sec".2. Database is a V2.1 database - upgrade"
+upgrade_ok_test $testdata/v2_1.sqlite3 $backupfile
+rm -f $tempfile $backupfile
+
+
+sec=`expr $sec + 1`
+echo $sec".1. Database is V2.2 database - check"
+check_version $testdata/v2_2.sqlite3 "V2.2"
+check_no_backup $tempfile $backupfile
+rm -f $tempfile $backupfile
+
+echo $sec".2. Database is a V2.2 database - upgrade"
+upgrade_ok_test $testdata/v2_2.sqlite3 $backupfile
+rm -f $tempfile $backupfile
+
+
+sec=`expr $sec + 1`
+echo $sec".1. Database is V2.0 database with empty schema table - check"
 check_version_fail $testdata/empty_version.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
-echo "8.2. Database is V2.0 database with empty schema table - upgrade"
+echo $sec".2. Database is V2.0 database with empty schema table - upgrade"
 upgrade_fail_test $testdata/empty_version.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "9.1. Database is V2.0 database with over-full schema table - check"
+sec=`expr $sec + 1`
+echo $sec".1. Database is V2.0 database with over-full schema table - check"
 check_version_fail $testdata/too_many_version.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
-echo "9.2. Database is V2.0 database with over-full schema table - upgrade"
+echo $sec".2. Database is V2.0 database with over-full schema table - upgrade"
 upgrade_fail_test $testdata/too_many_version.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "10.0. Upgrade corrupt database"
+sec=`expr $sec + 1`
+echo $sec". Upgrade corrupt database"
 upgrade_fail_test $testdata/corrupt.sqlite3 $backupfile
 rm -f $tempfile $backupfile
 
 
-echo "11. Record count test"
+sec=`expr $sec + 1`
+echo $sec". Record count test"
 record_count_test $testdata/new_v1.sqlite3
 rm -f $tempfile $backupfile
 
 
-echo "12. Backup file already exists"
+sec=`expr $sec + 1`
+echo $sec". Backup file already exists"
 touch $backupfile
 touch ${backupfile}-1
 upgrade_ok_test $testdata/v2_0.sqlite3 ${backupfile}-2
 rm -f $tempfile $backupfile ${backupfile}-1 ${backupfile}-2
 
 
-echo "13.1 Command-line errors"
+sec=`expr $sec + 1`
+echo $sec".1 Command-line errors"
 copy_file $testdata/old_v1.sqlite3 $tempfile
 ${SHELL} ../run_dbutil.sh $tempfile
 failzero $?
@@ -437,22 +475,22 @@ ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile $backupfile
 failzero $?
 rm -f $tempfile $backupfile
 
-echo "13.2 verbose flag"
+echo $sec".2 verbose flag"
 copy_file $testdata/old_v1.sqlite3 $tempfile
 ${SHELL} ../run_dbutil.sh --upgrade --noconfirm --verbose $tempfile
 passzero $?
 rm -f $tempfile $backupfile
 
-echo "13.3 Interactive prompt - yes"
+echo $sec".3 Interactive prompt - yes"
 copy_file $testdata/old_v1.sqlite3 $tempfile
 ${SHELL} ../run_dbutil.sh --upgrade $tempfile << .
 Yes
 .
 passzero $?
-check_version $tempfile "V2.1"
+check_version $tempfile "V2.2"
 rm -f $tempfile $backupfile
 
-echo "13.4 Interactive prompt - no"
+echo $sec".4 Interactive prompt - no"
 copy_file $testdata/old_v1.sqlite3 $tempfile
 ${SHELL} ../run_dbutil.sh --upgrade $tempfile << .
 no
@@ -462,7 +500,7 @@ diff $testdata/old_v1.sqlite3 $tempfile > /dev/null
 passzero $?
 rm -f $tempfile $backupfile
 
-echo "13.5 quiet flag"
+echo $sec".5 quiet flag"
 copy_file $testdata/old_v1.sqlite3 $tempfile
 ${SHELL} ../run_dbutil.sh --check --quiet $tempfile 2>&1 | grep .
 failzero $?
diff --git a/src/bin/dbutil/tests/testdata/Makefile.am b/src/bin/dbutil/tests/testdata/Makefile.am
index f4873f4..23149b9 100644
--- a/src/bin/dbutil/tests/testdata/Makefile.am
+++ b/src/bin/dbutil/tests/testdata/Makefile.am
@@ -11,3 +11,4 @@ EXTRA_DIST += README
 EXTRA_DIST += too_many_version.sqlite3
 EXTRA_DIST += v2_0.sqlite3
 EXTRA_DIST += v2_1.sqlite3
+EXTRA_DIST += v2_2.sqlite3
diff --git a/src/bin/dbutil/tests/testdata/v2_2.sqlite3 b/src/bin/dbutil/tests/testdata/v2_2.sqlite3
new file mode 100644
index 0000000..b8d6369
Binary files /dev/null and b/src/bin/dbutil/tests/testdata/v2_2.sqlite3 differ
diff --git a/src/bin/ddns/b10-ddns.xml b/src/bin/ddns/b10-ddns.xml
index fb895b9..5a80b7a 100644
--- a/src/bin/ddns/b10-ddns.xml
+++ b/src/bin/ddns/b10-ddns.xml
@@ -56,8 +56,8 @@
     <para>The <command>b10-ddns</command> daemon provides the BIND 10
       Dynamic Update (DDNS) service, as specified in RFC 2136.
       Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
     </para>
 
     <para>
@@ -119,7 +119,7 @@
         <listitem>
           <para>
             This value is ignored at this moment, but is provided for
-            compatibility with the <command>bind10</command> Boss process.
+            compatibility with the <command>b10-init</command> process.
           </para>
         </listitem>
       </varlistentry>
@@ -154,7 +154,7 @@
       <command>shutdown</command> exits <command>b10-ddns</command>.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the b10-init process may restart this service
       if configured.)
     </para>
 
@@ -171,6 +171,9 @@
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/ddns/ddns.py.in b/src/bin/ddns/ddns.py.in
index 094e0ec..d382495 100755
--- a/src/bin/ddns/ddns.py.in
+++ b/src/bin/ddns/ddns.py.in
@@ -32,7 +32,8 @@ import isc.util.cio.socketsession
 import isc.server_common.tsig_keyring
 from isc.server_common.dns_tcp import DNSTCPContext
 from isc.datasrc import DataSourceClient
-from isc.server_common.auth_command import auth_loadzone_command
+from isc.server_common.auth_command import AUTH_LOADZONE_COMMAND, \
+    auth_loadzone_params
 import select
 import time
 import errno
@@ -134,7 +135,7 @@ def get_datasrc_client(cc_session):
     function will simply be removed.
 
     '''
-    HARDCODED_DATASRC_CLASS = RRClass.IN()
+    HARDCODED_DATASRC_CLASS = RRClass.IN
     file, is_default = cc_session.get_remote_config_value("Auth",
                                                           "database_file")
     # See xfrout.py:get_db_file() for this trick:
@@ -469,7 +470,7 @@ class DDNSServer:
             self.__request_msg.clear(Message.PARSE)
             # specify PRESERVE_ORDER as we need to handle each RR separately.
             self.__request_msg.from_wire(req_data, Message.PRESERVE_ORDER)
-            if self.__request_msg.get_opcode() != Opcode.UPDATE():
+            if self.__request_msg.get_opcode() != Opcode.UPDATE:
                 raise self.InternalError('Update request has unexpected '
                                          'opcode: ' +
                                          str(self.__request_msg.get_opcode()))
@@ -536,7 +537,7 @@ class DDNSServer:
                 else:
                     tcp_ctx.close()
         except socket.error as ex:
-            logger.warn(DDNS_RESPONSE_SOCKET_ERROR, ClientFormatter(dest), ex)
+            logger.warn(DDNS_RESPONSE_SOCKET_SEND_FAILED, ClientFormatter(dest), ex)
             return False
 
         return True
@@ -544,42 +545,38 @@ class DDNSServer:
     def __notify_start_forwarder(self):
         '''Notify auth that DDNS Update messages can now be forwarded'''
         try:
-            seq = self._cc._session.group_sendmsg(create_command(
-                    "start_ddns_forwarder"), AUTH_MODULE_NAME)
-            answer, _ = self._cc._session.group_recvmsg(False, seq)
-            rcode, error_msg = parse_answer(answer)
-            if rcode != 0:
-                logger.error(DDNS_START_FORWARDER_ERROR, error_msg)
-        except (SessionTimeout, SessionError, ProtocolError) as ex:
+            self._cc.rpc_call("start_ddns_forwarder", AUTH_MODULE_NAME)
+        except (SessionTimeout, SessionError, ProtocolError,
+                RPCRecipientMissing) as ex:
             logger.error(DDNS_START_FORWARDER_FAIL, ex)
+        except RPCError as e:
+            logger.error(DDNS_START_FORWARDER_ERROR, e)
 
     def __notify_stop_forwarder(self):
         '''Notify auth that DDNS Update messages should no longer be forwarded.
 
         '''
         try:
-            seq = self._cc._session.group_sendmsg(create_command(
-                    "stop_ddns_forwarder"), AUTH_MODULE_NAME)
-            answer, _ = self._cc._session.group_recvmsg(False, seq)
-            rcode, error_msg = parse_answer(answer)
-            if rcode != 0:
-                logger.error(DDNS_STOP_FORWARDER_ERROR, error_msg)
-        except (SessionTimeout, SessionError, ProtocolError) as ex:
+            self._cc.rpc_call("stop_ddns_forwarder", AUTH_MODULE_NAME)
+        except (SessionTimeout, SessionError, ProtocolError,
+                RPCRecipientMissing) as ex:
             logger.error(DDNS_STOP_FORWARDER_FAIL, ex)
+        except RPCError as e:
+            logger.error(DDNS_STOP_FORWARDER_ERROR, e)
 
     def __notify_auth(self, zname, zclass):
         '''Notify auth of the update, if necessary.'''
-        msg = auth_loadzone_command(self._cc, zname, zclass)
-        if msg is not None:
-            self.__notify_update(AUTH_MODULE_NAME, msg, zname, zclass)
+        self.__notify_update(AUTH_MODULE_NAME, AUTH_LOADZONE_COMMAND,
+                             auth_loadzone_params(zname, zclass), zname,
+                             zclass)
 
     def __notify_xfrout(self, zname, zclass):
         '''Notify xfrout of the update.'''
         param = {'zone_name': zname.to_text(), 'zone_class': zclass.to_text()}
-        msg = create_command('notify', param)
-        self.__notify_update(XFROUT_MODULE_NAME, msg, zname, zclass)
+        self.__notify_update(XFROUT_MODULE_NAME, 'notify', param, zname,
+                             zclass)
 
-    def __notify_update(self, modname, msg, zname, zclass):
+    def __notify_update(self, modname, command, params, zname, zclass):
         '''Notify other module of the update.
 
         Note that we use blocking communication here.  While the internal
@@ -590,27 +587,17 @@ class DDNSServer:
         For a longer term we'll need to switch to asynchronous communication,
         but for now we rely on the blocking operation.
 
-        Note also that we directly refer to the "protected" member of
-        ccsession (_cc._session) rather than creating a separate channel.
-        It's probably not the best practice, but hopefully we can introduce
-        a cleaner way when we support asynchronous communication.
-        At the moment we prefer the brevity with the use of internal channel
-        of the cc session.
-
         '''
         try:
-            seq = self._cc._session.group_sendmsg(msg, modname)
-            answer, _ = self._cc._session.group_recvmsg(False, seq)
-            rcode, error_msg = parse_answer(answer)
-        except (SessionTimeout, SessionError, ProtocolError) as ex:
-            rcode = 1
-            error_msg = str(ex)
-        if rcode == 0:
+            # FIXME? Is really rpc_call the correct one? What if there are more
+            # than one recipient of the given kind? What if none? We need to
+            # think of some kind of notification/broadcast mechanism.
+            self._cc.rpc_call(command, modname, params=params)
             logger.debug(TRACE_BASIC, DDNS_UPDATE_NOTIFY, modname,
                          ZoneFormatter(zname, zclass))
-        else:
+        except (SessionTimeout, SessionError, ProtocolError, RPCError) as ex:
             logger.error(DDNS_UPDATE_NOTIFY_FAIL, modname,
-                         ZoneFormatter(zname, zclass), error_msg)
+                         ZoneFormatter(zname, zclass), ex)
 
     def handle_session(self, fileno):
         """Handle incoming session on the socket with given fileno.
@@ -683,7 +670,7 @@ class DDNSServer:
                 result = ctx[0].send_ready()
                 if result != DNSTCPContext.SENDING:
                     if result == DNSTCPContext.CLOSED:
-                        logger.warn(DDNS_RESPONSE_TCP_SOCKET_ERROR,
+                        logger.warn(DDNS_RESPONSE_TCP_SOCKET_SEND_FAILED,
                                     ClientFormatter(ctx[1]))
                     ctx[0].close()
                     del self._tcp_ctxs[fileno]
diff --git a/src/bin/ddns/ddns_messages.mes b/src/bin/ddns/ddns_messages.mes
index d128361..7d440d9 100644
--- a/src/bin/ddns/ddns_messages.mes
+++ b/src/bin/ddns/ddns_messages.mes
@@ -69,7 +69,7 @@ it's just a timing issue.  The number of total failed attempts is also
 logged.  If it reaches an internal threshold b10-ddns considers it a
 fatal error and terminates.  Even in that case, if b10-ddns is
 configured as a "dispensable" component (which is the default), the
-parent bind10 process will restart it, and there will be another
+parent ("init") process will restart it, and there will be another
 chance of getting the remote configuration successfully.  These are
 not the optimal behavior, but it's believed to be sufficient in
 practice (there would normally be no failure in the first place).  If
@@ -134,12 +134,12 @@ appropriate ACL configuration or some lower layer filtering.  The
 number of existing TCP clients are shown in the log, which should be
 identical to the current quota.
 
-% DDNS_RESPONSE_SOCKET_ERROR failed to send update response to %1: %2
+% DDNS_RESPONSE_SOCKET_SEND_FAILED failed to send update response to %1: %2
 Network I/O error happens in sending an update response.  The
 client's address that caused the error and error details are also
 logged.
 
-% DDNS_RESPONSE_TCP_SOCKET_ERROR failed to complete sending update response to %1 over TCP
+% DDNS_RESPONSE_TCP_SOCKET_SEND_FAILED failed to complete sending update response to %1 over TCP
 b10-ddns had tried to send an update response over TCP, and it hadn't
 been completed at that time, and a followup attempt to complete the
 send operation failed due to some network I/O error.  While a network
@@ -253,29 +253,19 @@ notify messages to secondary servers.
 b10-ddns has made updates to a zone based on an update request and
 tried to notify an external component of the updates, but the
 notification fails.  One possible cause of this is that the external
-component is not really running and it times out in waiting for the
-response, although it will be less likely to happen in practice
-because these components will normally be configured to run when the
-server provides the authoritative DNS service; ddns is rather optional
-among them.  If this happens, however, it will suspend b10-ddns for a
-few seconds during which it cannot handle new requests (some may be
-delayed, some may be dropped, depending on the volume of the incoming
-requests).  This is obviously bad, and if this error happens due to
-this reason, the administrator should make sure the component in
-question should be configured to run.  For a longer term, b10-ddns
-should be more robust about this case such as by making this
-notification asynchronously and/or detecting the existence of the
-external components to avoid hopeless notification in the first place.
-Severity of this error for the receiving components depends on the
-type of the component.  If it's b10-xfrout, this means DNS notify
-messages won't be sent to secondary servers of the zone.  It's
-suboptimal, but not necessarily critical as the secondary servers will
-try to check the zone's status periodically.  If it's b10-auth and the
-notification was needed to have it reload the corresponding zone, it's
-more serious because b10-auth won't be able to serve the new version
-of the zone unless some explicit recovery action is taken.  So the
-administrator needs to examine this message and takes an appropriate
-action.  In either case, this notification is generally expected to
-succeed; so the fact it fails itself means there's something wrong in
-the BIND 10 system, and it would be advisable to check other log
-messages.
+component is not really running, although it will be less likely to
+happen in practice because these components will normally be
+configured to run when the server provides the authoritative DNS
+service; ddns is rather optional among them. Severity of this error
+for the receiving components depends on the type of the component.  If
+it's b10-xfrout, this means DNS notify messages won't be sent to
+secondary servers of the zone.  It's suboptimal, but not necessarily
+critical as the secondary servers will try to check the zone's status
+periodically.  If it's b10-auth and the notification was needed to
+have it reload the corresponding zone, it's more serious because
+b10-auth won't be able to serve the new version of the zone unless
+some explicit recovery action is taken.  So the administrator needs to
+examine this message and takes an appropriate action.  In either case,
+this notification is generally expected to succeed; so the fact it
+fails itself means there's something wrong in the BIND 10 system, and
+it would be advisable to check other log messages.
diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py
index 0f5ca9b..e7d2099 100755
--- a/src/bin/ddns/tests/ddns_test.py
+++ b/src/bin/ddns/tests/ddns_test.py
@@ -39,9 +39,9 @@ TESTDATA_PATH = os.environ['TESTDATA_PATH'] + os.sep
 READ_ZONE_DB_FILE = TESTDATA_PATH + "rwtest.sqlite3" # original, to be copied
 TEST_ZONE_NAME = Name('example.org')
 TEST_ZONE_NAME_STR = TEST_ZONE_NAME.to_text()
-UPDATE_RRTYPE = RRType.SOA()
+UPDATE_RRTYPE = RRType.SOA
 TEST_QID = 5353                 # arbitrary chosen
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
 TEST_RRCLASS_STR = TEST_RRCLASS.to_text()
 TEST_SERVER6 = ('2001:db8::53', 53, 0, 0)
 TEST_CLIENT6 = ('2001:db8::1', 53000, 0, 0)
@@ -169,9 +169,9 @@ class FakeUpdateSession:
         self.__msg.make_response()
         self.__msg.clear_section(SECTION_ZONE)
         if self.__faked_result == UPDATE_SUCCESS:
-            self.__msg.set_rcode(Rcode.NOERROR())
+            self.__msg.set_rcode(Rcode.NOERROR)
         else:
-            self.__msg.set_rcode(Rcode.REFUSED())
+            self.__msg.set_rcode(Rcode.REFUSED)
         return self.__msg
 
 class FakeKeyringModule:
@@ -191,7 +191,7 @@ class FakeKeyringModule:
         '''Simply return the predefined TSIG keyring unconditionally.'''
         return TEST_TSIG_KEYRING
 
-class MyCCSession(isc.config.ConfigData):
+class MyCCSession(isc.config.ModuleCCSession):
     '''Fake session with minimal interface compliance.'''
 
     # faked CC sequence used in group_send/recvmsg
@@ -276,7 +276,8 @@ class MyCCSession(isc.config.ConfigData):
                     'secondary_zones')
                 return seczone_default, True
 
-    def group_sendmsg(self, msg, group):
+    def group_sendmsg(self, msg, group, instance='*', to='*',
+                      want_answer=False):
         # remember the passed parameter, and return dummy sequence
         self._sent_msg.append((msg, group))
         if self._sendmsg_exception is not None:
@@ -478,7 +479,7 @@ class TestDDNSServer(unittest.TestCase):
         # By default (in our faked config) it should be derived from the
         # test data source
         rrclass, datasrc_client = self.ddns_server._datasrc_info
-        self.assertEqual(RRClass.IN(), rrclass)
+        self.assertEqual(RRClass.IN, rrclass)
         self.assertEqual(DataSourceClient.SUCCESS,
                          datasrc_client.find_zone(Name('example.org'))[0])
 
@@ -491,7 +492,7 @@ class TestDDNSServer(unittest.TestCase):
             {'database_file': './notexistentdir/somedb.sqlite3'}
         self.__cc_session.add_remote_config_by_name('Auth')
         rrclass, datasrc_client = self.ddns_server._datasrc_info
-        self.assertEqual(RRClass.IN(), rrclass)
+        self.assertEqual(RRClass.IN, rrclass)
         self.assertRaises(isc.datasrc.Error,
                           datasrc_client.find_zone, Name('example.org'))
 
@@ -887,12 +888,12 @@ class TestDDNSServer(unittest.TestCase):
         self.__select_answer = ([], [10], [])
         self.assertRaises(KeyError, self.ddns_server.run)
 
-def create_msg(opcode=Opcode.UPDATE(), zones=[TEST_ZONE_RECORD], prereq=[],
+def create_msg(opcode=Opcode.UPDATE, zones=[TEST_ZONE_RECORD], prereq=[],
                tsigctx=None):
     msg = Message(Message.RENDER)
     msg.set_qid(TEST_QID)
     msg.set_opcode(opcode)
-    msg.set_rcode(Rcode.NOERROR())
+    msg.set_rcode(Rcode.NOERROR)
     for z in zones:
         msg.add_question(z)
     for p in prereq:
@@ -936,7 +937,7 @@ class TestDDNSSession(unittest.TestCase):
         return FakeUpdateSession(req_message, client_addr, zone_config,
                                  self.__faked_result)
 
-    def check_update_response(self, resp_wire, expected_rcode=Rcode.NOERROR(),
+    def check_update_response(self, resp_wire, expected_rcode=Rcode.NOERROR,
                               tsig_ctx=None, tcp=False):
         '''Check if given wire data are valid form of update response.
 
@@ -963,7 +964,7 @@ class TestDDNSSession(unittest.TestCase):
             self.assertNotEqual(None, tsig_record)
             self.assertEqual(TSIGError.NOERROR,
                              tsig_ctx.verify(tsig_record, resp_wire))
-        self.assertEqual(Opcode.UPDATE(), msg.get_opcode())
+        self.assertEqual(Opcode.UPDATE, msg.get_opcode())
         self.assertEqual(expected_rcode, msg.get_rcode())
         self.assertEqual(TEST_QID, msg.get_qid())
         for section in [SECTION_ZONE, SECTION_PREREQUISITE, SECTION_UPDATE]:
@@ -977,7 +978,7 @@ class TestDDNSSession(unittest.TestCase):
         server_addr = TEST_SERVER6 if ipv6 else TEST_SERVER4
         client_addr = TEST_CLIENT6 if ipv6 else TEST_CLIENT4
         tsig = TSIGContext(tsig_key) if tsig_key is not None else None
-        rcode = Rcode.NOERROR() if result == UPDATE_SUCCESS else Rcode.REFUSED()
+        rcode = Rcode.NOERROR if result == UPDATE_SUCCESS else Rcode.REFUSED
         has_response = (result != UPDATE_DROP)
 
         self.assertEqual(has_response,
@@ -1015,7 +1016,7 @@ class TestDDNSSession(unittest.TestCase):
 
         # Opcode is not UPDATE
         self.assertFalse(self.server.handle_request(
-                (self.__sock, None, None, create_msg(opcode=Opcode.QUERY()))))
+                (self.__sock, None, None, create_msg(opcode=Opcode.QUERY))))
         self.assertEqual((None, None), (s._sent_data, s._sent_addr))
 
         # TSIG verification error.  We use UPDATE_DROP to signal check_session
@@ -1031,7 +1032,7 @@ class TestDDNSSession(unittest.TestCase):
                                                      TEST_CLIENT6,
                                                      create_msg())))
         # this check ensures sendto() was really attempted.
-        self.check_update_response(self.__sock._sent_data, Rcode.NOERROR())
+        self.check_update_response(self.__sock._sent_data, Rcode.NOERROR)
 
     def test_tcp_request(self):
         # A simple case using TCP: all resopnse data are sent out at once.
@@ -1040,7 +1041,7 @@ class TestDDNSSession(unittest.TestCase):
         self.assertTrue(self.server.handle_request((s, TEST_SERVER6,
                                                     TEST_CLIENT6,
                                                     create_msg())))
-        self.check_update_response(s._sent_data, Rcode.NOERROR(), tcp=True)
+        self.check_update_response(s._sent_data, Rcode.NOERROR, tcp=True)
         # In the current implementation, the socket should be closed
         # immedidately after a successful send.
         self.assertEqual(1, s._close_called)
@@ -1071,7 +1072,7 @@ class TestDDNSSession(unittest.TestCase):
         s.make_send_ready()
         self.assertEqual(DNSTCPContext.SEND_DONE,
                          self.server._tcp_ctxs[s.fileno()][0].send_ready())
-        self.check_update_response(s._sent_data, Rcode.NOERROR(), tcp=True)
+        self.check_update_response(s._sent_data, Rcode.NOERROR, tcp=True)
 
     def test_tcp_request_error(self):
         # initial send() on the TCP socket will fail.  The request handling
@@ -1127,9 +1128,9 @@ class TestDDNSSession(unittest.TestCase):
         self.__faked_result = UPDATE_DROP
         # Put the same RR twice in the prerequisite section.  We should see
         # them as separate RRs.
-        dummy_record = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(),
+        dummy_record = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS,
                              RRTTL(0))
-        dummy_record.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS, "ns.example"))
+        dummy_record.add_rdata(Rdata(RRType.NS, TEST_RRCLASS, "ns.example."))
         self.server.handle_request((self.__sock, TEST_SERVER6, TEST_CLIENT6,
                                     create_msg(prereq=[dummy_record,
                                                        dummy_record])))
diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am
index 28f08f7..b3818c7 100644
--- a/src/bin/dhcp4/Makefile.am
+++ b/src/bin/dhcp4/Makefile.am
@@ -5,6 +5,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
@@ -51,12 +55,6 @@ b10_dhcp4_SOURCES += dhcp4_srv.cc dhcp4_srv.h
 nodist_b10_dhcp4_SOURCES = dhcp4_messages.h dhcp4_messages.cc
 EXTRA_DIST += dhcp4_messages.mes
 
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-b10_dhcp4_CXXFLAGS = -Wno-unused-parameter
-endif
-
 b10_dhcp4_LDADD  = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
diff --git a/src/bin/dhcp4/b10-dhcp4.xml b/src/bin/dhcp4/b10-dhcp4.xml
index 370fa04..72e46ac 100644
--- a/src/bin/dhcp4/b10-dhcp4.xml
+++ b/src/bin/dhcp4/b10-dhcp4.xml
@@ -79,6 +79,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>.
     </para>
diff --git a/src/bin/dhcp4/config_parser.cc b/src/bin/dhcp4/config_parser.cc
index fdb4240..d8a586b 100644
--- a/src/bin/dhcp4/config_parser.cc
+++ b/src/bin/dhcp4/config_parser.cc
@@ -18,6 +18,7 @@
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option_definition.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/dbaccess_parser.h>
 #include <dhcpsrv/dhcp_config_parser.h>
 #include <dhcpsrv/option_space_container.h>
 #include <util/encode/hex.h>
@@ -49,9 +50,6 @@ typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
 typedef boost::shared_ptr<StringParser> StringParserPtr;
 typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 
-/// @brief auxiliary type used for storing element name and its parser
-typedef pair<string, ConstElementPtr> ConfigPair;
-
 /// @brief a factory method that will create a parser for a given element name
 typedef isc::dhcp::DhcpConfigParser* ParserFactory(const std::string& config_id);
 
@@ -689,7 +687,7 @@ public:
     virtual void commit() {
         if (options_ == NULL) {
             isc_throw(isc::InvalidOperation, "parser logic error: storage must be set before "
-                      "commiting option data.");
+                      "committing option data.");
         } else  if (!option_descriptor_.option) {
             // Before we can commit the new option should be configured. If it is not
             // than somebody must have called commit() before build().
@@ -745,30 +743,34 @@ private:
     void createOption() {
         // Option code is held in the uint32_t storage but is supposed to
         // be uint16_t value. We need to check that value in the configuration
-        // does not exceed range of uint16_t and is not zero.
+        // does not exceed range of uint8_t and is not zero.
         uint32_t option_code = getParam<uint32_t>("code", uint32_values_);
         if (option_code == 0) {
-            isc_throw(DhcpConfigError, "Parser error: value of 'code' must not"
-                      << " be equal to zero. Option code '0' is reserved in"
-                      << " DHCPv4.");
-        } else if (option_code > std::numeric_limits<uint16_t>::max()) {
-            isc_throw(DhcpConfigError, "Parser error: value of 'code' must not"
-                      << " exceed " << std::numeric_limits<uint16_t>::max());
+            isc_throw(DhcpConfigError, "option code must not be zero."
+                      << " Option code '0' is reserved in DHCPv4.");
+        } else if (option_code > std::numeric_limits<uint8_t>::max()) {
+            isc_throw(DhcpConfigError, "invalid option code '" << option_code
+                      << "', it must not exceed '"
+                      << std::numeric_limits<uint8_t>::max() << "'");
         }
         // Check that the option name has been specified, is non-empty and does not
         // contain spaces.
-        // @todo possibly some more restrictions apply here?
         std::string option_name = getParam<std::string>("name", string_values_);
         if (option_name.empty()) {
-            isc_throw(DhcpConfigError, "Parser error: option name must not be"
-                      << " empty");
+            isc_throw(DhcpConfigError, "name of the option with code '"
+                      << option_code << "' is empty");
         } else if (option_name.find(" ") != std::string::npos) {
-            isc_throw(DhcpConfigError, "Parser error: option name must not contain"
-                      << " spaces");
+            isc_throw(DhcpConfigError, "invalid option name '" << option_name
+                      << "', space character is not allowed");
         }
 
         std::string option_space = getParam<std::string>("space", string_values_);
-        /// @todo Validate option space once #2313 is merged.
+        if (!OptionSpace::validateName(option_space)) {
+            isc_throw(DhcpConfigError, "invalid option space name '"
+                      << option_space << "' specified for option '"
+                      << option_name << "' (code '" << option_code
+                      << "')");
+        }
 
         OptionDefinitionPtr def;
         if (option_space == "dhcp4" &&
@@ -822,7 +824,7 @@ private:
             try {
                 util::encode::decodeHex(option_data, binary);
             } catch (...) {
-                isc_throw(DhcpConfigError, "Parser error: option data is not a valid"
+                isc_throw(DhcpConfigError, "option data is not a valid"
                           << " string of hexadecimal digits: " << option_data);
             }
         }
@@ -857,7 +859,7 @@ private:
             // definition of option value makes sense.
             if (def->getName() != option_name) {
                 isc_throw(DhcpConfigError, "specified option name '"
-                          << option_name << " does not match the "
+                          << option_name << "' does not match the "
                           << "option definition: '" << option_space
                           << "." << def->getName() << "'");
             }
@@ -877,6 +879,7 @@ private:
                           << ", code: " << option_code << "): "
                           << ex.what());
             }
+
         }
         // All went good, so we can set the option space name.
         option_space_ = option_space;
@@ -964,13 +967,13 @@ public:
         return (new OptionDataListParser(param_name));
     }
 
+    /// Pointer to options instances storage.
+    OptionStorage* options_;
     /// Intermediate option storage. This storage is used by
     /// lower level parsers to add new options.  Values held
     /// in this storage are assigned to main storage (options_)
     /// if overall parsing was successful.
     OptionStorage local_options_;
-    /// Pointer to options instances storage.
-    OptionStorage* options_;
     /// Collection of parsers;
     ParserCollection parsers_;
 };
@@ -978,7 +981,7 @@ public:
 /// @brief Parser for a single option definition.
 ///
 /// This parser creates an instance of a single option definition.
-class OptionDefParser: DhcpConfigParser {
+class OptionDefParser : public DhcpConfigParser {
 public:
 
     /// @brief Constructor.
@@ -1005,7 +1008,8 @@ public:
             std::string entry(param.first);
             ParserPtr parser;
             if (entry == "name" || entry == "type" ||
-                entry == "record-types" || entry == "space") {
+                entry == "record-types" || entry == "space" ||
+                entry == "encapsulate") {
                 StringParserPtr
                     str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
                 if (str_parser) {
@@ -1055,8 +1059,8 @@ public:
 
     /// @brief Stores the parsed option definition in a storage.
     void commit() {
-        // @todo validate option space name once 2313 is merged.
-        if (storage_ && option_definition_) {
+        if (storage_ && option_definition_ &&
+            OptionSpace::validateName(option_space_name_)) {
             storage_->addItem(option_definition_, option_space_name_);
         }
     }
@@ -1078,11 +1082,10 @@ private:
     void createOptionDef() {
         // Get the option space name and validate it.
         std::string space = getParam<std::string>("space", string_values_);
-        // @todo uncomment the code below when the #2313 is merged.
-        /*        if (!OptionSpace::validateName()) {
+        if (!OptionSpace::validateName(space)) {
             isc_throw(DhcpConfigError, "invalid option space name '"
                       << space << "'");
-                      } */
+        }
 
         // Get other parameters that are needed to create the
         // option definition.
@@ -1090,9 +1093,35 @@ private:
         uint32_t code = getParam<uint32_t>("code", uint32_values_);
         std::string type = getParam<std::string>("type", string_values_);
         bool array_type = getParam<bool>("array", boolean_values_);
+        std::string encapsulates = getParam<std::string>("encapsulate",
+                                                         string_values_);
 
-        OptionDefinitionPtr def(new OptionDefinition(name, code,
-                                                     type, array_type));
+        // Create option definition.
+        OptionDefinitionPtr def;
+        // We need to check if user has set encapsulated option space
+        // name. If so, different constructor will be used.
+        if (!encapsulates.empty()) {
+            // Arrays can't be used together with sub-options.
+            if (array_type) {
+                isc_throw(DhcpConfigError, "option '" << space << "."
+                          << "name" << "', comprising an array of data"
+                          << " fields may not encapsulate any option space");
+
+            } else if (encapsulates == space) {
+                isc_throw(DhcpConfigError, "option must not encapsulate"
+                          << " an option space it belongs to: '"
+                          << space << "." << name << "' is set to"
+                          << " encapsulate '" << space << "'");
+
+            } else {
+                def.reset(new OptionDefinition(name, code, type,
+                                               encapsulates.c_str()));
+            }
+
+        } else {
+            def.reset(new OptionDefinition(name, code, type, array_type));
+
+        }
         // The record-types field may carry a list of comma separated names
         // of data types that form a record.
         std::string record_types = getParam<std::string>("record-types",
@@ -1110,7 +1139,7 @@ private:
                 }
             } catch (const Exception& ex) {
                 isc_throw(DhcpConfigError, "invalid record type values"
-                          << " specified for the option  definition: "
+                          << " specified for the option definition: "
                           << ex.what());
             }
         }
@@ -1332,6 +1361,63 @@ private:
         return (false);
     }
 
+    /// @brief Append sub-options to an option.
+    ///
+    /// @param option_space a name of the encapsulated option space.
+    /// @param option option instance to append sub-options to.
+    void appendSubOptions(const std::string& option_space, OptionPtr& option) {
+        // Only non-NULL options are stored in option container.
+        // If this option pointer is NULL this is a serious error.
+        assert(option);
+
+        OptionDefinitionPtr def;
+        if (option_space == "dhcp4" &&
+            LibDHCP::isStandardOption(Option::V4, option->getType())) {
+            def = LibDHCP::getOptionDef(Option::V4, option->getType());
+            // Definitions for some of the standard options hasn't been
+            // implemented so it is ok to leave here.
+            if (!def) {
+                return;
+            }
+        } else {
+            const OptionDefContainerPtr defs =
+                option_def_intermediate.getItems(option_space);
+            const OptionDefContainerTypeIndex& idx = defs->get<1>();
+            const OptionDefContainerTypeRange& range =
+                idx.equal_range(option->getType());
+            // There is no definition so we have to leave.
+            if (std::distance(range.first, range.second) == 0) {
+                return;
+            }
+
+            def = *range.first;
+
+            // If the definition exists, it must be non-NULL.
+            // Otherwise it is a programming error.
+            assert(def);
+        }
+
+        // We need to get option definition for the particular option space
+        // and code. This definition holds the information whether our
+        // option encapsulates any option space.
+        // Get the encapsulated option space name.
+        std::string encapsulated_space = def->getEncapsulatedSpace();
+        // If option space name is empty it means that our option does not
+        // encapsulate any option space (does not include sub-options).
+        if (!encapsulated_space.empty()) {
+            // Get the sub-options that belong to the encapsulated
+            // option space.
+            const Subnet::OptionContainerPtr sub_opts =
+                option_defaults.getItems(encapsulated_space);
+            // Append sub-options to the option.
+            BOOST_FOREACH(Subnet::OptionDescriptor desc, *sub_opts) {
+                if (desc.option) {
+                    option->addOption(desc.option);
+                }
+            }
+        }
+    }
+
     /// @brief Create a new subnet using a data from child parsers.
     ///
     /// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing failed.
@@ -1407,6 +1493,8 @@ private:
                     LOG_WARN(dhcp4_logger, DHCP4_CONFIG_OPTION_DUPLICATE)
                         .arg(desc.option->getType()).arg(addr.toText());
                 }
+                // Add sub-options (if any).
+                appendSubOptions(option_space, desc.option);
                 // In any case, we add the option to the subnet.
                 subnet_->addOption(desc.option, false, option_space);
             }
@@ -1434,6 +1522,9 @@ private:
                 Subnet::OptionDescriptor existing_desc =
                     subnet_->getOptionDescriptor(option_space, desc.option->getType());
                 if (!existing_desc.option) {
+                    // Add sub-options (if any).
+                    appendSubOptions(option_space, desc.option);
+
                     subnet_->addOption(desc.option, false, option_space);
                 }
             }
@@ -1607,6 +1698,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
     factories["option-data"] = OptionDataListParser::factory;
     factories["option-def"] = OptionDefListParser::factory;
     factories["version"] = StringParser::factory;
+    factories["lease-database"] = DbAccessParser::factory;
 
     FactoryMap::iterator f = factories.find(config_id);
     if (f == factories.end()) {
@@ -1661,13 +1753,18 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
     // rollback informs whether error occured and original data
     // have to be restored to global storages.
     bool rollback = false;
-
+    // config_pair holds the details of the current parser when iterating over
+    // the parsers.  It is declared outside the loops so in case of an error,
+    // the name of the failing parser can be retrieved in the "catch" clause.
+    ConfigPair config_pair;
     try {
         // Make parsers grouping.
         const std::map<std::string, ConstElementPtr>& values_map =
             config_set->mapValue();
-        BOOST_FOREACH(ConfigPair config_pair, values_map) {
+        BOOST_FOREACH(config_pair, values_map) {
             ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first));
+            LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
+                      .arg(config_pair.first);
             if (config_pair.first == "subnet4") {
                 subnet_parser = parser;
 
@@ -1702,16 +1799,19 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
         }
 
     } catch (const isc::Exception& ex) {
-        answer =
-            isc::config::createAnswer(1, string("Configuration parsing failed: ") + ex.what());
+        LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
+                  .arg(config_pair.first).arg(ex.what());
+        answer = isc::config::createAnswer(1,
+                     string("Configuration parsing failed: ") + ex.what());
 
         // An error occured, so make sure that we restore original data.
         rollback = true;
 
     } catch (...) {
         // for things like bad_cast in boost::lexical_cast
-        answer =
-            isc::config::createAnswer(1, string("Configuration parsing failed"));
+        LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(config_pair.first);
+        answer = isc::config::createAnswer(1,
+                     string("Configuration parsing failed"));
 
         // An error occured, so make sure that we restore original data.
         rollback = true;
@@ -1728,14 +1828,16 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
             }
         }
         catch (const isc::Exception& ex) {
-            answer =
-                isc::config::createAnswer(2, string("Configuration commit failed: ") + ex.what());
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(2,
+                         string("Configuration commit failed: ") + ex.what());
             rollback = true;
 
         } catch (...) {
             // for things like bad_cast in boost::lexical_cast
-            answer =
-                isc::config::createAnswer(2, string("Configuration commit failed"));
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(2,
+                         string("Configuration commit failed"));
             rollback = true;
 
         }
@@ -1753,7 +1855,7 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
     LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE).arg(config_details);
 
     // Everything was fine. Configuration is successful.
-    answer = isc::config::createAnswer(0, "Configuration commited.");
+    answer = isc::config::createAnswer(0, "Configuration committed.");
     return (answer);
 }
 
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index 435a25e..8ac49d3 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -47,18 +47,61 @@ namespace dhcp {
 ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
 
 ConstElementPtr
+ControlledDhcpv4Srv::dhcp4StubConfigHandler(ConstElementPtr) {
+    // This configuration handler is intended to be used only
+    // when the initial configuration comes in. To receive this
+    // configuration a pointer to this handler must be passed
+    // using ModuleCCSession constructor. This constructor will
+    // invoke the handler and will store the configuration for
+    // the configuration session when the handler returns success.
+    // Since this configuration is partial we just pretend to
+    // parse it and always return success. The function that
+    // initiates the session must get the configuration on its
+    // own using getFullConfig.
+    return (isc::config::createAnswer(0, "Configuration accepted."));
+}
+
+ConstElementPtr
 ControlledDhcpv4Srv::dhcp4ConfigHandler(ConstElementPtr new_config) {
-    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_UPDATE)
-              .arg(new_config->str());
-    if (server_) {
-        return (configureDhcp4Server(*server_, new_config));
+    if (!server_ || !server_->config_session_) {
+        // That should never happen as we install config_handler
+        // after we instantiate the server.
+        ConstElementPtr answer =
+            isc::config::createAnswer(1, "Configuration rejected,"
+                                      " server is during startup/shutdown phase.");
+        return (answer);
     }
 
-    // That should never happen as we install config_handler after we instantiate
-    // the server.
-    ConstElementPtr answer = isc::config::createAnswer(1,
-           "Configuration rejected, server is during startup/shutdown phase.");
-    return (answer);
+    // The configuration passed to this handler function is partial.
+    // In other words, it just includes the values being modified.
+    // In the same time, there are dependencies between various
+    // DHCP configuration parsers. For example: the option value can
+    // be set if the definition of this option is set. If someone removes
+    // an existing option definition then the partial configuration that
+    // removes that definition is triggered while a relevant option value
+    // may remain configured. This eventually results in the DHCP server
+    // configuration being in the inconsistent state.
+    // In order to work around this problem we need to merge the new
+    // configuration with the existing (full) configuration.
+
+    // Let's create a new object that will hold the merged configuration.
+    boost::shared_ptr<MapElement> merged_config(new MapElement());
+    // Let's get the existing configuration.
+    ConstElementPtr full_config = server_->config_session_->getFullConfig();
+    // The full_config and merged_config should be always non-NULL
+    // but to provide some level of exception safety we check that they
+    // really are (in case we go out of memory).
+    if (full_config && merged_config) {
+        merged_config->setValue(full_config->mapValue());
+
+        // Merge an existing and new configuration.
+        isc::data::merge(merged_config, new_config);
+        LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_UPDATE)
+            .arg(full_config->str());
+    }
+
+    // Configure the server.
+    return (configureDhcp4Server(*server_, merged_config));
 }
 
 ConstElementPtr
@@ -109,8 +152,15 @@ void ControlledDhcpv4Srv::establishSession() {
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTING)
               .arg(specfile);
     cc_session_ = new Session(io_service_.get_io_service());
+    // Create a session with the dummy configuration handler.
+    // Dumy configuration handler is internally invoked by the
+    // constructor and on success the constructor updates
+    // the current session with the configuration that had been
+    // commited in the previous session. If we did not install
+    // the dummy handler, the previous configuration would have
+    // been lost.
     config_session_ = new ModuleCCSession(specfile, *cc_session_,
-                                          NULL,
+                                          dhcp4StubConfigHandler,
                                           dhcp4CommandHandler, false);
     config_session_->start();
 
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h
index 9bd261c..ac15c44 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.h
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h
@@ -49,7 +49,7 @@ public:
     /// @brief Establishes msgq session.
     ///
     /// Creates session that will be used to receive commands and updated
-    /// configuration from boss (or indirectly from user via bindctl).
+    /// configuration from cfgmgr (or indirectly from user via bindctl).
     void establishSession();
 
     /// @brief Terminates existing msgq session.
@@ -94,6 +94,27 @@ protected:
     static isc::data::ConstElementPtr
     dhcp4ConfigHandler(isc::data::ConstElementPtr new_config);
 
+    /// @brief A dummy configuration handler that always returns success.
+    ///
+    /// This configuration handler does not perform configuration
+    /// parsing and always returns success. A dummy hanlder should
+    /// be installed using \ref isc::config::ModuleCCSession ctor
+    /// to get the initial configuration. This initial configuration
+    /// comprises values for only those elements that were modified
+    /// the previous session. The \ref dhcp4ConfigHandler can't be
+    /// used to parse the initial configuration because it needs the
+    /// full configuration to satisfy dependencies between the
+    /// various configuration values. Installing the dummy handler
+    /// that guarantees to return success causes initial configuration
+    /// to be stored for the session being created and that it can
+    /// be later accessed with \ref isc::ConfigData::getFullConfig.
+    ///
+    /// @param new_config new configuration.
+    ///
+    /// @return success configuration status.
+    static isc::data::ConstElementPtr
+    dhcp4StubConfigHandler(isc::data::ConstElementPtr new_config);
+
     /// @brief A callback for handling incoming commands.
     ///
     /// @param command textual representation of the command
diff --git a/src/bin/dhcp4/dhcp4.dox b/src/bin/dhcp4/dhcp4.dox
index 05f1670..c189c8a 100644
--- a/src/bin/dhcp4/dhcp4.dox
+++ b/src/bin/dhcp4/dhcp4.dox
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 /**
  @page dhcp4 DHCPv4 Server Component
 
diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec
index c2b755c..59d727e 100644
--- a/src/bin/dhcp4/dhcp4.spec
+++ b/src/bin/dhcp4/dhcp4.spec
@@ -55,13 +55,13 @@
           { "item_name": "code",
             "item_type": "integer",
             "item_optional": false,
-            "item_default": 0,
+            "item_default": 0
           },
 
           { "item_name": "type",
             "item_type": "string",
             "item_optional": false,
-            "item_default": "",
+            "item_default": ""
           },
 
           { "item_name": "array",
@@ -70,16 +70,22 @@
             "item_default": False
           },
 
-          { "item_name": "record_types",
+          { "item_name": "record-types",
             "item_type": "string",
             "item_optional": false,
-            "item_default": "",
+            "item_default": ""
           },
 
           { "item_name": "space",
             "item_type": "string",
             "item_optional": false,
             "item_default": ""
+          },
+
+          { "item_name": "encapsulate",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
           } ]
         }
       },
@@ -125,6 +131,44 @@
         }
       },
 
+      { "item_name": "lease-database",
+        "item_type": "map",
+        "item_optional": false,
+        "item_default": {"type": "memfile"},
+        "map_item_spec": [
+            {
+                "item_name": "type",
+                "item_type": "string",
+                "item_optional": false,
+                "item_default": ""
+            },
+            {
+                "item_name": "name",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "user",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "host",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "password",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            }
+        ]
+      },
+
       { "item_name": "subnet4",
         "item_type": "list",
         "item_optional": false,
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index fc47823..2f49ac8 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2013  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
@@ -26,6 +26,12 @@ to establish a session with the BIND 10 control channel.
 A debug message listing the command (and possible arguments) received
 from the BIND 10 control system by the IPv4 DHCP server.
 
+% DHCP4_CONFIG_COMPLETE DHCPv4 server has completed configuration: %1
+This is an informational message announcing the successful processing of a
+new configuration. It is output during server startup, and when an updated
+configuration is committed by the administrator.  Additional information
+may be provided.
+
 % DHCP4_CONFIG_LOAD_FAIL failed to load configuration: %1
 This critical error message indicates that the initial DHCPv4
 configuration has failed. The server will start, but nothing will be
@@ -40,20 +46,14 @@ This warning message is issued on an attempt to configure multiple options
 with the same option code for a particular subnet. Adding multiple options
 is uncommon for DHCPv4, but is not prohibited.
 
-% DHCP4_CONFIG_UPDATE updated configuration received: %1
-A debug message indicating that the IPv4 DHCP server has received an
-updated configuration from the BIND 10 configuration system.
-
 % DHCP4_CONFIG_START DHCPv4 server is processing the following configuration: %1
 This is a debug message that is issued every time the server receives a
 configuration. That happens at start up and also when a server configuration
 change is committed by the administrator.
 
-% DHCP4_CONFIG_COMPLETE DHCPv4 server has completed configuration: %1
-This is an informational message announcing the successful processing of a
-new configuration. It is output during server startup, and when an updated
-configuration is committed by the administrator.  Additional information
-may be provided.
+% DHCP4_CONFIG_UPDATE updated configuration received: %1
+A debug message indicating that the IPv4 DHCP server has received an
+updated configuration from the BIND 10 configuration system.
 
 % DHCP4_DB_BACKEND_STARTED lease database started (type: %1, name: %2)
 This informational message is printed every time DHCPv4 server is started
@@ -94,6 +94,11 @@ server is about to open sockets on the specified port.
 The IPv4 DHCP server has received a packet that it is unable to
 interpret. The reason why the packet is invalid is included in the message.
 
+% DHCP4_PACKET_PROCESS_FAIL failed to process packet received from %1: %2
+This is a general catch-all message indicating that the processing of a
+received packet failed.  The reason is given in the message.  The server
+will not send a response but will instead ignore the packet.
+
 % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
 A debug message noting that the server has received the specified type of
 packet on the specified interface.  Note that a packet marked as UNKNOWN
@@ -115,6 +120,38 @@ This error is output if the server failed to assemble the data to be
 returned to the client into a valid packet.  The cause is most likely
 to be a programming error: please raise a bug report.
 
+% DHCP4_PARSER_COMMIT_EXCEPTION parser failed to commit changes
+On receipt of message containing details to a change of the IPv4 DHCP
+server configuration, a set of parsers were successfully created, but one
+of them failed to commit its changes due to a low-level system exception
+being raised.  Additional messages may be output indicating the reason.
+
+% DHCP4_PARSER_COMMIT_FAIL parser failed to commit changes: %1
+On receipt of message containing details to a change of the IPv4 DHCP
+server configuration, a set of parsers were successfully created, but
+one of them failed to commit its changes.  The reason for the failure
+is given in the message.
+
+% DHCP4_PARSER_CREATED created parser for configuration element %1
+A debug message output during a configuration update of the IPv4 DHCP
+server, notifying that the parser for the specified configuration element
+has been successfully created.
+
+% DHCP4_PARSER_EXCEPTION failed to create or run parser for configuration element %1
+On receipt of message containing details to a change of its configuration,
+the IPv4 DHCP server failed to create a parser to decode the contents of
+the named configuration element, or the creation succeeded but the parsing
+actions and committal of changes failed.  The message has been output in
+response to a non-BIND 10 exception being raised.  Additional messages
+may give further information.
+
+% DHCP4_PARSER_FAIL failed to create or run parser for configuration element %1: %2
+On receipt of message containing details to a change of its configuration,
+the IPv4 DHCP server failed to create a parser to decode the contents
+of the named configuration element, or the creation succeeded but the
+parsing actions and committal of changes failed.  The reason for the
+failure is given in the message.
+
 % DHCP4_QUERY_DATA received packet type %1, data is <%2>
 A debug message listing the data received from the client.
 
@@ -158,6 +195,26 @@ both clones use the same client-id.
 % DHCP4_RESPONSE_DATA responding with packet type %1, data is <%2>
 A debug message listing the data returned to the client.
 
+% DHCP4_SERVERID_GENERATED server-id %1 has been generated and will be stored in %2
+This informational messages indicates that the server was not able to
+read its server identifier and has generated a new one. This server-id
+will be stored in a file and will be read (and used) whenever the server
+is restarted. This is normal behavior when the server is started for the
+first time. If this message is printed every time the server is started,
+please check that the server has sufficient permission to write its
+server-id file and that the file is not corrupt.
+
+% DHCP4_SERVERID_LOADED server-id %1 has been loaded from file %2
+This debug message indicates that the server loaded its server identifier.
+That value is sent in all server responses and clients use it to
+discriminate between servers. This is a part of normal startup or
+reconfiguration procedure.
+
+% DHCP4_SERVERID_WRITE_FAIL server was not able to write its ID to file %1
+This warning message indicates that server was not able to write its
+server identifier to a file. The most likely cause is is that the server
+does not have permissions to write the server id file.
+
 % DHCP4_SERVER_FAILED server failed: %1
 The IPv4 DHCP server has encountered a fatal error and is terminating.
 The reason for the failure is included in the message.
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 88ccfea..261e213 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
@@ -17,6 +17,7 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/option4_addrlst.h>
 #include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/duid.h>
 #include <dhcp/hwaddr.h>
@@ -30,18 +31,31 @@
 #include <dhcpsrv/utils.h>
 #include <dhcpsrv/addr_utilities.h>
 
+#include <boost/algorithm/string/erase.hpp>
+
+#include <iomanip>
+#include <fstream>
+
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::log;
 using namespace std;
 
+namespace isc {
+namespace dhcp {
+
+/// @brief file name of a server-id file
+///
+/// Server must store its server identifier in persistent storage that must not
+/// change between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
+/// first run and then use it afterwards.
+static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
+
 // These are hardcoded parameters. Currently this is a skeleton server that only
 // grants those options and a single, fixed, hardcoded lease.
-const std::string HARDCODED_GATEWAY = "192.0.2.1";
-const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
-const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
-const std::string HARDCODED_SERVER_ID = "192.0.2.1";
 
 Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
@@ -56,7 +70,23 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
             IfaceMgr::instance().openSockets4(port);
         }
 
-        setServerID();
+        string srvid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_ID_FILE);
+        if (loadServerID(srvid_file)) {
+            LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_SERVERID_LOADED)
+                .arg(srvidToString(getServerID()))
+                .arg(srvid_file);
+        } else {
+            generateServerID();
+            LOG_INFO(dhcp4_logger, DHCP4_SERVERID_GENERATED)
+                .arg(srvidToString(getServerID()))
+                .arg(srvid_file);
+
+            if (!writeServerID(srvid_file)) {
+                LOG_WARN(dhcp4_logger, DHCP4_SERVERID_WRITE_FAIL)
+                    .arg(srvid_file);
+            }
+
+        }
 
         // Instantiate LeaseMgr
         LeaseMgrFactory::create(dbconfig);
@@ -80,7 +110,8 @@ Dhcpv4Srv::~Dhcpv4Srv() {
     IfaceMgr::instance().closeSockets();
 }
 
-void Dhcpv4Srv::shutdown() {
+void
+Dhcpv4Srv::shutdown() {
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_SHUTDOWN_REQUEST);
     shutdown_ = true;
 }
@@ -118,32 +149,53 @@ Dhcpv4Srv::run() {
             LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
                       .arg(query->toText());
 
-            switch (query->getType()) {
-            case DHCPDISCOVER:
-                rsp = processDiscover(query);
-                break;
-
-            case DHCPREQUEST:
-                rsp = processRequest(query);
-                break;
-
-            case DHCPRELEASE:
-                processRelease(query);
-                break;
-
-            case DHCPDECLINE:
-                processDecline(query);
-                break;
-
-            case DHCPINFORM:
-                processInform(query);
-                break;
-
-            default:
-                // Only action is to output a message if debug is enabled,
-                // and that will be covered by the debug statement before
-                // the "switch" statement.
-                ;
+            try {
+                switch (query->getType()) {
+                case DHCPDISCOVER:
+                    rsp = processDiscover(query);
+                    break;
+
+                case DHCPREQUEST:
+                    rsp = processRequest(query);
+                    break;
+
+                case DHCPRELEASE:
+                    processRelease(query);
+                    break;
+
+                case DHCPDECLINE:
+                    processDecline(query);
+                    break;
+
+                case DHCPINFORM:
+                    processInform(query);
+                    break;
+
+                default:
+                    // Only action is to output a message if debug is enabled,
+                    // and that is covered by the debug statement before the
+                    // "switch" statement.
+                    ;
+                }
+            } catch (const isc::Exception& e) {
+
+                // Catch-all exception (at least for ones based on the isc
+                // Exception class, which covers more or less all that
+                // are explicitly raised in the BIND 10 code).  Just log
+                // the problem and ignore the packet. (The problem is logged
+                // as a debug message because debug is disabled by default -
+                // it prevents a DDOS attack based on the sending of problem
+                // packets.)
+                if (dhcp4_logger.isDebugEnabled(DBG_DHCP4_BASIC)) {
+                    std::string source = "unknown";
+                    HWAddrPtr hwptr = query->getHWAddr();
+                    if (hwptr) {
+                        source = hwptr->toText();
+                    }
+                    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
+                              DHCP4_PACKET_PROCESS_FAIL)
+                              .arg(source).arg(e.what());
+                }
             }
 
             if (rsp) {
@@ -176,22 +228,117 @@ Dhcpv4Srv::run() {
                 }
             }
         }
+    }
+
+    return (true);
+}
+
+bool
+Dhcpv4Srv::loadServerID(const std::string& file_name) {
 
-        // TODO add support for config session (see src/bin/auth/main.cc)
-        //      so this daemon can be controlled from bob
+    // load content of the file into a string
+    fstream f(file_name.c_str(), ios::in);
+    if (!f.is_open()) {
+        return (false);
+    }
+
+    string hex_string;
+    f >> hex_string;
+    f.close();
+
+    // remove any spaces
+    boost::algorithm::erase_all(hex_string, " ");
+
+    try {
+        IOAddress addr(hex_string);
+
+        if (!addr.isV4()) {
+            return (false);
+        }
+
+        // Now create server-id option
+        serverid_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, addr));
+
+    } catch(...) {
+        // any kind of malformed input (empty string, IPv6 address, complete
+        // garbate etc.)
+        return (false);
     }
 
     return (true);
 }
 
 void
-Dhcpv4Srv::setServerID() {
-    /// @todo: implement this for real (see ticket #2588)
-    serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
-                                             IOAddress(HARDCODED_SERVER_ID)));
+Dhcpv4Srv::generateServerID() {
+
+    const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+    // Let's find suitable interface.
+    for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
+         iface != ifaces.end(); ++iface) {
+
+        // Let's don't use loopback.
+        if (iface->flag_loopback_) {
+            continue;
+        }
+
+        // Let's skip downed interfaces. It is better to use working ones.
+        if (!iface->flag_up_) {
+            continue;
+        }
+
+        const IfaceMgr::AddressCollection addrs = iface->getAddresses();
+
+        for (IfaceMgr::AddressCollection::const_iterator addr = addrs.begin();
+             addr != addrs.end(); ++addr) {
+            if (addr->getFamily() != AF_INET) {
+                continue;
+            }
+
+            serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
+                                                     *addr));
+            return;
+        }
+
+
+    }
+
+    isc_throw(BadValue, "No suitable interfaces for server-identifier found");
+}
+
+bool
+Dhcpv4Srv::writeServerID(const std::string& file_name) {
+    fstream f(file_name.c_str(), ios::out | ios::trunc);
+    if (!f.good()) {
+        return (false);
+    }
+    f << srvidToString(getServerID());
+    f.close();
+    return (true);
+}
+
+string 
+Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
+    if (!srvid) {
+        isc_throw(BadValue, "NULL pointer passed to srvidToString()");
+    }
+    boost::shared_ptr<Option4AddrLst> generated =
+        boost::dynamic_pointer_cast<Option4AddrLst>(srvid);
+    if (!srvid) {
+        isc_throw(BadValue, "Pointer to invalid option passed to srvidToString()");
+    }
+
+    Option4AddrLst::AddressContainer addrs = generated->getAddresses();
+    if (addrs.size() != 1) {
+        isc_throw(BadValue, "Malformed option passed to srvidToString(). "
+                  << "Expected to contain a single IPv4 address.");
+    }
+
+    return (addrs[0].toText());
 }
 
-void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
+void
+Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     answer->setIface(question->getIface());
     answer->setIndex(question->getIndex());
     answer->setCiaddr(question->getCiaddr());
@@ -220,7 +367,8 @@ void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     }
 }
 
-void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
+void
+Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
     OptionPtr opt;
 
     // add Message Type Option (type 53)
@@ -232,22 +380,80 @@ void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
     // more options will be added here later
 }
 
+void
+Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
 
-void Dhcpv4Srv::appendRequestedOptions(Pkt4Ptr& msg) {
-    OptionPtr opt;
+    // Get the subnet relevant for the client. We will need it
+    // to get the options associated with it.
+    Subnet4Ptr subnet = selectSubnet(question);
+    // If we can't find the subnet for the client there is no way
+    // to get the options to be sent to a client. We don't log an
+    // error because it will be logged by the assignLease method
+    // anyway.
+    if (!subnet) {
+        return;
+    }
 
-    // Domain name (type 15)
-    vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
-    opt = OptionPtr(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
-    msg->addOption(opt);
-    // TODO: Add Option_String class
+    // try to get the 'Parameter Request List' option which holds the
+    // codes of requested options.
+    OptionUint8ArrayPtr option_prl = boost::dynamic_pointer_cast<
+        OptionUint8Array>(question->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
+    // If there is no PRL option in the message from the client then
+    // there is nothing to do.
+    if (!option_prl) {
+        return;
+    }
 
-    // DNS servers (type 6)
-    opt = OptionPtr(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
-    msg->addOption(opt);
+    // Get the codes of requested options.
+    const std::vector<uint8_t>& requested_opts = option_prl->getValues();
+    // For each requested option code get the instance of the option
+    // to be returned to the client.
+    for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
+         opt != requested_opts.end(); ++opt) {
+        Subnet::OptionDescriptor desc =
+            subnet->getOptionDescriptor("dhcp4", *opt);
+        if (desc.option) {
+            msg->addOption(desc.option);
+        }
+    }
 }
 
-void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
+void
+Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
+    // Identify options that we always want to send to the
+    // client (if they are configured).
+    static const uint16_t required_options[] = {
+        DHO_SUBNET_MASK,
+        DHO_ROUTERS,
+        DHO_DOMAIN_NAME_SERVERS,
+        DHO_DOMAIN_NAME };
+
+    static size_t required_options_size =
+        sizeof(required_options) / sizeof(required_options[0]);
+
+    // Get the subnet.
+    Subnet4Ptr subnet = selectSubnet(question);
+    if (!subnet) {
+        return;
+    }
+
+    // Try to find all 'required' options in the outgoing
+    // message. Those that are not present will be added.
+    for (int i = 0; i < required_options_size; ++i) {
+        OptionPtr opt = msg->getOption(required_options[i]);
+        if (!opt) {
+            // Check whether option has been configured.
+            Subnet::OptionDescriptor desc =
+                subnet->getOptionDescriptor("dhcp4", required_options[i]);
+            if (desc.option) {
+                msg->addOption(desc.option);
+            }
+        }
+    }
+}
+
+void
+Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
 
     // We need to select a subnet the client is connected in.
     Subnet4Ptr subnet = selectSubnet(question);
@@ -316,10 +522,12 @@ void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
         opt->setUint32(lease->valid_lft_);
         answer->addOption(opt);
 
-        // @todo: include real router information here
         // Router (type 3)
-        opt = OptionPtr(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
-        answer->addOption(opt);
+        Subnet::OptionDescriptor opt_routers =
+            subnet->getOptionDescriptor("dhcp4", DHO_ROUTERS);
+        if (opt_routers.option) {
+            answer->addOption(opt_routers.option);
+        }
 
         // Subnet mask (type 1)
         answer->addOption(getNetmaskOption(subnet));
@@ -343,7 +551,8 @@ void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     }
 }
 
-OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
+OptionPtr
+Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
     uint32_t netmask = getNetmask4(subnet->get().second);
 
     OptionPtr opt(new OptionInt<uint32_t>(Option::V4,
@@ -352,33 +561,46 @@ OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
     return (opt);
 }
 
-Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
+Pkt4Ptr
+Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
     Pkt4Ptr offer = Pkt4Ptr
         (new Pkt4(DHCPOFFER, discover->getTransid()));
 
     copyDefaultFields(discover, offer);
     appendDefaultOptions(offer, DHCPOFFER);
-    appendRequestedOptions(offer);
+    appendRequestedOptions(discover, offer);
 
     assignLease(discover, offer);
 
+    // There are a few basic options that we always want to
+    // include in the response. If client did not request
+    // them we append them for him.
+    appendBasicOptions(discover, offer);
+
     return (offer);
 }
 
-Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
+Pkt4Ptr
+Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
     Pkt4Ptr ack = Pkt4Ptr
         (new Pkt4(DHCPACK, request->getTransid()));
 
     copyDefaultFields(request, ack);
     appendDefaultOptions(ack, DHCPACK);
-    appendRequestedOptions(ack);
+    appendRequestedOptions(request, ack);
 
     assignLease(request, ack);
 
+    // There are a few basic options that we always want to
+    // include in the response. If client did not request
+    // them we append them for him.
+    appendBasicOptions(request, ack);
+
     return (ack);
 }
 
-void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
+void
+Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
 
     // Try to find client-id
     ClientIdPtr client_id;
@@ -446,11 +668,13 @@ void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
 
 }
 
-void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
+void
+Dhcpv4Srv::processDecline(Pkt4Ptr& /* decline */) {
     /// TODO: Implement this.
 }
 
-Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
+Pkt4Ptr
+Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
     /// TODO: Currently implemented echo mode. Implement this for real
     return (inform);
 }
@@ -486,7 +710,8 @@ Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
     return (UNKNOWN);
 }
 
-Subnet4Ptr Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
+Subnet4Ptr
+Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
 
     // Is this relayed message?
     IOAddress relay = question->getGiaddr();
@@ -501,7 +726,8 @@ Subnet4Ptr Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
     }
 }
 
-void Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
+void
+Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
     OptionPtr server_id = pkt->getOption(DHO_DHCP_SERVER_IDENTIFIER);
     switch (serverid) {
     case FORBIDDEN:
@@ -524,3 +750,6 @@ void Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
         ;
     }
 }
+
+}   // namespace dhcp
+}   // namespace isc
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index 53401c5..1c988b1 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
@@ -173,8 +173,9 @@ protected:
     /// This method assigns options that were requested by client
     /// (sent in PRL) or are enforced by server.
     ///
+    /// @param question DISCOVER or REQUEST message from a client.
     /// @param msg outgoing message (options will be added here)
-    void appendRequestedOptions(Pkt4Ptr& msg);
+    void appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
 
     /// @brief Assigns a lease and appends corresponding options
     ///
@@ -186,6 +187,19 @@ protected:
     /// @param answer OFFER or ACK/NAK message (lease options will be added here)
     void assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer);
 
+    /// @brief Append basic options if they are not present.
+    ///
+    /// This function adds the following basic options if they
+    /// are not yet added to the message:
+    /// - Subnet Mask,
+    /// - Router,
+    /// - Name Server,
+    /// - Domain Name.
+    ///
+    /// @param question DISCOVER or REQUEST message from a client.
+    /// @param msg the message to add options to.
+    void appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
+
     /// @brief Attempts to renew received addresses
     ///
     /// Attempts to renew existing lease. This typically includes finding a lease that
@@ -216,7 +230,32 @@ protected:
     ///
     /// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
     //          previously stored configuration and no network interfaces available)
-    void setServerID();
+    void generateServerID();
+
+    /// @brief attempts to load server-id from a file
+    ///
+    /// Tries to load duid from a text file. If the load is successful,
+    /// it creates server-id option and stores it in serverid_ (to be used
+    /// later by getServerID()).
+    ///
+    /// @param file_name name of the server-id file to load
+    /// @return true if load was successful, false otherwise
+    bool loadServerID(const std::string& file_name);
+
+    /// @brief attempts to write server-id to a file
+    /// Tries to write server-id content (stored in serverid_) to a text file.
+    ///
+    /// @param file_name name of the server-id file to write
+    /// @return true if write was successful, false otherwise
+    bool writeServerID(const std::string& file_name);
+
+    /// @brief converts server-id to text
+    /// Converts content of server-id option to a text representation, e.g.
+    /// "192.0.2.1"
+    ///
+    /// @param opt option that contains server-id
+    /// @return string representation
+    static std::string srvidToString(const OptionPtr& opt);
 
     /// @brief Selects a subnet for a given client's packet.
     ///
diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am
index c0ebcb9..73bf00b 100644
--- a/src/bin/dhcp4/tests/Makefile.am
+++ b/src/bin/dhcp4/tests/Makefile.am
@@ -34,6 +34,10 @@ AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
@@ -56,12 +60,6 @@ dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
 dhcp4_unittests_SOURCES += config_parser_unittest.cc
 nodist_dhcp4_unittests_SOURCES = ../dhcp4_messages.h ../dhcp4_messages.cc
 
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-dhcp4_unittests_CXXFLAGS = -Wno-unused-parameter
-endif
-
 dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp4_unittests_LDADD = $(GTEST_LDADD)
diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc
index ba14edf..9b3be51 100644
--- a/src/bin/dhcp4/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp4/tests/config_parser_unittest.cc
@@ -21,6 +21,8 @@
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/config_parser.h>
 #include <dhcp/option4_addrlst.h>
+#include <dhcp/option_custom.h>
+#include <dhcp/option_int.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <boost/foreach.hpp>
@@ -61,7 +63,7 @@ public:
         EXPECT_EQ(expected_value, it->second);
     }
 
-    // Checks if config_result (result of DHCP server configuration) has
+    // Checks if the result of DHCP server configuration has
     // expected code (0 for success, other for failures).
     // Also stores result in rcode_ and comment_.
     void checkResult(ConstElementPtr status, int expected_code) {
@@ -345,7 +347,6 @@ TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
         "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
         "    \"subnet\": \"192.0.2.0/24\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -379,7 +380,6 @@ TEST_F(Dhcp4ParserTest, subnetLocal) {
         "    \"valid-lifetime\": 4,"
         "    \"subnet\": \"192.0.2.0/24\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -408,7 +408,6 @@ TEST_F(Dhcp4ParserTest, poolOutOfSubnet) {
         "    \"pool\": [ \"192.0.4.0/28\" ],"
         "    \"subnet\": \"192.0.2.0/24\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -433,7 +432,6 @@ TEST_F(Dhcp4ParserTest, poolPrefixLen) {
         "    \"pool\": [ \"192.0.2.128/28\" ],"
         "    \"subnet\": \"192.0.2.0/24\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -461,7 +459,8 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
         "      \"type\": \"ipv4-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -474,6 +473,7 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
     ConstElementPtr status;
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     ASSERT_TRUE(status);
+    checkResult(status, 0);
 
     // The option definition should now be available in the CfgMgr.
     def = CfgMgr::instance().getOptionDef("isc", 100);
@@ -484,6 +484,7 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
     EXPECT_EQ(100, def->getCode());
     EXPECT_FALSE(def->getArrayType());
     EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def->getType());
+    EXPECT_TRUE(def->getEncapsulatedSpace().empty());
 }
 
 // The goal of this test is to check whether an option definiiton
@@ -499,7 +500,8 @@ TEST_F(Dhcp4ParserTest, optionDefRecord) {
         "      \"type\": \"record\","
         "      \"array\": False,"
         "      \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -523,6 +525,7 @@ TEST_F(Dhcp4ParserTest, optionDefRecord) {
     EXPECT_EQ(100, def->getCode());
     EXPECT_EQ(OPT_RECORD_TYPE, def->getType());
     EXPECT_FALSE(def->getArrayType());
+    EXPECT_TRUE(def->getEncapsulatedSpace().empty());
 
     // The option comprises the record of data fields. Verify that all
     // fields are present and they are of the expected types.
@@ -546,7 +549,8 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
         "      \"type\": \"uint32\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  },"
         "  {"
         "      \"name\": \"foo-2\","
@@ -554,7 +558,8 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
         "      \"type\": \"ipv4-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -578,6 +583,7 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
     EXPECT_EQ(100, def1->getCode());
     EXPECT_EQ(OPT_UINT32_TYPE, def1->getType());
     EXPECT_FALSE(def1->getArrayType());
+    EXPECT_TRUE(def1->getEncapsulatedSpace().empty());
 
     // Check the second option definition we have created.
     OptionDefinitionPtr def2 = CfgMgr::instance().getOptionDef("isc", 101);
@@ -588,6 +594,7 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
     EXPECT_EQ(101, def2->getCode());
     EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def2->getType());
     EXPECT_FALSE(def2->getArrayType());
+    EXPECT_TRUE(def2->getEncapsulatedSpace().empty());
 }
 
 // The goal of this test is to verify that the duplicated option
@@ -604,7 +611,8 @@ TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
         "      \"type\": \"uint32\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  },"
         "  {"
         "      \"name\": \"foo-2\","
@@ -612,7 +620,8 @@ TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
         "      \"type\": \"ipv4-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -640,7 +649,8 @@ TEST_F(Dhcp4ParserTest, optionDefArray) {
         "      \"type\": \"uint32\","
         "      \"array\": True,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -664,6 +674,48 @@ TEST_F(Dhcp4ParserTest, optionDefArray) {
     EXPECT_EQ(100, def->getCode());
     EXPECT_EQ(OPT_UINT32_TYPE, def->getType());
     EXPECT_TRUE(def->getArrayType());
+    EXPECT_TRUE(def->getEncapsulatedSpace().empty());
+}
+
+// The purpose of this test to verify that encapsulated option
+// space name may be specified.
+TEST_F(Dhcp4ParserTest, optionDefEncapsulate) {
+
+    // Configuration string. Included the encapsulated
+    // option space name.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"sub-opts-space\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Make sure that the particular option definition does not exist.
+    OptionDefinitionPtr def = CfgMgr::instance().getOptionDef("isc", 100);
+    ASSERT_FALSE(def);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // The option definition should now be available in the CfgMgr.
+    def = CfgMgr::instance().getOptionDef("isc", 100);
+    ASSERT_TRUE(def);
+
+    // Check the option data.
+    EXPECT_EQ("foo", def->getName());
+    EXPECT_EQ(100, def->getCode());
+    EXPECT_EQ(OPT_UINT32_TYPE, def->getType());
+    EXPECT_FALSE(def->getArrayType());
+    EXPECT_EQ("sub-opts-space", def->getEncapsulatedSpace());
 }
 
 /// The purpose of this test is to verify that the option definition
@@ -678,7 +730,8 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidName) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -703,7 +756,8 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidType) {
         "      \"type\": \"sting\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -728,7 +782,62 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidRecordType) {
         "      \"type\": \"record\","
         "      \"array\": False,"
         "      \"record-types\": \"uint32,uint8,sting\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the invalid encapsulated
+/// option space name is not accepted.
+TEST_F(Dhcp4ParserTest, optionDefInvalidEncapsulatedSpace) {
+    // Configuration string. The encapsulated option space
+    // name is invalid (% character is not allowed).
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"invalid%space%name\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the encapsulated
+/// option space name can't be specified for the option that
+/// comprises an array of data fields.
+TEST_F(Dhcp4ParserTest, optionDefEncapsulatedSpaceAndArray) {
+    // Configuration string. The encapsulated option space
+    // name is set to non-empty value and the array flag
+    // is set.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": True,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"valid-space-name\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -741,6 +850,31 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidRecordType) {
     checkResult(status, 1);
 }
 
+/// The goal of this test is to verify that the option may not
+/// encapsulate option space it belongs to.
+TEST_F(Dhcp4ParserTest, optionDefEncapsulateOwnSpace) {
+    // Configuration string. Option is set to encapsulate
+    // option space it belongs to.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"isc\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
 
 /// The purpose of this test is to verify that it is not allowed
 /// to override the standard option (that belongs to dhcp4 option
@@ -759,7 +893,8 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"dhcp4\""
+        "      \"space\": \"dhcp4\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -794,7 +929,8 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"dhcp4\""
+        "      \"space\": \"dhcp4\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     json = Element::fromJSON(config);
@@ -907,7 +1043,8 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
         "    \"type\": \"uint32\","
         "    \"array\": False,"
         "    \"record-types\": \"\","
-        "    \"space\": \"isc\""
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
         " } ],"
         "\"subnet4\": [ { "
         "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
@@ -940,6 +1077,166 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
     ASSERT_FALSE(desc3.option);
 }
 
+// The goal of this test is to verify that it is possible to
+// encapsulate option space containing some options with
+// another option. In this test we create base option that
+// encapsulates option space 'isc' that comprises two other
+// options. Also, for all options their definitions are
+// created.
+TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
+
+    // @todo DHCP configurations has many dependencies between
+    // parameters. First of all, configuration for subnet is
+    // inherited from the global values. Thus subnet has to be
+    // configured when all global values have been configured.
+    // Also, an option can encapsulate another option only
+    // if the latter has been configured. For this reason in this
+    // test we created two-stage configuration where first we
+    // created options that belong to encapsulated option space.
+    // In the second stage we add the base option. Also, the Subnet
+    // object is configured in the second stage so it is created
+    // at the very end (when all other parameters are configured).
+
+    // Starting stage 1. Configure sub-options and their definitions.
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 1,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"isc\","
+        "    \"code\": 2,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 1,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 2,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " } ]"
+        "}";
+
+    ConstElementPtr status;
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Stage 2. Configure base option and a subnet. Please note that
+    // the configuration from the stage 2 is repeated because BIND
+    // configuration manager sends whole configuration for the lists
+    // where at least one element is being modified or added.
+    config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"base-option\","
+        "    \"space\": \"dhcp4\","
+        "    \"code\": 222,"
+        "    \"data\": \"11\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 1,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"isc\","
+        "    \"code\": 2,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"base-option\","
+        "    \"code\": 222,"
+        "    \"type\": \"uint8\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"dhcp4\","
+        "    \"encapsulate\": \"isc\""
+        "},"
+        "{"
+        "    \"name\": \"foo\","
+        "    \"code\": 1,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 2,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " } ],"
+        "\"subnet4\": [ { "
+        "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+        "    \"subnet\": \"192.0.2.0/24\""
+        " } ]"
+        "}";
+
+
+    json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Get the subnet.
+    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"));
+    ASSERT_TRUE(subnet);
+
+    // We should have one option available.
+    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    ASSERT_TRUE(options);
+    ASSERT_EQ(1, options->size());
+
+    // Get the option.
+    Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp4", 222);
+    EXPECT_TRUE(desc.option);
+    EXPECT_EQ(222, desc.option->getType());
+
+    // This opton should comprise two sub-options.
+    // One of them is 'foo' with code 1.
+    OptionPtr option_foo = desc.option->getOption(1);
+    ASSERT_TRUE(option_foo);
+    EXPECT_EQ(1, option_foo->getType());
+
+    // ...another one 'foo2' with code 2.
+    OptionPtr option_foo2 = desc.option->getOption(2);
+    ASSERT_TRUE(option_foo2);
+    EXPECT_EQ(2, option_foo2->getType());
+}
+
 // Goal of this test is to verify options configuration
 // for a single subnet. In particular this test checks
 // that local options configuration overrides global
@@ -1290,4 +1587,165 @@ TEST_F(Dhcp4ParserTest, DISABLED_Uint32Parser) {
     checkResult(status, 1);
 }
 
+// The goal of this test is to verify that the standard option can
+// be configured to encapsulate multiple other options.
+TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
+
+    // The configuration is two stage process in this test.
+    // In the first stahe we create definitions of suboptions
+    // that we will add to the base option.
+    // Let's create some dummy options: foo and foo2.
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"code\": 1,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"code\": 2,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 1,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 2,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"encapsulate\": \"\""
+        " } ]"
+        "}";
+
+    ConstElementPtr status;
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Once the definitions have been added we can configure the
+    // standard option #17. This option comprises an enterprise
+    // number and sub options. By convention (introduced in
+    // std_option_defs.h) option named 'vendor-opts'
+    // encapsulates the option space named 'vendor-opts-space'.
+    // We add our dummy options to this option space and thus
+    // they should be included as sub-options in the 'vendor-opts'
+    // option.
+    config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"vendor-encapsulated-options\","
+        "    \"space\": \"dhcp4\","
+        "    \"code\": 43,"
+        "    \"data\": \"\","
+        "    \"csv-format\": False"
+        " },"
+        " {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"code\": 1,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"code\": 2,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 1,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 2,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-encapsulated-options-space\","
+        "    \"encapsulate\": \"\""
+        " } ],"
+        "\"subnet4\": [ { "
+        "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+        "    \"subnet\": \"192.0.2.0/24\""
+        " } ]"
+        "}";
+
+
+    json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Get the subnet.
+    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"));
+    ASSERT_TRUE(subnet);
+
+    // We should have one option available.
+    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    ASSERT_TRUE(options);
+    ASSERT_EQ(1, options->size());
+
+    // Get the option.
+    Subnet::OptionDescriptor desc =
+        subnet->getOptionDescriptor("dhcp4", DHO_VENDOR_ENCAPSULATED_OPTIONS);
+    EXPECT_TRUE(desc.option);
+    EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, desc.option->getType());
+
+    // Option with the code 1 should be added as a sub-option.
+    OptionPtr option_foo = desc.option->getOption(1);
+    ASSERT_TRUE(option_foo);
+    EXPECT_EQ(1, option_foo->getType());
+    // This option comprises a single uint32_t value thus it is
+    // represented by OptionInt<uint32_t> class. Let's get the
+    // object of this type.
+    boost::shared_ptr<OptionInt<uint32_t> > option_foo_uint32 =
+        boost::dynamic_pointer_cast<OptionInt<uint32_t> >(option_foo);
+    ASSERT_TRUE(option_foo_uint32);
+    // Validate the value according to the configuration.
+    EXPECT_EQ(1234, option_foo_uint32->getValue());
+
+    // Option with the code 2 should be added as a sub-option.
+    OptionPtr option_foo2 = desc.option->getOption(2);
+    ASSERT_TRUE(option_foo2);
+    EXPECT_EQ(2, option_foo2->getType());
+    // This option comprises the IPV4 address. Such option is
+    // represented by OptionCustom object.
+    OptionCustomPtr option_foo2_v4 =
+        boost::dynamic_pointer_cast<OptionCustom>(option_foo2);
+    ASSERT_TRUE(option_foo2_v4);
+    // Get the IP address carried by this option and validate it.
+    EXPECT_EQ("192.168.2.1", option_foo2_v4->readAddress().toText());
+
+    // Option with the code 3 should not be added.
+    EXPECT_FALSE(desc.option->getOption(3));
+}
+
+
 };
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
index bc2246f..c938155 100644
--- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -18,6 +18,9 @@
 #include <asiolink/io_address.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/option.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option_custom.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcpsrv/cfgmgr.h>
@@ -49,9 +52,15 @@ public:
     using Dhcpv4Srv::processDecline;
     using Dhcpv4Srv::processInform;
     using Dhcpv4Srv::getServerID;
+    using Dhcpv4Srv::loadServerID;
+    using Dhcpv4Srv::generateServerID;
+    using Dhcpv4Srv::writeServerID;
     using Dhcpv4Srv::sanityCheck;
+    using Dhcpv4Srv::srvidToString;
 };
 
+static const char* SRVID_FILE = "server-id-test.txt";
+
 class Dhcpv4SrvTest : public ::testing::Test {
 public:
 
@@ -67,12 +76,83 @@ public:
 
         CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().addSubnet4(subnet_);
+
+        // Add Router option.
+        Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
+        opt_routers->setAddress(IOAddress("192.0.2.2"));
+        subnet_->addOption(opt_routers, false, "dhcp4");
+
+        // it's ok if that fails. There should not be such a file anyway
+        unlink(SRVID_FILE);
+    }
+
+    /// @brief Add 'Parameter Request List' option to the packet.
+    ///
+    /// This function PRL option comprising the following option codes:
+    /// - 5 - Name Server
+    /// - 15 - Domain Name
+    /// - 7 - Log Server
+    /// - 8 - Quotes Server
+    /// - 9 - LPR Server
+    ///
+    /// @param pkt packet to add PRL option to.
+    void addPrlOption(Pkt4Ptr& pkt) {
+
+        OptionUint8ArrayPtr option_prl =
+            OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
+                                                     DHO_DHCP_PARAMETER_REQUEST_LIST));
+
+        // Let's request options that have been configured for the subnet.
+        option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
+        option_prl->addValue(DHO_DOMAIN_NAME);
+        option_prl->addValue(DHO_LOG_SERVERS);
+        option_prl->addValue(DHO_COOKIE_SERVERS);
+        // Let's also request the option that hasn't been configured. In such
+        // case server should ignore request for this particular option.
+        option_prl->addValue(DHO_LPR_SERVERS);
+        // And add 'Parameter Request List' option into the DISCOVER packet.
+        pkt->addOption(option_prl);
+    }
+
+    /// @brief Configures options being requested in the PRL option.
+    ///
+    /// The lpr-servers option is NOT configured here altough it is
+    /// added to the 'Parameter Request List' option in the
+    /// \ref addPrlOption. When requested option is not configured
+    /// the server should not return it in its rensponse. The goal
+    /// of not configuring the requested option is to verify that
+    /// the server will not return it.
+    void configureRequestedOptions() {
+        // dns-servers
+        Option4AddrLstPtr
+            option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
+        option_dns_servers->addAddress(IOAddress("192.0.2.1"));
+        option_dns_servers->addAddress(IOAddress("192.0.2.100"));
+        ASSERT_NO_THROW(subnet_->addOption(option_dns_servers, false, "dhcp4"));
+
+        // domain-name
+        OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
+        boost::shared_ptr<OptionCustom>
+            option_domain_name(new OptionCustom(def, Option::V4));
+        option_domain_name->writeFqdn("example.com");
+        subnet_->addOption(option_domain_name, false, "dhcp4");
+
+        // log-servers
+        Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
+        option_log_servers->addAddress(IOAddress("192.0.2.2"));
+        option_log_servers->addAddress(IOAddress("192.0.2.10"));
+        ASSERT_NO_THROW(subnet_->addOption(option_log_servers, false, "dhcp4"));
+
+        // cookie-servers
+        Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
+        option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
+        ASSERT_NO_THROW(subnet_->addOption(option_cookie_servers, false, "dhcp4"));
     }
 
     /// @brief checks that the response matches request
     /// @param q query (client's message)
     /// @param a answer (server's message)
-    void MessageCheck(const boost::shared_ptr<Pkt4>& q,
+    void messageCheck(const boost::shared_ptr<Pkt4>& q,
                       const boost::shared_ptr<Pkt4>& a) {
         ASSERT_TRUE(q);
         ASSERT_TRUE(a);
@@ -82,20 +162,40 @@ public:
         EXPECT_EQ(q->getIndex(),  a->getIndex());
         EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
 
-        // Check that bare minimum of required options are there
+        // Check that bare minimum of required options are there.
+        // We don't check options requested by a client. Those
+        // are checked elsewhere.
         EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
         EXPECT_TRUE(a->getOption(DHO_ROUTERS));
         EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
         EXPECT_TRUE(a->getOption(DHO_DHCP_LEASE_TIME));
         EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
-        EXPECT_TRUE(a->getOption(DHO_ROUTERS));
-        EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME));
-        EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME_SERVERS));
 
         // Check that something is offered
         EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
     }
 
+    /// @brief Check that requested options are present.
+    ///
+    /// @param pkt packet to be checked.
+    void optionsCheck(const Pkt4Ptr& pkt) {
+        // Check that the requested and configured options are returned
+        // in the ACK message.
+        EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME))
+            << "domain-name not present in the response";
+        EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME_SERVERS))
+            << "dns-servers not present in the response";
+        EXPECT_TRUE(pkt->getOption(DHO_LOG_SERVERS))
+            << "log-servers not present in the response";
+        EXPECT_TRUE(pkt->getOption(DHO_COOKIE_SERVERS))
+            << "cookie-servers not present in the response";
+        // Check that the requested but not configured options are not
+        // returned in the ACK message.
+        EXPECT_FALSE(pkt->getOption(DHO_LPR_SERVERS))
+            << "domain-name present in the response but it is"
+            << " expected not to be present";
+    }
+
     /// @brief generates client-id option
     ///
     /// Generate client-id option of specified length
@@ -134,11 +234,13 @@ public:
     /// Check that address was returned from proper range, that its lease
     /// lifetime is correct, that T1 and T2 are returned properly
     /// @param rsp response to be checked
-    /// @param subnet subnet that should be used to verify assigned address and options
+    /// @param subnet subnet that should be used to verify assigned address
+    ///        and options
     /// @param t1_mandatory is T1 mandatory?
     /// @param t2_mandatory is T2 mandatory?
     void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
-                            bool t1_mandatory = false, bool t2_mandatory = false) {
+                            bool t1_mandatory = false,
+                            bool t2_mandatory = false) {
 
         // Technically inPool implies inRange, but let's be on the safe
         // side and check both.
@@ -168,7 +270,7 @@ public:
         if (opt) {
             EXPECT_EQ(opt->getUint32(), subnet->getT2());
         } else {
-            if (t1_mandatory) {
+            if (t2_mandatory) {
                 ADD_FAILURE() << "Required T2 option missing";
             }
         }
@@ -245,6 +347,9 @@ public:
 
     ~Dhcpv4SrvTest() {
         CfgMgr::instance().deleteSubnets4();
+
+        // Let's clean up if there is such a file.
+        unlink(SRVID_FILE);
     };
 
     /// @brief A subnet used in most tests
@@ -312,6 +417,12 @@ TEST_F(Dhcpv4SrvTest, processDiscover) {
     pkt->setHops(3);
     pkt->setRemotePort(DHCP4_SERVER_PORT);
 
+    // We are going to test that certain options are returned
+    // (or not returned) in the OFFER message when requested
+    // using 'Parameter Request List' option. Let's configure
+    // those options that are returned when requested.
+    configureRequestedOptions();
+
     // Should not throw
     EXPECT_NO_THROW(
         offer = srv->processDiscover(pkt);
@@ -325,7 +436,39 @@ TEST_F(Dhcpv4SrvTest, processDiscover) {
     // This is relayed message. It should be sent back to relay address.
     EXPECT_EQ(pkt->getGiaddr(), offer->getRemoteAddr());
 
-    MessageCheck(pkt, offer);
+    messageCheck(pkt, offer);
+
+    // There are some options that are always present in the
+    // message, even if not requested.
+    EXPECT_TRUE(offer->getOption(DHO_DOMAIN_NAME));
+    EXPECT_TRUE(offer->getOption(DHO_DOMAIN_NAME_SERVERS));
+
+    // We did not request any options so they should not be present
+    // in the OFFER.
+    EXPECT_FALSE(offer->getOption(DHO_LOG_SERVERS));
+    EXPECT_FALSE(offer->getOption(DHO_COOKIE_SERVERS));
+    EXPECT_FALSE(offer->getOption(DHO_LPR_SERVERS));
+
+    // Add 'Parameter Request List' option.
+    addPrlOption(pkt);
+
+    // Now repeat the test but request some options.
+    EXPECT_NO_THROW(
+        offer = srv->processDiscover(pkt);
+    );
+
+    // Should return something
+    ASSERT_TRUE(offer);
+
+    EXPECT_EQ(DHCPOFFER, offer->getType());
+
+    // This is relayed message. It should be sent back to relay address.
+    EXPECT_EQ(pkt->getGiaddr(), offer->getRemoteAddr());
+
+    messageCheck(pkt, offer);
+
+    // Check that the requested options are returned.
+    optionsCheck(offer);
 
     // Now repeat the test for directly sent message
     pkt->setHops(0);
@@ -345,7 +488,10 @@ TEST_F(Dhcpv4SrvTest, processDiscover) {
     // to relay.
     EXPECT_EQ(pkt->getRemoteAddr(), offer->getRemoteAddr());
 
-    MessageCheck(pkt, offer);
+    messageCheck(pkt, offer);
+
+    // Check that the requested options are returned.
+    optionsCheck(offer);
 
     delete srv;
 }
@@ -373,6 +519,12 @@ TEST_F(Dhcpv4SrvTest, processRequest) {
     req->setRemoteAddr(IOAddress("192.0.2.56"));
     req->setGiaddr(IOAddress("192.0.2.67"));
 
+    // We are going to test that certain options are returned
+    // in the ACK message when requested using 'Parameter
+    // Request List' option. Let's configure those options that
+    // are returned when requested.
+    configureRequestedOptions();
+
     // Should not throw
     ASSERT_NO_THROW(
         ack = srv->processRequest(req);
@@ -386,7 +538,37 @@ TEST_F(Dhcpv4SrvTest, processRequest) {
     // This is relayed message. It should be sent back to relay address.
     EXPECT_EQ(req->getGiaddr(), ack->getRemoteAddr());
 
-    MessageCheck(req, ack);
+    messageCheck(req, ack);
+
+    // There are some options that are always present in the
+    // message, even if not requested.
+    EXPECT_TRUE(ack->getOption(DHO_DOMAIN_NAME));
+    EXPECT_TRUE(ack->getOption(DHO_DOMAIN_NAME_SERVERS));
+
+    // We did not request any options so these should not be present
+    // in the ACK.
+    EXPECT_FALSE(ack->getOption(DHO_LOG_SERVERS));
+    EXPECT_FALSE(ack->getOption(DHO_COOKIE_SERVERS));
+    EXPECT_FALSE(ack->getOption(DHO_LPR_SERVERS));
+
+    // Add 'Parameter Request List' option.
+    addPrlOption(req);
+
+    // Repeat the test but request some options.
+    ASSERT_NO_THROW(
+        ack = srv->processRequest(req);
+    );
+
+    // Should return something
+    ASSERT_TRUE(ack);
+
+    EXPECT_EQ(DHCPACK, ack->getType());
+
+    // This is relayed message. It should be sent back to relay address.
+    EXPECT_EQ(req->getGiaddr(), ack->getRemoteAddr());
+
+    // Check that the requested options are returned.
+    optionsCheck(ack);
 
     // Now repeat the test for directly sent message
     req->setHops(0);
@@ -406,7 +588,10 @@ TEST_F(Dhcpv4SrvTest, processRequest) {
     // to relay.
     EXPECT_EQ(ack->getRemoteAddr(), req->getRemoteAddr());
 
-    MessageCheck(req, ack);
+    messageCheck(req, ack);
+
+    // Check that the requested options are returned.
+    optionsCheck(ack);
 
     delete srv;
 }
@@ -691,7 +876,7 @@ TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
     checkAddressParams(offer2, subnet_);
     checkAddressParams(offer3, subnet_);
 
-    // Check DUIDs
+    // Check server-ids
     checkServerId(offer1, srv->getServerID());
     checkServerId(offer2, srv->getServerID());
     checkServerId(offer3, srv->getServerID());
@@ -878,7 +1063,6 @@ TEST_F(Dhcpv4SrvTest, RenewBasic) {
 
     // let's create a lease and put it in the LeaseMgr
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
-    uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
     Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
                               &client_id_->getDuid()[0], client_id_->getDuid().size(),
                               temp_valid, temp_t1, temp_t2, temp_timestamp,
@@ -1126,4 +1310,34 @@ TEST_F(Dhcpv4SrvTest, ReleaseReject) {
     EXPECT_FALSE(l);
 }
 
+// This test verifies if the server-id disk operations (read, write) are
+// working properly.
+TEST_F(Dhcpv4SrvTest, ServerID) {
+    NakedDhcpv4Srv srv(0);
+
+    string srvid_text = "192.0.2.100";
+    IOAddress srvid(srvid_text);
+
+    fstream file1(SRVID_FILE, ios::out | ios::trunc);
+    file1 << srvid_text;
+    file1.close();
+
+    // Test reading from a file
+    EXPECT_TRUE(srv.loadServerID(SRVID_FILE));
+    ASSERT_TRUE(srv.getServerID());
+    EXPECT_EQ(srvid_text, srv.srvidToString(srv.getServerID()));
+
+    // Now test writing to a file
+    EXPECT_EQ(0, unlink(SRVID_FILE));
+    EXPECT_NO_THROW(srv.writeServerID(SRVID_FILE));
+
+    fstream file2(SRVID_FILE, ios::in);
+    ASSERT_TRUE(file2.good());
+    string text;
+    file2 >> text;
+    file2.close();
+
+    EXPECT_EQ(srvid_text, text);
+}
+
 } // end of anonymous namespace
diff --git a/src/bin/dhcp4/tests/dhcp4_test.py b/src/bin/dhcp4/tests/dhcp4_test.py
index e493e04..276456e 100644
--- a/src/bin/dhcp4/tests/dhcp4_test.py
+++ b/src/bin/dhcp4/tests/dhcp4_test.py
@@ -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_src import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+from init import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
 
 import unittest
 import sys
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index decd986..3b07510 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -6,6 +6,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
@@ -53,12 +57,6 @@ b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h
 nodist_b10_dhcp6_SOURCES = dhcp6_messages.h dhcp6_messages.cc
 EXTRA_DIST += dhcp6_messages.mes
 
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
-endif
-
 b10_dhcp6_LDADD  = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
diff --git a/src/bin/dhcp6/b10-dhcp6.xml b/src/bin/dhcp6/b10-dhcp6.xml
index 53227db..eb8d869 100644
--- a/src/bin/dhcp6/b10-dhcp6.xml
+++ b/src/bin/dhcp6/b10-dhcp6.xml
@@ -79,6 +79,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>.
     </para>
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index f2eb34c..76ed228 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -20,6 +20,7 @@
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/dbaccess_parser.h>
 #include <dhcpsrv/dhcp_config_parser.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/subnet.h>
@@ -59,9 +60,6 @@ typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
 typedef boost::shared_ptr<StringParser> StringParserPtr;
 typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 
-/// @brief Auxiliary type used for storing an element name and its parser.
-typedef pair<string, ConstElementPtr> ConfigPair;
-
 /// @brief Factory method that will create a parser for a given element name
 typedef isc::dhcp::DhcpConfigParser* ParserFactory(const std::string& config_id);
 
@@ -104,7 +102,6 @@ OptionStorage option_defaults;
 /// @brief Global storage for option definitions.
 OptionDefStorage option_def_intermediate;
 
-
 /// @brief a dummy configuration parser
 ///
 /// This is a debugging parser. It does not configure anything,
@@ -719,7 +716,7 @@ public:
     virtual void commit() {
         if (options_ == NULL) {
             isc_throw(isc::InvalidOperation, "parser logic error: storage must be set before "
-                      "commiting option data.");
+                      "committing option data.");
         } else  if (!option_descriptor_.option) {
             // Before we can commit the new option should be configured. If it is not
             // than somebody must have called commit() before build().
@@ -779,27 +776,31 @@ private:
         // does not exceed range of uint16_t and is not zero.
         uint32_t option_code = getParam<uint32_t>("code", uint32_values_);
         if (option_code == 0) {
-            isc_throw(DhcpConfigError, "Parser error: value of 'code' must not"
-                      << " be equal to zero. Option code '0' is reserved in"
-                      << " DHCPv6.");
+            isc_throw(DhcpConfigError, "option code must not be zero."
+                      << " Option code '0' is reserved in DHCPv6.");
         } else if (option_code > std::numeric_limits<uint16_t>::max()) {
-            isc_throw(DhcpConfigError, "Parser error: value of 'code' must not"
-                      << " exceed " << std::numeric_limits<uint16_t>::max());
+            isc_throw(DhcpConfigError, "invalid option code '" << option_code
+                      << "', it must not exceed '"
+                      << std::numeric_limits<uint16_t>::max() << "'");
         }
         // Check that the option name has been specified, is non-empty and does not
         // contain spaces.
-        // @todo possibly some more restrictions apply here?
         std::string option_name = getParam<std::string>("name", string_values_);
         if (option_name.empty()) {
-            isc_throw(DhcpConfigError, "Parser error: option name must not be"
-                      << " empty");
+            isc_throw(DhcpConfigError, "name of the option with code '"
+                      << option_code << "' is empty");
         } else if (option_name.find(" ") != std::string::npos) {
-            isc_throw(DhcpConfigError, "Parser error: option name must not contain"
-                      << " spaces");
+            isc_throw(DhcpConfigError, "invalid option name '" << option_name
+                      << "', space character is not allowed");
         }
 
         std::string option_space = getParam<std::string>("space", string_values_);
-        /// @todo Validate option space once #2313 is merged.
+        if (!OptionSpace::validateName(option_space)) {
+            isc_throw(DhcpConfigError, "invalid option space name '"
+                      << option_space << "' specified for option '"
+                      << option_name << "' (code '" << option_code
+                      << "')");
+        }
 
         OptionDefinitionPtr def;
         if (option_space == "dhcp6" &&
@@ -888,7 +889,7 @@ private:
             // definition of option value makes sense.
             if (def->getName() != option_name) {
                 isc_throw(DhcpConfigError, "specified option name '"
-                          << option_name << " does not match the "
+                          << option_name << "' does not match the "
                           << "option definition: '" << option_space
                           << "." << def->getName() << "'");
             }
@@ -995,13 +996,13 @@ public:
         return (new OptionDataListParser(param_name));
     }
 
+    /// Pointer to options instances storage.
+    OptionStorage* options_;
     /// Intermediate option storage. This storage is used by
     /// lower level parsers to add new options.  Values held
     /// in this storage are assigned to main storage (options_)
     /// if overall parsing was successful.
     OptionStorage local_options_;
-    /// Pointer to options instances storage.
-    OptionStorage* options_;
     /// Collection of parsers;
     ParserCollection parsers_;
 };
@@ -1035,8 +1036,8 @@ public:
         BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
             std::string entry(param.first);
             ParserPtr parser;
-            if (entry == "name" || entry == "type" ||
-                entry == "record-types" || entry == "space") {
+            if (entry == "name" || entry == "type" || entry == "record-types" ||
+                entry == "space" || entry == "encapsulate") {
                 StringParserPtr
                     str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
                 if (str_parser) {
@@ -1086,8 +1087,8 @@ public:
 
     /// @brief Stores the parsed option definition in the data store.
     void commit() {
-        // @todo validate option space name once 2313 is merged.
-        if (storage_ && option_definition_) {
+        if (storage_ && option_definition_ &&
+            OptionSpace::validateName(option_space_name_)) {
             storage_->addItem(option_definition_, option_space_name_);
         }
     }
@@ -1109,11 +1110,10 @@ private:
     void createOptionDef() {
         // Get the option space name and validate it.
         std::string space = getParam<std::string>("space", string_values_);
-        // @todo uncomment the code below when the #2313 is merged.
-        /*        if (!OptionSpace::validateName()) {
+        if (!OptionSpace::validateName(space)) {
             isc_throw(DhcpConfigError, "invalid option space name '"
                       << space << "'");
-                      } */
+        }
 
         // Get other parameters that are needed to create the
         // option definition.
@@ -1121,9 +1121,36 @@ private:
         uint32_t code = getParam<uint32_t>("code", uint32_values_);
         std::string type = getParam<std::string>("type", string_values_);
         bool array_type = getParam<bool>("array", boolean_values_);
+        std::string encapsulates = getParam<std::string>("encapsulate",
+                                                         string_values_);
+
+        // Create option definition.
+        OptionDefinitionPtr def;
+        // We need to check if user has set encapsulated option space
+        // name. If so, different constructor will be used.
+        if (!encapsulates.empty()) {
+            // Arrays can't be used together with sub-options.
+            if (array_type) {
+                isc_throw(DhcpConfigError, "option '" << space << "."
+                          << "name" << "', comprising an array of data"
+                          << " fields may not encapsulate any option space");
+
+            } else if (encapsulates == space) {
+                isc_throw(DhcpConfigError, "option must not encapsulate"
+                          << " an option space it belongs to: '"
+                          << space << "." << name << "' is set to"
+                          << " encapsulate '" << space << "'");
+
+            } else {
+                def.reset(new OptionDefinition(name, code, type,
+                                               encapsulates.c_str()));
+            }
+
+        } else {
+            def.reset(new OptionDefinition(name, code, type, array_type));
+
+        }
 
-        OptionDefinitionPtr def(new OptionDefinition(name, code,
-                                                     type, array_type));
         // The record-types field may carry a list of comma separated names
         // of data types that form a record.
         std::string record_types = getParam<std::string>("record-types",
@@ -1141,7 +1168,7 @@ private:
                 }
             } catch (const Exception& ex) {
                 isc_throw(DhcpConfigError, "invalid record type values"
-                          << " specified for the option  definition: "
+                          << " specified for the option definition: "
                           << ex.what());
             }
         }
@@ -1360,6 +1387,63 @@ private:
         return (false);
     }
 
+    /// @brief Append sub-options to an option.
+    ///
+    /// @param option_space a name of the encapsulated option space.
+    /// @param option option instance to append sub-options to.
+    void appendSubOptions(const std::string& option_space, OptionPtr& option) {
+        // Only non-NULL options are stored in option container.
+        // If this option pointer is NULL this is a serious error.
+        assert(option);
+
+        OptionDefinitionPtr def;
+        if (option_space == "dhcp6" &&
+            LibDHCP::isStandardOption(Option::V6, option->getType())) {
+            def = LibDHCP::getOptionDef(Option::V6, option->getType());
+            // Definitions for some of the standard options hasn't been
+            // implemented so it is ok to leave here.
+            if (!def) {
+                return;
+            }
+        } else {
+            const OptionDefContainerPtr defs =
+                option_def_intermediate.getItems(option_space);
+            const OptionDefContainerTypeIndex& idx = defs->get<1>();
+            const OptionDefContainerTypeRange& range =
+                idx.equal_range(option->getType());
+            // There is no definition so we have to leave.
+            if (std::distance(range.first, range.second) == 0) {
+                return;
+            }
+
+            def = *range.first;
+
+            // If the definition exists, it must be non-NULL.
+            // Otherwise it is a programming error.
+            assert(def);
+        }
+
+        // We need to get option definition for the particular option space
+        // and code. This definition holds the information whether our
+        // option encapsulates any option space.
+        // Get the encapsulated option space name.
+        std::string encapsulated_space = def->getEncapsulatedSpace();
+        // If option space name is empty it means that our option does not
+        // encapsulate any option space (does not include sub-options).
+        if (!encapsulated_space.empty()) {
+            // Get the sub-options that belong to the encapsulated
+            // option space.
+            const Subnet::OptionContainerPtr sub_opts =
+                option_defaults.getItems(encapsulated_space);
+            // Append sub-options to the option.
+            BOOST_FOREACH(Subnet::OptionDescriptor desc, *sub_opts) {
+                if (desc.option) {
+                    option->addOption(desc.option);
+                }
+            }
+        }
+    }
+
     /// @brief Create a new subnet using a data from child parsers.
     ///
     /// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing failed.
@@ -1460,6 +1544,8 @@ private:
                     LOG_WARN(dhcp6_logger, DHCP6_CONFIG_OPTION_DUPLICATE)
                         .arg(desc.option->getType()).arg(addr.toText());
                 }
+                // Add sub-options (if any).
+                appendSubOptions(option_space, desc.option);
                 // In any case, we add the option to the subnet.
                 subnet_->addOption(desc.option, false, option_space);
             }
@@ -1487,6 +1573,9 @@ private:
                 Subnet::OptionDescriptor existing_desc =
                     subnet_->getOptionDescriptor(option_space, desc.option->getType());
                 if (!existing_desc.option) {
+                    // Add sub-options (if any).
+                    appendSubOptions(option_space, desc.option);
+
                     subnet_->addOption(desc.option, false, option_space);
                 }
             }
@@ -1663,6 +1752,7 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
     factories["option-data"] = OptionDataListParser::factory;
     factories["option-def"] = OptionDefListParser::factory;
     factories["version"] = StringParser::factory;
+    factories["lease-database"] = DbAccessParser::factory;
 
     FactoryMap::iterator f = factories.find(config_id);
     if (f == factories.end()) {
@@ -1717,13 +1807,19 @@ configureDhcp6Server(Dhcpv6Srv&, ConstElementPtr config_set) {
     // rollback informs whether error occured and original data
     // have to be restored to global storages.
     bool rollback = false;
+    // config_pair holds ther details of the current parser when iterating over
+    // the parsers.  It is declared outside the loop so in case of error, the
+    // name of the failing parser can be retrieved within the "catch" clause.
+    ConfigPair config_pair;
     try {
 
         // Make parsers grouping.
         const std::map<std::string, ConstElementPtr>& values_map =
             config_set->mapValue();
-        BOOST_FOREACH(ConfigPair config_pair, values_map) {
+        BOOST_FOREACH(config_pair, values_map) {
             ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
+                      .arg(config_pair.first);
             if (config_pair.first == "subnet6") {
                 subnet_parser = parser;
 
@@ -1758,15 +1854,18 @@ configureDhcp6Server(Dhcpv6Srv&, ConstElementPtr config_set) {
         }
 
     } catch (const isc::Exception& ex) {
-        answer =
-            isc::config::createAnswer(1, string("Configuration parsing failed: ") + ex.what());
+        LOG_ERROR(dhcp6_logger, DHCP6_PARSER_FAIL)
+                  .arg(config_pair.first).arg(ex.what());
+        answer = isc::config::createAnswer(1,
+                     string("Configuration parsing failed: ") + ex.what());
         // An error occured, so make sure that we restore original data.
         rollback = true;
 
     } catch (...) {
         // for things like bad_cast in boost::lexical_cast
-        answer =
-            isc::config::createAnswer(1, string("Configuration parsing failed"));
+        LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(config_pair.first);
+        answer = isc::config::createAnswer(1,
+                     string("Configuration parsing failed"));
         // An error occured, so make sure that we restore original data.
         rollback = true;
     }
@@ -1782,15 +1881,16 @@ configureDhcp6Server(Dhcpv6Srv&, ConstElementPtr config_set) {
             }
         }
         catch (const isc::Exception& ex) {
-            answer =
-                isc::config::createAnswer(2, string("Configuration commit failed:") 
-                                          + ex.what());
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(2,
+                         string("Configuration commit failed:") + ex.what());
             // An error occured, so make sure to restore the original data.
             rollback = true;
         } catch (...) {
             // for things like bad_cast in boost::lexical_cast
-            answer =
-                isc::config::createAnswer(2, string("Configuration commit failed"));
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(2,
+                         string("Configuration commit failed"));
             // An error occured, so make sure to restore the original data.
             rollback = true;
         }
@@ -1808,7 +1908,7 @@ configureDhcp6Server(Dhcpv6Srv&, ConstElementPtr config_set) {
     LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
 
     // Everything was fine. Configuration is successful.
-    answer = isc::config::createAnswer(0, "Configuration commited.");
+    answer = isc::config::createAnswer(0, "Configuration committed.");
     return (answer);
 }
 
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index ba3e2c2..e4e17f1 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -42,23 +42,65 @@ using namespace std;
 namespace isc {
 namespace dhcp {
 
-
 ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
 
 ConstElementPtr
+ControlledDhcpv6Srv::dhcp6StubConfigHandler(ConstElementPtr) {
+    // This configuration handler is intended to be used only
+    // when the initial configuration comes in. To receive this
+    // configuration a pointer to this handler must be passed
+    // using ModuleCCSession constructor. This constructor will
+    // invoke the handler and will store the configuration for
+    // the configuration session when the handler returns success.
+    // Since this configuration is partial we just pretend to
+    // parse it and always return success. The function that
+    // initiates the session must get the configuration on its
+    // own using getFullConfig.
+    return (isc::config::createAnswer(0, "Configuration accepted."));
+}
+
+ConstElementPtr
 ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
-    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
-              .arg(new_config->str());
 
-    if (server_) {
-        return (configureDhcp6Server(*server_, new_config));
+    if (!server_ || !server_->config_session_) {
+        // That should never happen as we install config_handler
+        // after we instantiate the server.
+        ConstElementPtr answer =
+            isc::config::createAnswer(1, "Configuration rejected,"
+                                      " server is during startup/shutdown phase.");
+        return (answer);
     }
 
-    // That should never happen as we install config_handler after we instantiate
-    // the server.
-    ConstElementPtr answer = isc::config::createAnswer(1,
-           "Configuration rejected, server is during startup/shutdown phase.");
-    return (answer);
+    // The configuration passed to this handler function is partial.
+    // In other words, it just includes the values being modified.
+    // In the same time, there are dependencies between various
+    // DHCP configuration parsers. For example: the option value can
+    // be set if the definition of this option is set. If someone removes
+    // an existing option definition then the partial configuration that
+    // removes that definition is triggered while a relevant option value
+    // may remain configured. This eventually results in the DHCP server
+    // configuration being in the inconsistent state.
+    // In order to work around this problem we need to merge the new
+    // configuration with the existing (full) configuration.
+
+    // Let's create a new object that will hold the merged configuration.
+    boost::shared_ptr<MapElement> merged_config(new MapElement());
+    // Let's get the existing configuration.
+    ConstElementPtr full_config = server_->config_session_->getFullConfig();
+    // The full_config and merged_config should be always non-NULL
+    // but to provide some level of exception safety we check that they
+    // really are (in case we go out of memory).
+    if (full_config && merged_config) {
+        merged_config->setValue(full_config->mapValue());
+
+        // Merge an existing and new configuration.
+        isc::data::merge(merged_config, new_config);
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
+            .arg(merged_config->str());
+    }
+
+    // Configure the server.
+    return (configureDhcp6Server(*server_, merged_config));
 }
 
 ConstElementPtr
@@ -109,18 +151,26 @@ void ControlledDhcpv6Srv::establishSession() {
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTING)
               .arg(specfile);
     cc_session_ = new Session(io_service_.get_io_service());
+    // Create a session with the dummy configuration handler.
+    // Dumy configuration handler is internally invoked by the
+    // constructor and on success the constructor updates
+    // the current session with the configuration that had been
+    // commited in the previous session. If we did not install
+    // the dummy handler, the previous configuration would have
+    // been lost.
     config_session_ = new ModuleCCSession(specfile, *cc_session_,
-                                          NULL,
+                                          dhcp6StubConfigHandler,
                                           dhcp6CommandHandler, false);
     config_session_->start();
 
-    // We initially create ModuleCCSession() without configHandler, as
-    // the session module is too eager to send partial configuration.
-    // We want to get the full configuration, so we explicitly call
-    // getFullConfig() and then pass it to our configHandler.
+    // The constructor already pulled the configuration that had
+    // been created in the previous session thanks to the dummy
+    // handler. We can switch to the handler that will be
+    // parsing future changes to the configuration.
     config_session_->setConfigHandler(dhcp6ConfigHandler);
 
     try {
+        // Pull the full configuration out from the session.
         configureDhcp6Server(*this, config_session_->getFullConfig());
     } catch (const DhcpConfigError& ex) {
         LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL).arg(ex.what());
@@ -150,8 +200,8 @@ void ControlledDhcpv6Srv::disconnectSession() {
     IfaceMgr::instance().set_session_socket(IfaceMgr::INVALID_SOCKET, NULL);
 }
 
-ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port, const char* dbconfig)
-    : Dhcpv6Srv(port, dbconfig), cc_session_(NULL), config_session_(NULL) {
+ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
+    : Dhcpv6Srv(port), cc_session_(NULL), config_session_(NULL) {
     server_ = this; // remember this instance for use in callback
 }
 
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h
index ef1acab..0e699ce 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.h
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -41,9 +41,7 @@ public:
     /// @brief Constructor
     ///
     /// @param port UDP port to be opened for DHCP traffic
-    /// @param dbconfig Lease manager database configuration string
-    ControlledDhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT,
-                        const char* dbconfig = "type=memfile");
+    ControlledDhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
 
     /// @brief Destructor.
     ~ControlledDhcpv6Srv();
@@ -51,7 +49,7 @@ public:
     /// @brief Establishes msgq session.
     ///
     /// Creates session that will be used to receive commands and updated
-    /// configuration from boss (or indirectly from user via bindctl).
+    /// configuration from cfgmgr (or indirectly from user via bindctl).
     void establishSession();
 
     /// @brief Terminates existing msgq session.
@@ -94,6 +92,27 @@ protected:
     static isc::data::ConstElementPtr
     dhcp6ConfigHandler(isc::data::ConstElementPtr new_config);
 
+    /// @brief A dummy configuration handler that always returns success.
+    ///
+    /// This configuration handler does not perform configuration
+    /// parsing and always returns success. A dummy hanlder should
+    /// be installed using \ref isc::config::ModuleCCSession ctor
+    /// to get the initial configuration. This initial configuration
+    /// comprises values for only those elements that were modified
+    /// the previous session. The \ref dhcp6ConfigHandler can't be
+    /// used to parse the initial configuration because it needs the
+    /// full configuration to satisfy dependencies between the
+    /// various configuration values. Installing the dummy handler
+    /// that guarantees to return success causes initial configuration
+    /// to be stored for the session being created and that it can
+    /// be later accessed with \ref isc::ConfigData::getFullConfig.
+    ///
+    /// @param new_config new configuration.
+    ///
+    /// @return success configuration status.
+    static isc::data::ConstElementPtr
+    dhcp6StubConfigHandler(isc::data::ConstElementPtr new_config);
+
     /// @brief A callback for handling incoming commands.
     ///
     /// @param command textual representation of the command
diff --git a/src/bin/dhcp6/dhcp6.dox b/src/bin/dhcp6/dhcp6.dox
index fa37769..3a738ec 100644
--- a/src/bin/dhcp6/dhcp6.dox
+++ b/src/bin/dhcp6/dhcp6.dox
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 /**
  @page dhcp6 DHCPv6 Server Component
 
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index 7f80457..1129aec 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -61,13 +61,13 @@
           { "item_name": "code",
             "item_type": "integer",
             "item_optional": false,
-            "item_default": 0,
+            "item_default": 0
           },
 
           { "item_name": "type",
             "item_type": "string",
             "item_optional": false,
-            "item_default": "",
+            "item_default": ""
           },
 
           { "item_name": "array",
@@ -76,16 +76,22 @@
             "item_default": False
           },
 
-          { "item_name": "record_types",
+          { "item_name": "record-types",
             "item_type": "string",
             "item_optional": false,
-            "item_default": "",
+            "item_default": ""
           },
 
           { "item_name": "space",
             "item_type": "string",
             "item_optional": false,
             "item_default": ""
+          },
+
+          { "item_name": "encapsulate",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
           } ]
         }
       },
@@ -131,6 +137,44 @@
         }
       },
 
+      { "item_name": "lease-database",
+        "item_type": "map",
+        "item_optional": false,
+        "item_default": {"type": "memfile"},
+        "map_item_spec": [
+            {
+                "item_name": "type",
+                "item_type": "string",
+                "item_optional": false,
+                "item_default": ""
+            },
+            {
+                "item_name": "name",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "user",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "host",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            },
+            {
+                "item_name": "password",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": ""
+            }
+        ]
+      },
+
       { "item_name": "subnet6",
         "item_type": "list",
         "item_optional": false,
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 83f75d9..6b61473 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2013  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
@@ -65,13 +65,6 @@ This informational message is printed every time the IPv6 DHCP server
 is started.  It indicates what database backend type is being to store
 lease and other information.
 
-% DHCP6_LEASE_WITHOUT_DUID lease for address %1 does not have a DUID
-This error message indicates a database consistency failure. The lease
-database has an entry indicating that the given address is in use,
-but the lease does not contain any client identification. This is most
-likely due to a software error: please raise a bug report. As a temporary
-workaround, manually remove the lease entry from the database.
-
 % DHCP6_LEASE_ADVERT lease %1 advertised (client duid=%2, iaid=%3)
 This debug message indicates that the server successfully advertised
 a lease. It is up to the client to choose one server out of the
@@ -93,36 +86,12 @@ This message indicates that the server failed to grant (in response to
 received REQUEST) a lease for a given client. There may be many reasons for
 such failure. Each specific failure is logged in a separate log entry.
 
-% DHCP6_RELEASE address %1 belonging to client duid=%2, iaid=%3 was released properly.
-This debug message indicates that an address was released properly. It
-is a normal operation during client shutdown.
-
-% DHCP6_RELEASE_FAIL failed to remove lease for address %1 for duid=%2, iaid=%3
-This error message indicates that the software failed to remove a
-lease from the lease database.  It probably due to an error during a
-database operation: resolution will most likely require administrator
-intervention (e.g. check if DHCP process has sufficient privileges to
-update the database). It may also be triggered if a lease was manually
-removed from the database during RELEASE message processing.
-
-% DHCP6_RELEASE_FAIL_WRONG_DUID client (duid=%1) tried to release address %2, but it belongs to client (duid=%3)
-This warning message indicates that client tried to release an address
-that belongs to a different client. This should not happen in normal
-circumstances and may indicate a misconfiguration of the client.  However,
-since the client releasing the address will stop using it anyway, there
-is a good chance that the situation will correct itself.
-
-% DHCP6_RELEASE_FAIL_WRONG_IAID client (duid=%1) tried to release address %2, but it used wrong IAID (expected %3, but got %4)
-This warning message indicates that client tried to release an address
-that does belong to it, but the address was expected to be in a different
-IA (identity association) container. This probably means that the client's
-support for multiple addresses is flawed.
-
-% DHCP6_RELEASE_MISSING_CLIENTID client (address=%1) sent RELEASE message without mandatory client-id
-This warning message indicates that client sent RELEASE message without
-mandatory client-id option. This is most likely caused by a buggy client
-(or a relay that malformed forwarded message). This request will not be
-processed and a response with error status code will be sent back.
+% DHCP6_LEASE_WITHOUT_DUID lease for address %1 does not have a DUID
+This error message indicates a database consistency failure. The lease
+database has an entry indicating that the given address is in use,
+but the lease does not contain any client identification. This is most
+likely due to a software error: please raise a bug report. As a temporary
+workaround, manually remove the lease entry from the database.
 
 % DHCP6_NOT_RUNNING IPv6 DHCP server is not running
 A warning message is issued when an attempt is made to shut down the
@@ -132,18 +101,6 @@ IPv6 DHCP server but it is not running.
 During startup the IPv6 DHCP server failed to detect any network
 interfaces and is therefore shutting down.
 
-% DHCP6_NO_SUBNET_DEF_OPT failed to find subnet for address %1 when adding default options
-This warning message indicates that when attempting to add default options
-to a response, the server found that it was not configured to support
-the subnet from which the DHCPv6 request was received.  The packet has
-been ignored.
-
-% DHCP6_NO_SUBNET_REQ_OPT failed to find subnet for address %1 when adding requested options
-This warning message indicates that when attempting to add requested
-options to a response, the server found that it was not configured
-to support the subnet from which the DHCPv6 request was received.
-The packet has been ignored.
-
 % DHCP6_OPEN_SOCKET opening sockets on port %1
 A debug message issued during startup, this indicates that the IPv6 DHCP
 server is about to open sockets on the specified port.
@@ -151,6 +108,11 @@ server is about to open sockets on the specified port.
 % DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
 The IPv6 DHCP server has received a packet that it is unable to interpret.
 
+% DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3
+This is a general catch-all message indicating that the processing of the
+specified packet type from the indicated address failed.  The reason is given in the
+message.  The server will not send a response but will instead ignore the packet.
+
 % DHCP6_PACKET_RECEIVED %1 packet received
 A debug message noting that the server has received the specified type
 of packet.  Note that a packet marked as UNKNOWN may well be a valid
@@ -172,6 +134,43 @@ This error is output if the server failed to assemble the data to be
 returned to the client into a valid packet.  The reason is most likely
 to be to a programming error: please raise a bug report.
 
+% DHCP6_PARSER_COMMIT_EXCEPTION parser failed to commit changes
+On receipt of message containing details to a change of the IPv6 DHCP
+server configuration, a set of parsers were successfully created, but one
+of them failed to commit its changes due to a low-level system exception
+being raised.  Additional messages may be output indicating the reason.
+
+% DHCP6_PARSER_COMMIT_FAIL parser failed to commit changes: %1
+On receipt of message containing details to a change of the IPv6 DHCP
+server configuration, a set of parsers were successfully created, but
+one of them failed to commit its changes.  The reason for the failure
+is given in the message.
+
+% DHCP6_PARSER_CREATED created parser for configuration element %1
+A debug message output during a configuration update of the IPv6 DHCP
+server, notifying that the parser for the specified configuration element
+has been successfully created.
+
+% DHCP6_PARSER_EXCEPTION failed to create or run parser for configuration element %1
+On receipt of message containing details to a change of its configuration,
+the IPv6 DHCP server failed to create a parser to decode the contents of
+the named configuration element, or the creation succeeded but the parsing
+actions and committal of changes failed.  The message has been output in
+response to a non-BIND 10 exception being raised.  Additional messages
+may give further information.
+
+The most likely cause of this is that the specification file for the server
+(which details the allowable contents of the configuration) is not correct for
+this version of BIND 10.  This former may be the result of an interrupted
+installation of an update to BIND 10.
+
+% DHCP6_PARSER_FAIL failed to create or run parser for configuration element %1: %2
+On receipt of message containing details to a change of its configuration,
+the IPv6 DHCP server failed to create a parser to decode the contents
+of the named configuration element, or the creation succeeded but the
+parsing actions and committal of changes failed.  The reason for the
+failure is given in the message.
+
 % DHCP6_PROCESS_IA_NA_REQUEST server is processing IA_NA option (duid=%1, iaid=%2, hint=%3)
 This is a debug message that indicates a processing of received IA_NA
 option. It may optionally contain an address that may be used by the server
@@ -180,6 +179,47 @@ as a hint for possible requested address.
 % DHCP6_QUERY_DATA received packet length %1, data length %2, data is %3
 A debug message listing the data received from the client or relay.
 
+% DHCP6_RELEASE address %1 belonging to client duid=%2, iaid=%3 was released properly.
+This debug message indicates that an address was released properly. It
+is a normal operation during client shutdown.
+
+% DHCP6_RELEASE_FAIL failed to remove lease for address %1 for duid=%2, iaid=%3
+This error message indicates that the software failed to remove a
+lease from the lease database.  It probably due to an error during a
+database operation: resolution will most likely require administrator
+intervention (e.g. check if DHCP process has sufficient privileges to
+update the database). It may also be triggered if a lease was manually
+removed from the database during RELEASE message processing.
+
+% DHCP6_RELEASE_FAIL_WRONG_DUID client (duid=%1) tried to release address %2, but it belongs to client (duid=%3)
+This warning message indicates that client tried to release an address
+that belongs to a different client. This should not happen in normal
+circumstances and may indicate a misconfiguration of the client.  However,
+since the client releasing the address will stop using it anyway, there
+is a good chance that the situation will correct itself.
+
+% DHCP6_RELEASE_FAIL_WRONG_IAID client (duid=%1) tried to release address %2, but it used wrong IAID (expected %3, but got %4)
+This warning message indicates that client tried to release an address
+that does belong to it, but the address was expected to be in a different
+IA (identity association) container. This probably means that the client's
+support for multiple addresses is flawed.
+
+% DHCP6_RELEASE_MISSING_CLIENTID client (address=%1) sent RELEASE message without mandatory client-id
+This warning message indicates that client sent RELEASE message without
+mandatory client-id option. This is most likely caused by a buggy client
+(or a relay that malformed forwarded message). This request will not be
+processed and a response with error status code will be sent back.
+
+% DHCP6_RENEW_UNKNOWN_SUBNET RENEW message received from client on unknown subnet (duid=%1, iaid=%2)
+A warning message indicating that a client is attempting to renew his lease,
+but the server does not have any information about the subnet this client belongs
+to. This may mean that faulty the mobile client changed its location and is trying to
+renew its old address (client is supposed to send confirm, not rewew in such cases,
+according to RFC3315) or the server configuration has changed and information about
+existing subnet was removed. Note that in a sense this is worse case of DHCP6_UNKNOWN_RENEW,
+as not only the lease is unknown, but also the subnet is. Depending on the reasons
+of this condition, it may or may not correct on its own.
+
 % DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3
 This message indicates that received DHCPv6 packet is invalid.  This may be due
 to a number of reasons, e.g. the mandatory client-id option is missing,
@@ -190,6 +230,34 @@ etc. The exact reason for rejecting the packet is included in the message.
 % DHCP6_RESPONSE_DATA responding with packet type %1 data is %2
 A debug message listing the data returned to the client.
 
+% DHCP6_SERVERID_GENERATED server-id %1 has been generated and will be stored in %2
+This informational messages indicates that the server was not able to read
+its server identifier (DUID) and has generated a new one. This server-id
+will be stored in a file and will be read and used during next restart. It
+is normal behavior when the server is started for the first time. If
+this message is printed every start, please check that the server have
+sufficient permission to write its server-id file and that the file is not
+corrupt.
+
+Changing the server identifier in a production environment is not
+recommended as existing clients will not recognize the server and may go
+through a rebind phase. However, they should be able to recover without
+losing their leases.
+
+% DHCP6_SERVERID_LOADED server-id %1 has been loaded from file %2
+This debug message indicates that the server loaded its server identifier.
+That value is sent in all server responses and clients use it to
+discriminate between servers. This is a part of normal startup or
+reconfiguration procedure.
+
+% DHCP6_SERVERID_WRITE_FAIL server was not able to write its ID to file %1
+This warning message indicates that server was not able to write its
+server identifier (DUID) to a file. This likely indicates lack of write
+permission to a given file or directory. This is not cricital and the
+server will continue to operate, but server will generate different DUID
+during every start and clients will need to go through a rebind phase
+to recover.
+
 % DHCP6_SERVER_FAILED server failed: %1
 The IPv6 DHCP server has encountered a fatal error and is terminating.
 The reason for the failure is included in the message.
@@ -240,6 +308,11 @@ to a misconfiguration of the server. The packet processing will continue, but
 the response will only contain generic configuration parameters and no
 addresses or prefixes.
 
+% DHCP6_UNKNOWN_RELEASE received RELEASE from unknown client (duid=%1, iaid=%2)
+This warning message is printed when client attempts to release a lease,
+but no such lease is known by the server. See DHCP6_UNKNOWN_RENEW for
+possible reasons for such behavior.
+
 % DHCP6_UNKNOWN_RENEW received RENEW from client (duid=%1, iaid=%2) in subnet %3
 This warning message is printed when client attempts to renew a lease,
 but no such lease is known by the server. It typically means that
@@ -254,8 +327,3 @@ recently and does not recognize its well-behaving clients. This is more
 probable if you see many such messages. Clients will recover from this,
 but they will most likely get a different IP addresses and experience
 a brief service interruption.
-
-% DHCP6_UNKNOWN_RELEASE received RELEASE from unknown client (duid=%1, iaid=%2)
-This warning message is printed when client attempts to release a lease,
-but no such lease is known by the server. See DHCP6_UNKNOWN_RENEW for
-possible reasons for such behavior.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 8fb55ec..5f1580f 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -36,11 +36,16 @@
 #include <exceptions/exceptions.h>
 #include <util/io_utilities.h>
 #include <util/range_utilities.h>
+#include <util/encode/hex.h>
 
 #include <boost/foreach.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/erase.hpp>
 
 #include <stdlib.h>
 #include <time.h>
+#include <iomanip>
+#include <fstream>
 
 using namespace isc;
 using namespace isc::asiolink;
@@ -51,7 +56,17 @@ using namespace std;
 namespace isc {
 namespace dhcp {
 
-Dhcpv6Srv::Dhcpv6Srv(uint16_t port, const char* dbconfig)
+/// @brief file name of a server-id file
+///
+/// Server must store its duid in persistent storage that must not change
+/// between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// double digit hex values separated by colons format, e.g.
+/// 01:ff:02:03:06:80:90:ab:cd:ef. Server will create it during first
+/// run and then use it afterwards.
+static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
+
+Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
     : alloc_engine_(), serverid_(), shutdown_(true) {
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
@@ -70,13 +85,23 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port, const char* dbconfig)
             IfaceMgr::instance().openSockets6(port);
         }
 
-        setServerID();
+        string duid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_DUID_FILE);
+        if (loadServerID(duid_file)) {
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_SERVERID_LOADED)
+                .arg(duidToString(getServerID()))
+                .arg(duid_file);
+        } else {
+            generateServerID();
+            LOG_INFO(dhcp6_logger, DHCP6_SERVERID_GENERATED)
+                .arg(duidToString(getServerID()))
+                .arg(duid_file);
+
+            if (!writeServerID(duid_file)) {
+                LOG_WARN(dhcp6_logger, DHCP6_SERVERID_WRITE_FAIL)
+                    .arg(duid_file);
+            }
 
-        // Instantiate LeaseMgr
-        LeaseMgrFactory::create(dbconfig);
-        LOG_INFO(dhcp6_logger, DHCP6_DB_BACKEND_STARTED)
-            .arg(LeaseMgrFactory::instance().getType())
-            .arg(LeaseMgrFactory::instance().getName());
+        }
 
         // Instantiate allocation engine
         alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
@@ -157,8 +182,8 @@ bool Dhcpv6Srv::run() {
                     break;
 
                 case DHCPV6_RELEASE:
-                rsp = processRelease(query);
-                break;
+                    rsp = processRelease(query);
+                    break;
 
                 case DHCPV6_DECLINE:
                     rsp = processDecline(query);
@@ -174,11 +199,26 @@ bool Dhcpv6Srv::run() {
                     // the "switch" statement.
                     ;
                 }
+
             } catch (const RFCViolation& e) {
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
                     .arg(query->getName())
                     .arg(query->getRemoteAddr())
                     .arg(e.what());
+
+            } catch (const isc::Exception& e) {
+
+                // Catch-all exception (at least for ones based on the isc
+                // Exception class, which covers more or less all that
+                // are explicitly raised in the BIND 10 code).  Just log
+                // the problem and ignore the packet. (The problem is logged
+                // as a debug message because debug is disabled by default -
+                // it prevents a DDOS attack based on the sending of problem
+                // packets.)
+                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
+                    .arg(query->getName())
+                    .arg(query->getRemoteAddr())
+                    .arg(e.what());
             }
 
             if (rsp) {
@@ -191,7 +231,7 @@ bool Dhcpv6Srv::run() {
 
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
                           DHCP6_RESPONSE_DATA)
-                          .arg(rsp->getType()).arg(rsp->toText());
+                    .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 
                 if (rsp->pack()) {
                     try {
@@ -209,10 +249,71 @@ bool Dhcpv6Srv::run() {
     return (true);
 }
 
-void Dhcpv6Srv::setServerID() {
+bool Dhcpv6Srv::loadServerID(const std::string& file_name) {
+
+    // load content of the file into a string
+    fstream f(file_name.c_str(), ios::in);
+    if (!f.is_open()) {
+        return (false);
+    }
+
+    string hex_string;
+    f >> hex_string;
+    f.close();
+
+    // remove any spaces
+    boost::algorithm::erase_all(hex_string, " ");
+
+    // now remove :
+    /// @todo: We should check first if the format is sane.
+    /// Otherwise 1:2:3:4 will be converted to 0x12, 0x34
+    boost::algorithm::erase_all(hex_string, ":");
+
+    std::vector<uint8_t> bin;
+
+    // Decode the hex string and store it in bin (which happens
+    // to be OptionBuffer format)
+    isc::util::encode::decodeHex(hex_string, bin);
+
+    // Now create server-id option
+    serverid_.reset(new Option(Option::V6, D6O_SERVERID, bin));
+
+    return (true);
+}
+
+std::string
+Dhcpv6Srv::duidToString(const OptionPtr& opt) {
+    stringstream tmp;
+
+    OptionBuffer data = opt->getData();
+
+    bool colon = false;
+    for (OptionBufferConstIter it = data.begin(); it != data.end(); ++it) {
+        if (colon) {
+            tmp << ":";
+        }
+        tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(*it);
+        if (!colon) {
+            colon = true;
+        }
+    }
+
+    return tmp.str();
+}
+
+bool
+Dhcpv6Srv::writeServerID(const std::string& file_name) {
+    fstream f(file_name.c_str(), ios::out | ios::trunc);
+    if (!f.good()) {
+        return (false);
+    }
+    f << duidToString(getServerID());
+    f.close();
+    return (true);
+}
 
-    /// @todo: DUID should be generated once and then stored, rather
-    /// than generated each time
+void
+Dhcpv6Srv::generateServerID() {
 
     /// @todo: This code implements support for DUID-LLT (the recommended one).
     /// We should eventually add support for other DUID types: DUID-LL, DUID-EN
@@ -295,7 +396,8 @@ void Dhcpv6Srv::setServerID() {
                                      srvid.begin(), srvid.end()));
 }
 
-void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     // Add client-id.
     OptionPtr clientid = question->getOption(D6O_CLIENTID);
     if (clientid) {
@@ -305,28 +407,22 @@ void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
 }
 
-void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr&, Pkt6Ptr& answer) {
     // add server-id
     answer->addOption(getServerID());
-
-    // Get the subnet object. It holds options to be sent to the client
-    // that belongs to the particular subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
-    // Warn if subnet is not supported and quit.
-    if (!subnet) {
-        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_DEF_OPT)
-            .arg(question->getRemoteAddr().toText());
-        return;
-    }
-
 }
 
-void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-    // Get the subnet for a particular address.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+void
+Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+    // Get the configured subnet suitable for the incoming packet.
+    Subnet6Ptr subnet = selectSubnet(question);
+    // Leave if there is no subnet matching the incoming packet.
+    // There is no need to log the error message here because
+    // it will be logged in the assignLease() when it fails to
+    // pick the suitable subnet. We don't want to duplicate
+    // error messages in such case.
     if (!subnet) {
-        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT)
-            .arg(question->getRemoteAddr().toText());
         return;
     }
 
@@ -340,20 +436,16 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
     }
     // Get the list of options that client requested.
     const std::vector<uint16_t>& requested_opts = option_oro->getValues();
-    // Get the list of options configured for a subnet.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-    // Try to match requested options with those configured for a subnet.
-    // If match is found, append configured option to the answer message.
     BOOST_FOREACH(uint16_t opt, requested_opts) {
-        const Subnet::OptionContainerTypeRange& range = idx.equal_range(opt);
-        BOOST_FOREACH(Subnet::OptionDescriptor desc, range) {
+        Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", opt);
+        if (desc.option) {
             answer->addOption(desc.option);
         }
     }
 }
 
-OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
+OptionPtr
+Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
     // @todo This function uses OptionCustom class to manage contents
     // of the data fields. Since this this option is frequently used
     // it may be good to implement dedicated class to avoid performance
@@ -379,8 +471,9 @@ OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
     return (option_status);
 }
 
-void Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
-                            RequirementLevel serverid) {
+void
+Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
+                       RequirementLevel serverid) {
     Option::OptionCollection client_ids = pkt->getOptions(D6O_CLIENTID);
     switch (clientid) {
     case MANDATORY:
@@ -427,7 +520,8 @@ void Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
     }
 }
 
-Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
+Subnet6Ptr
+Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
 
     /// @todo: pass interface information only if received direct (non-relayed) message
 
@@ -443,7 +537,8 @@ Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
     return (subnet);
 }
 
-void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
 
     // We need to allocate addresses for all IA_NA options in the client's
     // question (i.e. SOLICIT or REQUEST) message.
@@ -461,9 +556,7 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
         // thing this client can get is some global information (like DNS
         // servers).
 
-        // perhaps this should be logged on some higher level? This is most likely
-        // configuration bug.
-        LOG_ERROR(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
+        LOG_WARN(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
             .arg(question->getRemoteAddr().toText())
             .arg(question->getName());
 
@@ -512,8 +605,9 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     }
 }
 
-OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
-                                 Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                       Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
     // If there is no subnet selected for handling this IA_NA, the only thing to do left is
     // to say that we are sorry, but the user won't get an address. As a convenience, we
     // use a different status text to indicate that (compare to the same status code,
@@ -596,11 +690,10 @@ OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
         // cause of that failure. The only thing left is to insert
         // status code to pass the sad news to the client.
 
-        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation?
-                  DHCP6_LEASE_ADVERT_FAIL:DHCP6_LEASE_ALLOC_FAIL)
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation ?
+                  DHCP6_LEASE_ADVERT_FAIL : DHCP6_LEASE_ALLOC_FAIL)
             .arg(duid?duid->toText():"(no-duid)")
-            .arg(ia->getIAID())
-            .arg(subnet->toText());
+            .arg(ia->getIAID());
 
         ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
                           "Sorry, no address could be allocated."));
@@ -608,8 +701,24 @@ OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
     return (ia_rsp);
 }
 
-OptionPtr Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
-                                Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                      Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia) {
+    if (!subnet) {
+        // There's no subnet select for this client. There's nothing to renew.
+        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+        // Insert status code NoAddrsAvail.
+        ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
+                          "Sorry, no known leases for this duid/iaid."));
+
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_RENEW_UNKNOWN_SUBNET)
+            .arg(duid->toText())
+            .arg(ia->getIAID());
+
+        return (ia_rsp);
+    }
+
     Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(*duid, ia->getIAID(),
                                                             subnet->getID());
 
@@ -652,7 +761,8 @@ OptionPtr Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
     return (ia_rsp);
 }
 
-void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
+void
+Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
 
     // We need to renew addresses for all IA_NA options in the client's
     // RENEW message.
@@ -670,9 +780,9 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
         // thing this client can get is some global information (like DNS
         // servers).
 
-        // perhaps this should be logged on some higher level? This is most likely
-        // configuration bug.
-        LOG_ERROR(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED);
+        LOG_WARN(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
+            .arg(renew->getRemoteAddr().toText())
+            .arg(renew->getName());
     } else {
         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_SUBNET_SELECTED)
             .arg(subnet->toText());
@@ -708,7 +818,8 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
     }
 }
 
-void Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
+void
+Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
 
     // We need to release addresses for all IA_NA options in the client's
     // RELEASE message.
@@ -764,9 +875,9 @@ void Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
                      "Summary status for all processed IA_NAs"));
 }
 
-OptionPtr Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
-                                  int& general_status,
-                                  boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
+                        int& general_status, boost::shared_ptr<Option6IA> ia) {
     // Release can be done in one of two ways:
     // Approach 1: extract address from client's IA_NA and see if it belongs
     // to this particular client.
@@ -875,8 +986,8 @@ OptionPtr Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
     }
 }
 
-
-Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
+Pkt6Ptr
+Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
 
     sanityCheck(solicit, MANDATORY, FORBIDDEN);
 
@@ -891,7 +1002,8 @@ Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
     return (advertise);
 }
 
-Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
+Pkt6Ptr
+Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
 
     sanityCheck(request, MANDATORY, MANDATORY);
 
@@ -906,7 +1018,8 @@ Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
     return (reply);
 }
 
-Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+Pkt6Ptr
+Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
 
     sanityCheck(renew, MANDATORY, MANDATORY);
 
@@ -921,19 +1034,22 @@ Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
     return reply;
 }
 
-Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+Pkt6Ptr
+Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
     /// @todo: Implement this
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
     return reply;
 }
 
-Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
+Pkt6Ptr
+Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
     /// @todo: Implement this
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
     return reply;
 }
 
-Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+Pkt6Ptr
+Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
 
     sanityCheck(release, MANDATORY, MANDATORY);
 
@@ -947,13 +1063,15 @@ Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
     return reply;
 }
 
-Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+Pkt6Ptr
+Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
     /// @todo: Implement this
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
     return reply;
 }
 
-Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
+Pkt6Ptr
+Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
     /// @todo: Implement this
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
     return reply;
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 30abb50..bdcb560 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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,10 +64,7 @@ public:
     /// old or create new DUID.
     ///
     /// @param port port on will all sockets will listen
-    /// @param dbconfig Lease manager configuration string.  The default
-    ///        of the "memfile" manager is used for testing.
-    Dhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT,
-              const char* dbconfig = "type=memfile");
+    Dhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
 
     /// @brief Destructor. Used during DHCPv6 service shutdown.
     virtual ~Dhcpv6Srv();
@@ -290,15 +287,39 @@ protected:
 
     /// @brief Sets server-identifier.
     ///
-    /// This method attempts to set server-identifier DUID. It loads it
-    /// from a file. If file load fails, it generates new DUID using
-    /// interface link-layer addresses (EUI-64) + timestamp (DUID type
-    /// duid-llt, see RFC3315, section 9.2). If there are no suitable
+    /// This method attempts to generate server-identifier DUID. It generates a
+    /// new DUID using interface link-layer addresses (EUI-64) + timestamp (DUID
+    /// type duid-llt, see RFC3315, section 9.2). If there are no suitable
     /// interfaces present, exception it thrown
     ///
     /// @throws isc::Unexpected Failed to read DUID file and no suitable
     ///         interfaces for new DUID generation are detected.
-    void setServerID();
+    void generateServerID();
+
+    /// @brief attempts to load DUID from a file
+    ///
+    /// Tries to load duid from a text file. If the load is successful,
+    /// it creates server-id option and stores it in serverid_ (to be used
+    /// later by getServerID()).
+    ///
+    /// @param file_name name of the DUID file to load
+    /// @return true if load was successful, false otherwise
+    bool loadServerID(const std::string& file_name);
+
+    /// @brief attempts to write DUID to a file
+    /// Tries to write duid content (stored in serverid_) to a text file.
+    ///
+    /// @param file_name name of the DUID file to write
+    /// @return true if write was successful, false otherwise
+    bool writeServerID(const std::string& file_name);
+
+    /// @brief converts DUID to text
+    /// Converts content of DUID option to a text representation, e.g.
+    /// 01:ff:02:03:06:80:90:ab:cd:ef
+    ///
+    /// @param opt option that contains DUID
+    /// @return string representation
+    static std::string duidToString(const OptionPtr& opt);
 
 private:
     /// @brief Allocation Engine.
diff --git a/src/bin/dhcp6/main.cc b/src/bin/dhcp6/main.cc
index ced7422..269eae4 100644
--- a/src/bin/dhcp6/main.cc
+++ b/src/bin/dhcp6/main.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -36,17 +36,6 @@ using namespace std;
 /// Dhcpv6Srv and other classes, see \ref dhcpv6Session.
 
 namespace {
-// @todo: Replace the next line by extraction from configuration parameters
-// This is the "dbconfig" string for the MySQL database.  It is likely
-// that a long-term solution will be to create the instance of the lease manager
-// somewhere other than the Dhcpv6Srv constructor, to give time to extract
-// the connection string from the configuration database.
-#ifdef HAVE_MYSQL
-const char* DBCONFIG = "type=mysql name=kea user=kea password=kea host=localhost";
-#else
-const char* DBCONFIG = "type=memfile";
-#endif
-
 const char* const DHCP6_NAME = "b10-dhcp6";
 
 void
@@ -115,7 +104,7 @@ main(int argc, char* argv[]) {
 
     int ret = EXIT_SUCCESS;
     try {
-        ControlledDhcpv6Srv server(port_number, DBCONFIG);
+        ControlledDhcpv6Srv server(port_number);
         if (!stand_alone) {
             try {
                 server.establishSession();
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index d251df3..feb4bfa 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -30,6 +30,10 @@ AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
@@ -53,12 +57,6 @@ dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc
 dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
 nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc
 
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-dhcp6_unittests_CXXFLAGS = -Wno-unused-parameter
-endif
-
 dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp6_unittests_LDADD = $(GTEST_LDADD)
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index b3fe88e..4430cb2 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -18,6 +18,8 @@
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/option_custom.h>
+#include <dhcp/option_int.h>
 #include <dhcp6/config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcpsrv/cfgmgr.h>
@@ -275,9 +277,9 @@ public:
                             expected_data_len));
     }
 
+    int rcode_;
     Dhcpv6Srv srv_;
 
-    int rcode_;
     ConstElementPtr comment_;
 
     string valid_iface_;
@@ -349,7 +351,6 @@ TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) {
         "    \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
         "    \"subnet\": \"2001:db8:1::/64\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -388,7 +389,6 @@ TEST_F(Dhcp6ParserTest, subnetLocal) {
         "    \"valid-lifetime\": 4,"
         "    \"subnet\": \"2001:db8:1::/64\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -514,7 +514,7 @@ TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
         "    \"pool\": [ \"4001:db8:1::/80\" ],"
         "    \"subnet\": \"2001:db8:1::/64\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
+
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -542,7 +542,6 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) {
         "    \"pool\": [ \"2001:db8:1::/80\" ],"
         "    \"subnet\": \"2001:db8:1::/64\" } ],"
         "\"valid-lifetime\": 4000 }";
-    cout << config << endl;
 
     ElementPtr json = Element::fromJSON(config);
 
@@ -573,7 +572,8 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
         "      \"type\": \"ipv6-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -611,7 +611,8 @@ TEST_F(Dhcp6ParserTest, optionDefRecord) {
         "      \"type\": \"record\","
         "      \"array\": False,"
         "      \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -658,7 +659,8 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
         "      \"type\": \"uint32\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  },"
         "  {"
         "      \"name\": \"foo-2\","
@@ -666,7 +668,8 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
         "      \"type\": \"ipv4-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -716,7 +719,8 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
         "      \"type\": \"uint32\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  },"
         "  {"
         "      \"name\": \"foo-2\","
@@ -724,7 +728,8 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
         "      \"type\": \"ipv4-address\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -752,7 +757,8 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
         "      \"type\": \"uint32\","
         "      \"array\": True,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -778,6 +784,47 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
     EXPECT_TRUE(def->getArrayType());
 }
 
+// The purpose of this test to verify that encapsulated option
+// space name may be specified.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulate) {
+
+    // Configuration string. Included the encapsulated
+    // option space name.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"sub-opts-space\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Make sure that the particular option definition does not exist.
+    OptionDefinitionPtr def = CfgMgr::instance().getOptionDef("isc", 100);
+    ASSERT_FALSE(def);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // The option definition should now be available in the CfgMgr.
+    def = CfgMgr::instance().getOptionDef("isc", 100);
+    ASSERT_TRUE(def);
+
+    // Check the option data.
+    EXPECT_EQ("foo", def->getName());
+    EXPECT_EQ(100, def->getCode());
+    EXPECT_EQ(OPT_UINT32_TYPE, def->getType());
+    EXPECT_FALSE(def->getArrayType());
+    EXPECT_EQ("sub-opts-space", def->getEncapsulatedSpace());
+}
+
 /// The purpose of this test is to verify that the option definition
 /// with invalid name is not accepted.
 TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
@@ -790,7 +837,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -815,7 +863,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidType) {
         "      \"type\": \"sting\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -840,7 +889,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
         "      \"type\": \"record\","
         "      \"array\": False,"
         "      \"record-types\": \"uint32,uint8,sting\","
-        "      \"space\": \"isc\""
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -853,6 +903,85 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
     checkResult(status, 1);
 }
 
+/// The goal of this test is to verify that the invalid encapsulated
+/// option space name is not accepted.
+TEST_F(Dhcp6ParserTest, optionDefInvalidEncapsulatedSpace) {
+    // Configuration string. The encapsulated option space
+    // name is invalid (% character is not allowed).
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"invalid%space%name\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the encapsulated
+/// option space name can't be specified for the option that
+/// comprises an array of data fields.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulatedSpaceAndArray) {
+    // Configuration string. The encapsulated option space
+    // name is set to non-empty value and the array flag
+    // is set.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": True,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"valid-space-name\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the option may not
+/// encapsulate option space it belongs to.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulateOwnSpace) {
+    // Configuration string. Option is set to encapsulate
+    // option space it belongs to.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 100,"
+        "      \"type\": \"uint32\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"isc\","
+        "      \"encapsulate\": \"isc\""
+        "  } ]"
+        "}";
+    ElementPtr json = Element::fromJSON(config);
+
+    // Use the configuration string to create new option definition.
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    // Expecting parsing error (error code 1).
+    checkResult(status, 1);
+}
 
 /// The purpose of this test is to verify that it is not allowed
 /// to override the standard option (that belongs to dhcp6 option
@@ -871,7 +1000,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"dhcp6\""
+        "      \"space\": \"dhcp6\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     ElementPtr json = Element::fromJSON(config);
@@ -906,7 +1036,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
-        "      \"space\": \"dhcp6\""
+        "      \"space\": \"dhcp6\","
+        "      \"encapsulate\": \"\""
         "  } ]"
         "}";
     json = Element::fromJSON(config);
@@ -1028,7 +1159,8 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
         "    \"type\": \"uint32\","
         "    \"array\": False,"
         "    \"record-types\": \"\","
-        "    \"space\": \"isc\""
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
         " } ],"
         "\"subnet6\": [ { "
         "    \"pool\": [ \"2001:db8:1::/80\" ],"
@@ -1061,81 +1193,164 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
     ASSERT_FALSE(desc3.option);
 }
 
-// The goal of this test is to verify options configuration
-// for a single subnet. In particular this test checks
-// that local options configuration overrides global
-// option setting.
-TEST_F(Dhcp6ParserTest, optionDataInSingleSubnet) {
-    ConstElementPtr x;
+// The goal of this test is to verify that it is possible to
+// encapsulate option space containing some options with
+// another option. In this test we create base option that
+// encapsulates option space 'isc' that comprises two other
+// options. Also, for all options their definitions are
+// created.
+TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
+
+    // @todo DHCP configurations has many dependencies between
+    // parameters. First of all, configuration for subnet is
+    // inherited from the global values. Thus subnet has to be
+    // configured when all global values have been configured.
+    // Also, an option can encapsulate another option only
+    // if the latter has been configured. For this reason in this
+    // test we created two-stage configuration where first we
+    // created options that belong to encapsulated option space.
+    // In the second stage we add the base option. Also, the Subnet
+    // object is configured in the second stage so it is created
+    // at the very end (when all other parameters are configured).
+
+    // Starting stage 1. Configure sub-options and their definitions.
     string config = "{ \"interface\": [ \"all\" ],"
-        "\"preferred-lifetime\": 3000,"
-        "\"rebind-timer\": 2000, "
-        "\"renew-timer\": 1000, "
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
         "\"option-data\": [ {"
-        "      \"name\": \"subscriber-id\","
-        "      \"space\": \"dhcp6\","
-        "      \"code\": 38,"
-        "      \"data\": \"AB\","
-        "      \"csv-format\": False"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 110,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"isc\","
+        "    \"code\": 111,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 110,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 111,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " } ]"
+        "}";
+
+    ConstElementPtr status;
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Stage 2. Configure base option and a subnet. Please note that
+    // the configuration from the stage 2 is repeated because BIND
+    // configuration manager sends whole configuration for the lists
+    // where at least one element is being modified or added.
+    config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"base-option\","
+        "    \"space\": \"dhcp6\","
+        "    \"code\": 100,"
+        "    \"data\": \"11\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 110,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"isc\","
+        "    \"code\": 111,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"base-option\","
+        "    \"code\": 100,"
+        "    \"type\": \"uint8\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"dhcp6\","
+        "    \"encapsulate\": \"isc\""
+        "},"
+        "{"
+        "    \"name\": \"foo\","
+        "    \"code\": 110,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 111,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"isc\","
+        "    \"encapsulate\": \"\""
         " } ],"
         "\"subnet6\": [ { "
         "    \"pool\": [ \"2001:db8:1::/80\" ],"
-        "    \"subnet\": \"2001:db8:1::/64\", "
-        "    \"option-data\": [ {"
-        "          \"name\": \"subscriber-id\","
-        "          \"space\": \"dhcp6\","
-        "          \"code\": 38,"
-        "          \"data\": \"AB CDEF0105\","
-        "          \"csv-format\": False"
-        "        },"
-        "        {"
-        "          \"name\": \"preference\","
-        "          \"space\": \"dhcp6\","
-        "          \"code\": 7,"
-        "          \"data\": \"01\","
-        "          \"csv-format\": False"
-        "        } ]"
-        " } ],"
-        "\"valid-lifetime\": 4000 }";
+        "    \"subnet\": \"2001:db8:1::/64\""
+        " } ]"
+        "}";
 
-    ElementPtr json = Element::fromJSON(config);
 
-    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-    ASSERT_EQ(0, rcode_);
+    json = Element::fromJSON(config);
 
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Get the subnet.
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
-    ASSERT_EQ(2, options->size());
 
-    // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-
-    // Get the options for specified index. Expecting one option to be
-    // returned but in theory we may have multiple options with the same
-    // code so we get the range.
-    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
-        idx.equal_range(D6O_SUBSCRIBER_ID);
-    // Expect single option with the code equal to 38.
-    ASSERT_EQ(1, std::distance(range.first, range.second));
-    const uint8_t subid_expected[] = {
-        0xAB, 0xCD, 0xEF, 0x01, 0x05
-    };
-    // Check if option is valid in terms of code and carried data.
-    testOption(*range.first, D6O_SUBSCRIBER_ID, subid_expected,
-               sizeof(subid_expected));
+    // We should have one option available.
+    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    ASSERT_TRUE(options);
+    ASSERT_EQ(1, options->size());
 
-    range = idx.equal_range(D6O_PREFERENCE);
-    ASSERT_EQ(1, std::distance(range.first, range.second));
-    // Do another round of testing with second option.
-    const uint8_t pref_expected[] = {
-        0x01
-    };
-    testOption(*range.first, D6O_PREFERENCE, pref_expected,
-               sizeof(pref_expected));
+    // Get the option.
+    Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", 100);
+    EXPECT_TRUE(desc.option);
+    EXPECT_EQ(100, desc.option->getType());
+
+    // This opton should comprise two sub-options.
+    // Onf of them is 'foo' with code 110.
+    OptionPtr option_foo = desc.option->getOption(110);
+    ASSERT_TRUE(option_foo);
+    EXPECT_EQ(110, option_foo->getType());
+
+    // ...another one 'foo2' with code 111.
+    OptionPtr option_foo2 = desc.option->getOption(111);
+    ASSERT_TRUE(option_foo2);
+    EXPECT_EQ(111, option_foo2->getType());
 }
 
 // Goal of this test is to verify options configuration
@@ -1377,4 +1592,164 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
     EXPECT_EQ(1516, optionIA->getT2());
 }
 
+// The goal of this test is to verify that the standard option can
+// be configured to encapsulate multiple other options.
+TEST_F(Dhcp6ParserTest, stdOptionDataEncapsulate) {
+
+    // The configuration is two stage process in this test.
+    // In the first stahe we create definitions of suboptions
+    // that we will add to the base option.
+    // Let's create some dummy options: foo and foo2.
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"code\": 110,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"code\": 111,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 110,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 111,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"encapsulate\": \"\""
+        " } ]"
+        "}";
+
+    ConstElementPtr status;
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Once the definitions have been added we can configure the
+    // standard option #17. This option comprises an enterprise
+    // number and sub options. By convention (introduced in
+    // std_option_defs.h) option named 'vendor-opts'
+    // encapsulates the option space named 'vendor-opts-space'.
+    // We add our dummy options to this option space and thus
+    // they should be included as sub-options in the 'vendor-opts'
+    // option.
+    config = "{ \"interface\": [ \"all\" ],"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"vendor-opts\","
+        "    \"space\": \"dhcp6\","
+        "    \"code\": 17,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"code\": 110,"
+        "    \"data\": \"1234\","
+        "    \"csv-format\": True"
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"code\": 111,"
+        "    \"data\": \"192.168.2.1\","
+        "    \"csv-format\": True"
+        " } ],"
+        "\"option-def\": [ {"
+        "    \"name\": \"foo\","
+        "    \"code\": 110,"
+        "    \"type\": \"uint32\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"encapsulate\": \"\""
+        " },"
+        " {"
+        "    \"name\": \"foo2\","
+        "    \"code\": 111,"
+        "    \"type\": \"ipv4-address\","
+        "    \"array\": False,"
+        "    \"record-types\": \"\","
+        "    \"space\": \"vendor-opts-space\","
+        "    \"encapsulate\": \"\""
+        " } ],"
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\""
+        " } ]"
+        "}";
+
+
+    json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    checkResult(status, 0);
+
+    // Get the subnet.
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet);
+
+    // We should have one option available.
+    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    ASSERT_TRUE(options);
+    ASSERT_EQ(1, options->size());
+
+    // Get the option.
+    Subnet::OptionDescriptor desc =
+        subnet->getOptionDescriptor("dhcp6", D6O_VENDOR_OPTS);
+    EXPECT_TRUE(desc.option);
+    EXPECT_EQ(D6O_VENDOR_OPTS, desc.option->getType());
+
+    // Option with the code 110 should be added as a sub-option.
+    OptionPtr option_foo = desc.option->getOption(110);
+    ASSERT_TRUE(option_foo);
+    EXPECT_EQ(110, option_foo->getType());
+    // This option comprises a single uint32_t value thus it is
+    // represented by OptionInt<uint32_t> class. Let's get the
+    // object of this type.
+    boost::shared_ptr<OptionInt<uint32_t> > option_foo_uint32 =
+        boost::dynamic_pointer_cast<OptionInt<uint32_t> >(option_foo);
+    ASSERT_TRUE(option_foo_uint32);
+    // Validate the value according to the configuration.
+    EXPECT_EQ(1234, option_foo_uint32->getValue());
+
+    // Option with the code 111 should be added as a sub-option.
+    OptionPtr option_foo2 = desc.option->getOption(111);
+    ASSERT_TRUE(option_foo2);
+    EXPECT_EQ(111, option_foo2->getType());
+    // This option comprises the IPV4 address. Such option is
+    // represented by OptionCustom object.
+    OptionCustomPtr option_foo2_v4 =
+        boost::dynamic_pointer_cast<OptionCustom>(option_foo2);
+    ASSERT_TRUE(option_foo2_v4);
+    // Get the IP address carried by this option and validate it.
+    EXPECT_EQ("192.168.2.1", option_foo2_v4->readAddress().toText());
+
+    // Option with the code 112 should not be added.
+    EXPECT_FALSE(desc.option->getOption(112));
+}
+
 };
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 0ed4e85..b742a13 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -35,7 +35,7 @@
 
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
-
+#include <unistd.h>
 #include <fstream>
 #include <iostream>
 #include <sstream>
@@ -55,7 +55,16 @@ namespace {
 class NakedDhcpv6Srv: public Dhcpv6Srv {
     // "naked" Interface Manager, exposes internal members
 public:
-    NakedDhcpv6Srv(uint16_t port):Dhcpv6Srv(port) { }
+    NakedDhcpv6Srv(uint16_t port) : Dhcpv6Srv(port) {
+        // Open the "memfile" database for leases
+        std::string memfile = "type=memfile";
+        LeaseMgrFactory::create(memfile);
+    }
+
+    virtual ~NakedDhcpv6Srv() {
+        // Close the lease database
+        LeaseMgrFactory::destroy();
+    }
 
     using Dhcpv6Srv::processSolicit;
     using Dhcpv6Srv::processRequest;
@@ -64,10 +73,16 @@ public:
     using Dhcpv6Srv::createStatusCode;
     using Dhcpv6Srv::selectSubnet;
     using Dhcpv6Srv::sanityCheck;
+    using Dhcpv6Srv::loadServerID;
+    using Dhcpv6Srv::writeServerID;
 };
 
+static const char* DUID_FILE = "server-id-test.txt";
+
 class Dhcpv6SrvTest : public ::testing::Test {
 public:
+    /// Name of the server-id file (used in server-id tests)
+
     // these are empty for now, but let's keep them around
     Dhcpv6SrvTest() : rcode_(-1) {
         subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
@@ -77,6 +92,9 @@ public:
 
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().addSubnet6(subnet_);
+
+        // it's ok if that fails. There should not be such a file anyway
+        unlink(DUID_FILE);
     }
 
     // Generate IA_NA option with specified parameters
@@ -204,7 +222,8 @@ public:
     // Check that generated IAADDR option contains expected address.
     void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
                      const IOAddress& expected_addr,
-                     uint32_t expected_preferred, uint32_t expected_valid) {
+                     uint32_t /* expected_preferred */,
+                     uint32_t /* expected_valid */) {
 
         // Check that the assigned address is indeed from the configured pool.
         // Note that when comparing addresses, we compare the textual
@@ -246,6 +265,9 @@ public:
 
     ~Dhcpv6SrvTest() {
         CfgMgr::instance().deleteSubnets6();
+
+        // Let's clean up if there is such a file.
+        unlink(DUID_FILE);
     };
 
     // A subnet used in most tests
@@ -1407,7 +1429,38 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
 
     pkt->setIface("wifi1");
     EXPECT_EQ(subnet3, srv.selectSubnet(pkt));
+}
+
+// This test verifies if the server-id disk operations (read, write) are
+// working properly.
+TEST_F(Dhcpv6SrvTest, ServerID) {
+    NakedDhcpv6Srv srv(0);
+
+    string duid1_text = "01:ff:02:03:06:80:90:ab:cd:ef";
+    uint8_t duid1[] = { 0x01, 0xff, 2, 3, 6, 0x80, 0x90, 0xab, 0xcd, 0xef };
+    OptionBuffer expected_duid1(duid1, duid1 + sizeof(duid1));
+
+    fstream file1(DUID_FILE, ios::out | ios::trunc);
+    file1 << duid1_text;
+    file1.close();
+
+    // Test reading from a file
+    EXPECT_TRUE(srv.loadServerID(DUID_FILE));
+    ASSERT_TRUE(srv.getServerID());
+    ASSERT_EQ(sizeof(duid1) + Option::OPTION6_HDR_LEN, srv.getServerID()->len());
+    ASSERT_TRUE(expected_duid1 == srv.getServerID()->getData());
+
+    // Now test writing to a file
+    EXPECT_EQ(0, unlink(DUID_FILE));
+    EXPECT_NO_THROW(srv.writeServerID(DUID_FILE));
+
+    fstream file2(DUID_FILE, ios::in);
+    ASSERT_TRUE(file2.good());
+    string text;
+    file2 >> text;
+    file2.close();
 
+    EXPECT_EQ(duid1_text, text);
 }
 
 /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py
index 1870392..3333111 100644
--- a/src/bin/dhcp6/tests/dhcp6_test.py
+++ b/src/bin/dhcp6/tests/dhcp6_test.py
@@ -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_src import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+from init import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
 
 import unittest
 import sys
@@ -157,7 +157,7 @@ class TestDhcpv6Daemon(unittest.TestCase):
 
     def test_alive(self):
         """
-        Simple test. Checks that b10-dhcp6 can be started and prints out info 
+        Simple test. Checks that b10-dhcp6 can be started and prints out info
         about starting DHCPv6 operation.
         """
         print("Note: Purpose of some of the tests is to check if DHCPv6 server can be started,")
diff --git a/src/bin/loadzone/loadzone.py.in b/src/bin/loadzone/loadzone.py.in
index 3ed3b7d..736aa31 100755
--- a/src/bin/loadzone/loadzone.py.in
+++ b/src/bin/loadzone/loadzone.py.in
@@ -25,6 +25,7 @@ from isc.datasrc import *
 import isc.util.process
 import isc.log
 from isc.log_messages.loadzone_messages import *
+from datetime import timedelta
 
 isc.util.process.rename()
 
@@ -87,7 +88,6 @@ class LoadZoneRunner:
     '''
     def __init__(self, command_args):
         self.__command_args = command_args
-        self.__loaded_rrs = 0
         self.__interrupted = False # will be set to True on receiving signal
 
         # system-wide log configuration.  We need to configure logging this
@@ -103,8 +103,9 @@ class LoadZoneRunner:
                                           [{"output": "stderr",
                                             "destination": "console"}]}]}
 
-        # These are essentially private, and defined as "protected" for the
+        # These are essentially private, but defined as "protected" for the
         # convenience of tests inspecting them
+        self._loaded_rrs = 0
         self._zone_class = None
         self._zone_name = None
         self._zone_file = None
@@ -113,6 +114,10 @@ class LoadZoneRunner:
         self._log_severity = 'INFO'
         self._log_debuglevel = 0
         self._report_interval = LOAD_INTERVAL_DEFAULT
+        self._start_time = None
+        # This one will be used in (rare) cases where we want to allow tests to
+        # fake time.time()
+        self._get_time = time.time
 
         self._config_log()
 
@@ -159,7 +164,7 @@ class LoadZoneRunner:
             self._zone_class = RRClass(options.zone_class)
         except isc.dns.InvalidRRClass as ex:
             raise BadArgument('Invalid zone class: ' + str(ex))
-        if self._zone_class != RRClass.IN():
+        if self._zone_class != RRClass.IN:
             raise BadArgument("RR class is not supported: " +
                               str(self._zone_class))
 
@@ -200,16 +205,37 @@ class LoadZoneRunner:
         logger.info(LOADZONE_SQLITE3_USING_DEFAULT_CONFIG, default_db_file)
         return '{"database_file": "' + default_db_file + '"}'
 
-    def _report_progress(self, loaded_rrs):
+    def _report_progress(self, loaded_rrs, progress, dump=True):
         '''Dump the current progress report to stdout.
 
         This is essentially private, but defined as "protected" for tests.
+        Normally dump is True, but tests will set it False to get the
+        text to be reported.  Tests may also fake self._get_time (which
+        is set to time.time() by default) and self._start_time for control
+        time related conditions.
 
         '''
-        elapsed = time.time() - self.__start_time
-        sys.stdout.write("\r" + (80 * " "))
-        sys.stdout.write("\r%d RRs loaded in %.2f seconds" %
-                         (loaded_rrs, elapsed))
+        elapsed = self._get_time() - self._start_time
+        speed = int(loaded_rrs / elapsed) if elapsed > 0 else 0
+        etc = None            # calculate estimated time of completion
+        if progress != ZoneLoader.PROGRESS_UNKNOWN:
+            etc = (1 - progress) * (elapsed / progress)
+
+        # Build report text
+        report_txt = '\r%d RRs' % loaded_rrs
+        if progress != ZoneLoader.PROGRESS_UNKNOWN:
+            report_txt += ' (%.1f%%)' % (progress * 100)
+        report_txt += ' in %s, %d RRs/sec' % \
+            (str(timedelta(seconds=int(elapsed))), speed)
+        if etc is not None:
+            report_txt += ', %s ETC' % str(timedelta(seconds=int(etc)))
+
+        # Dump or return the report text.
+        if dump:
+            sys.stdout.write("\r" + (80 * " "))
+            sys.stdout.write(report_txt)
+        else:
+            return report_txt
 
     def _do_load(self):
         '''Main part of the load logic.
@@ -230,7 +256,7 @@ class LoadZoneRunner:
                             self._zone_class)
             loader = ZoneLoader(datasrc_client, self._zone_name,
                                 self._zone_file)
-            self.__start_time = time.time()
+            self._start_time = time.time()
             if self._report_interval > 0:
                 limit = self._report_interval
             else:
@@ -239,17 +265,20 @@ class LoadZoneRunner:
                 limit = LOAD_INTERVAL_DEFAULT
             while (not self.__interrupted and
                    not loader.load_incremental(limit)):
-                self.__loaded_rrs += self._report_interval
+                self._loaded_rrs += self._report_interval
                 if self._report_interval > 0:
-                    self._report_progress(self.__loaded_rrs)
+                    self._report_progress(self._loaded_rrs,
+                                          loader.get_progress())
             if self.__interrupted:
                 raise LoadFailure('loading interrupted by signal')
 
             # On successful completion, add final '\n' to the progress
             # report output (on failure don't bother to make it prettier).
             if (self._report_interval > 0 and
-                self.__loaded_rrs >= self._report_interval):
+                self._loaded_rrs >= self._report_interval):
                 sys.stdout.write('\n')
+            # record the final count of the loaded RRs for logging
+            self._loaded_rrs = loader.get_rr_count()
         except Exception as ex:
             # release any remaining lock held in the loader
             loader = None
@@ -273,8 +302,8 @@ class LoadZoneRunner:
             self._set_signal_handlers()
             self._parse_args()
             self._do_load()
-            total_elapsed_txt = "%.2f" % (time.time() - self.__start_time)
-            logger.info(LOADZONE_DONE, self.__loaded_rrs, self._zone_name,
+            total_elapsed_txt = "%.2f" % (time.time() - self._start_time)
+            logger.info(LOADZONE_DONE, self._loaded_rrs, self._zone_name,
                         self._zone_class, total_elapsed_txt)
             return 0
         except BadArgument as ex:
diff --git a/src/bin/loadzone/loadzone_messages.mes b/src/bin/loadzone/loadzone_messages.mes
index ca241b3..744a1a4 100644
--- a/src/bin/loadzone/loadzone_messages.mes
+++ b/src/bin/loadzone/loadzone_messages.mes
@@ -27,16 +27,11 @@ LOADZONE_ZONE_CREATED), but the loading operation has subsequently
 failed.  The newly created zone has been removed from the data source,
 so that the data source will go back to the original state.
 
-% LOADZONE_DONE Loaded (at least) %1 RRs into zone %2/%3 in %4 seconds
+% LOADZONE_DONE Loaded %1 RRs into zone %2/%3 in %4 seconds
 b10-loadzone has successfully loaded the specified zone.  If there was
 an old version of the zone in the data source, it is now deleted.
-It also prints (a lower bound of) the number of RRs that have been loaded
-and the time spent for the loading.  Due to a limitation of the
-current implementation of the underlying library however, it cannot show the
-exact number of the loaded RRs; it's counted for every N-th RR where N
-is the value of the -i command line option.  So, for smaller zones that
-don't even contain N RRs, the reported value will be 0.  This will be
-improved in a future version.
+It also prints the number of RRs that have been loaded
+and the time spent for the loading.
 
 % LOADZONE_LOAD_ERROR Failed to load zone %1/%2: %3
 Loading a zone by b10-loadzone fails for some reason in the middle of
diff --git a/src/bin/loadzone/run_loadzone.sh.in b/src/bin/loadzone/run_loadzone.sh.in
index b3d61d3..178cf11 100755
--- a/src/bin/loadzone/run_loadzone.sh.in
+++ b/src/bin/loadzone/run_loadzone.sh.in
@@ -18,7 +18,7 @@
 PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
 export PYTHON_EXEC
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/loadzone/tests/correct/correct_test.sh.in b/src/bin/loadzone/tests/correct/correct_test.sh.in
index 9b90d13..505411c 100755
--- a/src/bin/loadzone/tests/correct/correct_test.sh.in
+++ b/src/bin/loadzone/tests/correct/correct_test.sh.in
@@ -18,9 +18,6 @@
 PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
 export PYTHON_EXEC
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python:$PYTHONPATH
-export PYTHONPATH
-
 LOADZONE_PATH=@abs_top_builddir@/src/bin/loadzone
 TEST_FILE_PATH=@abs_top_srcdir@/src/bin/loadzone/tests/correct
 TEST_OUTPUT_PATH=@abs_top_builddir@/src/bin/loadzone//tests/correct
diff --git a/src/bin/loadzone/tests/correct/example.db b/src/bin/loadzone/tests/correct/example.db
index 38d1329..fe012cf 100644
--- a/src/bin/loadzone/tests/correct/example.db
+++ b/src/bin/loadzone/tests/correct/example.db
@@ -2,17 +2,11 @@
 $ORIGIN example.com.
 $TTL 60
 @    IN SOA   ns1.example.com. hostmaster.example.com. (1 43200 900 1814400 7200)
-; these need #2390
-;     IN     20      NS  ns1
-;                    NS  ns2
-     IN     20      NS  ns1.example.com.
-                    NS  ns2.example.com.
+     IN     20      NS  ns1
+                    NS  ns2
 ns1  IN     30      A   192.168.1.102
-; these need #2390
-;            70      NS  ns3
-;     IN             NS  ns4
-            70      NS  ns3.example.com.
-     IN             NS  ns4.example.com.
+            70      NS  ns3
+     IN             NS  ns4
      10     IN      MX  10  mail.example.com.
 ns2         80      A   1.1.1.1
 ns3  IN             A   2.2.2.2
diff --git a/src/bin/loadzone/tests/correct/include.db b/src/bin/loadzone/tests/correct/include.db
index 53871bb..f60a240 100644
--- a/src/bin/loadzone/tests/correct/include.db
+++ b/src/bin/loadzone/tests/correct/include.db
@@ -7,9 +7,7 @@ $TTL 300
 				1814400
 				3600
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.include.
+			NS	ns
 
 ns			A	127.0.0.1
 
diff --git a/src/bin/loadzone/tests/correct/mix1.db b/src/bin/loadzone/tests/correct/mix1.db
index 059fde7..a9d58a8 100644
--- a/src/bin/loadzone/tests/correct/mix1.db
+++ b/src/bin/loadzone/tests/correct/mix1.db
@@ -6,9 +6,7 @@ $ORIGIN mix1.
 				1814400
 				3
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.mix1.
+			NS	ns
 ns			A	10.53.0.1
 a			TXT	"soa minttl 3"
 b		2	TXT	"explicit ttl 2"
diff --git a/src/bin/loadzone/tests/correct/mix2.db b/src/bin/loadzone/tests/correct/mix2.db
index e89c2af..2c8153d 100644
--- a/src/bin/loadzone/tests/correct/mix2.db
+++ b/src/bin/loadzone/tests/correct/mix2.db
@@ -6,9 +6,7 @@ $ORIGIN mix2.
 				1814400
 				3
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.mix2.
+			NS	ns
 ns			A	10.53.0.1
 a			TXT	"inherited ttl 1"
 $INCLUDE mix2sub1.txt
diff --git a/src/bin/loadzone/tests/correct/ttl1.db b/src/bin/loadzone/tests/correct/ttl1.db
index 7f04ff8..aa6e2bb 100644
--- a/src/bin/loadzone/tests/correct/ttl1.db
+++ b/src/bin/loadzone/tests/correct/ttl1.db
@@ -6,9 +6,7 @@ $ORIGIN ttl1.
 				1814400
 				3
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.ttl1.
+			NS	ns
 ns			A	10.53.0.1
 a			TXT	"soa minttl 3"
 b		2	TXT	"explicit ttl 2"
diff --git a/src/bin/loadzone/tests/correct/ttl2.db b/src/bin/loadzone/tests/correct/ttl2.db
index b7df040..f7f6eee 100644
--- a/src/bin/loadzone/tests/correct/ttl2.db
+++ b/src/bin/loadzone/tests/correct/ttl2.db
@@ -6,9 +6,7 @@ $ORIGIN ttl2.
 				1814400
 				3
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.ttl2.
+			NS	ns
 ns			A	10.53.0.1
 a			TXT	"inherited ttl 1"
 b		2	TXT	"explicit ttl 2"
diff --git a/src/bin/loadzone/tests/correct/ttlext.db b/src/bin/loadzone/tests/correct/ttlext.db
index 844f452..f8b96ea 100644
--- a/src/bin/loadzone/tests/correct/ttlext.db
+++ b/src/bin/loadzone/tests/correct/ttlext.db
@@ -6,9 +6,7 @@ $ORIGIN ttlext.
 				1814400
 				3
 				)
-; this needs #2390
-;			NS	ns
-			NS	ns.ttlext.
+			NS	ns
 ns			A	10.53.0.1
 a			TXT	"soa minttl 3"
 b		2S	TXT	"explicit ttl 2"
diff --git a/src/bin/loadzone/tests/loadzone_test.py b/src/bin/loadzone/tests/loadzone_test.py
index d1ee131..351bc59 100755
--- a/src/bin/loadzone/tests/loadzone_test.py
+++ b/src/bin/loadzone/tests/loadzone_test.py
@@ -79,7 +79,7 @@ class TestLoadZoneRunner(unittest.TestCase):
         self.assertEqual(DATASRC_CONFIG, self.__runner._datasrc_config)
         self.assertEqual('sqlite3', self.__runner._datasrc_type) # default
         self.assertEqual(10000, self.__runner._report_interval) # default
-        self.assertEqual(RRClass.IN(), self.__runner._zone_class) # default
+        self.assertEqual(RRClass.IN, self.__runner._zone_class) # default
         self.assertEqual('INFO', self.__runner._log_severity) # default
         self.assertEqual(0, self.__runner._log_debuglevel)
 
@@ -135,14 +135,14 @@ class TestLoadZoneRunner(unittest.TestCase):
                           'memory')
 
     def __common_load_setup(self):
-        self.__runner._zone_class = RRClass.IN()
+        self.__runner._zone_class = RRClass.IN
         self.__runner._zone_name = TEST_ZONE_NAME
         self.__runner._zone_file = NEW_ZONE_TXT_FILE
         self.__runner._datasrc_type = 'sqlite3'
         self.__runner._datasrc_config = DATASRC_CONFIG
         self.__runner._report_interval = 1
         self.__reports = []
-        self.__runner._report_progress = lambda x: self.__reports.append(x)
+        self.__runner._report_progress = lambda x, _: self.__reports.append(x)
 
     def __check_zone_soa(self, soa_txt, zone_name=TEST_ZONE_NAME):
         """Check that the given SOA RR exists and matches the expected string
@@ -159,7 +159,7 @@ class TestLoadZoneRunner(unittest.TestCase):
             self.assertEqual(client.NOTFOUND, result)
             return
         self.assertEqual(client.SUCCESS, result)
-        result, rrset, _ = finder.find(zone_name, RRType.SOA())
+        result, rrset, _ = finder.find(zone_name, RRType.SOA)
         if soa_txt:
             self.assertEqual(finder.SUCCESS, result)
             self.assertEqual(soa_txt, rrset.to_text())
@@ -175,6 +175,7 @@ class TestLoadZoneRunner(unittest.TestCase):
         # be 3 RRs
         self.assertEqual([1, 2, 3], self.__reports)
         self.__check_zone_soa(NEW_SOA_TXT)
+        self.assertEqual(3, self.__runner._loaded_rrs)
 
     def test_load_update_skipped_report(self):
         '''successful loading, with reports for every 2 RRs'''
@@ -182,6 +183,8 @@ class TestLoadZoneRunner(unittest.TestCase):
         self.__runner._report_interval = 2
         self.__runner._do_load()
         self.assertEqual([2], self.__reports)
+        # total RRs should still be set the actual value
+        self.assertEqual(3, self.__runner._loaded_rrs)
 
     def test_load_update_no_report(self):
         '''successful loading, without progress reports'''
@@ -190,6 +193,36 @@ class TestLoadZoneRunner(unittest.TestCase):
         self.__runner._do_load()
         self.assertEqual([], self.__reports) # no report
         self.__check_zone_soa(NEW_SOA_TXT)   # but load is completed
+        self.assertEqual(3, self.__runner._loaded_rrs)
+
+    def test_report_progress(self):
+        '''Check the output format of report_progress.
+
+        For some simple scenario and minor corner cases.  We tweak the
+        start and current times so the test results will be predicatble.
+
+        '''
+        # 10 RRs in 10 sec, which is 25% of the entire zone.  it'll take
+        # 30 sec more
+        self.__runner._start_time = 10
+        self.__runner._get_time = lambda: 20
+        self.assertEqual('\r10 RRs (25.0%) in 0:00:10, 1 RRs/sec, ' +
+                         '0:00:30 ETC',
+                         self.__runner._report_progress(10, 0.25, False))
+
+        # start time == current time.  unlikely to happen in practice, but
+        # it shouldn't cause disruption.
+        self.__runner._get_time = lambda: 10
+        self.assertEqual('\r10 RRs (25.0%) in 0:00:00, 0 RRs/sec, ' +
+                         '0:00:00 ETC',
+                         self.__runner._report_progress(10, 0.25, False))
+
+        # progress is unknown
+        self.__runner._get_time = lambda: 20
+        unknown_progress = isc.datasrc.ZoneLoader.PROGRESS_UNKNOWN
+        self.assertEqual('\r10 RRs in 0:00:10, 1 RRs/sec',
+                         self.__runner._report_progress(10, unknown_progress,
+                                                        False))
 
     def test_create_and_load(self):
         '''successful case to loading contents to a new zone (created).'''
@@ -275,7 +308,8 @@ class TestLoadZoneRunner(unittest.TestCase):
     def test_load_interrupted(self):
         '''Load attempt fails due to signal interruption'''
         self.__common_load_setup()
-        self.__runner._report_progress = lambda x: self.__interrupt_progress(x)
+        self.__runner._report_progress = \
+            lambda x, _: self.__interrupt_progress(x)
         # The interrupting _report_progress() will terminate the loading
         # in the middle.  the number of reports is smaller, and the zone
         # won't be changed.
@@ -290,7 +324,8 @@ class TestLoadZoneRunner(unittest.TestCase):
 
         '''
         self.__common_load_setup()
-        self.__runner._report_progress = lambda x: self.__interrupt_progress(x)
+        self.__runner._report_progress = \
+            lambda x, _: self.__interrupt_progress(x)
         self.__runner._zone_name = Name('example.com')
         self.__runner._zone_file = ALT_NEW_ZONE_TXT_FILE
         self.__check_zone_soa(None, zone_name=Name('example.com'))
diff --git a/src/bin/msgq/msgq.py.in b/src/bin/msgq/msgq.py.in
index edca400..63d008e 100755
--- a/src/bin/msgq/msgq.py.in
+++ b/src/bin/msgq/msgq.py.in
@@ -33,6 +33,7 @@ import threading
 import isc.config.ccsession
 from optparse import OptionParser, OptionValueError
 import isc.util.process
+from isc.cc.proto_defs import *
 import isc.log
 from isc.log_messages.msgq_messages import *
 
@@ -70,6 +71,23 @@ SPECFILE_LOCATION = SPECFILE_PATH + "/msgq.spec"
 
 class MsgQReceiveError(Exception): pass
 
+class MsgQCloseOnReceive(Exception):
+    """Exception raised when reading data from a socket results in 'shutdown'.
+
+    This happens when msgq received 0-length data.  This class holds whether
+    it happens in the middle of reading (i.e. after reading some) via
+    partial_read parameter, which is set to True if and only if so.
+    This will be used by an upper layer catching the exception to distinguish
+    the severity of the event.
+
+    """
+    def __init__(self, reason, partial_read):
+        self.partial_read = partial_read
+        self.__reason = reason
+
+    def __str__(self):
+        return self.__reason
+
 class SubscriptionManager:
     def __init__(self, cfgmgr_ready):
         """
@@ -311,24 +329,22 @@ class MsgQ:
         lname = self.newlname()
         self.lnames[lname] = newsocket
 
+        logger.debug(TRACE_BASIC, MSGQ_SOCKET_REGISTERED, newsocket.fileno(),
+                     lname)
+
         if self.poller:
             self.poller.register(newsocket, select.POLLIN)
         else:
             self.add_kqueue_socket(newsocket)
 
-    def process_socket(self, fd):
-        """Process a read on a socket."""
-        if not fd in self.sockets:
-            logger.error(MSGQ_READ_UNKNOWN_FD, fd)
-            return
-        sock = self.sockets[fd]
-#        sys.stderr.write("[b10-msgq] Got read on fd %d\n" %fd)
-        self.process_packet(fd, sock)
-
     def kill_socket(self, fd, sock):
         """Fully close down the socket."""
+        # Unregister events on the socket.  Note that we don't have to do
+        # this for kqueue because the registered events are automatically
+        # deleted when the corresponding socket is closed.
         if self.poller:
             self.poller.unregister(sock)
+
         self.subs.unsubscribe_all(sock)
         lname = [ k for k, v in self.lnames.items() if v == sock ][0]
         del self.lnames[lname]
@@ -338,24 +354,35 @@ class MsgQ:
             del self.sendbuffs[fd]
         logger.debug(TRACE_BASIC, MSGQ_SOCK_CLOSE, fd)
 
-    def getbytes(self, fd, sock, length):
+    def __getbytes(self, fd, sock, length, continued):
         """Get exactly the requested bytes, or raise an exception if
-           EOF."""
+           EOF.
+
+           continued is set to True if this method is called to complete
+           already read data.
+           """
         received = b''
         while len(received) < length:
             try:
                 data = sock.recv(length - len(received))
-            except socket.error:
-                raise MsgQReceiveError(socket.error)
+
+            except socket.error as err:
+                # This case includes ECONNRESET, which seems to happen when
+                # the remote client has closed its socket at some subtle
+                # timing (it should normally result in receiving empty data).
+                # Since we didn't figure out how exactly that could happen,
+                # we treat it just like other really-unexpected socket errors.
+                raise MsgQReceiveError(str(err))
             if len(data) == 0:
-                raise MsgQReceiveError("EOF")
+                raise MsgQCloseOnReceive("EOF", continued)
             received += data
+            continued = True
         return received
 
     def read_packet(self, fd, sock):
         """Read a correctly formatted packet.  Will raise exceptions if
            something fails."""
-        lengths = self.getbytes(fd, sock, 6)
+        lengths = self.__getbytes(fd, sock, 6, False)
         overall_length, routing_length = struct.unpack(">IH", lengths)
         if overall_length < 2:
             raise MsgQReceiveError("overall_length < 2")
@@ -366,9 +393,9 @@ class MsgQ:
             raise MsgQReceiveError("routing_length == 0")
         data_length = overall_length - routing_length
         # probably need to sanity check lengths here...
-        routing = self.getbytes(fd, sock, routing_length)
+        routing = self.__getbytes(fd, sock, routing_length, True)
         if data_length > 0:
-            data = self.getbytes(fd, sock, data_length)
+            data = self.__getbytes(fd, sock, data_length, True)
         else:
             data = None
         return (routing, data)
@@ -377,8 +404,15 @@ class MsgQ:
         """Process one packet."""
         try:
             routing, data = self.read_packet(fd, sock)
-        except MsgQReceiveError as err:
-            logger.error(MSGQ_RECV_ERR, fd, err)
+        except (MsgQReceiveError, MsgQCloseOnReceive) as err:
+            # If it's MsgQCloseOnReceive and that happens without reading
+            # any data, it basically means the remote clinet has closed the
+            # socket, so we log it as debug information.  Otherwise, it's
+            # a somewhat unexpected event, so we consider it an "error".
+            if isinstance(err, MsgQCloseOnReceive) and not err.partial_read:
+                logger.debug(TRACE_BASIC, MSGQ_CLOSE_ON_RECV, fd)
+            else:
+                logger.error(MSGQ_RECV_ERROR, fd, err)
             self.kill_socket(fd, sock)
             return
 
@@ -386,7 +420,7 @@ class MsgQ:
             routingmsg = isc.cc.message.from_wire(routing)
         except DecodeError as err:
             self.kill_socket(fd, sock)
-            logger.error(MSGQ_HDR_DECODE_ERR, fd, err)
+            logger.error(MSGQ_HDR_DECODE_ERROR, fd, err)
             return
 
         self.process_command(fd, sock, routingmsg, data)
@@ -429,9 +463,12 @@ class MsgQ:
     def sendmsg(self, sock, env, msg = None):
         self.send_prepared_msg(sock, self.preparemsg(env, msg))
 
-    def __send_data(self, sock, data):
+    def _send_data(self, sock, data):
         """
-        Send a piece of data to the given socket.
+        Send a piece of data to the given socket.  This method is
+        essentially "private" to MsgQ, but defined as if it were "protected"
+        for easier access from tests.
+
         Parameters:
         sock: The socket to send to
         data: The list of bytes to send
@@ -447,15 +484,17 @@ class MsgQ:
             sock.setblocking(0)
             return sock.send(data)
         except socket.error as e:
-            if e.errno in [ errno.EAGAIN,
-                            errno.EWOULDBLOCK,
-                            errno.EINTR ]:
+            if e.errno in [ errno.EAGAIN, errno.EWOULDBLOCK, errno.EINTR ]:
                 return 0
-            elif e.errno in [ errno.EPIPE,
-                              errno.ECONNRESET,
-                              errno.ENOBUFS ]:
-                logger.error(MSGQ_SEND_ERR, sock.fileno(),
-                             errno.errorcode[e.errno])
+            elif e.errno in [ errno.EPIPE, errno.ECONNRESET, errno.ENOBUFS ]:
+                # EPIPE happens if the remote module has terminated by the time
+                # of this send; its severity can vary, but in many cases it
+                # shouldn't be critical, so we log it separately as a warning.
+                if e.errno == errno.EPIPE:
+                    logger.warn(MSGQ_CLOSE_ON_SEND, sock.fileno())
+                else:
+                    logger.error(MSGQ_SEND_ERROR, sock.fileno(),
+                                 errno.errorcode[e.errno])
                 self.kill_socket(sock.fileno(), sock)
                 return None
             else:
@@ -465,15 +504,24 @@ class MsgQ:
             sock.setblocking(1)
 
     def send_prepared_msg(self, sock, msg):
+        '''
+        Add a message to the queue. If there's nothing waiting, try
+        to send it right away.
+
+        Return if the socket is still alive. It can return false if the
+        socket dies (for example due to EPIPE in the attempt to send).
+        Returning true does not guarantee the message will be delivered,
+        but returning false means it won't.
+        '''
         # Try to send the data, but only if there's nothing waiting
         fileno = sock.fileno()
         if fileno in self.sendbuffs:
             amount_sent = 0
         else:
-            amount_sent = self.__send_data(sock, msg)
+            amount_sent = self._send_data(sock, msg)
             if amount_sent is None:
                 # Socket has been killed, drop the send
-                return
+                return False
 
         # Still something to send, add it to outgoing queue
         if amount_sent < len(msg):
@@ -483,23 +531,24 @@ class MsgQ:
                 (last_sent, buff) = self.sendbuffs[fileno]
                 if now - last_sent > 0.1:
                     self.kill_socket(fileno, sock)
-                    return
+                    return False
                 buff += msg
             else:
                 buff = msg[amount_sent:]
                 last_sent = now
                 if self.poller:
                     self.poller.register(fileno, select.POLLIN |
-                        select.POLLOUT)
+                                         select.POLLOUT)
                 else:
                     self.add_kqueue_socket(sock, True)
             self.sendbuffs[fileno] = (last_sent, buff)
+        return True
 
     def __process_write(self, fileno):
         # Try to send some data from the buffer
         (_, msg) = self.sendbuffs[fileno]
         sock = self.sockets[fileno]
-        amount_sent = self.__send_data(sock, msg)
+        amount_sent = self._send_data(sock, msg)
         if amount_sent is not None:
             # Keep the rest
             msg = msg[amount_sent:]
@@ -528,26 +577,65 @@ class MsgQ:
         self.sendmsg(sock, { "type" : "getlname" }, { "lname" : lname })
 
     def process_command_send(self, sock, routing, data):
-        group = routing["group"]
-        instance = routing["instance"]
-        to = routing["to"]
+        group = routing[CC_HEADER_GROUP]
+        instance = routing[CC_HEADER_INSTANCE]
+        to = routing[CC_HEADER_TO]
         if group == None or instance == None:
+            # FIXME: Should we log them instead?
             return  # ignore invalid packets entirely
 
-        if to == "*":
+        if to == CC_TO_WILDCARD:
             sockets = self.subs.find(group, instance)
         else:
             if to in self.lnames:
                 sockets = [ self.lnames[to] ]
             else:
-                return # recipient doesn't exist
+                sockets = []
 
         msg = self.preparemsg(routing, data)
 
         if sock in sockets:
+            # Don't bounce to self
             sockets.remove(sock)
+
+        has_recipient = False
         for socket in sockets:
-            self.send_prepared_msg(socket, msg)
+            if self.send_prepared_msg(socket, msg):
+                has_recipient = True
+        if not has_recipient and routing.get(CC_HEADER_WANT_ANSWER) and \
+            CC_HEADER_REPLY not in routing:
+            # We have no recipients. But the sender insists on a reply
+            # (and the message isn't a reply itself). We need to send
+            # an error to satisfy the request, since there's nobody
+            # else who can.
+            #
+            # We omit the replies on purpose. The recipient might generate
+            # the response by copying and mangling the header of incoming
+            # message (just like we do below) and would include the want_answer
+            # by accident. And we want to avoid loops of errors. Also, it
+            # is unclear if the knowledge of undeliverable reply would be
+            # of any use to the sender, and it should be much rarer situation.
+
+            # The real errors would be positive, 1 most probably. We use
+            # negative errors for delivery errors to distinguish them a
+            # little. We probably should have a way to provide more data
+            # in the error message.
+            payload = isc.config.ccsession.create_answer(CC_REPLY_NO_RECPT,
+                                                         "No such recipient")
+            # We create the header based on the current one. But we don't
+            # want to mangle it for the caller, so we get a copy. A shallow
+            # one should be enough, we modify the dict only.
+            header = routing.copy()
+            header[CC_HEADER_REPLY] = routing[CC_HEADER_SEQ]
+            # Dummy lname not assigned to clients
+            header[CC_HEADER_FROM] = "msgq"
+            header[CC_HEADER_TO] = routing[CC_HEADER_FROM]
+            # We keep the seq as it is. We don't need to track the message
+            # and we will not confuse the sender. The sender would use an
+            # unique id for each message, so we won't return one twice to it.
+            errmsg = self.preparemsg(header, payload)
+            # Send it back.
+            self.send_prepared_msg(sock, errmsg)
 
     def process_command_subscribe(self, sock, routing, data):
         group = routing["group"]
@@ -582,7 +670,7 @@ class MsgQ:
                 if err.args[0] == errno.EINTR:
                     events = []
                 else:
-                    logger.fatal(MSGQ_POLL_ERR, err)
+                    logger.fatal(MSGQ_POLL_ERROR, err)
                     break
             with self.__lock:
                 for (fd, event) in events:
@@ -593,12 +681,17 @@ class MsgQ:
                         self.running = False
                         break
                     else:
-                        if event & select.POLLOUT:
-                            self.__process_write(fd)
-                        elif event & select.POLLIN:
-                            self.process_socket(fd)
-                        else:
+                        writable = event & select.POLLOUT
+                        # Note: it may be okay to read data if available
+                        # immediately after write some, but due to unexpected
+                        # regression (see comments on the kqueue version below)
+                        # we restrict one operation per iteration for now.
+                        # In future we may clarify the point and enable the
+                        # "read/write" mode.
+                        readable = not writable and (event & select.POLLIN)
+                        if not writable and not readable:
                             logger.error(MSGQ_POLL_UNKNOWN_EVENT, fd, event)
+                        self._process_fd(fd, writable, readable, False)
 
     def run_kqueue(self):
         while self.running:
@@ -617,14 +710,35 @@ class MsgQ:
                         self.running = False
                         break;
                     else:
-                        if event.filter == select.KQ_FILTER_WRITE:
-                            self.__process_write(event.ident)
-                        if event.filter == select.KQ_FILTER_READ and \
-                                event.data > 0:
-                            self.process_socket(event.ident)
-                        elif event.flags & select.KQ_EV_EOF:
-                            self.kill_socket(event.ident,
-                                             self.sockets[event.ident])
+                        fd = event.ident
+                        writable = event.filter == select.KQ_FILTER_WRITE
+                        readable = (event.filter == select.KQ_FILTER_READ and
+                                    event.data > 0)
+                        # It seems to break some of our test cases if we
+                        # immediately close the socket on EOF after reading
+                        # some data.  It may be possible to avoid by tweaking
+                        # the test, but unless we can be sure we'll hold off.
+                        closed = (not readable and
+                                  (event.flags & select.KQ_EV_EOF))
+                        self._process_fd(fd, writable, readable, closed)
+
+    def _process_fd(self, fd, writable, readable, closed):
+        '''Process a single FD: unified subroutine of run_kqueue/poller.
+
+        closed can be True only in the case of kqueue.  This is essentially
+        private but is defined as if it were "protected" so it's callable
+        from tests.
+
+        '''
+        # We need to check if FD is still in the sockets dict, because
+        # it's possible that the socket has been "killed" while processing
+        # other FDs; it's even possible it's killed within this method.
+        if writable and fd in self.sockets:
+            self.__process_write(fd)
+        if readable and fd in self.sockets:
+            self.process_packet(fd, self.sockets[fd])
+        if closed and fd in self.sockets:
+            self.kill_socket(fd, self.sockets[fd])
 
     def stop(self):
         # Signal it should terminate.
@@ -650,6 +764,18 @@ class MsgQ:
         logger.debug(TRACE_START, MSGQ_SHUTDOWN)
         self.listen_socket.close()
         self.cleanup_signalsock()
+        # Close all the sockets too. In real life, there should be none now,
+        # as Msgq should be the last one. But some tests don't adhere to this
+        # and create a new Msgq for each test, which led to huge socket leaks.
+        # Some other threads put some other things in instead of sockets, so
+        # we catch whatever exceptions there we can. This should be safe,
+        # because in real operation, we will terminate now anyway, implicitly
+        # closing anything anyway.
+        for sock in self.sockets.values():
+            try:
+                sock.close()
+            except Exception:
+                pass
         if os.path.exists(self.socket_file):
             os.remove(self.socket_file)
 
@@ -749,3 +875,5 @@ if __name__ == "__main__":
         pass
 
     msgq.shutdown()
+
+    logger.info(MSGQ_EXITING)
diff --git a/src/bin/msgq/msgq.xml b/src/bin/msgq/msgq.xml
index 43c72a4..8cef10c 100644
--- a/src/bin/msgq/msgq.xml
+++ b/src/bin/msgq/msgq.xml
@@ -69,7 +69,7 @@
 
       <listitem><para>
         <command>getlname</command>
-        — receive local name. 
+        — receive local name.
       </para></listitem>
 
       <listitem><para>
@@ -134,6 +134,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
diff --git a/src/bin/msgq/msgq_messages.mes b/src/bin/msgq/msgq_messages.mes
index 75e4227..09c9030 100644
--- a/src/bin/msgq/msgq_messages.mes
+++ b/src/bin/msgq/msgq_messages.mes
@@ -23,6 +23,31 @@
 This is a debug message. The message queue has little bit of special handling
 for the configuration manager. This special handling is happening now.
 
+% MSGQ_CLOSE_ON_RECV Reading from socket canceled as it's closed: FD=%1
+A debug message.  The msgq daemon was notified of a read event on a
+socket, but its initial read operation failed because the remote
+client has closed its socket.  This is possible in a normal operation
+when a module shuts down.
+
+% MSGQ_CLOSE_ON_SEND Sending to socket failed as already closed (okay to ignore on shutdown): FD=%1
+The msgq daemon tries to send some data to a client module, but it
+failed because the socket has been closed.  This normally means the
+client terminates (for some reason - either gracefully or as a crash)
+while other modules try to send a message to the terminated module.
+Since msgq doesn't keep track of the status of client modules, this
+can happen and is not really an error for msgq; however, it can still
+be an unexpected event for the BIND 10 system as a whole in that this
+particular message is lost, so it's logged as a warning.  If this
+message is logged for a running BIND 10 system, it's suggested to
+check other log messages; there may be an error from other modules
+reporting a missing response message.  One common, less critical case
+where this message is logged is during shutdown.  The ordering of
+process shutdown is basically arbitrary at this moment, so it's
+possible that some module tries to send a "quitting" message to some
+other module but the latter has already shut down.  Such cases are
+generally non critical, but you may want to check other possible error
+messages.
+
 % MSGQ_COMMAND Running command %1 with arguments %2
 Debug message. The message queue received a command and it is running it.
 
@@ -34,13 +59,21 @@ the message queue version and version of the module.
 % MSGQ_CONFIG_DATA Received configuration update for the msgq: %1
 Debug message. The message queue received a configuration update, handling it.
 
-% MSGQ_HDR_DECODE_ERR Error decoding header received from socket %1: %2
+% MSGQ_EXITING exiting
+The msgq daemon is exiting.
+
+% MSGQ_HDR_DECODE_ERROR Error decoding header received from socket %1: %2
 The socket with mentioned file descriptor sent a packet. However, it was not
 possible to decode the routing header of the packet. The packet is ignored.
 This may be caused by a programmer error (one of the components sending invalid
 data) or possibly by incompatible version of msgq and the component (but that's
 unlikely, as the protocol is not changed often).
 
+% MSGQ_INVALID_CMD Received invalid command: %1
+An unknown command listed in the log has been received. It is ignored. This
+indicates either a programmer error (eg. a typo in the command name) or
+incompatible version of a module and message queue daemon.
+
 % MSGQ_LISTENER_FAILED Failed to initialize listener on socket file '%1': %2
 The message queue daemon tried to listen on a file socket (the path is in the
 message), but it failed. The error from the operating system is logged.
@@ -52,7 +85,7 @@ Debug message. The listener is trying to open a listening socket.
 Debug message. The message queue successfully opened a listening socket and
 waits for incoming connections.
 
-% MSGQ_POLL_ERR Error while polling for events: %1
+% MSGQ_POLL_ERROR Error while polling for events: %1
 A low-level error happened when waiting for events, the error is logged. The
 reason for this varies, but it usually means the system is short on some
 resources.
@@ -63,30 +96,41 @@ happen and it is either a programmer error or OS bug. The event is ignored. The
 number noted as the event is the raw encoded value, which might be useful to
 the authors when figuring the problem out.
 
-% MSGQ_READ_UNKNOWN_FD Got read on strange socket %1
-The OS reported a file descriptor is ready to read. But the daemon doesn't know
-the mentioned file descriptor, which is either a programmer error or OS bug.
-The read event is ignored.
-
-% MSGQ_RECV_ERR Error reading from socket %1: %2
+% MSGQ_RECV_ERROR Error reading from socket %1: %2
 There was a low-level error when reading from a socket. The error is logged and
-the corresponding socket is dropped.
+the corresponding socket is dropped.  The errors include receiving
+broken or (non empty but) incomplete data.  In either case it usually suggests
+something unexpected happens within the BIND 10 system; it's probably
+better to restart the system, and if it continues it should be
+reported as a bug.  One known, probably non critical case is
+the "connection reset by peer" (or its variants) socket error appearing
+on shutdown.  It's known this happens when the remote client closes the
+connection as part of shutdown process.  Such cases are normally expected
+to be reported as receiving empty data (which we log it at the debug level
+as the MSGQ_CLOSE_ON_RECV message), but for some (yet) unknown reason
+it can also be reported as the system error.  At shutdown time it's expected
+that connections are closed, so it's probably safe to ignore these messages
+in such a case.  We still log them as an error as we've not figured out
+how exactly that can happen.  In future, we may make the shutdown process
+more robust so the msgq daemon can explicitly know when a client shuts down
+more reliably.  If and when it's implemented this error message won't appear
+on shutdown unless there's really something unexpected.
 
 % MSGQ_RECV_HDR Received header: %1
 Debug message. This message includes the whole routing header of a packet.
 
-% MSGQ_INVALID_CMD Received invalid command: %1
-An unknown command listed in the log has been received. It is ignored. This
-indicates either a programmer error (eg. a typo in the command name) or
-incompatible version of a module and message queue daemon.
-
-% MSGQ_SEND_ERR Error while sending to socket %1: %2
+% MSGQ_SEND_ERROR Error while sending to socket %1: %2
 There was a low-level error when sending data to a socket. The error is logged
 and the corresponding socket is dropped.
 
 % MSGQ_SHUTDOWN Stopping Msgq
 Debug message. The message queue is shutting down.
 
+% MSGQ_SOCKET_REGISTERED Registered a socket descriptor %1 with lname %2
+Debug message. The msgq daemon accepted a session request on the
+shown descriptor of socket and assigned a unique identifier (lname)
+for the client on that socket.
+
 % MSGQ_SOCK_CLOSE Closing socket fd %1
 Debug message. Closing the mentioned socket.
 
diff --git a/src/bin/msgq/run_msgq.sh.in b/src/bin/msgq/run_msgq.sh.in
index 3ab4024..c9fef64 100644
--- a/src/bin/msgq/run_msgq.sh.in
+++ b/src/bin/msgq/run_msgq.sh.in
@@ -20,7 +20,7 @@ export PYTHON_EXEC
 
 MYPATH_PATH=@abs_top_builddir@/src/bin/msgq
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/log/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/log/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/msgq/tests/msgq_test.py b/src/bin/msgq/tests/msgq_test.py
index 00e15d8..98705bf 100644
--- a/src/bin/msgq/tests/msgq_test.py
+++ b/src/bin/msgq/tests/msgq_test.py
@@ -1,3 +1,19 @@
+# Copyright (C) 2010-2013  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 msgq
 from msgq import SubscriptionManager, MsgQ
 
 import unittest
@@ -11,6 +27,8 @@ import threading
 import isc.cc
 import collections
 import isc.log
+import struct
+import json
 
 #
 # Currently only the subscription part and some sending is implemented...
@@ -140,6 +158,150 @@ class TestSubscriptionManager(unittest.TestCase):
         self.sm.subscribe('ConfigManager', '*', 's3')
         self.assertEqual(1, self.__cfgmgr_ready_called)
 
+class MsgQTest(unittest.TestCase):
+    """
+    Tests for the behaviour of MsgQ. This is for the core of MsgQ, other
+    subsystems are in separate test fixtures.
+    """
+    def setUp(self):
+        self.__msgq = MsgQ()
+
+    def parse_msg(self, msg):
+        """
+        Parse a binary representation of message to the routing header and the
+        data payload. It assumes the message is correctly encoded and the
+        payload is not omitted. It'd probably throw in other cases, but we
+        don't use it in such situations in this test.
+        """
+        (length, header_len) = struct.unpack('>IH', msg[:6])
+        header = json.loads(msg[6:6 + header_len].decode('utf-8'))
+        data = json.loads(msg[6 + header_len:].decode('utf-8'))
+        return (header, data)
+
+    def test_undeliverable_errors(self):
+        """
+        Send several packets through the MsgQ and check it generates
+        undeliverable notifications under the correct circumstances.
+
+        The test is not exhaustive as it doesn't test all combination
+        of existence of the recipient, addressing schemes, want_answer
+        header and the reply header. It is not needed, these should
+        be mostly independant. That means, for example, if the message
+        is a reply and there's no recipient to send it to, the error
+        would not be generated no matter if we addressed the recipient
+        by lname or group. If we included everything, the test would
+        have too many scenarios with little benefit.
+        """
+        self.__sent_messages = []
+        def fake_send_prepared_msg(socket, msg):
+            self.__sent_messages.append((socket, msg))
+            return True
+        self.__msgq.send_prepared_msg = fake_send_prepared_msg
+        # These would be real sockets in the MsgQ, but we pass them as
+        # parameters only, so we don't need them to be. We use simple
+        # integers to tell one from another.
+        sender = 1
+        recipient = 2
+        another_recipiet = 3
+        # The routing headers and data to test with.
+        routing = {
+            'to': '*',
+            'from': 'sender',
+            'group': 'group',
+            'instance': '*',
+            'seq': 42
+        }
+        data = {
+            "data": "Just some data"
+        }
+
+        # Some common checking patterns
+        def check_error():
+            self.assertEqual(1, len(self.__sent_messages))
+            self.assertEqual(1, self.__sent_messages[0][0])
+            self.assertEqual(({
+                                  'group': 'group',
+                                  'instance': '*',
+                                  'reply': 42,
+                                  'seq': 42,
+                                  'from': 'msgq',
+                                  'to': 'sender',
+                                  'want_answer': True
+                              }, {'result': [-1, "No such recipient"]}),
+                              self.parse_msg(self.__sent_messages[0][1]))
+            self.__sent_messages = []
+
+        def check_no_message():
+            self.assertEqual([], self.__sent_messages)
+
+        def check_delivered(rcpt_socket=recipient):
+            self.assertEqual(1, len(self.__sent_messages))
+            self.assertEqual(rcpt_socket, self.__sent_messages[0][0])
+            self.assertEqual((routing, data),
+                             self.parse_msg(self.__sent_messages[0][1]))
+            self.__sent_messages = []
+
+        # Send the message. No recipient, but errors are not requested,
+        # so none is generated.
+        self.__msgq.process_command_send(sender, routing, data)
+        check_no_message()
+
+        # It should act the same if we explicitly say we do not want replies.
+        routing["want_answer"] = False
+        self.__msgq.process_command_send(sender, routing, data)
+        check_no_message()
+
+        # Ask for errors if it can't be delivered.
+        routing["want_answer"] = True
+        self.__msgq.process_command_send(sender, routing, data)
+        check_error()
+
+        # If the message is a reply itself, we never generate the errors
+        routing["reply"] = 3
+        self.__msgq.process_command_send(sender, routing, data)
+        check_no_message()
+
+        # If there are recipients (but no "reply" header), the error should not
+        # be sent and the message should get delivered.
+        del routing["reply"]
+        self.__msgq.subs.find = lambda group, instance: [recipient]
+        self.__msgq.process_command_send(sender, routing, data)
+        check_delivered()
+
+        # When we send a direct message and the recipient is not there, we get
+        # the error too
+        routing["to"] = "lname"
+        self.__msgq.process_command_send(sender, routing, data)
+        check_error()
+
+        # But when the recipient is there, it is delivered and no error is
+        # generated.
+        self.__msgq.lnames["lname"] = recipient
+        self.__msgq.process_command_send(sender, routing, data)
+        check_delivered()
+
+        # If an attempt to send fails, consider it no recipient.
+        def fail_send_prepared_msg(socket, msg):
+            '''
+            Pretend sending a message failed. After one call, return to the
+            usual mock, so the errors or other messages can be sent.
+            '''
+            self.__msgq.send_prepared_msg = fake_send_prepared_msg
+            return False
+
+        self.__msgq.send_prepared_msg = fail_send_prepared_msg
+        self.__msgq.process_command_send(sender, routing, data)
+        check_error()
+
+        # But if there are more recipients and only one fails, it should
+        # be delivered to the other and not considered an error
+        self.__msgq.send_prepared_msg = fail_send_prepared_msg
+        routing["to"] = '*'
+        self.__msgq.subs.find = lambda group, instance: [recipient,
+                                                         another_recipiet]
+        self.__msgq.process_command_send(sender, routing, data)
+        check_delivered(rcpt_socket=another_recipiet)
+
 class DummySocket:
     """
     Dummy socket class.
@@ -244,17 +406,27 @@ class SendNonblock(unittest.TestCase):
             self.assertEqual(0, status,
                 "The task did not complete successfully in time")
 
+    def get_msgq_with_sockets(self):
+        '''
+        Create a message queue and prepare it for use with a socket pair.
+        The write end is put into the message queue, so we can check it.
+        It returns (msgq, read_end, write_end). It is expected the sockets
+        are closed by the caller afterwards.
+        '''
+        msgq = MsgQ()
+        # We do only partial setup, so we don't create the listening socket
+        msgq.setup_poller()
+        (read, write) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+        msgq.register_socket(write)
+        return (msgq, read, write)
+
     def infinite_sender(self, sender):
         """
         Sends data until an exception happens. socket.error is caught,
         as it means the socket got closed. Sender is called to actually
         send the data.
         """
-        msgq = MsgQ()
-        # We do only partial setup, so we don't create the listening socket
-        msgq.setup_poller()
-        (read, write) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
-        msgq.register_socket(write)
+        (msgq, read, write) = self.get_msgq_with_sockets()
         # Keep sending while it is not closed by the msgq
         try:
             while True:
@@ -290,6 +462,34 @@ class SendNonblock(unittest.TestCase):
         self.terminate_check(lambda: self.infinite_sender(
             lambda msgq, socket: msgq.send_prepared_msg(socket, data)))
 
+    def test_sendprepared_success(self):
+        '''
+        Test the send_prepared_msg returns success when queueing messages.
+        It does so on the first attempt (when it actually tries to send
+        something to the socket) and on any attempt that follows and the
+        buffer is already full.
+        '''
+        (msgq, read, write) = self.get_msgq_with_sockets()
+        # Now keep sending until we fill in something into the internal
+        # buffer.
+        while not write.fileno() in msgq.sendbuffs:
+            self.assertTrue(msgq.send_prepared_msg(write, b'data'))
+        read.close()
+        write.close()
+
+    def test_sendprepared_epipe(self):
+        '''
+        Test the send_prepared_msg returns false when we try to queue a
+        message and the other side is not there any more. It should be done
+        with EPIPE, so not a fatal error.
+        '''
+        (msgq, read, write) = self.get_msgq_with_sockets()
+        # Close one end. It should make a EPIPE on the other.
+        read.close()
+        # Now it should soft-fail
+        self.assertFalse(msgq.send_prepared_msg(write, b'data'))
+        write.close()
+
     def send_many(self, data):
         """
         Tries that sending a command many times and getting an answer works.
@@ -454,9 +654,8 @@ class SendNonblock(unittest.TestCase):
         Two tests are done: one where the error is raised on the 3rd octet,
                             and one on the 23rd.
         """
-        sockerr = socket.error
         for err in [ errno.EAGAIN, errno.EWOULDBLOCK, errno.EINTR ]:
-            sockerr.errno = err
+            sockerr = socket.error(err, 'Socket error')
             self.do_send_with_send_error(3, sockerr)
             self.do_send_with_send_error(23, sockerr)
 
@@ -467,9 +666,8 @@ class SendNonblock(unittest.TestCase):
         Two tests are done: one where the error is raised on the 3rd octet,
                             and one on the 23rd.
         """
-        sockerr = socket.error
         for err in [ errno.EPIPE, errno.ENOBUFS, errno.ECONNRESET ]:
-            sockerr.errno = err
+            sockerr = socket.error(err, 'Socket error')
             self.do_send_with_send_error(3, sockerr, False)
             self.do_send_with_send_error(23, sockerr, False)
 
@@ -561,6 +759,178 @@ class ThreadTests(unittest.TestCase):
         test_thread.join(60)
         self.assertTrue(self.__result)
 
+class SocketTests(unittest.TestCase):
+    '''Test cases for micro behaviors related to socket operations.
+
+    Some cases are covered as part of other tests, but in this fixture
+    we check more details of specific method related to socket operation,
+    with the help of mock classes to avoid expensive overhead.
+
+    '''
+    class MockSocket():
+        '''A mock socket used instead of standard socket objects.'''
+        def __init__(self):
+            self.ex_on_send = None # raised from send() if not None
+            self.recv_result = b'test' # dummy data or exception
+            self.blockings = [] # history of setblocking() params
+        def setblocking(self, on):
+            self.blockings.append(on)
+        def send(self, data):
+            if self.ex_on_send is not None:
+                raise self.ex_on_send
+            return 10           # arbitrary choice
+        def recv(self, len):
+            if isinstance(self.recv_result, Exception):
+                raise self.recv_result
+            ret = self.recv_result
+            self.recv_result = b'' # if called again, return empty data
+            return ret
+        def fileno(self):
+            return 42           # arbitrary choice
+
+    class LoggerWrapper():
+        '''A simple wrapper of logger to inspect log messages.'''
+        def __init__(self, logger):
+            self.error_called = 0
+            self.warn_called = 0
+            self.debug_called = 0
+            self.orig_logger = logger
+        def error(self, *args):
+            self.error_called += 1
+            self.orig_logger.error(*args)
+        def warn(self, *args):
+            self.warn_called += 1
+            self.orig_logger.warn(*args)
+        def debug(self, *args):
+            self.debug_called += 1
+            self.orig_logger.debug(*args)
+
+    def mock_kill_socket(self, fileno, sock):
+        '''A replacement of MsgQ.kill_socket method for inspection.'''
+        self.__killed_socket = (fileno, sock)
+        if fileno in self.__msgq.sockets:
+            del self.__msgq.sockets[fileno]
+
+    def setUp(self):
+        self.__msgq = MsgQ()
+        self.__msgq.kill_socket = self.mock_kill_socket
+        self.__sock = self.MockSocket()
+        self.__data = b'dummy'
+        self.__msgq.sockets[42] = self.__sock
+        self.__msgq.sendbuffs[42] = (None, b'testdata')
+        self.__sock_error = socket.error()
+        self.__killed_socket = None
+        self.__logger = self.LoggerWrapper(msgq.logger)
+        msgq.logger = self.__logger
+
+    def tearDown(self):
+        msgq.logger = self.__logger.orig_logger
+
+    def test_send_data(self):
+        # Successful case: _send_data() returns the hardcoded value, and
+        # setblocking() is called twice with the expected parameters
+        self.assertEqual(10, self.__msgq._send_data(self.__sock, self.__data))
+        self.assertEqual([0, 1], self.__sock.blockings)
+        self.assertIsNone(self.__killed_socket)
+
+    def test_send_data_interrupt(self):
+        '''send() is interruptted. send_data() returns 0, sock isn't killed.'''
+        expected_blockings = []
+        for eno in [errno.EAGAIN, errno.EWOULDBLOCK, errno.EINTR]:
+            self.__sock_error.errno = eno
+            self.__sock.ex_on_send = self.__sock_error
+            self.assertEqual(0, self.__msgq._send_data(self.__sock,
+                                                       self.__data))
+            expected_blockings.extend([0, 1])
+            self.assertEqual(expected_blockings, self.__sock.blockings)
+            self.assertIsNone(self.__killed_socket)
+
+    def test_send_data_error(self):
+        '''Unexpected error happens on send().  The socket is killed.
+
+        If the error is EPIPE, it's logged at the warn level; otherwise
+        an error message is logged.
+
+        '''
+        expected_blockings = []
+        expected_errors = 0
+        expected_warns = 0
+        for eno in [errno.EPIPE, errno.ECONNRESET, errno.ENOBUFS]:
+            self.__sock_error.errno = eno
+            self.__sock.ex_on_send = self.__sock_error
+            self.__killed_socket = None # clear any previuos value
+            self.assertEqual(None, self.__msgq._send_data(self.__sock,
+                                                          self.__data))
+            self.assertEqual((42, self.__sock), self.__killed_socket)
+            expected_blockings.extend([0, 1])
+            self.assertEqual(expected_blockings, self.__sock.blockings)
+
+            if eno == errno.EPIPE:
+                expected_warns += 1
+            else:
+                expected_errors += 1
+            self.assertEqual(expected_errors, self.__logger.error_called)
+            self.assertEqual(expected_warns, self.__logger.warn_called)
+
+    def test_process_fd_read_after_bad_write(self):
+        '''Check the specific case of write fail followed by read attempt.
+
+        The write failure results in kill_socket, then read shouldn't tried.
+
+        '''
+        self.__sock_error.errno = errno.EPIPE
+        self.__sock.ex_on_send = self.__sock_error
+        self.__msgq.process_socket = None # if called, trigger an exception
+        self.__msgq._process_fd(42, True, True, False) # shouldn't crash
+
+        # check the socket is deleted from the fileno=>sock dictionary
+        self.assertEqual({}, self.__msgq.sockets)
+
+    def test_process_fd_close_after_bad_write(self):
+        '''Similar to the previous, but for checking dup'ed kill attempt'''
+        self.__sock_error.errno = errno.EPIPE
+        self.__sock.ex_on_send = self.__sock_error
+        self.__msgq._process_fd(42, True, False, True) # shouldn't crash
+        self.assertEqual({}, self.__msgq.sockets)
+
+    def test_process_fd_writer_after_close(self):
+        '''Emulate a "writable" socket has been already closed and killed.'''
+        # This just shouldn't crash
+        self.__msgq._process_fd(4200, True, False, False)
+
+    def test_process_packet(self):
+        '''Check some failure cases in handling an incoming message.'''
+        expected_errors = 0
+        expected_debugs = 0
+
+        # if socket.recv() fails due to socket.error, it will be logged
+        # as error and the socket will be killed regardless of errno.
+        for eno in [errno.ENOBUFS, errno.ECONNRESET]:
+            self.__sock_error.errno = eno
+            self.__sock.recv_result = self.__sock_error
+            self.__killed_socket = None # clear any previuos value
+            self.__msgq.process_packet(42, self.__sock)
+            self.assertEqual((42, self.__sock), self.__killed_socket)
+            expected_errors += 1
+            self.assertEqual(expected_errors, self.__logger.error_called)
+            self.assertEqual(expected_debugs, self.__logger.debug_called)
+
+        # if socket.recv() returns empty data, the result depends on whether
+        # there's any preceding data; in the second case below, at least
+        # 6 bytes of data will be expected, and the second call to our faked
+        # recv() returns empty data.  In that case it will be logged as error.
+        for recv_data in [b'', b'short']:
+            self.__sock.recv_result = recv_data
+            self.__killed_socket = None
+            self.__msgq.process_packet(42, self.__sock)
+            self.assertEqual((42, self.__sock), self.__killed_socket)
+            if len(recv_data) == 0:
+                expected_debugs += 1
+            else:
+                expected_errors += 1
+            self.assertEqual(expected_errors, self.__logger.error_called)
+            self.assertEqual(expected_debugs, self.__logger.debug_called)
+
 if __name__ == '__main__':
     isc.log.resetUnitTestRootLogger()
     unittest.main()
diff --git a/src/bin/resolver/b10-resolver.xml b/src/bin/resolver/b10-resolver.xml
index 485d022..afca976 100644
--- a/src/bin/resolver/b10-resolver.xml
+++ b/src/bin/resolver/b10-resolver.xml
@@ -52,10 +52,15 @@
     <title>DESCRIPTION</title>
     <para>The <command>b10-resolver</command> daemon provides the BIND 10
       recursive DNS server.  Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
     </para>
 
+    <note><simpara>
+      The <command>b10-resolver</command> is an experimental proof
+      of concept.
+    </simpara></note>
+
     <para>
       This daemon communicates with other BIND 10 components over a
       <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
@@ -205,7 +210,7 @@ once that is merged you can for instance do 'config add Resolver/forward_address
       <command>shutdown</command> exits <command>b10-resolver</command>.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the b10-init process may restart this service
       if configured.)
     </para>
 
@@ -227,7 +232,7 @@ once that is merged you can for instance do 'config add Resolver/forward_address
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
-        <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 9536608..a3de340 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -431,13 +431,14 @@ Resolver::processMessage(const IOMessage& io_message,
 
         // Ignore all responses.
         if (query_message->getHeaderFlag(Message::HEADERFLAG_QR)) {
-            LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_UNEXPECTED_RESPONSE);
+            LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+                      RESOLVER_UNEXPECTED_RESPONSE);
             server->resume(false);
             return;
         }
     } catch (const Exception& ex) {
-        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_HEADER_ERROR)
-                  .arg(ex.what());
+        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+                  RESOLVER_HEADER_PROCESSING_FAILED).arg(ex.what());
         server->resume(false);
         return;
     }
@@ -446,14 +447,16 @@ Resolver::processMessage(const IOMessage& io_message,
     try {
         query_message->fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
-        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_PROTOCOL_ERROR)
+        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+                  RESOLVER_PROTOCOL_BODY_PARSE_FAILED)
                   .arg(error.what()).arg(error.getRcode());
         makeErrorMessage(query_message, answer_message,
                          buffer, error.getRcode());
         server->resume(true);
         return;
     } catch (const Exception& ex) {
-        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_MESSAGE_ERROR)
+        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+                  RESOLVER_MESSAGE_PROCESSING_FAILED)
                   .arg(ex.what()).arg(Rcode::SERVFAIL());
         makeErrorMessage(query_message, answer_message,
                          buffer, Rcode::SERVFAIL());
diff --git a/src/bin/resolver/resolver_messages.mes b/src/bin/resolver/resolver_messages.mes
index 214519b..c722af1 100644
--- a/src/bin/resolver/resolver_messages.mes
+++ b/src/bin/resolver/resolver_messages.mes
@@ -81,7 +81,7 @@ has passed a set of checks (message is well-formed, it is allowed by the
 ACL, it is a supported opcode, etc.) and is being forwarded to upstream
 servers.
 
-% RESOLVER_HEADER_ERROR message received, exception when processing header: %1
+% RESOLVER_HEADER_PROCESSING_FAILED message received, exception when processing header: %1
 This is a debug message from the resolver noting that an exception
 occurred during the processing of a received packet.  The packet has
 been dropped.
@@ -97,7 +97,7 @@ During the update of the resolver's configuration parameters, the value
 of the lookup timeout was found to be too small.  The configuration
 update will not be applied.
 
-% RESOLVER_MESSAGE_ERROR error parsing received message: %1 - returning %2
+% RESOLVER_MESSAGE_PROCESSING_FAILED error parsing received message: %1 - returning %2
 This is a debug message noting that parsing of the body of a received
 message by the resolver failed due to some error (although the parsing of
 the header succeeded).  The message parameters give a textual description
@@ -135,18 +135,11 @@ A warning message issued during resolver startup, this indicates that
 no root addresses have been set.  This may be because the resolver will
 get them from a priming query.
 
-% RESOLVER_PARSE_ERROR error parsing received message: %1 - returning %2
-This is a debug message noting that the resolver received a message and
-the parsing of the body of the message failed due to some non-protocol
-related reason (although the parsing of the header succeeded).
-The message parameters give a textual description of the problem and
-the RCODE returned.
-
 % RESOLVER_PRINT_COMMAND print message command, arguments are: %1
 This debug message is logged when a "print_message" command is received
 by the resolver over the command channel.
 
-% RESOLVER_PROTOCOL_ERROR protocol error parsing received message: %1 - returning %2
+% RESOLVER_PROTOCOL_BODY_PARSE_FAILED protocol error parsing received message: %1 - returning %2
 This is a debug message noting that the resolver received a message and
 the parsing of the body of the message failed due to some protocol error
 (although the parsing of the header succeeded).  The message parameters
diff --git a/src/bin/sockcreator/b10-sockcreator.xml b/src/bin/sockcreator/b10-sockcreator.xml
index 6c51deb..ad9a71e 100644
--- a/src/bin/sockcreator/b10-sockcreator.xml
+++ b/src/bin/sockcreator/b10-sockcreator.xml
@@ -53,7 +53,7 @@
       The <command>b10-sockcreator</command> daemon's entire job
       is to create sockets and assign names to them.
       It is started by
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       and communicates with it.
       The new socket is sent over a file descriptor.
     </para>
@@ -71,6 +71,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
diff --git a/src/bin/sockcreator/tests/sockcreator_tests.cc b/src/bin/sockcreator/tests/sockcreator_tests.cc
index 9604567..b834e1c 100644
--- a/src/bin/sockcreator/tests/sockcreator_tests.cc
+++ b/src/bin/sockcreator/tests/sockcreator_tests.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 "../sockcreator.h"
 
 #include <util/unittests/fork.h>
@@ -195,7 +197,12 @@ TEST(get_sock, tcp4_create) {
     testAnyCreate<sockaddr_in>(SOCK_STREAM, tcpCheck);
 }
 
-TEST(get_sock, udp6_create) {
+#ifdef HAVE_BROKEN_GET_IPV6_USE_MIN_MTU
+TEST(get_sock, DISABLED_udp6_create)
+#else
+TEST(get_sock, udp6_create)
+#endif
+{
     testAnyCreate<sockaddr_in6>(SOCK_DGRAM, udpCheck<sockaddr_in6>);
 }
 
diff --git a/src/bin/stats/b10-stats-httpd.xml b/src/bin/stats/b10-stats-httpd.xml
index 28d6ac9..4510110 100644
--- a/src/bin/stats/b10-stats-httpd.xml
+++ b/src/bin/stats/b10-stats-httpd.xml
@@ -54,7 +54,7 @@
       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
+      by the b10-init process and eventually
       exited by it.  The server is intended to serve requests by HTTP
       clients like web browsers and third-party modules. When the server is
       asked, it requests BIND 10 statistics data or its schema from
@@ -74,7 +74,7 @@
       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
+      by <command>b10-init</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
@@ -151,7 +151,7 @@
 	    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>.
+	    through <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
 	  </para>
         </listitem>
       </varlistentry>
@@ -176,7 +176,7 @@
 	    exits the <command>b10-stats-httpd</command> process.
             This has an optional <varname>pid</varname> argument to
             select the process ID to stop.
-            (Note that the BIND 10 boss process may restart this service
+            (Note that the b10-init process may restart this service
             if configured.)
           </para>
         </listitem>
@@ -188,13 +188,16 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
-        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
-        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
diff --git a/src/bin/stats/b10-stats.xml b/src/bin/stats/b10-stats.xml
index ee89ad2..83fdd36 100644
--- a/src/bin/stats/b10-stats.xml
+++ b/src/bin/stats/b10-stats.xml
@@ -56,18 +56,18 @@
       from each BIND 10 module. Its statistics information may be
       reported via <command>bindctl</command> or
       <command>b10-stats-httpd</command>.  It is started by
-      <command>bind10</command> and communicates by using the
+      <command>b10-init</command> and communicates by using the
       Command Channel by <command>b10-msgq</command> with other
-      modules like <command>bind10</command>, <command>b10-auth</command>
+      modules like <command>b10-init</command>, <command>b10-auth</command>
       and so on. <command>b10-stats</command> periodically requests statistics
       data from each module. The interval time can be configured
       via <command>bindctl</command>. <command>b10-stats</command> cannot
       accept any command from other modules for updating statistics data. The
       stats module collects data and
       aggregates it. <command>b10-stats</command> invokes an internal
-      command for <command>bind10</command> after its initial
+      command for <command>b10-init</command> after its initial
       starting to make sure it collects statistics data from
-      <command>bind10</command>.
+      <command>b10-init</command>.
     </para>
   </refsect1>
 
@@ -131,7 +131,7 @@
       <command>b10-stats</command> process.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the b10-init process may restart this service
       if configured.)
     </para>
 
@@ -223,6 +223,9 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>b10-stats-httpd</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
@@ -231,9 +234,6 @@
       <citerefentry>
         <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
       </citerefentry>,
-      <citerefentry>
-        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
index 7123c53..577afe6 100755
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -26,7 +26,8 @@ from optparse import OptionParser, OptionValueError
 import errno
 import select
 
-import isc
+import isc.cc
+import isc.config
 import isc.util.process
 import isc.log
 from isc.log_messages.stats_messages import *
@@ -189,12 +190,19 @@ class Stats:
     """
     Main class of stats module
     """
-    def __init__(self):
+    def __init__(self, module_ccsession_class=isc.config.ModuleCCSession):
+        '''Constructor
+
+        module_ccsession_class is parameterized so that test can specify
+        a mocked class to test the behavior without involing network I/O.
+        In other cases this parameter shouldn't be specified.
+
+        '''
         self.running = False
         # create ModuleCCSession object
-        self.mccs = isc.config.ModuleCCSession(SPECFILE_LOCATION,
-                                               self.config_handler,
-                                               self.command_handler)
+        self.mccs = module_ccsession_class(SPECFILE_LOCATION,
+                                           self.config_handler,
+                                           self.command_handler)
         self.cc_session = self.mccs._session
         # get module spec
         self.module_name = self.mccs.get_module_spec().get_module_name()
@@ -224,7 +232,16 @@ class Stats:
                 ])
         # set a absolute timestamp polling at next time
         self.next_polltime = get_timestamp() + self.get_interval()
-        # initialized Statistics data
+
+        self._init_statistics_data()
+
+    def _init_statistics_data(self):
+        """initialized Statistics data.
+
+        This method is a dedicated subroutine of __int__(), but extracted
+        so tests can override it to avoid blocking network operation.
+
+        """
         self.update_modules()
         if self.update_statistics_data(
             self.module_name,
@@ -249,42 +266,46 @@ class Stats:
 
         # It counts the number of instances of same module by
         # examining the third value from the array result of
-        # 'show_processes' of Boss
-        seq = self.cc_session.group_sendmsg(
-            isc.config.ccsession.create_command("show_processes"),
-            'Boss')
-        (answer, env) = self.cc_session.group_recvmsg(False, seq)
+        # 'show_processes' of Init
+        try:
+            value = self.mccs.rpc_call('show_processes', 'Init')
+        except isc.config.RPCRecipientMissing:
+            # This has been SessionTimeout before, so we keep the original
+            # behavior.
+            raise
+        except isc.config.RPCError:
+            # TODO: Is it OK to just pass? As part of refactoring, preserving
+            # the original behaviour.
+            value = None
         modules = []
-        if answer:
-            (rcode, value) = isc.config.ccsession.parse_answer(answer)
-            if rcode == 0 and type(value) is list:
-                # NOTE: For example, the "show_processes" command
-                # of Boss is assumed to return the response in this
-                # format:
-                #  [
-                #  ...
-                #    [
-                #      20061,
-                #      "b10-auth",
-                #      "Auth"
-                #    ],
-                #    [
-                #      20103,
-                #      "b10-auth-2",
-                #      "Auth"
-                #    ]
-                #  ...
-                #  ]
-                # If multiple instances of the same module are
-                # running, the address names of them, which are at the
-                # third element, must be also same. Thus, the value of
-                # the third element of each outer element is read here
-                # for counting multiple instances.  This is a
-                # workaround for counting the instances. This should
-                # be fixed in another proper way in the future
-                # release.
-                modules = [ v[2] if type(v) is list and len(v) > 2 \
-                                else None for v in value ]
+        if type(value) is list:
+            # NOTE: For example, the "show_processes" command
+            # of Init is assumed to return the response in this
+            # format:
+            #  [
+            #  ...
+            #    [
+            #      20061,
+            #      "b10-auth",
+            #      "Auth"
+            #    ],
+            #    [
+            #      20103,
+            #      "b10-auth-2",
+            #      "Auth"
+            #    ]
+            #  ...
+            #  ]
+            # If multiple instances of the same module are
+            # running, the address names of them, which are at the
+            # third element, must be also same. Thus, the value of
+            # the third element of each outer element is read here
+            # for counting multiple instances.  This is a
+            # workaround for counting the instances. This should
+            # be fixed in another proper way in the future
+            # release.
+            modules = [ v[2] if type(v) is list and len(v) > 2 \
+                            else None for v in value ]
         # start requesting each module to collect statistics data
         sequences = []
         for (module_name, data) in self.get_statistics_data().items():
@@ -295,7 +316,12 @@ class Stats:
                          module_name)
             cmd = isc.config.ccsession.create_command(
                 "getstats", None) # no argument
-            seq = self.cc_session.group_sendmsg(cmd, module_name)
+            # Not using rpc_call here. We first send a bunch of commands, then
+            # collect all the answers. This eliminates some of the round-trip
+            # times. Unfortunately, rpc_call is not flexible enough to allow
+            # this, though the future rpc_call_async could.
+            seq = self.cc_session.group_sendmsg(cmd, module_name,
+                                                want_answer=True)
             sequences.append((module_name, seq))
             cnt = modules.count(module_name)
             if cnt > 1:
@@ -306,11 +332,9 @@ class Stats:
         while len(sequences) > 0:
             try:
                 (module_name, seq) = sequences.pop(0)
-                answer, env = self.cc_session.group_recvmsg(
-                    False, seq)
+                answer, env = self.cc_session.group_recvmsg(False, seq)
                 if answer:
-                    rcode, args = isc.config.ccsession.parse_answer(
-                        answer)
+                    rcode, args = isc.config.ccsession.parse_answer(answer)
                     if rcode == 0:
                         _statistics_data.append(
                             (module_name, env['from'], args))
@@ -337,31 +361,35 @@ class Stats:
         # if successfully done, set the last time of polling
         self._lasttime_poll = get_timestamp()
 
+    def _check_command(self, nonblock=False):
+        """check invoked command by waiting for 'poll-interval' seconds
+
+        This is a dedicated subroutine of start(), but extracted and defined
+        as a 'protected' method so that tests can replace it.
+
+        """
+        # backup original timeout
+        orig_timeout = self.cc_session.get_timeout()
+        # set cc-session timeout to half of a second(500ms)
+        self.cc_session.set_timeout(500)
+        try:
+            answer, env = self.cc_session.group_recvmsg(nonblock)
+            self.mccs.check_command_without_recvmsg(answer, env)
+        except isc.cc.session.SessionTimeout:
+            pass # waited for poll-interval seconds
+        # restore timeout
+        self.cc_session.set_timeout(orig_timeout)
+
     def start(self):
         """
         Start stats module
         """
         logger.info(STATS_STARTING)
 
-        def _check_command(nonblock=False):
-            """check invoked command by waiting for 'poll-interval'
-            seconds"""
-            # backup original timeout
-            orig_timeout = self.cc_session.get_timeout()
-            # set cc-session timeout to half of a second(500ms)
-            self.cc_session.set_timeout(500)
-            try:
-                answer, env = self.cc_session.group_recvmsg(nonblock)
-                self.mccs.check_command_without_recvmsg(answer, env)
-            except isc.cc.session.SessionTimeout:
-                pass # waited for poll-interval seconds
-            # restore timeout
-            self.cc_session.set_timeout(orig_timeout)
-
         try:
             self.running = True
             while self.running:
-                _check_command()
+                self._check_command()
                 now = get_timestamp()
                 intval = self.get_interval()
                 if intval > 0 and now >= self.next_polltime:
@@ -420,21 +448,17 @@ class Stats:
         raises StatsError.
         """
         modules = {}
-        seq = self.cc_session.group_sendmsg(
-            isc.config.ccsession.create_command(
-                isc.config.ccsession.COMMAND_GET_STATISTICS_SPEC),
-            'ConfigManager')
-        (answer, env) = self.cc_session.group_recvmsg(False, seq)
-        if answer:
-            (rcode, value) = isc.config.ccsession.parse_answer(answer)
-            if rcode == 0:
-                for mod in value:
-                    spec = { "module_name" : mod }
-                    if value[mod] and type(value[mod]) is list:
-                        spec["statistics"] = value[mod]
-                    modules[mod] = isc.config.module_spec.ModuleSpec(spec)
-            else:
-                raise StatsError("Updating module spec fails: " + str(value))
+        try:
+            value = self.mccs.rpc_call(isc.config.ccsession. \
+                                       COMMAND_GET_STATISTICS_SPEC,
+                                       'ConfigManager')
+        except isc.config.RPCError as e:
+            raise StatsError("Updating module spec fails: " + str(e))
+        for mod in value:
+            spec = { "module_name" : mod }
+            if value[mod] and type(value[mod]) is list:
+                spec["statistics"] = value[mod]
+            modules[mod] = isc.config.module_spec.ModuleSpec(spec)
         modules[self.module_name] = self.mccs.get_module_spec()
         self.modules = modules
 
@@ -470,16 +494,16 @@ class Stats:
         updates statistics data. If specified data is invalid for
         statistics spec of specified owner, it returns a list of error
         messages. If there is no error or if neither owner nor data is
-        specified in args, it returns None. The 'mid' argument is an identifier of
-        the sender module in order for stats to identify which
+        specified in args, it returns None. The 'mid' argument is an
+        identifier of the sender module in order for stats to identify which
         instance sends statistics data in the situation that multiple
         instances are working.
         """
         # Note:
         # The fix of #1751 is for multiple instances working. It is
         # assumed here that they send different statistics data with
-        # each sender module id (mid). Stats should save their statistics data by
-        # mid. The statistics data, which is the existing variable, is
+        # each sender module id (mid). Stats should save their statistics data
+        # by mid. The statistics data, which is the existing variable, is
         # preserved by accumlating from statistics data by the mid. This
         # is an ad-hoc fix because administrators can not see
         # statistics by each instance via bindctl or HTTP/XML. These
@@ -529,8 +553,7 @@ class Stats:
                             # merge recursively old value and new
                             # value each other
                             _data[owner][mid] = \
-                                merge_oldnew(_data[owner][mid],
-                                             {_key: _val})
+                                merge_oldnew(_data[owner][mid], {_key: _val})
                         continue
                     # the key string might be a "xx/yy/zz[0]"
                     # type. try it.
@@ -540,22 +563,20 @@ class Stats:
                         if errors: errors.pop()
                         # try updata and check validation in adavance
                         __data = _data.copy()
-                        if owner not in _data:
+                        if owner not in __data:
                             __data[owner] = {}
-                        if mid not in _data[owner]:
+                        if mid not in __data[owner]:
                             __data[owner][mid] = {}
                         # use the isc.cc.data.set method
                         try:
-                            isc.cc.data.set(__data[owner][mid],
-                                            _key, _val)
+                            isc.cc.data.set(__data[owner][mid], _key, _val)
                             if self.modules[owner].validate_statistics(
                                 False, __data[owner][mid], errors):
                                 _data = __data
                         except Exception as e:
-                            errors.append(
-                                "%s: %s" % (e.__class__.__name__, e))
+                            errors.append("%s: %s" % (e.__class__.__name__, e))
             except KeyError:
-                errors.append("unknown module name: " + str(owner))
+                errors.append("unknown module name: " + owner)
             if not errors:
                 self.statistics_data_bymid = _data
 
@@ -578,8 +599,7 @@ class Stats:
                     # values are not replaced.
                     self.statistics_data[m] = merge_oldnew(
                         self.statistics_data[m],
-                        _accum_bymodule(
-                            self.statistics_data_bymid[m]))
+                        _accum_bymodule(self.statistics_data_bymid[m]))
 
         if errors: return errors
 
@@ -696,3 +716,5 @@ if __name__ == "__main__":
         sys.exit(1)
     except KeyboardInterrupt as kie:
         logger.info(STATS_STOPPED_BY_KEYBOARD)
+
+    logger.info(STATS_EXITING)
diff --git a/src/bin/stats/stats.spec b/src/bin/stats/stats.spec
index 6fbf7bb..dab10a2 100644
--- a/src/bin/stats/stats.spec
+++ b/src/bin/stats/stats.spec
@@ -92,7 +92,7 @@
         "item_optional": false,
         "item_default": "1970-01-01T00:00:00Z",
         "item_title": "Last update time",
-        "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
+        "item_description": "The latest date time when the stats module receives from other modules like auth server or b10-init process and so on",
         "item_format": "date-time"
       },
       {
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
old mode 100644
new mode 100755
index 057b8ca..fd9ac93
--- a/src/bin/stats/stats_httpd.py.in
+++ b/src/bin/stats/stats_httpd.py.in
@@ -43,8 +43,8 @@ isc.log.init("b10-stats-httpd", buffer=True)
 logger = isc.log.Logger("stats-httpd")
 
 # Some constants for debug levels.
-DBG_STATHTTPD_INIT = logger.DBGLVL_START_SHUT
-DBG_STATHTTPD_MESSAGING = logger.DBGLVL_COMMAND
+DBG_STATSHTTPD_INIT = logger.DBGLVL_START_SHUT
+DBG_STATSHTTPD_MESSAGING = logger.DBGLVL_COMMAND
 
 # If B10_FROM_SOURCE is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
@@ -130,9 +130,9 @@ def item_name_list(element, identifier):
     return ret
 
 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()"""
+    """HTTP handler class for HttpServer class. The class inherits the super
+    class http.server.BaseHTTPRequestHandler. It implements do_GET()
+    and do_HEAD() and overrides log_message()"""
     def do_GET(self):
         body = self.send_head()
         if body is not None:
@@ -187,11 +187,11 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
             # Couldn't find neither specified module name nor
             # specified item name
             self.send_error(404)
-            logger.error(STATHTTPD_SERVER_DATAERROR, err)
+            logger.error(STATSHTTPD_SERVER_DATAERROR, err)
             return None
         except Exception as err:
             self.send_error(500)
-            logger.error(STATHTTPD_SERVER_ERROR, err)
+            logger.error(STATSHTTPD_SERVER_ERROR, err)
             return None
         else:
             self.send_response(200)
@@ -201,6 +201,14 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
             self.end_headers()
             return body
 
+    def log_message(self, format, *args):
+        """overrides the parent method log_message()
+        to use the bind10 logging framework.
+        """
+        logger.debug(DBG_STATSHTTPD_MESSAGING, STATSHTTPD_HTTPLOG,
+                     self.address_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."""
@@ -263,7 +271,7 @@ class StatsHttpd:
     def open_mccs(self):
         """Opens a ModuleCCSession object"""
         # create ModuleCCSession
-        logger.debug(DBG_STATHTTPD_INIT, STATHTTPD_STARTING_CC_SESSION)
+        logger.debug(DBG_STATSHTTPD_INIT, STATSHTTPD_STARTING_CC_SESSION)
         self.mccs = isc.config.ModuleCCSession(
             SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self.cc_session = self.mccs._session
@@ -274,7 +282,7 @@ class StatsHttpd:
             return
         self.mccs.send_stopping()
 
-        logger.debug(DBG_STATHTTPD_INIT, STATHTTPD_CLOSING_CC_SESSION)
+        logger.debug(DBG_STATSHTTPD_INIT, STATSHTTPD_CLOSING_CC_SESSION)
         self.mccs.close()
         self.mccs = None
 
@@ -317,7 +325,7 @@ class StatsHttpd:
                 server_address, HttpHandler,
                 self.xml_handler, self.xsd_handler, self.xsl_handler,
                 self.write_log)
-            logger.info(STATHTTPD_STARTED, server_address[0],
+            logger.info(STATSHTTPD_STARTED, server_address[0],
                         server_address[1])
             return httpd
         except (socket.gaierror, socket.error,
@@ -333,7 +341,7 @@ class StatsHttpd:
         """Closes sockets for HTTP"""
         while len(self.httpd)>0:
             ht = self.httpd.pop()
-            logger.info(STATHTTPD_CLOSING, ht.server_address[0],
+            logger.info(STATSHTTPD_CLOSING, ht.server_address[0],
                         ht.server_address[1])
             ht.server_close()
 
@@ -369,7 +377,7 @@ class StatsHttpd:
     def stop(self):
         """Stops the running StatsHttpd objects. Closes CC session and
         HTTP handling sockets"""
-        logger.info(STATHTTPD_SHUTDOWN)
+        logger.info(STATSHTTPD_SHUTDOWN)
         self.close_httpd()
         self.close_mccs()
         self.running = False
@@ -387,7 +395,7 @@ class StatsHttpd:
     def config_handler(self, new_config):
         """Config handler for the ModuleCCSession object. It resets
         addresses and ports to listen HTTP requests on."""
-        logger.debug(DBG_STATHTTPD_MESSAGING, STATHTTPD_HANDLE_CONFIG,
+        logger.debug(DBG_STATSHTTPD_MESSAGING, STATSHTTPD_HANDLE_CONFIG,
                    new_config)
         errors = []
         if not self.mccs.get_module_spec().\
@@ -405,7 +413,7 @@ class StatsHttpd:
         try:
             self.open_httpd()
         except HttpServerError as err:
-            logger.error(STATHTTPD_SERVER_ERROR, err)
+            logger.error(STATSHTTPD_SERVER_INIT_ERROR, err)
             # restore old config
             self.load_config(old_config)
             self.open_httpd()
@@ -417,18 +425,18 @@ class StatsHttpd:
         """Command handler for the ModuleCCSesson object. It handles
         "status" and "shutdown" commands."""
         if command == "status":
-            logger.debug(DBG_STATHTTPD_MESSAGING,
-                         STATHTTPD_RECEIVED_STATUS_COMMAND)
+            logger.debug(DBG_STATSHTTPD_MESSAGING,
+                         STATSHTTPD_RECEIVED_STATUS_COMMAND)
             return isc.config.ccsession.create_answer(
                 0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")")
         elif command == "shutdown":
-            logger.debug(DBG_STATHTTPD_MESSAGING,
-                         STATHTTPD_RECEIVED_SHUTDOWN_COMMAND)
+            logger.debug(DBG_STATSHTTPD_MESSAGING,
+                         STATSHTTPD_RECEIVED_SHUTDOWN_COMMAND)
             self.running = False
             return isc.config.ccsession.create_answer(0)
         else:
-            logger.debug(DBG_STATHTTPD_MESSAGING,
-                         STATHTTPD_RECEIVED_UNKNOWN_COMMAND, command)
+            logger.debug(DBG_STATSHTTPD_MESSAGING,
+                         STATSHTTPD_RECEIVED_UNKNOWN_COMMAND, command)
             return isc.config.ccsession.create_answer(
                 1, "Unknown command: " + str(command))
 
@@ -451,20 +459,14 @@ class StatsHttpd:
         if name is not None:
             param['name'] = name
         try:
-            seq = self.cc_session.group_sendmsg(
-                isc.config.ccsession.create_command('show', param), 'Stats')
-            (answer, env) = self.cc_session.group_recvmsg(False, seq)
-            if answer:
-                (rcode, value) = isc.config.ccsession.parse_answer(answer)
+            return self.mccs.rpc_call('show', 'Stats', params=param)
         except (isc.cc.session.SessionTimeout,
-                isc.cc.session.SessionError) as err:
+                isc.cc.session.SessionError,
+                isc.config.RPCRecipientMissing) as err:
             raise StatsHttpdError("%s: %s" %
                                   (err.__class__.__name__, err))
-        else:
-            if rcode == 0:
-                return value
-            else:
-                raise StatsHttpdDataError("Stats module: %s" % str(value))
+        except isc.config.RPCError as e:
+            raise StatsHttpdDataError("Stats module: %s" % str(e))
 
     def get_stats_spec(self, owner=None, name=None):
         """Requests statistics data to the Stats daemon and returns
@@ -485,15 +487,9 @@ class StatsHttpd:
         if name is not None:
             param['name'] = name
         try:
-            seq = self.cc_session.group_sendmsg(
-                isc.config.ccsession.create_command('showschema', param), 'Stats')
-            (answer, env) = self.cc_session.group_recvmsg(False, seq)
-            if answer:
-                (rcode, value) = isc.config.ccsession.parse_answer(answer)
-                if rcode == 0:
-                    return value
-                else:
-                    raise StatsHttpdDataError("Stats module: %s" % str(value))
+            return self.mccs.rpc_call('showschema', 'Stats', params=param)
+        except isc.config.RPCError as e:
+            raise StatsHttpdDataError("Stats module: %s" % str(e))
         except (isc.cc.session.SessionTimeout,
                 isc.cc.session.SessionError) as err:
             raise StatsHttpdError("%s: %s" %
@@ -613,13 +609,15 @@ if __name__ == "__main__":
         stats_httpd = StatsHttpd()
         stats_httpd.start()
     except OptionValueError as ove:
-        logger.fatal(STATHTTPD_BAD_OPTION_VALUE, ove)
+        logger.fatal(STATSHTTPD_BAD_OPTION_VALUE, ove)
         sys.exit(1)
     except isc.cc.session.SessionError as se:
-        logger.fatal(STATHTTPD_CC_SESSION_ERROR, se)
+        logger.fatal(STATSHTTPD_CC_SESSION_ERROR, se)
         sys.exit(1)
     except HttpServerError as hse:
-        logger.fatal(STATHTTPD_START_SERVER_INIT_ERROR, hse)
+        logger.fatal(STATSHTTPD_START_SERVER_INIT_ERROR, hse)
         sys.exit(1)
     except KeyboardInterrupt as kie:
-        logger.info(STATHTTPD_STOPPED_BY_KEYBOARD)
+        logger.info(STATSHTTPD_STOPPED_BY_KEYBOARD)
+
+    logger.info(STATSHTTPD_EXITING)
diff --git a/src/bin/stats/stats_httpd_messages.mes b/src/bin/stats/stats_httpd_messages.mes
index ad2e97f..93491b6 100644
--- a/src/bin/stats/stats_httpd_messages.mes
+++ b/src/bin/stats/stats_httpd_messages.mes
@@ -15,81 +15,90 @@
 # No namespace declaration - these constants go in the global namespace
 # of the stats_httpd_messages python module.
 
-% STATHTTPD_BAD_OPTION_VALUE bad command line argument: %1
+% STATSHTTPD_BAD_OPTION_VALUE bad command line argument: %1
 The stats-httpd module was called with a bad command-line argument
 and will not start.
 
-% STATHTTPD_CC_SESSION_ERROR error connecting to message bus: %1
+% STATSHTTPD_CC_SESSION_ERROR error connecting to message bus: %1
 The stats-httpd module was unable to connect to the BIND 10 command
 and control bus. A likely problem is that the message bus daemon
 (b10-msgq) is not running. The stats-httpd module will now shut down.
 
-% STATHTTPD_CLOSING closing %1#%2
+% STATSHTTPD_CLOSING closing %1#%2
 The stats-httpd daemon will stop listening for requests on the given
 address and port number.
 
-% STATHTTPD_CLOSING_CC_SESSION stopping cc session
+% STATSHTTPD_CLOSING_CC_SESSION stopping cc session
 Debug message indicating that the stats-httpd module is disconnecting
 from the command and control bus.
 
-% STATHTTPD_HANDLE_CONFIG reading configuration: %1
+% STATSHTTPD_EXITING exiting
+The stats HTTP server is exiting.
+
+% STATSHTTPD_HANDLE_CONFIG reading configuration: %1
 The stats-httpd daemon has received new configuration data and will now
 process it. The (changed) data is printed.
 
-% STATHTTPD_RECEIVED_SHUTDOWN_COMMAND shutdown command received
+% STATSHTTPD_HTTPLOG %1 %2
+Debug HTTP log message. These are the messages logged by the http server
+instance. For most logs, the message shows HTTP client and query
+information like HTTP method, URI, and status code, but the http server
+can also log other information, such as extended status reports.
+
+% STATSHTTPD_RECEIVED_SHUTDOWN_COMMAND shutdown command received
 A shutdown command was sent to the stats-httpd module, and it will
 now shut down.
 
-% STATHTTPD_RECEIVED_STATUS_COMMAND received command to return status
+% STATSHTTPD_RECEIVED_STATUS_COMMAND received command to return status
 A status command was sent to the stats-httpd module, and it will
 respond with 'Stats Httpd is up.' and its PID.
 
-% STATHTTPD_RECEIVED_UNKNOWN_COMMAND received unknown command: %1
+% STATSHTTPD_RECEIVED_UNKNOWN_COMMAND received unknown command: %1
 An unknown command has been sent to the stats-httpd module. The
 stats-httpd module will respond with an error, and the command will
 be ignored.
 
-% STATHTTPD_SERVER_DATAERROR HTTP server data error: %1
+% STATSHTTPD_SERVER_DATAERROR HTTP server data error: %1
 An internal error occurred while handling an HTTP request. An HTTP 404
 response will be sent back, and the specific error is printed. This
 is an error condition that likely points the specified data
 corresponding to the requested URI is incorrect.
 
-% STATHTTPD_SERVER_ERROR HTTP server error: %1
+% STATSHTTPD_SERVER_ERROR HTTP server error: %1
 An internal error occurred while handling an HTTP request. An HTTP 500
 response will be sent back, and the specific error is printed. This
 is an error condition that likely points to a module that is not
-responding correctly to statistic requests.
+responding correctly to statistics requests.
 
-% STATHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1
+% STATSHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1
 There was a problem initializing the HTTP server in the stats-httpd
 module upon receiving its configuration data. The most likely cause
 is a port binding problem or a bad configuration value. The specific
 error is printed in the message. The new configuration is ignored,
 and an error is sent back.
 
-% STATHTTPD_SHUTDOWN shutting down
+% STATSHTTPD_SHUTDOWN shutting down
 The stats-httpd daemon is shutting down.
 
-% STATHTTPD_STARTED listening on %1#%2
+% STATSHTTPD_STARTED listening on %1#%2
 The stats-httpd daemon will now start listening for requests on the
 given address and port number.
 
-% STATHTTPD_STARTING_CC_SESSION starting cc session
+% STATSHTTPD_STARTING_CC_SESSION starting cc session
 Debug message indicating that the stats-httpd module is connecting to
 the command and control bus.
 
-% STATHTTPD_START_SERVER_INIT_ERROR HTTP server initialization error: %1
+% STATSHTTPD_START_SERVER_INIT_ERROR HTTP server initialization error: %1
 There was a problem initializing the HTTP server in the stats-httpd
 module upon startup. The most likely cause is that it was not able
 to bind to the listening port. The specific error is printed, and the
 module will shut down.
 
-% STATHTTPD_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down
+% STATSHTTPD_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down
 There was a keyboard interrupt signal to stop the stats-httpd
 daemon. The daemon will now shut down.
 
-% STATHTTPD_UNKNOWN_CONFIG_ITEM unknown configuration item: %1
+% STATSHTTPD_UNKNOWN_CONFIG_ITEM unknown configuration item: %1
 The stats-httpd daemon received a configuration update from the
 configuration manager. However, one of the items in the
 configuration is unknown. The new configuration is ignored, and an
diff --git a/src/bin/stats/stats_messages.mes b/src/bin/stats/stats_messages.mes
index 3960c26..b6f0b16 100644
--- a/src/bin/stats/stats_messages.mes
+++ b/src/bin/stats/stats_messages.mes
@@ -24,6 +24,9 @@ The stats module was unable to connect to the BIND 10 command and
 control bus. A likely problem is that the message bus daemon
 (b10-msgq) is not running. The stats module will now shut down.
 
+% STATS_EXITING exiting
+The stats module process is exiting.
+
 % STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1
 Invalid statistics data has been received from the module while
 polling and it has been discarded.
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
index 997ac41..466e448 100644
--- a/src/bin/stats/tests/b10-stats-httpd_test.py
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -34,6 +34,7 @@ import http.client
 import xml.etree.ElementTree
 import random
 import urllib.parse
+import sys
 # load this module for xml validation with xsd. For this test, an
 # installation of lxml is required in advance. See http://lxml.de/.
 try:
@@ -42,11 +43,12 @@ except ImportError:
     lxml_etree = None
 
 import isc
+import isc.log
 import stats_httpd
 import stats
 from test_utils import BaseModules, ThreadingServerManager, MyStats,\
                        MyStatsHttpd, SignalHandler,\
-                       send_command, send_shutdown, CONST_BASETIME
+                       send_command, CONST_BASETIME
 from isc.testutils.ccsession_mock import MockModuleCCSession
 
 # This test suite uses xml.etree.ElementTree.XMLParser via
@@ -67,7 +69,7 @@ XMLNS_XSD = "http://www.w3.org/2001/XMLSchema"
 XMLNS_XSI = stats_httpd.XMLNS_XSI
 
 DUMMY_DATA = {
-    'Boss' : {
+    'Init' : {
         "boot_time": time.strftime('%Y-%m-%dT%H:%M:%SZ', CONST_BASETIME)
         },
     'Auth' : {
@@ -249,6 +251,7 @@ class TestHttpHandler(unittest.TestCase):
         # reset the signal handler
         self.sig_handler.reset()
 
+    @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
     @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
     def test_do_GET(self):
         self.assertTrue(type(self.stats_httpd.httpd) is list)
@@ -277,7 +280,7 @@ class TestHttpHandler(unittest.TestCase):
                              + stats_httpd.XSD_URL_PATH)
             # check the path of XSL
             self.assertTrue(xsl_doctype.startswith(
-                    '<?xml-stylesheet type="text/xsl" href="' + 
+                    '<?xml-stylesheet type="text/xsl" href="' +
                     stats_httpd.XSL_URL_PATH
                     + '"?>'))
             # check whether the list of 'identifier' attributes in
@@ -396,7 +399,7 @@ class TestHttpHandler(unittest.TestCase):
 
         # 404 NotFound (too long path)
         self.client._http_vsn_str = 'HTTP/1.0'
-        self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Boss/boot_time/a')
+        self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Init/boot_time/a')
         self.client.endheaders()
         response = self.client.getresponse()
         self.assertEqual(response.status, 404)
@@ -458,7 +461,8 @@ class TestHttpHandler(unittest.TestCase):
                          (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
         # failure case(Stats is down)
         self.assertTrue(self.stats.running)
-        self.assertEqual(send_shutdown("Stats"), (0, None)) # Stats is down
+        self.assertEqual(send_command("shutdown", "Stats"),
+                         (0, None)) # Stats is down
         self.assertFalse(self.stats.running)
         self.stats_httpd.cc_session.set_timeout(milliseconds=100)
 
@@ -605,8 +609,16 @@ class TestStatsHttpd(unittest.TestCase):
         self.stats_server.run()
         # checking IPv6 enabled on this platform
         self.ipv6_enabled = is_ipv6_enabled()
+        # instantiation of StatsHttpd indirectly calls gethostbyaddr(), which
+        # can block for an uncontrollable period, leading many undesirable
+        # results.  We should rather eliminate the reliance, but until we
+        # can make such fundamental cleanup we replace it with a faked method;
+        # in our test scenario the return value doesn't matter.
+        self.__gethostbyaddr_orig = socket.gethostbyaddr
+        socket.gethostbyaddr = lambda x: ('test.example.', [], None)
 
     def tearDown(self):
+        socket.gethostbyaddr = self.__gethostbyaddr_orig
         if hasattr(self, "stats_httpd"):
             self.stats_httpd.stop()
         self.stats_server.shutdown()
@@ -748,7 +760,7 @@ class TestStatsHttpd(unittest.TestCase):
         self.stats_httpd_server = ThreadingServerManager(MyStatsHttpd, server_addresses)
         self.stats_httpd_server.run()
         self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd, server_addresses)
-        send_shutdown("StatsHttpd")
+        send_command("shutdown", "StatsHttpd")
 
     def test_running(self):
         self.stats_httpd_server = ThreadingServerManager(MyStatsHttpd, get_availaddr())
@@ -758,7 +770,7 @@ class TestStatsHttpd(unittest.TestCase):
         self.assertEqual(send_command("status", "StatsHttpd"),
                          (0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
         self.assertTrue(self.stats_httpd.running)
-        self.assertEqual(send_shutdown("StatsHttpd"), (0, None))
+        self.assertEqual(send_command("shutdown", "StatsHttpd"), (0, None))
         self.assertFalse(self.stats_httpd.running)
         self.stats_httpd_server.shutdown()
 
@@ -1000,7 +1012,7 @@ class TestStatsHttpd(unittest.TestCase):
             self.assertFalse('item_format' in spec)
             self.assertFalse('format' in stats_xml[i].attrib)
 
-    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser") 
+    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
     def test_xsd_handler(self):
         self.stats_httpd = MyStatsHttpd(get_availaddr())
         xsd_string = self.stats_httpd.xsd_handler()
@@ -1035,7 +1047,7 @@ class TestStatsHttpd(unittest.TestCase):
                 self.assertEqual(attribs[i][1], stats_xsd[i].attrib['type'])
             self.assertEqual(attribs[i][2], stats_xsd[i].attrib['use'])
 
-    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser") 
+    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
     def test_xsl_handler(self):
         self.stats_httpd = MyStatsHttpd(get_availaddr())
         xsl_string = self.stats_httpd.xsl_handler()
@@ -1066,4 +1078,5 @@ class TestStatsHttpd(unittest.TestCase):
             imp.reload(stats_httpd)
 
 if __name__ == "__main__":
+    isc.log.resetUnitTestRootLogger()
     unittest.main()
diff --git a/src/bin/stats/tests/b10-stats_test.py b/src/bin/stats/tests/b10-stats_test.py
index 193f46c..7732902 100644
--- a/src/bin/stats/tests/b10-stats_test.py
+++ b/src/bin/stats/tests/b10-stats_test.py
@@ -27,10 +27,13 @@ import threading
 import io
 import time
 import imp
+import sys
 
 import stats
+import isc.log
 import isc.cc.session
-from test_utils import BaseModules, ThreadingServerManager, MyStats, SignalHandler, send_command, send_shutdown
+from test_utils import BaseModules, ThreadingServerManager, MyStats, \
+    SimpleStats, SignalHandler, MyModuleCCSession, send_command
 from isc.testutils.ccsession_mock import MockModuleCCSession
 
 class TestUtilties(unittest.TestCase):
@@ -245,11 +248,17 @@ class TestStats(unittest.TestCase):
         self.const_timestamp = 1308730448.965706
         self.const_datetime = '2011-06-22T08:14:08Z'
         self.const_default_datetime = '1970-01-01T00:00:00Z'
+        # Record original module-defined functions in case we replace them
+        self.__orig_timestamp = stats.get_timestamp
+        self.__orig_get_datetime = stats.get_datetime
 
     def tearDown(self):
         self.base.shutdown()
         # reset the signal handler
         self.sig_handler.reset()
+        # restore the stored original function in case we replaced them
+        stats.get_timestamp = self.__orig_timestamp
+        stats.get_datetime = self.__orig_get_datetime
 
     def test_init(self):
         self.stats = stats.Stats()
@@ -285,133 +294,212 @@ class TestStats(unittest.TestCase):
         self.assertRaises(stats.StatsError, stats.Stats)
         stats.SPECFILE_LOCATION = orig_spec_location
 
+    def __send_command(self, stats, command_name, params=None):
+        '''Emulate a command arriving to stats by directly calling callback'''
+        return isc.config.ccsession.parse_answer(
+            stats.command_handler(command_name, params))
+
     def test_start(self):
+        # Define a separate exception class so we can be sure that's actually
+        # the one raised in __check_start() below
+        class CheckException(Exception):
+            pass
+
+        def __check_start(tested_stats):
+            self.assertTrue(tested_stats.running)
+            raise CheckException # terminate the loop
+
         # start without err
-        self.stats_server = ThreadingServerManager(MyStats)
-        self.stats = self.stats_server.server
-        self.assertFalse(self.stats.running)
-        self.stats_server.run()
-        self.assertEqual(send_command("status", "Stats"),
-                (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
-        self.assertTrue(self.stats.running)
-        # Due to a race-condition related to the threads used in these
-        # tests, use of the mock session and the stopped check (see
-        # below), are temporarily disabled
-        # See ticket #1668
-        # Override moduleCCSession so we can check if send_stopping is called
-        #self.stats.mccs = MockModuleCCSession()
-        self.assertEqual(send_shutdown("Stats"), (0, None))
-        self.assertFalse(self.stats.running)
-        # Call server.shutdown with argument True so the thread.join() call
-        # blocks and we are sure the main loop has finished (and set
-        # mccs.stopped)
-        self.stats_server.shutdown(True)
-        # Also temporarily disabled for #1668, see above
-        #self.assertTrue(self.stats.mccs.stopped)
+        stats = SimpleStats()
+        self.assertFalse(stats.running)
+        stats._check_command = lambda: __check_start(stats)
+        # We are going to confirm start() will set running to True, avoiding
+        # to fall into a loop with the exception trick.
+        self.assertRaises(CheckException, stats.start)
+        self.assertEqual(self.__send_command(stats, "status"),
+                         (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
+
+    def test_shutdown(self):
+        def __check_shutdown(tested_stats):
+            self.assertTrue(tested_stats.running)
+            self.assertEqual(self.__send_command(tested_stats, "shutdown"),
+                             (0, None))
+            self.assertFalse(tested_stats.running)
+            # override get_interval() so it won't go poll statistics
+            tested_stats.get_interval = lambda : 0
+
+        stats = SimpleStats()
+        stats._check_command = lambda: __check_shutdown(stats)
+        stats.start()
+        self.assertTrue(stats.mccs.stopped)
 
     def test_handlers(self):
-        self.stats_server = ThreadingServerManager(MyStats)
-        self.stats = self.stats_server.server
-        self.stats_server.run()
+        """Test command_handler"""
 
-        # command_handler
+        __stats = SimpleStats()
+
+        # 'show' command.  We're going to check the expected methods are
+        # called in the expected order, and check the resulting response.
+        # Details of each method are tested separately.
+        call_log = []
+        def __steal_method(fn_name, *arg):
+            call_log.append((fn_name, arg))
+            if fn_name == 'update_stat':
+                return False        # "no error"
+            if fn_name == 'showschema':
+                return isc.config.create_answer(0, 'no error')
+
+        # Fake some methods and attributes for inspection
+        __stats.do_polling = lambda: __steal_method('polling')
+        __stats.update_statistics_data = \
+            lambda x, y, z: __steal_method('update_stat', x, y, z)
+        __stats.update_modules = lambda: __steal_method('update_module')
+        __stats.mccs.lname = 'test lname'
+        __stats.statistics_data = {'Init': {'boot_time': self.const_datetime}}
+
+        # skip initial polling
+        stats.get_timestamp = lambda: 0
+        __stats._lasttime_poll = 0
+
+        stats.get_datetime = lambda: 42 # make the result predictable
+
+        # now send the command
         self.assertEqual(
-            send_command(
-                'show', 'Stats',
-                params={ 'owner' : 'Boss',
-                  'name'  : 'boot_time' }),
-            (0, {'Boss': {'boot_time': self.const_datetime}}))
+            self.__send_command(
+                __stats, 'show',
+                params={ 'owner' : 'Init', 'name'  : 'boot_time' }),
+            (0, {'Init': {'boot_time': self.const_datetime}}))
+        # Check if expected methods are called
+        self.assertEqual([('update_stat',
+                           ('Stats', 'test lname',
+                            {'timestamp': 0,
+                             'report_time': 42})),
+                          ('update_module', ())], call_log)
+
+        # Then update faked timestamp so the intial polling will happen, and
+        # confirm that.
+        call_log = []
+        stats.get_timestamp = lambda: 10
         self.assertEqual(
-            send_command(
-                'show', 'Stats',
-                params={ 'owner' : 'Boss',
-                  'name'  : 'boot_time' }),
-            (0, {'Boss': {'boot_time': self.const_datetime}}))
+            self.__send_command(
+                __stats, 'show',
+                params={ 'owner' : 'Init', 'name'  : 'boot_time' }),
+            (0, {'Init': {'boot_time': self.const_datetime}}))
+        self.assertEqual([('polling', ()),
+                          ('update_stat',
+                           ('Stats', 'test lname',
+                            {'timestamp': 10,
+                             'report_time': 42})),
+                          ('update_module', ())], call_log)
+
+        # 'status' command.  We can confirm the behavior without any fake
         self.assertEqual(
-            send_command('status', 'Stats'),
+            self.__send_command(__stats, 'status'),
             (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
 
-        (rcode, value) = send_command('show', 'Stats')
-        self.assertEqual(rcode, 0)
-        self.assertEqual(len(value), 3)
-        self.assertTrue('Boss' in value)
-        self.assertTrue('Stats' in value)
-        self.assertTrue('Auth' in value)
-        self.assertEqual(len(value['Stats']), 5)
-        self.assertEqual(len(value['Boss']), 1)
-        self.assertTrue('boot_time' in value['Boss'])
-        self.assertEqual(value['Boss']['boot_time'], self.const_datetime)
-        self.assertTrue('report_time' in value['Stats'])
-        self.assertTrue('boot_time' in value['Stats'])
-        self.assertTrue('last_update_time' in value['Stats'])
-        self.assertTrue('timestamp' in value['Stats'])
-        self.assertTrue('lname' in value['Stats'])
-        (rcode, value) = send_command('showschema', 'Stats')
-        self.assertEqual(rcode, 0)
-        self.assertEqual(len(value), 3)
-        self.assertTrue('Boss' in value)
-        self.assertTrue('Stats' in value)
-        self.assertTrue('Auth' in value)
-        self.assertEqual(len(value['Stats']), 5)
-        self.assertEqual(len(value['Boss']), 1)
-        for item in value['Boss']:
-            self.assertTrue(len(item) == 7)
-            self.assertTrue('item_name' in item)
-            self.assertTrue('item_type' in item)
-            self.assertTrue('item_optional' in item)
-            self.assertTrue('item_default' in item)
-            self.assertTrue('item_title' in item)
-            self.assertTrue('item_description' in item)
-            self.assertTrue('item_format' in item)
-        for item in value['Stats']:
-            self.assertTrue(len(item) == 6 or len(item) == 7)
-            self.assertTrue('item_name' in item)
-            self.assertTrue('item_type' in item)
-            self.assertTrue('item_optional' in item)
-            self.assertTrue('item_default' in item)
-            self.assertTrue('item_title' in item)
-            self.assertTrue('item_description' in item)
-            if len(item) == 7:
-                self.assertTrue('item_format' in item)
+        # 'showschema' command.  update_modules() will be called, which
+        # (implicitly) cofirms the correct method is called; further details
+        # are tested seprately.
+        call_log = []
+        (rcode, value) = self.__send_command(__stats, 'showschema')
+        self.assertEqual([('update_module', ())], call_log)
 
+        # Unknown command.  Error should be returned
         self.assertEqual(
-            send_command('__UNKNOWN__', 'Stats'),
+            self.__send_command(__stats, '__UNKNOWN__'),
             (1, "Unknown command: '__UNKNOWN__'"))
 
-        self.stats_server.shutdown()
-
     def test_update_modules(self):
-        self.stats = stats.Stats()
-        self.assertEqual(len(self.stats.modules), 3) # Auth, Boss, Stats
+        """Confirm the behavior of Stats.update_modules().
+
+        It checks whether the expected command is sent to ConfigManager,
+        and whether the answer from ConfigManager is handled as expected.
+
+        """
+
+        def __check_rpc_call(command, group):
+            self.assertEqual('ConfigManager', group)
+            self.assertEqual(command,
+                             isc.config.ccsession.COMMAND_GET_STATISTICS_SPEC)
+            answer_value = {'Init': [{
+                        "item_name": "boot_time",
+                        "item_type": "string",
+                        "item_optional": False,
+                        # Use a different default so we can check it below
+                        "item_default": "2013-01-01T00:00:01Z",
+                        "item_title": "Boot time",
+                        "item_description": "dummy desc",
+                        "item_format": "date-time"
+                        }]}
+            return answer_value
+
+        self.stats = SimpleStats()
+        self.stats.cc_session.rpc_call = __check_rpc_call
+
         self.stats.update_modules()
+
+        # Stats is always incorporated.  For others, only the ones returned
+        # by group_recvmsg() above is available.
         self.assertTrue('Stats' in self.stats.modules)
-        self.assertTrue('Boss' in self.stats.modules)
+        self.assertTrue('Init' in self.stats.modules)
         self.assertFalse('Dummy' in self.stats.modules)
-        my_statistics_data = stats.get_spec_defaults(self.stats.modules['Stats'].get_statistics_spec())
+
+        my_statistics_data = stats.get_spec_defaults(
+            self.stats.modules['Stats'].get_statistics_spec())
         self.assertTrue('report_time' in my_statistics_data)
         self.assertTrue('boot_time' in my_statistics_data)
         self.assertTrue('last_update_time' in my_statistics_data)
         self.assertTrue('timestamp' in my_statistics_data)
         self.assertTrue('lname' in my_statistics_data)
-        self.assertEqual(my_statistics_data['report_time'], self.const_default_datetime)
-        self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
-        self.assertEqual(my_statistics_data['last_update_time'], self.const_default_datetime)
+        self.assertEqual(my_statistics_data['report_time'],
+                         self.const_default_datetime)
+        self.assertEqual(my_statistics_data['boot_time'],
+                         self.const_default_datetime)
+        self.assertEqual(my_statistics_data['last_update_time'],
+                         self.const_default_datetime)
         self.assertEqual(my_statistics_data['timestamp'], 0.0)
         self.assertEqual(my_statistics_data['lname'], "")
-        my_statistics_data = stats.get_spec_defaults(self.stats.modules['Boss'].get_statistics_spec())
+        my_statistics_data = stats.get_spec_defaults(
+            self.stats.modules['Init'].get_statistics_spec())
         self.assertTrue('boot_time' in my_statistics_data)
-        self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
+        self.assertEqual(my_statistics_data['boot_time'],
+                         "2013-01-01T00:00:01Z")
+
+        # Error case
+        def __raise_on_rpc_call(x, y):
+            raise isc.config.RPCError(99, 'error')
         orig_parse_answer = stats.isc.config.ccsession.parse_answer
-        stats.isc.config.ccsession.parse_answer = lambda x: (99, 'error')
+        self.stats.cc_session.rpc_call = __raise_on_rpc_call
         self.assertRaises(stats.StatsError, self.stats.update_modules)
-        stats.isc.config.ccsession.parse_answer = orig_parse_answer
 
     def test_get_statistics_data(self):
-        self.stats = stats.Stats()
+        """Confirm the behavior of Stats.get_statistics_data().
+
+        It should first call update_modules(), and then retrieve the requested
+        data from statistics_data.  We confirm this by fake update_modules()
+        where we set the expected data in statistics_data.
+
+        """
+        self.stats = SimpleStats()
+        def __faked_update_modules():
+            self.stats.statistics_data = { \
+                'Stats': {
+                    'report_time': self.const_default_datetime,
+                    'boot_time': None,
+                    'last_update_time': None,
+                    'timestamp': 0.0,
+                    'lname': 'dummy name'
+                    },
+                'Init': { 'boot_time': None }
+                }
+
+        self.stats.update_modules = __faked_update_modules
+
         my_statistics_data = self.stats.get_statistics_data()
         self.assertTrue('Stats' in my_statistics_data)
-        self.assertTrue('Boss' in my_statistics_data)
-        self.assertTrue('boot_time' in my_statistics_data['Boss'])
+        self.assertTrue('Init' in my_statistics_data)
+        self.assertTrue('boot_time' in my_statistics_data['Init'])
+
         my_statistics_data = self.stats.get_statistics_data(owner='Stats')
         self.assertTrue('Stats' in my_statistics_data)
         self.assertTrue('report_time' in my_statistics_data['Stats'])
@@ -419,16 +507,28 @@ class TestStats(unittest.TestCase):
         self.assertTrue('last_update_time' in my_statistics_data['Stats'])
         self.assertTrue('timestamp' in my_statistics_data['Stats'])
         self.assertTrue('lname' in my_statistics_data['Stats'])
-        self.assertRaises(stats.StatsError, self.stats.get_statistics_data, owner='Foo')
-        my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='report_time')
-        self.assertEqual(my_statistics_data['Stats']['report_time'], self.const_default_datetime)
-        my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='boot_time')
+        self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
+                          owner='Foo')
+
+        my_statistics_data = self.stats.get_statistics_data(
+            owner='Stats', name='report_time')
+        self.assertEqual(my_statistics_data['Stats']['report_time'],
+                         self.const_default_datetime)
+
+        my_statistics_data = self.stats.get_statistics_data(
+            owner='Stats', name='boot_time')
         self.assertTrue('boot_time' in my_statistics_data['Stats'])
-        my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='last_update_time')
+
+        my_statistics_data = self.stats.get_statistics_data(
+            owner='Stats', name='last_update_time')
         self.assertTrue('last_update_time' in my_statistics_data['Stats'])
-        my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='timestamp')
+
+        my_statistics_data = self.stats.get_statistics_data(
+            owner='Stats', name='timestamp')
         self.assertEqual(my_statistics_data['Stats']['timestamp'], 0.0)
-        my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='lname')
+
+        my_statistics_data = self.stats.get_statistics_data(
+            owner='Stats', name='lname')
         self.assertTrue(len(my_statistics_data['Stats']['lname']) >0)
         self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
                           owner='Stats', name='Bar')
@@ -439,7 +539,7 @@ class TestStats(unittest.TestCase):
 
     def test_update_statistics_data(self):
         """test for list-type statistics"""
-        self.stats = stats.Stats()
+        self.stats = SimpleStats()
         _test_exp1 = {
               'zonename': 'test1.example',
               'queries.tcp': 5,
@@ -516,42 +616,20 @@ class TestStats(unittest.TestCase):
 
     def test_update_statistics_data_pt2(self):
         """test for named_set-type statistics"""
-        self.stats = stats.Stats()
-        self.stats.do_polling()
-        _test_exp1 = {
-              'test10.example': {
-                  'queries.tcp': 5,
-                  'queries.udp': 4
-              }
-            }
-        _test_exp2 = {
-              'test20.example': {
-                  'queries.tcp': 3,
-                  'queries.udp': 2
-              }
-            }
+        self.stats = SimpleStats()
+        _test_exp1 = \
+            { 'test10.example': { 'queries.tcp': 5, 'queries.udp': 4 } }
+        _test_exp2 = \
+            { 'test20.example': { 'queries.tcp': 3, 'queries.udp': 2 } }
         _test_exp3 = {}
-        _test_exp4 = {
-              'test20.example': {
-                  'queries.udp': 4
-              }
-            }
-        _test_exp5_1 = {
-              'test10.example': {
-                 'queries.udp': 5432
-              }
-            }
+        _test_exp4 = { 'test20.example': { 'queries.udp': 4 } }
+        _test_exp5_1 = { 'test10.example': { 'queries.udp': 5432 } }
         _test_exp5_2 ={
               'nds_queries.perzone/test10.example/queries.udp':
-                  isc.cc.data.find(_test_exp5_1,
-                                   'test10.example/queries.udp')
-            }
-        _test_exp6 = {
-              'foo/bar':  'brabra'
-            }
-        _test_exp7 = {
-              'foo[100]': 'bar'
+                  isc.cc.data.find(_test_exp5_1, 'test10.example/queries.udp')
             }
+        _test_exp6 = { 'foo/bar':  'brabra' }
+        _test_exp7 = { 'foo[100]': 'bar' }
         # Success cases
         self.assertIsNone(self.stats.update_statistics_data(
             'Auth', 'foo1', {'nds_queries.perzone': _test_exp1}))
@@ -564,13 +642,15 @@ class TestStats(unittest.TestCase):
                              ['foo1']['nds_queries.perzone'],\
                          dict(_test_exp1,**_test_exp2))
         self.assertIsNone(self.stats.update_statistics_data(
-            'Auth', 'foo1', {'nds_queries.perzone': dict(_test_exp1,**_test_exp2)}))
+            'Auth', 'foo1', {'nds_queries.perzone':
+                                 dict(_test_exp1, **_test_exp2)}))
         self.assertEqual(self.stats.statistics_data_bymid['Auth']\
                              ['foo1']['nds_queries.perzone'],
-                         dict(_test_exp1,**_test_exp2))
+                         dict(_test_exp1, **_test_exp2))
         # differential update
         self.assertIsNone(self.stats.update_statistics_data(
-            'Auth', 'foo1', {'nds_queries.perzone': dict(_test_exp3,**_test_exp4)}))
+            'Auth', 'foo1', {'nds_queries.perzone':
+                                 dict(_test_exp3, **_test_exp4)}))
         _new_val = dict(_test_exp1,
                         **stats.merge_oldnew(_test_exp2,_test_exp4))
         self.assertEqual(self.stats.statistics_data_bymid['Auth']\
@@ -590,7 +670,8 @@ class TestStats(unittest.TestCase):
                              _test_exp5_1)
         # Error cases
         self.assertEqual(self.stats.update_statistics_data(
-                'Auth', 'foo1', {'nds_queries.perzone': None}), ['None should be a map'])
+                'Auth', 'foo1', {'nds_queries.perzone': None}),
+                         ['None should be a map'])
         self.assertEqual(self.stats.statistics_data_bymid['Auth']\
                              ['foo1']['nds_queries.perzone'],\
                              _new_val)
@@ -600,36 +681,61 @@ class TestStats(unittest.TestCase):
                              ['foo1']['nds_queries.perzone'],\
                              _new_val)
         self.assertEqual(self.stats.update_statistics_data(
-                'Boss', 'bar1', _test_exp7), ["KeyError: 'foo'"])
+                'Init', 'bar1', _test_exp7), ["KeyError: 'foo'"])
         self.assertEqual(self.stats.update_statistics_data(
                 'Foo', 'foo1', _test_exp6), ['unknown module name: Foo'])
 
     def test_update_statistics_data_withmid(self):
-        self.stats = stats.Stats()
+        self.stats = SimpleStats()
+
+        # This test relies on existing statistics data at the Stats object.
+        # This version of test prepares the data using the do_polling() method;
+        # that's a bad practice because a unittest for a method
+        # (update_statistics_data) would heavily depend on details of another
+        # method (do_polling).  However, there's currently no direct test
+        # for do_polling (which is also bad), so we still keep that approach,
+        # partly for testing do_polling indirectly.  #2781 should provide
+        # direct test for do_polling, with which this test scenario should
+        # also be changed to be more stand-alone.
+
+        # We use the knowledge of what kind of messages are sent via
+        # do_polling, and return the following faked answer directly.
+        create_answer = isc.config.ccsession.create_answer # shortcut
+        self.stats._answers = [\
+            # Answer for "show_processes"
+            (create_answer(0, [[1034, 'b10-auth-1', 'Auth'],
+                               [1035, 'b10-auth-2', 'Auth']]),  None),
+            # Answers for "getstats".  2 for Auth instances and 1 for Init.
+            # we return some bogus values for Init, but the rest of the test
+            # doesn't need it, so it's okay.
+            (create_answer(0, self.stats._auth_sdata), {'from': 'auth1'}),
+            (create_answer(0, self.stats._auth_sdata), {'from': 'auth2'}),
+            (create_answer(0, self.stats._auth_sdata), {'from': 'auth3'})
+            ]
+        # do_polling calls update_modules internally; in our scenario there's
+        # no change in modules, so we make it no-op.
+        self.stats.update_modules = lambda: None
+        # Now call do_polling.
         self.stats.do_polling()
+
         # samples of query number
         bar1_tcp = 1001
         bar2_tcp = 2001
         bar3_tcp = 1002
         bar3_udp = 1003
-        # two auth instances invoked
-        list_auth = [ self.base.auth.server,
-                      self.base.auth2.server ]
-        sum_qtcp = 0
-        for a in list_auth:
-            sum_qtcp += a.queries_tcp
-        sum_qudp = 0
-        for a in list_auth:
-            sum_qudp += a.queries_udp
+        # two auth instances invoked, so we double the pre-set stat values
+        sum_qtcp = self.stats._queries_tcp * 2
+        sum_qudp = self.stats._queries_udp * 2
         self.stats.update_statistics_data('Auth', "bar1 at foo",
-                                          {'queries.tcp':bar1_tcp})
+                                          {'queries.tcp': bar1_tcp})
         self.assertTrue('Auth' in self.stats.statistics_data)
         self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
         self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'],
                          bar1_tcp + sum_qtcp)
         self.assertTrue('Auth' in self.stats.statistics_data_bymid)
         self.assertTrue('bar1 at foo' in self.stats.statistics_data_bymid['Auth'])
-        self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar1 at foo'])
+        self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid
+                        ['Auth']['bar1 at foo'])
         self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar1 at foo'],
                          {'queries.tcp': bar1_tcp})
         # check consolidation of statistics data even if there is
@@ -655,10 +761,11 @@ class TestStats(unittest.TestCase):
         self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
         self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'],
                          bar1_tcp + bar2_tcp + sum_qtcp)
-        self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], sum_qudp)
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'],
+                         sum_qudp)
         self.assertTrue('Auth' in self.stats.statistics_data_bymid)
         # restore statistics data of killed auth
-        # self.base.boss.server.pid_list = [ killed ] + self.base.boss.server.pid_list[:]
+        # self.base.b10_init.server.pid_list = [ killed ] + self.base.b10_init.server.pid_list[:]
         self.stats.update_statistics_data('Auth',
                                           "bar1 at foo",
                                           {'queries.tcp': bar1_tcp})
@@ -687,8 +794,8 @@ class TestStats(unittest.TestCase):
     def test_config(self):
         orig_get_timestamp = stats.get_timestamp
         stats.get_timestamp = lambda : self.const_timestamp
-        stats_server = ThreadingServerManager(MyStats)
-        stat = stats_server.server
+        stat = SimpleStats()
+
         # test updating poll-interval
         self.assertEqual(stat.config['poll-interval'], 60)
         self.assertEqual(stat.get_interval(), 60)
@@ -712,14 +819,25 @@ class TestStats(unittest.TestCase):
         self.assertEqual(stat.config_handler({'poll-interval': 0}),
                          isc.config.create_answer(0))
         self.assertEqual(stat.config['poll-interval'], 0)
-        stats_server.run()
+
+        # see the comment for test_update_statistics_data_withmid.  We abuse
+        # do_polling here, too.  With #2781 we should make it more direct.
+        create_answer = isc.config.ccsession.create_answer # shortcut
+        stat._answers = [\
+            # Answer for "show_processes"
+            (create_answer(0, []),  None),
+            # Answers for "getstats" for Init (the other one for Auth, but
+            # that doesn't matter for this test)
+            (create_answer(0, stat._init_sdata), {'from': 'init'}),
+            (create_answer(0, stat._init_sdata), {'from': 'init'})
+            ]
+        stat.update_modules = lambda: None
+
         self.assertEqual(
-            send_command(
-                'show', 'Stats',
-                params={ 'owner' : 'Boss',
-                  'name'  : 'boot_time' }),
-            (0, {'Boss': {'boot_time': self.const_datetime}}))
-        stats_server.shutdown()
+            self.__send_command(
+                stat, 'show',
+                params={ 'owner' : 'Init', 'name'  : 'boot_time' }),
+            (0, {'Init': {'boot_time': self.const_datetime}}))
 
     def test_commands(self):
         self.stats = stats.Stats()
@@ -735,6 +853,7 @@ class TestStats(unittest.TestCase):
                          isc.config.create_answer(0))
         self.assertFalse(self.stats.running)
 
+    @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
     def test_command_show(self):
         # two auth instances invoked
         list_auth = [ self.base.auth.server,
@@ -832,7 +951,7 @@ class TestStats(unittest.TestCase):
         self.assertEqual(rcode, 0)
         self.assertEqual(len(value), 3)
         self.assertTrue('Stats' in value)
-        self.assertTrue('Boss' in value)
+        self.assertTrue('Init' in value)
         self.assertTrue('Auth' in value)
         self.assertFalse('__Dummy__' in value)
         schema = value['Stats']
@@ -848,7 +967,7 @@ class TestStats(unittest.TestCase):
             if len(item) == 7:
                 self.assertTrue('item_format' in item)
 
-        schema = value['Boss']
+        schema = value['Init']
         self.assertEqual(len(schema), 1)
         for item in schema:
             self.assertTrue(len(item) == 7)
@@ -878,7 +997,7 @@ class TestStats(unittest.TestCase):
             self.stats.command_showschema(owner='Stats'))
         self.assertEqual(rcode, 0)
         self.assertTrue('Stats' in value)
-        self.assertFalse('Boss' in value)
+        self.assertFalse('Init' in value)
         self.assertFalse('Auth' in value)
         for item in value['Stats']:
             self.assertTrue(len(item) == 6 or len(item) == 7)
@@ -895,7 +1014,7 @@ class TestStats(unittest.TestCase):
             self.stats.command_showschema(owner='Stats', name='report_time'))
         self.assertEqual(rcode, 0)
         self.assertTrue('Stats' in value)
-        self.assertFalse('Boss' in value)
+        self.assertFalse('Init' in value)
         self.assertFalse('Auth' in value)
         self.assertEqual(len(value['Stats'][0]), 7)
         self.assertTrue('item_name' in value['Stats'][0])
@@ -1142,6 +1261,7 @@ class TestStats(unittest.TestCase):
                          isc.config.create_answer(
                 1, "module name is not specified"))
 
+    @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
     def test_polling(self):
         stats_server = ThreadingServerManager(MyStats)
         stat = stats_server.server
@@ -1149,15 +1269,15 @@ class TestStats(unittest.TestCase):
         self.assertEqual(
             send_command('show', 'Stats'),
             (0, stat.statistics_data))
-        # check statistics data of 'Boss'
-        boss = self.base.boss.server
+        # check statistics data of 'Init'
+        b10_init = self.base.b10_init.server
         self.assertEqual(
-            stat.statistics_data_bymid['Boss'][boss.cc_session.lname],
+            stat.statistics_data_bymid['Init'][b10_init.cc_session.lname],
             {'boot_time': self.const_datetime})
         self.assertEqual(
-            len(stat.statistics_data_bymid['Boss']), 1)
+            len(stat.statistics_data_bymid['Init']), 1)
         self.assertEqual(
-            stat.statistics_data['Boss'],
+            stat.statistics_data['Init'],
             {'boot_time': self.const_datetime})
         # check statistics data of each 'Auth' instances
         list_auth = ['', '2']
@@ -1218,17 +1338,17 @@ class TestStats(unittest.TestCase):
 
     def test_polling2(self):
         # set invalid statistics
-        boss = self.base.boss.server
-        boss.statistics_data = {'boot_time':1}
+        b10_init = self.base.b10_init.server
+        b10_init.statistics_data = {'boot_time':1}
         stats_server = ThreadingServerManager(MyStats)
         stat = stats_server.server
         stats_server.run()
         self.assertEqual(
             send_command('status', 'Stats'),
             (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
-        # check default statistics data of 'Boss'
+        # check default statistics data of 'Init'
         self.assertEqual(
-            stat.statistics_data['Boss'],
+            stat.statistics_data['Init'],
             {'boot_time': self.const_default_datetime})
         stats_server.shutdown()
 
@@ -1254,8 +1374,6 @@ class TestOSEnv(unittest.TestCase):
         os.environ["B10_FROM_SOURCE"] = path
         imp.reload(stats)
 
-def test_main():
-    unittest.main()
-
 if __name__ == "__main__":
-    test_main()
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()
diff --git a/src/bin/stats/tests/test_utils.py b/src/bin/stats/tests/test_utils.py
index 96f7046..bfabc13 100644
--- a/src/bin/stats/tests/test_utils.py
+++ b/src/bin/stats/tests/test_utils.py
@@ -51,30 +51,18 @@ class SignalHandler():
         """envokes unittest.TestCase.fail as a signal handler"""
         self.fail_handler("A deadlock might be detected")
 
-def send_command(command_name, module_name, params=None, session=None, nonblock=False, timeout=None):
-    if session is not None:
-        cc_session = session
-    else:
-        cc_session = isc.cc.Session()
-    if timeout is not None:
-        orig_timeout = cc_session.get_timeout()
-        cc_session.set_timeout(timeout * 1000)
+def send_command(command_name, module_name, params=None):
+    cc_session = isc.cc.Session()
     command = isc.config.ccsession.create_command(command_name, params)
     seq = cc_session.group_sendmsg(command, module_name)
     try:
-        (answer, env) = cc_session.group_recvmsg(nonblock, seq)
+        (answer, env) = cc_session.group_recvmsg(False, seq)
         if answer:
             return isc.config.ccsession.parse_answer(answer)
     except isc.cc.SessionTimeout:
         pass
     finally:
-        if timeout is not None:
-            cc_session.set_timeout(orig_timeout)
-        if session is None:
-            cc_session.close()
-
-def send_shutdown(module_name, **kwargs):
-    return send_command("shutdown", module_name, **kwargs)
+        cc_session.close()
 
 class ThreadingServerManager:
     def __init__(self, server, *args, **kwargs):
@@ -103,20 +91,9 @@ class ThreadingServerManager:
         else:
             self.server._thread.join(0) # timeout is 0
 
-def do_nothing(*args, **kwargs): pass
-
-class dummy_sys:
-    """Dummy for sys"""
-    class dummy_io:
-        write = do_nothing
-    stdout = stderr = dummy_io()
-
 class MockMsgq:
     def __init__(self):
         self._started = threading.Event()
-        # suppress output to stdout and stderr
-        msgq.sys = dummy_sys()
-        msgq.print = do_nothing
         self.msgq = msgq.MsgQ(verbose=False)
         result = self.msgq.setup()
         if result:
@@ -124,10 +101,15 @@ class MockMsgq:
 
     def run(self):
         self._started.set()
-        self.msgq.run()
+        try:
+            self.msgq.run()
+        finally:
+            # Make sure all the sockets, etc, are removed once it stops.
+            self.msgq.shutdown()
 
     def shutdown(self):
-        self.msgq.shutdown()
+        # Ask it to terminate nicely
+        self.msgq.stop()
 
 class MockCfgmgr:
     def __init__(self):
@@ -146,11 +128,11 @@ class MockCfgmgr:
     def shutdown(self):
         self.cfgmgr.running = False
 
-class MockBoss:
+class MockInit:
     spec_str = """\
 {
   "module_spec": {
-    "module_name": "Boss",
+    "module_name": "Init",
     "module_description": "Mock Master process",
     "config_data": [
       {
@@ -216,7 +198,7 @@ class MockBoss:
       },
       {
         "command_name": "ping",
-        "command_description": "Ping the boss process",
+        "command_description": "Ping the b10-init process",
         "command_args": []
       },
       {
@@ -473,6 +455,140 @@ class MockAuth:
             return isc.config.create_answer(0, sdata)
         return isc.config.create_answer(1, "Unknown Command")
 
+class MyModuleCCSession(isc.config.ConfigData):
+    """Mocked ModuleCCSession class.
+
+    This class incorporates the module spec directly from the file,
+    and works as if the ModuleCCSession class as much as possible
+    without involving network I/O.
+
+    """
+    def __init__(self, spec_file, config_handler, command_handler):
+        module_spec = isc.config.module_spec_from_file(spec_file)
+        isc.config.ConfigData.__init__(self, module_spec)
+        self._session = self
+        self.stopped = False
+        self.lname = 'mock_mod_ccs'
+
+    def start(self):
+        pass
+
+    def send_stopping(self):
+        self.stopped = True     # just record it's called to inspect it later
+
+class SimpleStats(stats.Stats):
+    """A faked Stats class for unit tests.
+
+    This class inherits most of the real Stats class, but replace the
+    ModuleCCSession with a fake one so we can avoid network I/O in tests,
+    and can also inspect or tweak messages via the session more easily.
+    This class also maintains some faked module information and statistics
+    data that can be retrieved from the implementation of the Stats class.
+
+    """
+    def __init__(self):
+        # First, setup some internal attributes.  All of them are essentially
+        # private (so prefixed with double '_'), but some are defined as if
+        # "protected" (with a single '_') for the convenient of tests that
+        # may want to inspect or tweak them.
+
+        # initial seq num for faked group_sendmsg, arbitrary choice.
+        self.__seq = 4200
+        # if set, use them as faked response to group_recvmsg (see below).
+        # it's a list of tuples, each of which is of (answer, envelope).
+        self._answers = []
+        # the default answer from faked recvmsg if _answers is empty
+        self.__default_answer = isc.config.ccsession.create_answer(
+            0, {'Init':
+                    json.loads(MockInit.spec_str)['module_spec']['statistics'],
+                'Auth':
+                    json.loads(MockAuth.spec_str)['module_spec']['statistics']
+                })
+        # setup faked auth statistics
+        self.__init_auth_stat()
+        # statistics data for faked Init module
+        self._init_sdata = {
+            'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', CONST_BASETIME)
+            }
+
+        # Incorporate other setups of the real Stats module.  We use the faked
+        # ModuleCCSession to avoid blocking network operation.  Note also that
+        # we replace _init_statistics_data() (see below), so we don't
+        # initialize statistics data yet.
+        stats.Stats.__init__(self, MyModuleCCSession)
+
+        # replace some (faked) ModuleCCSession methods so we can inspect/fake
+        # the data exchanged via the CC session, then call
+        # _init_statistics_data.  This will get the Stats module info from
+        # the file directly and some amount information about the Init and
+        # Auth modules (hardcoded below).
+        self.cc_session.group_sendmsg = self.__group_sendmsg
+        self.cc_session.group_recvmsg = self.__group_recvmsg
+        self.cc_session.rpc_call = self.__rpc_call
+        stats.Stats._init_statistics_data(self)
+
+    def __init_auth_stat(self):
+        self._queries_tcp = 3
+        self._queries_udp = 2
+        self.__queries_per_zone = [{
+                'zonename': 'test1.example', 'queries.tcp': 5, 'queries.udp': 4
+                }]
+        self.__nds_queries_per_zone = \
+            { 'test10.example': { 'queries.tcp': 5, 'queries.udp': 4 } }
+        self._auth_sdata = \
+            { 'queries.tcp': self._queries_tcp,
+              'queries.udp': self._queries_udp,
+              'queries.perzone' : self.__queries_per_zone,
+              'nds_queries.perzone' : {
+                'test10.example': {
+                    'queries.tcp': isc.cc.data.find(
+                        self.__nds_queries_per_zone,
+                        'test10.example/queries.tcp')
+                    }
+                },
+              'nds_queries.perzone/test10.example/queries.udp' :
+                  isc.cc.data.find(self.__nds_queries_per_zone,
+                                   'test10.example/queries.udp')
+              }
+
+    def _init_statistics_data(self):
+        # Inherited from real Stats class, just for deferring the
+        # initialization until we are ready.
+        pass
+
+    def __group_sendmsg(self, command, destination, want_answer=False):
+        """Faked ModuleCCSession.group_sendmsg for tests.
+
+        Skipping actual network communication, and just returning an internally
+        generated sequence number.
+
+        """
+        self.__seq += 1
+        return self.__seq
+
+    def __group_recvmsg(self, nonblocking, seq):
+        """Faked ModuleCCSession.group_recvmsg for tests.
+
+        Skipping actual network communication, and returning an internally
+        prepared answer. sequence number.  If faked anser is given in
+        _answers, use it; otherwise use the default.  we don't actually check
+        the sequence.
+
+        """
+        if len(self._answers) == 0:
+            return self.__default_answer, {'from': 'no-matter'}
+        return self._answers.pop(0)
+
+    def __rpc_call(self, command, group):
+        """Faked ModuleCCSession.rpc_call for tests.
+
+        At the moment we don't have to cover failure cases, so this is a
+        simple wrapper for the faked group_recvmsg().
+
+        """
+        answer, _ = self.__group_recvmsg(None, None)
+        return isc.config.ccsession.parse_answer(answer)[1]
+
 class MyStats(stats.Stats):
 
     stats._BASETIME = CONST_BASETIME
@@ -543,9 +659,9 @@ class BaseModules:
         # MockCfgmgr
         self.cfgmgr = ThreadingServerManager(MockCfgmgr)
         self.cfgmgr.run()
-        # MockBoss
-        self.boss = ThreadingServerManager(MockBoss)
-        self.boss.run()
+        # MockInit
+        self.b10_init = ThreadingServerManager(MockInit)
+        self.b10_init.run()
         # MockAuth
         self.auth = ThreadingServerManager(MockAuth)
         self.auth.run()
@@ -554,15 +670,20 @@ class BaseModules:
 
 
     def shutdown(self):
+        # MockMsgq. We need to wait (blocking) for it, otherwise it'll wipe out
+        # a socket for another test during its shutdown.
+        self.msgq.shutdown(True)
+
+        # We also wait for the others, but these are just so we don't create
+        # too many threads in parallel.
+
         # MockAuth
-        self.auth2.shutdown()
-        self.auth.shutdown()
-        # MockBoss
-        self.boss.shutdown()
+        self.auth2.shutdown(True)
+        self.auth.shutdown(True)
+        # MockInit
+        self.b10_init.shutdown(True)
         # MockCfgmgr
-        self.cfgmgr.shutdown()
-        # MockMsgq
-        self.msgq.shutdown()
+        self.cfgmgr.shutdown(True)
         # remove the unused socket file
         socket_file = self.msgq.server.msgq.socket_file
         try:
diff --git a/src/bin/stats/tests/testdata/b10-config.db b/src/bin/stats/tests/testdata/b10-config.db
index 2f89b98..7dd9daf 100644
--- a/src/bin/stats/tests/testdata/b10-config.db
+++ b/src/bin/stats/tests/testdata/b10-config.db
@@ -1,5 +1,5 @@
 { "version": 2,
-  "Boss": {
+  "Init": {
     "components": {
       "b10-auth": {
         "kind": "needed",
diff --git a/src/bin/sysinfo/run_sysinfo.sh.in b/src/bin/sysinfo/run_sysinfo.sh.in
index 268b5a4..b5593b9 100755
--- a/src/bin/sysinfo/run_sysinfo.sh.in
+++ b/src/bin/sysinfo/run_sysinfo.sh.in
@@ -20,19 +20,8 @@ export PYTHON_EXEC
 
 SYSINFO_PATH=@abs_top_builddir@/src/bin/sysinfo
 
-# Note: we shouldn't need log_messages except for the seemingly necessary
-# dependency due to the automatic import in the isc package (its __init__.py
-# imports some other modules)
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python/isc/log_messages
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python
 export PYTHONPATH
 
-# Likewise, we need only because isc.log requires some loadable modules.
-# sysinfo itself shouldn't need any of them.
-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/dns/python/.libs:@abs_top_builddir@/src/lib/cryptolink/.libs:@abs_top_builddir@/src/lib/cc/.libs:@abs_top_builddir@/src/lib/config/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/acl/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:@abs_top_builddir@/src/lib/datasrc/.libs:$@ENV_LIBRARY_PATH@
-	export @ENV_LIBRARY_PATH@
-fi
-
 cd ${SYSINFO_PATH}
 exec ${PYTHON_EXEC} -O sysinfo.py "$@"
diff --git a/src/bin/tests/process_rename_test.py.in b/src/bin/tests/process_rename_test.py.in
index 055ebdc..ea8ad87 100644
--- a/src/bin/tests/process_rename_test.py.in
+++ b/src/bin/tests/process_rename_test.py.in
@@ -42,7 +42,7 @@ class TestRename(unittest.TestCase):
 
         # Scripts named in this list are not expected to be renamed and
         # should be excluded from the scan.
-        EXCLUDED_SCRIPTS = ['isc-sysinfo']
+        EXCLUDED_SCRIPTS = ['isc-sysinfo', 'bind10']
 
         # Regexp to find all the *_SCRIPTS = something lines (except for
         # noinst_SCRIPTS, which are scripts for tests), including line
diff --git a/src/bin/xfrin/b10-xfrin.xml b/src/bin/xfrin/b10-xfrin.xml
index eb16ab3..588048a 100644
--- a/src/bin/xfrin/b10-xfrin.xml
+++ b/src/bin/xfrin/b10-xfrin.xml
@@ -56,8 +56,8 @@
     <para>The <command>b10-xfrin</command> daemon provides the BIND 10
       incoming DNS zone transfer service.
       Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
       When triggered it can request and receive a zone transfer and store
       the zone in a BIND 10 zone data source.
     </para>
@@ -180,8 +180,8 @@ in separate zonemgr process.
 
     <para>
       <command>shutdown</command> stops all incoming zone transfers
-      and exits <command>b10-xfrin</command>. (Note that the BIND 10
-      boss process will restart this service.)
+      and exits <command>b10-xfrin</command>. (Note that the
+      b10-init process will restart this service.)
     </para>
 <!-- TODO:
 add a usage example of xfrin -->
@@ -246,6 +246,9 @@ operation
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 99c5e1e..272124b 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -40,7 +40,7 @@ import sqlite3
 #
 TEST_ZONE_NAME_STR = "example.com."
 TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
 TEST_RRCLASS_STR = 'IN'
 TEST_DB_FILE = 'db_file'
 TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
@@ -59,21 +59,21 @@ TEST_MASTER_PORT = '53535'
 TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
 
 # SOA intended to be used for the new SOA as a result of transfer.
-soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
                   'master.example.com. admin.example.com. ' +
                   '1234 3600 1800 2419200 7200')
-soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
+soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA, RRTTL(3600))
 soa_rrset.add_rdata(soa_rdata)
 
 # SOA intended to be used for the current SOA at the secondary side.
 # Note that its serial is smaller than that of soa_rdata.
-begin_soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+begin_soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
                         'master.example.com. admin.example.com. ' +
                         '1230 3600 1800 2419200 7200')
-begin_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
+begin_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA, RRTTL(3600))
 begin_soa_rrset.add_rdata(begin_soa_rdata)
-example_axfr_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR())
-example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA())
+example_axfr_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)
+example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA)
 default_questions = [example_axfr_question]
 default_answers = [soa_rrset]
 
@@ -153,13 +153,19 @@ class MockCC(MockModuleCCSession):
     def remove_remote_config(self, module_name):
         pass
 
+class MockRRsetCollection:
+    '''
+    A mock RRset collection. We don't use it really (we mock the method that
+    it is passed to too), so it's empty.
+    '''
+    pass
+
 class MockDataSourceClient():
     '''A simple mock data source client.
 
     This class provides a minimal set of wrappers related the data source
     API that would be used by Diff objects.  For our testing purposes they
-    only keep truck of the history of the changes.
-
+    only keep track of the history of the changes.
     '''
     def __init__(self):
         self.force_fail = False # if True, raise an exception on commit
@@ -202,12 +208,12 @@ class MockDataSourceClient():
         zone names.
 
         '''
-        if name == TEST_ZONE_NAME and rrtype == RRType.SOA():
+        if name == TEST_ZONE_NAME and rrtype == RRType.SOA:
             return (ZoneFinder.SUCCESS, begin_soa_rrset, 0)
         if name == Name('no-soa.example'):
             return (ZoneFinder.NXDOMAIN, None, 0)
         if name == Name('dup-soa.example'):
-            dup_soa_rrset = RRset(name, TEST_RRCLASS, RRType.SOA(), RRTTL(0))
+            dup_soa_rrset = RRset(name, TEST_RRCLASS, RRType.SOA, RRTTL(0))
             dup_soa_rrset.add_rdata(begin_soa_rdata)
             dup_soa_rrset.add_rdata(soa_rdata)
             return (ZoneFinder.SUCCESS, dup_soa_rrset, 0)
@@ -217,6 +223,12 @@ class MockDataSourceClient():
         self._journaling_enabled = journaling
         return self
 
+    def get_rrset_collection(self):
+        '''
+        Pretend to be a zone updater and provide a (dummy) rrset collection.
+        '''
+        return MockRRsetCollection()
+
     def add_rrset(self, rrset):
         self.diffs.append(('add', rrset))
 
@@ -317,7 +329,7 @@ class MockXfrinConnection(XfrinConnection):
         return len(data)
 
     def create_response_data(self, response=True, auth=True, bad_qid=False,
-                             rcode=Rcode.NOERROR(),
+                             rcode=Rcode.NOERROR,
                              questions=default_questions,
                              answers=default_answers,
                              authorities=[],
@@ -327,7 +339,7 @@ class MockXfrinConnection(XfrinConnection):
         if bad_qid:
             qid += 1
         resp.set_qid(qid)
-        resp.set_opcode(Opcode.QUERY())
+        resp.set_opcode(Opcode.QUERY)
         resp.set_rcode(rcode)
         if response:
             resp.set_header_flag(Message.HEADERFLAG_QR)
@@ -354,17 +366,17 @@ class TestXfrinState(unittest.TestCase):
                                         TEST_RRCLASS, None, threading.Event(),
                                         TEST_MASTER_IPV4_ADDRINFO)
         self.conn.init_socket()
-        self.begin_soa = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+        self.begin_soa = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
                                RRTTL(3600))
-        self.begin_soa.add_rdata(Rdata(RRType.SOA(), TEST_RRCLASS,
+        self.begin_soa.add_rdata(Rdata(RRType.SOA, TEST_RRCLASS,
                                        'm. r. 1230 0 0 0 0'))
-        self.ns_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(),
+        self.ns_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS,
                               RRTTL(3600))
-        self.ns_rrset.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS,
-                                      'ns.example.com'))
-        self.a_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.A(),
+        self.ns_rrset.add_rdata(Rdata(RRType.NS, TEST_RRCLASS,
+                                      'ns.example.com.'))
+        self.a_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.A,
                              RRTTL(3600))
-        self.a_rrset.add_rdata(Rdata(RRType.A(), TEST_RRCLASS, '192.0.2.1'))
+        self.a_rrset.add_rdata(Rdata(RRType.A, TEST_RRCLASS, '192.0.2.1'))
 
         self.conn._datasrc_client = MockDataSourceClient()
         self.conn._diff = Diff(self.conn._datasrc_client, TEST_ZONE_NAME)
@@ -396,14 +408,14 @@ class TestXfrinInitialSOA(TestXfrinState):
                           self.ns_rrset)
 
     def test_handle_ixfr_uptodate(self):
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         self.conn._request_serial = isc.dns.Serial(1234) # same as soa_rrset
         self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual(type(XfrinIXFRUptodate()),
                          type(self.conn.get_xfrstate()))
 
     def test_handle_ixfr_uptodate2(self):
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         self.conn._request_serial = isc.dns.Serial(1235) # > soa_rrset
         self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual(type(XfrinIXFRUptodate()),
@@ -412,7 +424,7 @@ class TestXfrinInitialSOA(TestXfrinState):
     def test_handle_ixfr_uptodate3(self):
         # Similar to the previous case, but checking serial number arithmetic
         # comparison
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         self.conn._request_serial = isc.dns.Serial(0xffffffff)
         self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual(type(XfrinFirstData()),
@@ -420,7 +432,7 @@ class TestXfrinInitialSOA(TestXfrinState):
 
     def test_handle_axfr_uptodate(self):
         # "request serial" should matter only for IXFR
-        self.conn._request_type = RRType.AXFR()
+        self.conn._request_type = RRType.AXFR
         self.conn._request_serial = isc.dns.Serial(1234) # same as soa_rrset
         self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual(type(XfrinFirstData()),
@@ -433,13 +445,13 @@ class TestXfrinFirstData(TestXfrinState):
     def setUp(self):
         super().setUp()
         self.state = XfrinFirstData()
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         # arbitrary chosen serial < 1234:
         self.conn._request_serial = isc.dns.Serial(1230)
         self.conn._diff = None           # should be replaced in the AXFR case
 
     def test_handle_ixfr_begin_soa(self):
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         self.assertFalse(self.state.handle_rr(self.conn, self.begin_soa))
         self.assertEqual(type(XfrinIXFRDeleteSOA()),
                          type(self.conn.get_xfrstate()))
@@ -447,7 +459,7 @@ class TestXfrinFirstData(TestXfrinState):
     def test_handle_axfr(self):
         # If the original type is AXFR, other conditions aren't considered,
         # and AXFR processing will continue
-        self.conn._request_type = RRType.AXFR()
+        self.conn._request_type = RRType.AXFR
         self.assertFalse(self.state.handle_rr(self.conn, self.begin_soa))
         self.assertEqual(type(XfrinAXFR()), type(self.conn.get_xfrstate()))
 
@@ -586,9 +598,9 @@ class TestXfrinIXFRAdd(TestXfrinState):
         # First, push a starting SOA inside. This should be OK, nothing checked
         # yet.
         self.state.handle_rr(self.conn, self.begin_soa)
-        end_soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+        end_soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
                               'm. r. 1234 0 0 0 0')
-        end_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+        end_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
                                 RRTTL(3600))
         end_soa_rrset.add_rdata(end_soa_rdata)
         # This would try to finish up. But the TSIG pretends not everything is
@@ -712,7 +724,7 @@ class TestXfrinConnection(unittest.TestCase):
             'bad_qid': False,
             'response': True,
             'auth': True,
-            'rcode': Rcode.NOERROR(),
+            'rcode': Rcode.NOERROR,
             'answers': default_answers,
             'authorities': [],
             'tsig': False,
@@ -726,11 +738,27 @@ class TestXfrinConnection(unittest.TestCase):
             'tsig_1st': None,
             'tsig_2nd': None
             }
+        self.__orig_check_zone = xfrin.check_zone
+        xfrin.check_zone = self.__check_zone
+        self._check_zone_result = True
+        self._check_zone_params = None
 
     def tearDown(self):
         self.conn.close()
         if os.path.exists(TEST_DB_FILE):
             os.remove(TEST_DB_FILE)
+        xfrin.check_zone = self.__orig_check_zone
+
+    def __check_zone(self, name, rrclass, rrsets, callbacks):
+        '''
+        A mock function used instead of dns.check_zone.
+        '''
+        self._check_zone_params = (name, rrclass, rrsets, callbacks)
+        # Call both callbacks to see they do nothing. This checks
+        # the transfer depends on the result only.
+        callbacks[0]("Test error")
+        callbacks[1]("Test warning")
+        return self._check_zone_result
 
     def _create_normal_response_data(self):
         # This helper method creates a simple sequence of DNS messages that
@@ -789,21 +817,21 @@ class TestXfrinConnection(unittest.TestCase):
         self.conn.reply_data += bogus_data
 
     def _create_a(self, address):
-        rrset = RRset(Name('a.example.com'), TEST_RRCLASS, RRType.A(),
+        rrset = RRset(Name('a.example.com'), TEST_RRCLASS, RRType.A,
                       RRTTL(3600))
-        rrset.add_rdata(Rdata(RRType.A(), TEST_RRCLASS, address))
+        rrset.add_rdata(Rdata(RRType.A, TEST_RRCLASS, address))
         return rrset
 
     def _create_soa(self, serial):
-        rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+        rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
                       RRTTL(3600))
         rdata_str = 'm. r. ' + serial + ' 3600 1800 2419200 7200'
-        rrset.add_rdata(Rdata(RRType.SOA(), TEST_RRCLASS, rdata_str))
+        rrset.add_rdata(Rdata(RRType.SOA, TEST_RRCLASS, rdata_str))
         return rrset
 
     def _create_ns(self, nsname='ns.'+TEST_ZONE_NAME_STR):
-        rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(), RRTTL(3600))
-        rrset.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS, nsname))
+        rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS, RRTTL(3600))
+        rrset.add_rdata(Rdata(RRType.NS, TEST_RRCLASS, nsname))
         return rrset
 
     def _set_test_zone(self, zone_name):
@@ -825,6 +853,7 @@ class TestAXFR(TestXfrinConnection):
 
     def tearDown(self):
         time.time = self.orig_time_time
+        super().tearDown()
 
     def __create_mock_tsig(self, key, error, has_last_signature=True):
         # This helper function creates a MockTSIGContext for a given key
@@ -870,19 +899,19 @@ class TestAXFR(TestXfrinConnection):
         c.close()
 
     def test_init_chclass(self):
-        c = MockXfrinConnection({}, TEST_ZONE_NAME, RRClass.CH(), None,
+        c = MockXfrinConnection({}, TEST_ZONE_NAME, RRClass.CH, None,
                                 threading.Event(), TEST_MASTER_IPV4_ADDRINFO)
         c.init_socket()
-        axfrmsg = c._create_query(RRType.AXFR())
+        axfrmsg = c._create_query(RRType.AXFR)
         self.assertEqual(axfrmsg.get_question()[0].get_class(),
-                         RRClass.CH())
+                         RRClass.CH)
         c.close()
 
     def test_create_query(self):
         def check_query(expected_qtype, expected_auth):
             '''Helper method to repeat the same pattern of tests'''
-            self.assertEqual(Opcode.QUERY(), msg.get_opcode())
-            self.assertEqual(Rcode.NOERROR(), msg.get_rcode())
+            self.assertEqual(Opcode.QUERY, msg.get_opcode())
+            self.assertEqual(Rcode.NOERROR, msg.get_rcode())
             self.assertEqual(1, msg.get_rr_count(Message.SECTION_QUESTION))
             self.assertEqual(TEST_ZONE_NAME, msg.get_question()[0].get_name())
             self.assertEqual(expected_qtype, msg.get_question()[0].get_type())
@@ -907,16 +936,16 @@ class TestAXFR(TestXfrinConnection):
 
         # Actual tests start here
         # SOA query
-        msg = self.conn._create_query(RRType.SOA())
-        check_query(RRType.SOA(), None)
+        msg = self.conn._create_query(RRType.SOA)
+        check_query(RRType.SOA, None)
 
         # AXFR query
-        msg = self.conn._create_query(RRType.AXFR())
-        check_query(RRType.AXFR(), None)
+        msg = self.conn._create_query(RRType.AXFR)
+        check_query(RRType.AXFR, None)
 
         # IXFR query
-        msg = self.conn._create_query(RRType.IXFR())
-        check_query(RRType.IXFR(), begin_soa_rrset)
+        msg = self.conn._create_query(RRType.IXFR)
+        check_query(RRType.IXFR, begin_soa_rrset)
         self.assertEqual(1230, self.conn._request_serial.get_value())
 
     def test_create_ixfr_query_fail(self):
@@ -925,20 +954,20 @@ class TestAXFR(TestXfrinConnection):
 
         self._set_test_zone(Name('no-such-zone.example'))
         self.assertRaises(XfrinException, self.conn._create_query,
-                          RRType.IXFR())
+                          RRType.IXFR)
 
         self._set_test_zone(Name('partial-match-zone.example'))
         self.assertRaises(XfrinException, self.conn._create_query,
-                          RRType.IXFR())
+                          RRType.IXFR)
 
         self._set_test_zone(Name('no-soa.example'))
         self.assertRaises(XfrinException, self.conn._create_query,
-                          RRType.IXFR())
+                          RRType.IXFR)
 
         self._set_test_zone(Name('dup-soa.example'))
         self.conn._zone_soa = self.conn._get_zone_soa()
         self.assertRaises(XfrinException, self.conn._create_query,
-                          RRType.IXFR())
+                          RRType.IXFR)
 
     def test_send_query(self):
         def message_has_tsig(data):
@@ -951,11 +980,11 @@ class TestAXFR(TestXfrinConnection):
 
         # soa request with tsig
         self.conn._tsig_key = TSIG_KEY
-        self.conn._send_query(RRType.SOA())
+        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.conn._send_query(RRType.AXFR)
         self.assertTrue(message_has_tsig(self.conn.query_data[2:]))
 
     def test_response_with_invalid_msg(self):
@@ -966,14 +995,14 @@ class TestAXFR(TestXfrinConnection):
     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._send_query(RRType.SOA)
         self.conn.reply_data = \
-            self.conn.create_response_data(rcode=Rcode.NOTAUTH())
+            self.conn.create_response_data(rcode=Rcode.NOTAUTH)
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
 
     def test_response_without_end_soa(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data()
         # This should result in timeout in the asyncore loop.  We emulate
         # that situation in recv() by emptying the reply data buffer.
@@ -981,7 +1010,7 @@ class TestAXFR(TestXfrinConnection):
                           self.conn._handle_xfrin_responses)
 
     def test_response_bad_qid(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(bad_qid=True)
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
@@ -990,9 +1019,9 @@ class TestAXFR(TestXfrinConnection):
         self.conn._tsig_key = TSIG_KEY
         self.conn._tsig_ctx_creator = \
             lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(
-                rcode=Rcode.SERVFAIL())
+                rcode=Rcode.SERVFAIL)
         # xfrin should check TSIG before other part of incoming message
         # validate log message for XfrinException
         self.__match_exception(XfrinProtocolError,
@@ -1003,7 +1032,7 @@ class TestAXFR(TestXfrinConnection):
         self.conn._tsig_key = TSIG_KEY
         self.conn._tsig_ctx_creator = \
             lambda key: self.__create_mock_tsig(key, TSIGError.BAD_KEY)
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(bad_qid=True)
         # xfrin should check TSIG before other part of incoming message
         # validate log message for XfrinException
@@ -1012,26 +1041,26 @@ class TestAXFR(TestXfrinConnection):
                                self.conn._handle_xfrin_responses)
 
     def test_response_non_response(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(response=False)
         self.assertRaises(XfrinException, self.conn._handle_xfrin_responses)
 
     def test_response_error_code(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(
-            rcode=Rcode.SERVFAIL())
+            rcode=Rcode.SERVFAIL)
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
 
     def test_response_multi_question(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(
             questions=[example_axfr_question, example_axfr_question])
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
 
     def test_response_non_response(self):
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(response = False)
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
@@ -1069,7 +1098,7 @@ class TestAXFR(TestXfrinConnection):
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
     def test_soacheck_error_code(self):
-        self.soa_response_params['rcode'] = Rcode.SERVFAIL()
+        self.soa_response_params['rcode'] = Rcode.SERVFAIL
         self.conn.response_generator = self._create_soa_response_data
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
@@ -1117,21 +1146,21 @@ class TestAXFR(TestXfrinConnection):
         self.conn.response_generator = self._create_soa_response_data
         self.soa_response_params['questions'] = [Question(Name('example.org'),
                                                           TEST_RRCLASS,
-                                                          RRType.SOA())]
+                                                          RRType.SOA)]
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
     def test_soacheck_question_class_mismatch(self):
         self.conn.response_generator = self._create_soa_response_data
         self.soa_response_params['questions'] = [Question(TEST_ZONE_NAME,
-                                                          RRClass.CH(),
-                                                          RRType.SOA())]
+                                                          RRClass.CH,
+                                                          RRType.SOA)]
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
     def test_soacheck_question_type_mismatch(self):
         self.conn.response_generator = self._create_soa_response_data
         self.soa_response_params['questions'] = [Question(TEST_ZONE_NAME,
                                                           TEST_RRCLASS,
-                                                          RRType.AAAA())]
+                                                          RRType.AAAA)]
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
     def test_soacheck_no_soa(self):
@@ -1149,8 +1178,8 @@ class TestAXFR(TestXfrinConnection):
 
     def test_soacheck_soa_class_mismatch(self):
         self.conn.response_generator = self._create_soa_response_data
-        soa = RRset(TEST_ZONE_NAME, RRClass.CH(), RRType.SOA(), RRTTL(0))
-        soa.add_rdata(Rdata(RRType.SOA(), RRClass.CH(), 'm. r. 1234 0 0 0 0'))
+        soa = RRset(TEST_ZONE_NAME, RRClass.CH, RRType.SOA, RRTTL(0))
+        soa.add_rdata(Rdata(RRType.SOA, RRClass.CH, 'm. r. 1234 0 0 0 0'))
         self.soa_response_params['answers'] = [soa]
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
@@ -1168,7 +1197,7 @@ class TestAXFR(TestXfrinConnection):
     def test_soacheck_referral_response(self):
         self.conn.response_generator = self._create_soa_response_data
         self.soa_response_params['answers'] = []
-        self.soa_response_params['authorities'] = [create_ns('ns.example.com')]
+        self.soa_response_params['authorities'] = [create_ns('ns.example.com.')]
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
 
     def test_soacheck_nodata_response(self):
@@ -1191,7 +1220,7 @@ class TestAXFR(TestXfrinConnection):
         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.soa_response_params['rcode'] = Rcode.NOTAUTH
         self.conn.response_generator = self._create_soa_response_data
 
         self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
@@ -1228,7 +1257,7 @@ class TestAXFR(TestXfrinConnection):
     def test_response_shutdown(self):
         self.conn.response_generator = self._create_normal_response_data
         self.conn._shutdown_event.set()
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.assertRaises(XfrinException, self.conn._handle_xfrin_responses)
 
     def test_response_timeout(self):
@@ -1243,13 +1272,13 @@ class TestAXFR(TestXfrinConnection):
 
     def test_response_bad_message(self):
         self.conn.response_generator = self._create_broken_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.assertRaises(Exception, self.conn._handle_xfrin_responses)
 
     def test_axfr_response(self):
         # A simple normal case: AXFR consists of SOA, NS, then trailing SOA.
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1270,7 +1299,7 @@ class TestAXFR(TestXfrinConnection):
                                                    self._create_ns(),
                                                    soa_rrset]
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1285,10 +1314,9 @@ class TestAXFR(TestXfrinConnection):
         '''
         ns_rr = self._create_ns()
         a_rr = self._create_a('192.0.2.1')
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                RRType.AXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)],
             # begin serial=1230, end serial=1234. end will be used.
             answers=[begin_soa_rrset, ns_rr, a_rr, soa_rrset])
         self.conn._handle_xfrin_responses()
@@ -1297,6 +1325,32 @@ class TestAXFR(TestXfrinConnection):
                     [[('add', ns_rr), ('add', a_rr), ('add', soa_rrset)]],
                     self.conn._datasrc_client.committed_diffs)
 
+    def test_axfr_response_fail_validation(self):
+        """
+        Test we reject a zone transfer if it fails the check_zone validation.
+        """
+        a_rr = self._create_a('192.0.2.1')
+        self.conn._send_query(RRType.AXFR)
+        self.conn.reply_data = self.conn.create_response_data(
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)],
+            # begin serial=1230, end serial=1234. end will be used.
+            answers=[begin_soa_rrset, a_rr, soa_rrset])
+        # Make it fail the validation
+        self._check_zone_result = False
+        self.assertRaises(XfrinZoneError, self.conn._handle_xfrin_responses)
+        self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
+        self.assertEqual([], self.conn._datasrc_client.committed_diffs)
+        # Check the validation is called with the correct parameters
+        self.assertEqual(TEST_ZONE_NAME, self._check_zone_params[0])
+        self.assertEqual(TEST_RRCLASS, self._check_zone_params[1])
+        self.assertTrue(isinstance(self._check_zone_params[2],
+                                   MockRRsetCollection))
+        # Check we can safely call the callbacks. They have no sideeffects
+        # we can check (checking logging is hard), but we at least check
+        # they don't crash.
+        self._check_zone_params[3][0]("Test error")
+        self._check_zone_params[3][1]("Test warning")
+
     def test_axfr_response_extra(self):
         '''Test with an extra RR after the end of AXFR session.
 
@@ -1305,10 +1359,10 @@ class TestAXFR(TestXfrinConnection):
         '''
         ns_rr = self._create_ns()
         a_rr = self._create_a('192.0.2.1')
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn.reply_data = self.conn.create_response_data(
             questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                RRType.AXFR())],
+                                RRType.AXFR)],
             answers=[soa_rrset, ns_rr, a_rr, soa_rrset, a_rr])
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
@@ -1322,9 +1376,9 @@ class TestAXFR(TestXfrinConnection):
 
         '''
         self.axfr_response_params['question_1st'] = \
-            [Question(Name('mismatch.example'), TEST_RRCLASS, RRType.AXFR())]
+            [Question(Name('mismatch.example'), TEST_RRCLASS, RRType.AXFR)]
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1338,9 +1392,9 @@ class TestAXFR(TestXfrinConnection):
 
         '''
         self.axfr_response_params['question_1st'] = \
-            [Question(TEST_ZONE_NAME, RRClass.CH(), RRType.AXFR())]
+            [Question(TEST_ZONE_NAME, RRClass.CH, RRType.AXFR)]
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1355,9 +1409,9 @@ class TestAXFR(TestXfrinConnection):
         '''
         # returning IXFR in question to AXFR query
         self.axfr_response_params['question_1st'] = \
-            [Question(TEST_ZONE_NAME, RRClass.CH(), RRType.IXFR())]
+            [Question(TEST_ZONE_NAME, RRClass.CH, RRType.IXFR)]
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1372,7 +1426,7 @@ class TestAXFR(TestXfrinConnection):
         '''
         self.axfr_response_params['question_1st'] = []
         self.conn.response_generator = self._create_normal_response_data
-        self.conn._send_query(RRType.AXFR())
+        self.conn._send_query(RRType.AXFR)
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
         check_diffs(self.assertEqual,
@@ -1499,6 +1553,15 @@ class TestAXFR(TestXfrinConnection):
         self.conn.response_generator = self._create_normal_response_data
         self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
 
+    def test_do_xfrin_invalid_zone(self):
+        """
+        Test receiving an invalid zone. We mock the check and see the whole
+        transfer is rejected.
+        """
+        self._check_zone_result = False
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
     def test_do_soacheck_and_xfrin(self):
         self.conn.response_generator = self._create_soa_response_data
         self.assertEqual(self.conn.do_xfrin(True), XFRIN_OK)
@@ -1552,7 +1615,7 @@ class TestIXFRResponse(TestXfrinConnection):
         super().setUp()
         self.conn._query_id = self.conn.qid = 1035
         self.conn._request_serial = isc.dns.Serial(1230)
-        self.conn._request_type = RRType.IXFR()
+        self.conn._request_type = RRType.IXFR
         self.conn._datasrc_client = MockDataSourceClient()
         XfrinInitialSOA().set_xfrstate(self.conn, XfrinInitialSOA())
 
@@ -1566,7 +1629,7 @@ class TestIXFRResponse(TestXfrinConnection):
 
         '''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1576,12 +1639,32 @@ class TestIXFRResponse(TestXfrinConnection):
                     [[('delete', begin_soa_rrset), ('add', soa_rrset)]],
                     self.conn._datasrc_client.committed_diffs)
 
+    def test_ixfr_response_fail_validation(self):
+        '''
+        An IXFR that fails validation later on. Check it is rejected.
+        '''
+        self.conn.reply_data = self.conn.create_response_data(
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
+            answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
+        self._check_zone_result = False
+        self.assertRaises(XfrinZoneError, self.conn._handle_xfrin_responses)
+        self.assertEqual([], self.conn._datasrc_client.committed_diffs)
+        self.assertEqual(TEST_ZONE_NAME, self._check_zone_params[0])
+        self.assertEqual(TEST_RRCLASS, self._check_zone_params[1])
+        self.assertTrue(isinstance(self._check_zone_params[2],
+                                   MockRRsetCollection))
+        # Check we can safely call the callbacks. They have no sideeffects
+        # we can check (checking logging is hard), but we at least check
+        # they don't crash.
+        self._check_zone_params[3][0]("Test error")
+        self._check_zone_params[3][1]("Test warning")
+
     def test_ixfr_response_multi_sequences(self):
         '''Similar to the previous case, but with multiple diff seqs.
 
         '''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset,
                      # removing one A in serial 1230
                      begin_soa_rrset, self._create_a('192.0.2.1'),
@@ -1621,10 +1704,10 @@ class TestIXFRResponse(TestXfrinConnection):
 
         '''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, begin_soa_rrset, soa_rrset])
         self.conn.reply_data += self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset])
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1635,7 +1718,7 @@ class TestIXFRResponse(TestXfrinConnection):
     def test_ixfr_response_uptodate(self):
         '''IXFR response indicates the zone is new enough'''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[begin_soa_rrset])
         self.assertRaises(XfrinZoneUptodate, self.conn._handle_xfrin_responses)
         # no diffs should have been committed
@@ -1648,7 +1731,7 @@ class TestIXFRResponse(TestXfrinConnection):
         '''
         # SOA sequence is out-of-sync
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, begin_soa_rrset, soa_rrset,
                      self._create_soa('1235')])
         self.assertRaises(XfrinProtocolError,
@@ -1665,7 +1748,7 @@ class TestIXFRResponse(TestXfrinConnection):
         specification, but it is how BIND 9 works and we do the same.
         '''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset,
                      self._create_a('192.0.2.1')])
         self.assertRaises(XfrinProtocolError,
@@ -1682,7 +1765,7 @@ class TestIXFRResponse(TestXfrinConnection):
 
         '''
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[begin_soa_rrset, soa_rrset])
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
@@ -1699,7 +1782,7 @@ class TestIXFRResponse(TestXfrinConnection):
         ns_rr = self._create_ns()
         a_rr = self._create_a('192.0.2.1')
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, ns_rr, a_rr, soa_rrset])
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
@@ -1721,7 +1804,7 @@ class TestIXFRResponse(TestXfrinConnection):
         ns_rr = self._create_ns()
         a_rr = self._create_a('192.0.2.1')
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, ns_rr, a_rr, begin_soa_rrset])
         self.conn._handle_xfrin_responses()
         self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
@@ -1740,7 +1823,7 @@ class TestIXFRResponse(TestXfrinConnection):
         ns_rr = self._create_ns()
         a_rr = self._create_a('192.0.2.1')
         self.conn.reply_data = self.conn.create_response_data(
-            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+            questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
             answers=[soa_rrset, ns_rr, a_rr, soa_rrset, a_rr])
         self.assertRaises(XfrinProtocolError,
                           self.conn._handle_xfrin_responses)
@@ -1767,10 +1850,10 @@ class TestIXFRSession(TestXfrinConnection):
         def create_ixfr_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.IXFR())],
+                                    RRType.IXFR)],
                 answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
         self.conn.response_generator = create_ixfr_response
-        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
 
         # Check some details of the IXFR protocol processing
         self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1784,7 +1867,7 @@ class TestIXFRSession(TestXfrinConnection):
         qmsg.from_wire(qdata, len(qdata))
         self.assertEqual(1, qmsg.get_rr_count(Message.SECTION_QUESTION))
         self.assertEqual(TEST_ZONE_NAME, qmsg.get_question()[0].get_name())
-        self.assertEqual(RRType.IXFR(), qmsg.get_question()[0].get_type())
+        self.assertEqual(RRType.IXFR, qmsg.get_question()[0].get_type())
 
         self.assertEqual(1, self.conn._transfer_stats.message_count)
         self.assertEqual(0, self.conn._transfer_stats.axfr_rr_count)
@@ -1801,18 +1884,18 @@ class TestIXFRSession(TestXfrinConnection):
         def create_ixfr_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.IXFR())],
+                                    RRType.IXFR)],
                 answers=[soa_rrset, begin_soa_rrset, soa_rrset,
                          self._create_soa('1235')])
         self.conn.response_generator = create_ixfr_response
-        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
 
     def test_do_xfrin_fail2(self):
         '''IXFR fails due to a bogus DNS message.
 
         '''
         self._create_broken_response_data()
-        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
 
     def test_do_xfrin_uptodate(self):
         '''IXFR is (gracefully) aborted because serial is not new
@@ -1821,10 +1904,10 @@ class TestIXFRSession(TestXfrinConnection):
         def create_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.IXFR())],
+                                    RRType.IXFR)],
                 answers=[begin_soa_rrset])
         self.conn.response_generator = create_response
-        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
 
         self.assertEqual(1, self.conn._transfer_stats.message_count)
         self.assertEqual(0, self.conn._transfer_stats.axfr_rr_count)
@@ -1871,7 +1954,7 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
     def get_zone_serial(self):
         result, finder = self.conn._datasrc_client.find_zone(TEST_ZONE_NAME)
         self.assertEqual(DataSourceClient.SUCCESS, result)
-        result, soa, _ = finder.find(TEST_ZONE_NAME, RRType.SOA())
+        result, soa, _ = finder.find(TEST_ZONE_NAME, RRType.SOA)
         self.assertEqual(ZoneFinder.SUCCESS, result)
         self.assertEqual(1, soa.get_rdata_count())
         return get_soa_serial(soa.get_rdata()[0])
@@ -1886,13 +1969,13 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
         def create_ixfr_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.IXFR())],
+                                    RRType.IXFR)],
                 answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
         self.conn.response_generator = create_ixfr_response
 
         # Confirm xfrin succeeds and SOA is updated
         self.assertEqual(1230, self.get_zone_serial().get_value())
-        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
         self.assertEqual(1234, self.get_zone_serial().get_value())
 
         # Also confirm the corresponding diffs are stored in the diffs table
@@ -1917,18 +2000,18 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
         def create_ixfr_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.IXFR())],
+                                    RRType.IXFR)],
                 answers=[soa_rrset, begin_soa_rrset, soa_rrset,
                          self._create_soa('1235')])
         self.conn.response_generator = create_ixfr_response
 
         self.assertEqual(1230, self.get_zone_serial().get_value())
-        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
         self.assertEqual(1230, self.get_zone_serial().get_value())
 
     def test_do_ixfrin_nozone_sqlite3(self):
         self._set_test_zone(Name('nosuchzone.example'))
-        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+        self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
         # This should fail even before starting state transition
         self.assertEqual(None, self.conn.get_xfrstate())
 
@@ -1945,23 +2028,23 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
         # Confirm xfrin succeeds and SOA is updated, A RR is deleted.
         self.assertEqual(1230, self.get_zone_serial().get_value())
         self.assertTrue(self.record_exist(Name('dns01.example.com'),
-                                          RRType.A()))
+                                          RRType.A))
         self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, type))
         self.assertEqual(1234, self.get_zone_serial().get_value())
         self.assertFalse(self.record_exist(Name('dns01.example.com'),
-                                           RRType.A()))
+                                           RRType.A))
 
     def test_do_ixfrin_axfr_sqlite3(self):
         '''AXFR-style IXFR.
 
         '''
-        self.axfr_check(RRType.IXFR())
+        self.axfr_check(RRType.IXFR)
 
     def test_do_axfrin_sqlite3(self):
         '''AXFR.
 
         '''
-        self.axfr_check(RRType.AXFR())
+        self.axfr_check(RRType.AXFR)
 
     def axfr_failure_check(self, type):
         '''Similar to the previous two tests, but xfrin fails due to error.
@@ -1977,23 +2060,23 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
 
         self.assertEqual(1230, self.get_zone_serial().get_value())
         self.assertTrue(self.record_exist(Name('dns01.example.com'),
-                                          RRType.A()))
+                                          RRType.A))
         self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, type))
         self.assertEqual(1230, self.get_zone_serial().get_value())
         self.assertTrue(self.record_exist(Name('dns01.example.com'),
-                                          RRType.A()))
+                                          RRType.A))
 
     def test_do_xfrin_axfr_sqlite3_fail(self):
         '''Failure case for AXFR-style IXFR.
 
         '''
-        self.axfr_failure_check(RRType.IXFR())
+        self.axfr_failure_check(RRType.IXFR)
 
     def test_do_axfrin_sqlite3_fail(self):
         '''Failure case for AXFR.
 
         '''
-        self.axfr_failure_check(RRType.AXFR())
+        self.axfr_failure_check(RRType.AXFR)
 
     def test_do_axfrin_nozone_sqlite3(self):
         '''AXFR test with an empty SQLite3 DB file, thus no target zone there.
@@ -2010,16 +2093,16 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
         def create_response():
             self.conn.reply_data = self.conn.create_response_data(
                 questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                    RRType.AXFR())],
+                                    RRType.AXFR)],
                 answers=[soa_rrset, self._create_ns(), soa_rrset])
         self.conn.response_generator = create_response
         self._set_test_zone(Name('example.com'))
-        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.AXFR()))
+        self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.AXFR))
         self.assertEqual(type(XfrinAXFREnd()),
                          type(self.conn.get_xfrstate()))
         self.assertEqual(1234, self.get_zone_serial().get_value())
         self.assertFalse(self.record_exist(Name('dns01.example.com'),
-                                           RRType.A()))
+                                           RRType.A))
 
 class TestXfrinRecorder(unittest.TestCase):
     def setUp(self):
@@ -2128,7 +2211,7 @@ class TestXfrinProcess(unittest.TestCase):
         # Normal, successful case.  We only check that things are cleaned up
         # at the tearDown time.
         process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
-                      self.master,  False, None, RRType.AXFR(),
+                      self.master,  False, None, RRType.AXFR,
                       self.create_xfrinconn)
 
     def test_process_xfrin_exception_on_connect(self):
@@ -2136,7 +2219,7 @@ class TestXfrinProcess(unittest.TestCase):
         # cleaned up.
         self.do_raise_on_connect = True
         process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
-                      self.master,  False, None, RRType.AXFR(),
+                      self.master,  False, None, RRType.AXFR,
                       self.create_xfrinconn)
 
     def test_process_xfrin_exception_on_close(self):
@@ -2146,7 +2229,7 @@ class TestXfrinProcess(unittest.TestCase):
         self.do_raise_on_connect = True
         self.do_raise_on_close = True
         process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
-                      self.master,  False, None, RRType.AXFR(),
+                      self.master,  False, None, RRType.AXFR,
                       self.create_xfrinconn)
 
     def test_process_xfrin_exception_on_publish(self):
@@ -2154,7 +2237,7 @@ class TestXfrinProcess(unittest.TestCase):
         # everything must still be cleaned up.
         self.do_raise_on_publish = True
         process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
-                      self.master,  False, None, RRType.AXFR(),
+                      self.master,  False, None, RRType.AXFR,
                       self.create_xfrinconn)
 
 class TestXfrin(unittest.TestCase):
@@ -2207,7 +2290,7 @@ class TestXfrin(unittest.TestCase):
 
     def test_parse_cmd_params_chclass(self):
         self.args['zone_class'] = 'CH'
-        self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH())
+        self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH)
 
     def test_parse_cmd_params_bogusclass(self):
         self.args['zone_class'] = 'XXX'
@@ -2254,7 +2337,7 @@ class TestXfrin(unittest.TestCase):
         self.assertEqual(self.args['master'], self.xfr.xfrin_started_master_addr)
         self.assertEqual(int(self.args['port']), self.xfr.xfrin_started_master_port)
         # By default we use AXFR (for now)
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_retransfer_short_command1(self):
         # try it when only specifying the zone name (of unknown zone)
@@ -2368,7 +2451,7 @@ class TestXfrin(unittest.TestCase):
         self.assertEqual(int(TEST_MASTER_PORT),
                          self.xfr.xfrin_started_master_port)
         # By default we use AXFR (for now)
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_notify(self):
         # at this level, refresh is no different than retransfer.
@@ -2435,7 +2518,7 @@ class TestXfrin(unittest.TestCase):
                              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())
+            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:
@@ -2610,16 +2693,16 @@ class TestXfrin(unittest.TestCase):
     def test_command_handler_retransfer_ixfr_enabled(self):
         # If IXFR is explicitly enabled in config, IXFR will be used
         self.common_ixfr_setup('retransfer', True)
-        self.assertEqual(RRType.IXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.IXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_refresh_ixfr_enabled(self):
         # Same for refresh
         self.common_ixfr_setup('refresh', True)
-        self.assertEqual(RRType.IXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.IXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_retransfer_with_tsig(self):
         self.common_ixfr_setup('retransfer', False, 'example.com.key')
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_retransfer_with_tsig_bad_key(self):
         # bad keys should not reach xfrin, but should they somehow,
@@ -2633,7 +2716,7 @@ class TestXfrin(unittest.TestCase):
 
     def test_command_handler_refresh_with_tsig(self):
         self.common_ixfr_setup('refresh', False, 'example.com.key')
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_refresh_with_tsig_bad_key(self):
         # bad keys should not reach xfrin, but should they somehow,
@@ -2649,12 +2732,12 @@ class TestXfrin(unittest.TestCase):
         # Similar to the previous case, but explicitly disabled.  AXFR should
         # be used.
         self.common_ixfr_setup('retransfer', False)
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
     def test_command_handler_refresh_ixfr_disabled(self):
         # Same for refresh
         self.common_ixfr_setup('refresh', False)
-        self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+        self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
 
 class TestXfrinMemoryZones(unittest.TestCase):
     def setUp(self):
@@ -2826,7 +2909,7 @@ class TestXfrinProcessMockCCSession:
         self.recv_called = False
         self.recv_called_correctly = False
 
-    def group_sendmsg(self, msg, module):
+    def group_sendmsg(self, msg, module, want_answer=False):
         self.send_called = True
         if module == 'Auth' and msg['command'][0] == 'loadzone':
             self.send_called_correctly = True
@@ -2930,7 +3013,7 @@ class TestXfrinProcess(unittest.TestCase):
         self.__rets = rets
         published = rets[-1]
         xfrin.process_xfrin(self, XfrinRecorder(), Name("example.org."),
-                            RRClass.IN(), None, None, None, True, None,
+                            RRClass.IN, None, None, None, True, None,
                             request_type, self.__get_connection)
         self.assertEqual([], self.__rets)
         self.assertEqual(transfers, self.__transfers)
@@ -2942,7 +3025,7 @@ class TestXfrinProcess(unittest.TestCase):
         """
         Everything OK the first time, over IXFR.
         """
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
+        self.__do_test([XFRIN_OK], [RRType.IXFR], RRType.IXFR)
         # Check there was loadzone command
         self.assertTrue(self._send_cc_session.send_called)
         self.assertTrue(self._send_cc_session.send_called_correctly)
@@ -2953,7 +3036,7 @@ class TestXfrinProcess(unittest.TestCase):
         """
         Everything OK the first time, over AXFR.
         """
-        self.__do_test([XFRIN_OK], [RRType.AXFR()], RRType.AXFR())
+        self.__do_test([XFRIN_OK], [RRType.AXFR], RRType.AXFR)
 
     def test_axfr_fail(self):
         """
@@ -2961,15 +3044,15 @@ class TestXfrinProcess(unittest.TestCase):
         to fail on AXFR, but succeed on IXFR and we didn't use IXFR in the first
         place for some reason.
         """
-        self.__do_test([XFRIN_FAIL], [RRType.AXFR()], RRType.AXFR())
+        self.__do_test([XFRIN_FAIL], [RRType.AXFR], RRType.AXFR)
 
     def test_ixfr_fallback(self):
         """
         The transfer fails over IXFR, but suceeds over AXFR. It should fall back
         to it and say everything is OK.
         """
-        self.__do_test([XFRIN_FAIL, XFRIN_OK], [RRType.IXFR(), RRType.AXFR()],
-                       RRType.IXFR())
+        self.__do_test([XFRIN_FAIL, XFRIN_OK], [RRType.IXFR, RRType.AXFR],
+                       RRType.IXFR)
 
     def test_ixfr_fail(self):
         """
@@ -2977,13 +3060,13 @@ class TestXfrinProcess(unittest.TestCase):
         (only once) and should try both before giving up.
         """
         self.__do_test([XFRIN_FAIL, XFRIN_FAIL],
-                       [RRType.IXFR(), RRType.AXFR()], RRType.IXFR())
+                       [RRType.IXFR, RRType.AXFR], RRType.IXFR)
 
     def test_send_loadzone(self):
         """
         Check the loadzone command is sent after successful transfer.
         """
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
+        self.__do_test([XFRIN_OK], [RRType.IXFR], RRType.IXFR)
         self.assertTrue(self._send_cc_session.send_called)
         self.assertTrue(self._send_cc_session.send_called_correctly)
         self.assertTrue(self._send_cc_session.recv_called)
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index d70f3f1..65a27bb 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -36,6 +36,7 @@ from isc.xfrin.diff import Diff
 from isc.server_common.auth_command import auth_loadzone_command
 from isc.server_common.tsig_keyring import init_keyring, get_keyring
 from isc.log_messages.xfrin_messages import *
+from isc.dns import *
 
 isc.log.init("b10-xfrin", buffer=True)
 logger = isc.log.Logger("xfrin")
@@ -45,13 +46,6 @@ logger = isc.log.Logger("xfrin")
 DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
 DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
 
-try:
-    from pydnspp import *
-except ImportError as e:
-    # C++ loadable module may not be installed; even so the xfrin process
-    # must keep running, so we warn about it and move forward.
-    logger.error(XFRIN_IMPORT_DNS, str(e))
-
 isc.util.process.rename()
 
 # If B10_FROM_BUILD or B10_FROM_SOURCE is set in the environment, we
@@ -84,7 +78,7 @@ DBG_XFRIN_TRACE = logger.DBGLVL_TRACE_BASIC
 # (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()
+DEFAULT_ZONE_CLASS = RRClass.IN
 
 __version__ = 'BIND10'
 
@@ -100,8 +94,17 @@ class XfrinProtocolError(Exception):
     '''
     pass
 
+class XfrinZoneError(Exception):
+    '''
+    An exception raised when the received zone is broken enough to be unusable.
+    '''
+    pass
+
 class XfrinZoneUptodate(Exception):
-    '''TBD
+    '''
+    Thrown when the zone is already up to date, so there's no need to download
+    the zone. This is not really an error case (but it's still an exceptional
+    condition and the control flow is different than usual).
     '''
     pass
 
@@ -132,7 +135,7 @@ 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 it is None, this function returns the default RRClass.IN"""
     if zone_class_str is None:
         return DEFAULT_ZONE_CLASS
     try:
@@ -313,12 +316,12 @@ class XfrinState:
 
 class XfrinInitialSOA(XfrinState):
     def handle_rr(self, conn, rr):
-        if rr.get_type() != RRType.SOA():
+        if rr.get_type() != RRType.SOA:
             raise XfrinProtocolError('First RR in zone transfer must be SOA ('
                                      + rr.get_type().to_text() + ' received)')
         conn._end_serial = get_soa_serial(rr.get_rdata()[0])
 
-        if conn._request_type == RRType.IXFR() and \
+        if conn._request_type == RRType.IXFR and \
                 conn._end_serial <= conn._request_serial:
             logger.info(XFRIN_IXFR_UPTODATE, conn.zone_str(),
                         conn._request_serial, conn._end_serial)
@@ -361,8 +364,8 @@ class XfrinFirstData(XfrinState):
         http://www.ietf.org/mail-archive/web/dnsext/current/msg07908.html
 
         '''
-        if conn._request_type == RRType.IXFR() and \
-                rr.get_type() == RRType.SOA() and \
+        if conn._request_type == RRType.IXFR and \
+                rr.get_type() == RRType.SOA and \
                 conn._request_serial == get_soa_serial(rr.get_rdata()[0]):
             logger.debug(DBG_XFRIN_TRACE, XFRIN_GOT_INCREMENTAL_RESP,
                          conn.zone_str())
@@ -379,7 +382,7 @@ class XfrinFirstData(XfrinState):
 
 class XfrinIXFRDeleteSOA(XfrinState):
     def handle_rr(self, conn, rr):
-        if rr.get_type() != RRType.SOA():
+        if rr.get_type() != RRType.SOA:
             # this shouldn't happen; should this occur it means an internal
             # bug.
             raise XfrinException(rr.get_type().to_text() +
@@ -399,7 +402,7 @@ class XfrinIXFRDeleteSOA(XfrinState):
 
 class XfrinIXFRDelete(XfrinState):
     def handle_rr(self, conn, rr):
-        if rr.get_type() == RRType.SOA():
+        if rr.get_type() == RRType.SOA:
             # This is the only place where current_serial is set
             conn._current_serial = get_soa_serial(rr.get_rdata()[0])
             self.set_xfrstate(conn, XfrinIXFRAddSOA())
@@ -410,7 +413,7 @@ class XfrinIXFRDelete(XfrinState):
 
 class XfrinIXFRAddSOA(XfrinState):
     def handle_rr(self, conn, rr):
-        if rr.get_type() != RRType.SOA():
+        if rr.get_type() != RRType.SOA:
             # this shouldn't happen; should this occur it means an internal
             # bug.
             raise XfrinException(rr.get_type().to_text() +
@@ -422,15 +425,15 @@ class XfrinIXFRAddSOA(XfrinState):
 
 class XfrinIXFRAdd(XfrinState):
     def handle_rr(self, conn, rr):
-        if rr.get_type() == RRType.SOA():
+        if rr.get_type() == RRType.SOA:
             # This SOA marks the end of a difference sequence
             conn.get_transfer_stats().ixfr_changeset_count += 1
             soa_serial = get_soa_serial(rr.get_rdata()[0])
             if soa_serial == conn._end_serial:
-                # The final part is there. Check all was signed
-                # and commit it to the database.
-                conn._check_response_tsig_last()
-                conn._diff.commit()
+                # The final part is there. Finish the transfer by
+                # checking the last TSIG (if required), the zone data and
+                # commiting.
+                conn.finish_transfer()
                 self.set_xfrstate(conn, XfrinIXFREnd())
                 return True
             elif soa_serial != conn._current_serial:
@@ -477,7 +480,7 @@ class XfrinAXFR(XfrinState):
         Handle the RR by putting it into the zone.
         """
         conn._diff.add_data(rr)
-        if rr.get_type() == RRType.SOA():
+        if rr.get_type() == RRType.SOA:
             # SOA means end.  Don't commit it yet - we need to perform
             # post-transfer checks
 
@@ -500,15 +503,11 @@ class XfrinAXFREnd(XfrinState):
         """
         Final processing after processing an entire AXFR session.
 
-        In this process all the AXFR changes are committed to the
-        data source.
-
-        There might be more actions here, but for now we simply return False,
-        indicating there will be no more message to receive.
-
+        This simply calls the finish_transfer method of the connection
+        that ensures it is signed by TSIG (if required), the zone data
+        is valid and commits it.
         """
-        conn._check_response_tsig_last()
-        conn._diff.commit()
+        conn.finish_transfer()
         return False
 
 class XfrinTransferStats:
@@ -663,7 +662,7 @@ class XfrinConnection(asyncore.dispatcher):
             result, finder = self._datasrc_client.find_zone(self._zone_name)
         if result != DataSourceClient.SUCCESS:
             return None
-        result, soa_rrset, _ = finder.find(self._zone_name, RRType.SOA())
+        result, soa_rrset, _ = finder.find(self._zone_name, RRType.SOA)
         if result != ZoneFinder.SUCCESS:
             logger.info(XFRIN_ZONE_NO_SOA, self.zone_str())
             return None
@@ -715,8 +714,8 @@ class XfrinConnection(asyncore.dispatcher):
         query_id = random.randint(0, 0xFFFF)
         self._query_id = query_id
         msg.set_qid(query_id)
-        msg.set_opcode(Opcode.QUERY())
-        msg.set_rcode(Rcode.NOERROR())
+        msg.set_opcode(Opcode.QUERY)
+        msg.set_rcode(Rcode.NOERROR)
         msg.add_question(Question(self._zone_name, self._rrclass, query_type))
 
         # Remember our serial, if known
@@ -724,7 +723,7 @@ class XfrinConnection(asyncore.dispatcher):
             if self._zone_soa is not None else None
 
         # Set the authority section with our SOA for IXFR
-        if query_type == RRType.IXFR():
+        if query_type == RRType.IXFR:
             if self._zone_soa is None:
                 # (incremental) IXFR doesn't work without known SOA
                 raise XfrinException('Failed to create IXFR query due to no ' +
@@ -805,6 +804,31 @@ class XfrinConnection(asyncore.dispatcher):
                 raise XfrinProtocolError('TSIG verify fail: no TSIG on last '+
                                          'message')
 
+    def __validate_error(self, reason):
+        '''
+        Used as error callback below.
+        '''
+        logger.error(XFRIN_ZONE_INVALID, self._zone_name, self._rrclass,
+                     reason)
+
+    def __validate_warning(self, reason):
+        '''
+        Used as warning callback below.
+        '''
+        logger.warn(XFRIN_ZONE_WARN, self._zone_name, self._rrclass, reason)
+
+    def finish_transfer(self):
+        """
+        Perform any necessary checks after a transfer. Then complete the
+        transfer by commiting the transaction into the data source.
+        """
+        self._check_response_tsig_last()
+        if not check_zone(self._zone_name, self._rrclass,
+                          self._diff.get_rrset_collection(),
+                          (self.__validate_error, self.__validate_warning)):
+            raise XfrinZoneError('Validation of the new zone failed')
+        self._diff.commit()
+
     def __parse_soa_response(self, msg, response_data):
         '''Parse a response to SOA query and extract the SOA from answer.
 
@@ -831,7 +855,7 @@ class XfrinConnection(asyncore.dispatcher):
         resp_question = msg.get_question()[0]
         if resp_question.get_name() != self._zone_name or \
                 resp_question.get_class() != self._rrclass or \
-                resp_question.get_type() != RRType.SOA():
+                resp_question.get_type() != RRType.SOA:
             raise XfrinProtocolError('Invalid response to SOA query: '
                                      'question mismatch: ' +
                                      str(resp_question))
@@ -839,21 +863,21 @@ class XfrinConnection(asyncore.dispatcher):
         # Look into the answer section for SOA
         soa = None
         for rr in msg.get_section(Message.SECTION_ANSWER):
-            if rr.get_type() == RRType.SOA():
+            if rr.get_type() == RRType.SOA:
                 if soa is not None:
                     raise XfrinProtocolError('SOA response had multiple SOAs')
                 soa = rr
             # There should not be a CNAME record at top of zone.
-            if rr.get_type() == RRType.CNAME():
+            if rr.get_type() == RRType.CNAME:
                 raise XfrinProtocolError('SOA query resulted in CNAME')
 
         # If SOA is not found, try to figure out the reason then report it.
         if soa is None:
             # See if we have any SOA records in the authority section.
             for rr in msg.get_section(Message.SECTION_AUTHORITY):
-                if rr.get_type() == RRType.NS():
+                if rr.get_type() == RRType.NS:
                     raise XfrinProtocolError('SOA query resulted in referral')
-                if rr.get_type() == RRType.SOA():
+                if rr.get_type() == RRType.SOA:
                     raise XfrinProtocolError('SOA query resulted in NODATA')
             raise XfrinProtocolError('No SOA record found in response to ' +
                                      'SOA query')
@@ -877,7 +901,7 @@ class XfrinConnection(asyncore.dispatcher):
 
         '''
 
-        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)
@@ -901,7 +925,7 @@ class XfrinConnection(asyncore.dispatcher):
 
         return XFRIN_OK
 
-    def do_xfrin(self, check_soa, request_type=RRType.AXFR()):
+    def do_xfrin(self, check_soa, request_type=RRType.AXFR):
         '''Do an xfr session by sending xfr request and parsing responses.'''
 
         try:
@@ -909,7 +933,7 @@ class XfrinConnection(asyncore.dispatcher):
             self._request_type = request_type
             # Right now RRType.[IA]XFR().to_text() is 'TYPExxx', so we need
             # to hardcode here.
-            req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
+            req_str = 'IXFR' if request_type == RRType.IXFR else 'AXFR'
             if check_soa:
                 self._check_soa_serial()
                 self.close()
@@ -950,8 +974,15 @@ class XfrinConnection(asyncore.dispatcher):
             # of trying another primary server, etc, but for now we treat it
             # as "success".
             pass
+        except XfrinZoneError:
+            # The log message doesn't contain the exception text, since there's
+            # only one place where the exception is thrown now and it'd be the
+            # same generic message every time.
+            logger.error(XFRIN_INVALID_ZONE_DATA, self.zone_str(),
+                         format_addrinfo(self._master_addrinfo))
+            ret = XFRIN_FAIL
         except XfrinProtocolError as e:
-            logger.info(XFRIN_XFR_TRANSFER_PROTOCOL_ERROR, req_str,
+            logger.info(XFRIN_XFR_TRANSFER_PROTOCOL_VIOLATION, req_str,
                         self.zone_str(),
                         format_addrinfo(self._master_addrinfo), str(e))
             ret = XFRIN_FAIL
@@ -992,7 +1023,7 @@ class XfrinConnection(asyncore.dispatcher):
         # cause interoperability trouble with stricter checks.
 
         msg_rcode = msg.get_rcode()
-        if msg_rcode != Rcode.NOERROR():
+        if msg_rcode != Rcode.NOERROR:
             raise XfrinProtocolError('error response: %s' %
                                      msg_rcode.to_text())
 
@@ -1088,13 +1119,13 @@ def __process_xfrin(server, zone_name, rrclass, db_file,
             ret = XFRIN_FAIL
             if conn.connect_to_master():
                 ret = conn.do_xfrin(check_soa, request_type)
-                if ret == XFRIN_FAIL and request_type == RRType.IXFR():
+                if ret == XFRIN_FAIL and request_type == RRType.IXFR:
                     # IXFR failed for some reason. It might mean the server can't
                     # handle it, or we don't have the zone or we are out of sync or
                     # whatever else. So we retry with with AXFR, as it may succeed
                     # in many such cases.
                     retry = True
-                    request_type = RRType.AXFR()
+                    request_type = RRType.AXFR
                     logger.warn(XFRIN_XFR_TRANSFER_FALLBACK, conn.zone_str())
                     conn.close()
                     conn = None
@@ -1140,7 +1171,7 @@ def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
     xfrin_recorder.decrement(zone_name)
 
     if exception is not None:
-        typestr = "AXFR" if request_type == RRType.AXFR() else "IXFR"
+        typestr = "AXFR" if request_type == RRType.AXFR else "IXFR"
         logger.error(XFRIN_XFR_PROCESS_FAILURE, typestr, zone_name.to_text(),
                      str(rrclass), str(exception))
 
@@ -1292,7 +1323,8 @@ def _do_auth_loadzone(server, zone_name, zone_class):
         param = msg['command'][1]
         logger.debug(DBG_XFRIN_TRACE, XFRIN_AUTH_LOADZONE, param["origin"],
                      param["class"])
-        seq = server._send_cc_session.group_sendmsg(msg, AUTH_MODULE_NAME)
+        seq = server._send_cc_session.group_sendmsg(msg, AUTH_MODULE_NAME,
+                                                    want_answer=True)
         answer, env = server._send_cc_session.group_recvmsg(False, seq)
 
 class Xfrin:
@@ -1475,9 +1507,9 @@ class Xfrin:
                     logger.info(XFRIN_RETRANSFER_UNKNOWN_ZONE, zone_str)
                     answer = create_answer(1, errmsg)
                 else:
-                    request_type = RRType.AXFR()
+                    request_type = RRType.AXFR
                     if zone_info.use_ixfr:
-                        request_type = RRType.IXFR()
+                        request_type = RRType.IXFR
                     master_addr = zone_info.get_master_addr_info()
                     if notify_addr[0] == master_addr[0] and\
                        notify_addr[2] == master_addr[2]:
@@ -1506,11 +1538,11 @@ class Xfrin:
                                                           rrclass)
                 zone_info = self._get_zone_info(zone_name, rrclass)
                 tsig_key = None
-                request_type = RRType.AXFR()
+                request_type = RRType.AXFR
                 if zone_info:
                     tsig_key = zone_info.get_tsig_key()
                     if zone_info.use_ixfr:
-                        request_type = RRType.IXFR()
+                        request_type = RRType.IXFR
                 db_file = args.get('db_file') or self._get_db_file()
                 ret = self.xfrin_start(zone_name,
                                        rrclass,
@@ -1598,18 +1630,29 @@ class Xfrin:
         param = {'zone_name': zone_name.to_text(),
                  'zone_class': zone_class.to_text()}
         if xfr_result == XFRIN_OK:
+            # FIXME: Due to the hack with two different CC sessions
+            # (see the _cc_setup comment) and the fact the rpc_call
+            # is a high-level call present only at ModuleCCSession,
+            # we are forced to use the primitive way of manually
+            # calling group_sendmsg and the group_recvmsg. Also, why
+            # do we do group_recvmsg when we don't need the answer?
+            # And why is this direct RPC call if a notification would
+            # be more appropriate?
             _do_auth_loadzone(self, zone_name, zone_class)
             msg = create_command(notify_out.ZONE_NEW_DATA_READY_CMD, param)
             # catch the exception, in case msgq has been killed.
             try:
                 seq = self._send_cc_session.group_sendmsg(msg,
-                                                          XFROUT_MODULE_NAME)
+                                                          XFROUT_MODULE_NAME,
+                                                          want_answer=True)
                 try:
                     answer, env = self._send_cc_session.group_recvmsg(False,
                                                                       seq)
                 except isc.cc.session.SessionTimeout:
                     pass        # for now we just ignore the failure
-                seq = self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+                seq = self._send_cc_session.group_sendmsg(msg,
+                                                          ZONE_MANAGER_MODULE_NAME,
+                                                          want_answer=True)
                 try:
                     answer, env = self._send_cc_session.group_recvmsg(False,
                                                                       seq)
@@ -1622,7 +1665,8 @@ class Xfrin:
             msg = create_command(notify_out.ZONE_XFRIN_FAILED, param)
             # catch the exception, in case msgq has been killed.
             try:
-                seq = self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+                seq = self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME,
+                                                          want_answer=True)
                 try:
                     answer, env = self._send_cc_session.group_recvmsg(False,
                                                                       seq)
@@ -1706,5 +1750,7 @@ def main(xfrin_class, use_signal=True):
     if xfrind:
         xfrind.shutdown()
 
+    logger.info(XFRIN_EXITING)
+
 if __name__ == '__main__':
     main(Xfrin)
diff --git a/src/bin/xfrin/xfrin_messages.mes b/src/bin/xfrin/xfrin_messages.mes
index 770a8b2..1d90b75 100644
--- a/src/bin/xfrin/xfrin_messages.mes
+++ b/src/bin/xfrin/xfrin_messages.mes
@@ -60,6 +60,9 @@ error is given in the log message.
 There was an error opening a connection to the master. The error is
 shown in the log message.
 
+% XFRIN_EXITING exiting
+The xfrin daemon is exiting.
+
 % XFRIN_GOT_INCREMENTAL_RESP got incremental response for %1
 In an attempt of IXFR processing, the beginning SOA of the first difference
 (following the initial SOA that specified the final SOA for all the
@@ -77,6 +80,11 @@ is not equal to the requested SOA serial.
 There was an error importing the python DNS module pydnspp. The most
 likely cause is a PYTHONPATH problem.
 
+% XFRIN_INVALID_ZONE_DATA zone %1 received from %2 is broken and unusable
+The zone was received, but it failed sanity validation. The previous version
+of zone (if any is available) will be used. Look for previous
+XFRIN_ZONE_INVALID messages to see the exact problem(s).
+
 % XFRIN_IXFR_TRANSFER_SUCCESS incremental IXFR transfer of zone %1 succeeded (messages: %2, changesets: %3, deletions: %4, additions: %5, bytes: %6, run time: %7 seconds, %8 bytes/second)
 The IXFR transfer for the given zone was successful.
 The provided information contains the following values:
@@ -117,10 +125,6 @@ There was a problem sending a message to the xfrout module or the
 zone manager. This most likely means that the msgq daemon has quit or
 was killed.
 
-% XFRIN_MSGQ_SEND_ERROR_AUTH error while contacting %1
-There was a problem sending a message to b10-auth. This most likely
-means that the msgq daemon has quit or was killed.
-
 % XFRIN_MSGQ_SEND_ERROR_ZONE_MANAGER error while contacting %1
 There was a problem sending a message to the zone manager. This most
 likely means that the msgq daemon has quit or was killed.
@@ -175,6 +179,10 @@ exception message is printed in the log message.
 The XFR transfer for the given zone has failed due to a problem outside
 of the xfrin module.  Possible reasons are a broken DNS message or failure
 in database connection.  The error is shown in the log message.
+One common cause of this error could be a locked database; especially when
+using sqlite3 where a single transaction involving write operations blocks
+any other read or write transactions. This is not a critical error, and
+the transfer will be attempted again at the next retry time.
 
 % XFRIN_XFR_PROCESS_FAILURE %1 transfer of zone %2/%3 failed: %4
 An XFR session failed outside the main protocol handling.  This
@@ -201,7 +209,7 @@ such that the remote server doesn't support IXFR, we don't have the SOA record
 (or the zone at all), we are out of sync, etc. In many of these situations,
 AXFR could still work. Therefore we try that one in case it helps.
 
-% XFRIN_XFR_TRANSFER_PROTOCOL_ERROR %1 transfer of zone %2 with %3 failed: %4
+% XFRIN_XFR_TRANSFER_PROTOCOL_VIOLATION %1 transfer of zone %2 with %3 failed: %4
 The XFR transfer for the given zone has failed due to a protocol
 error, such as an unexpected response from the primary server.  The
 error is shown in the log message.  It may be because the primary
@@ -228,6 +236,12 @@ zones at a higher level.  In future it is more likely that a separate
 zone management framework is provided, and the situation where the
 given zone isn't found in xfrout will be treated as an error.
 
+% XFRIN_ZONE_INVALID Newly received zone %1/%2 fails validation: %3
+The zone was received successfully, but it failed validation. The problem
+is severe enough that the new version of zone is discarded and the old version,
+if any, will stay in use. New transfer will be attempted after some time.
+The problem needs to be fixed in the zone data on the remote server.
+
 % XFRIN_ZONE_MULTIPLE_SOA Zone %1 has %2 SOA RRs
 On starting an xfrin session, it is identified that the zone to be
 transferred has multiple SOA RRs.  Such a zone is broken, but could be
@@ -254,3 +268,9 @@ the latest version of the zone.  But if the primary server is known to
 be the real source of the zone, some unexpected inconsistency may have
 happened, and you may want to take a closer look.  In this case xfrin
 doesn't perform subsequent zone transfer.
+
+% XFRIN_ZONE_WARN Newly received zone %1/%2 has a problem: %3
+The zone was received successfully, but when checking it, it was discovered
+there's some issue with it. It might be correct, but it should be checked
+and possibly fixed on the remote server. The problem is described in the
+message. The problem does not stop the zone from being used.
diff --git a/src/bin/xfrout/b10-xfrout.xml b/src/bin/xfrout/b10-xfrout.xml
index 5765ce5..5c71e05 100644
--- a/src/bin/xfrout/b10-xfrout.xml
+++ b/src/bin/xfrout/b10-xfrout.xml
@@ -55,8 +55,8 @@
       outgoing DNS zone transfer service using AXFR or IXFR.
       It is also used to send outgoing NOTIFY messages.
       Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
       When the <command>b10-auth</command> DNS server receives
       a transfer request, <command>b10-xfrout</command> sends the
       zone as found in the BIND 10 zone data store.
@@ -147,7 +147,7 @@
       and exits <command>b10-xfrout</command>.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the BIND 10 b10-init process may restart this service
       if configured.)
     </para>
 
@@ -352,6 +352,9 @@
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index b90f419..2802ace 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -38,7 +38,7 @@ TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
 #
 TEST_ZONE_NAME_STR = "example.com."
 TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
 IXFR_OK_VERSION = 2011111802
 IXFR_NG_VERSION = 2011111803
 SOA_CURRENT_VERSION = 2011112001
@@ -109,16 +109,16 @@ class MockDataSrcClient:
         zone names.
 
         '''
-        if name == Name('nosoa.example.com') and rrtype == RRType.SOA():
+        if name == Name('nosoa.example.com') and rrtype == RRType.SOA:
             return (ZoneFinder.NXDOMAIN, None, 0)
-        elif name == Name('multisoa.example.com') and rrtype == RRType.SOA():
+        elif name == Name('multisoa.example.com') and rrtype == RRType.SOA:
             soa_rrset = create_soa(SOA_CURRENT_VERSION)
             soa_rrset.add_rdata(soa_rrset.get_rdata()[0])
             return (ZoneFinder.SUCCESS, soa_rrset, 0)
         elif name == Name('maxserial.example.com'):
             soa_rrset = create_soa(0xffffffff)
             return (ZoneFinder.SUCCESS, soa_rrset, 0)
-        elif rrtype == RRType.SOA():
+        elif rrtype == RRType.SOA:
             return (ZoneFinder.SUCCESS, create_soa(SOA_CURRENT_VERSION), 0)
         raise ValueError('Unexpected input to mock finder: bug in test case?')
 
@@ -238,17 +238,17 @@ class TestXfroutSessionBase(unittest.TestCase):
         msg = Message(Message.RENDER)
         query_id = 0x1035
         msg.set_qid(query_id)
-        msg.set_opcode(Opcode.QUERY())
-        msg.set_rcode(Rcode.NOERROR())
-        req_type = RRType.AXFR() if ixfr is None else RRType.IXFR()
+        msg.set_opcode(Opcode.QUERY)
+        msg.set_rcode(Rcode.NOERROR)
+        req_type = RRType.AXFR if ixfr is None else RRType.IXFR
         if with_question:
-            msg.add_question(Question(zone_name, RRClass.IN(),
+            msg.add_question(Question(zone_name, RRClass.IN,
                                       req_type if qtype is None else qtype))
-        if req_type == RRType.IXFR():
-            soa = RRset(zone_name, soa_class, RRType.SOA(), RRTTL(0))
+        if req_type == RRType.IXFR:
+            soa = RRset(zone_name, soa_class, RRType.SOA, RRTTL(0))
             # In the RDATA only the serial matters.
             for i in range(0, num_soa):
-                soa.add_rdata(Rdata(RRType.SOA(), soa_class,
+                soa.add_rdata(Rdata(RRType.SOA, soa_class,
                                     'm. r. ' + str(ixfr) + ' 1 1 1 1'))
             msg.add_rrset(Message.SECTION_AUTHORITY, soa)
 
@@ -263,7 +263,7 @@ class TestXfroutSessionBase(unittest.TestCase):
 
     def set_request_type(self, type):
         self.xfrsess._request_type = type
-        if type == RRType.AXFR():
+        if type == RRType.AXFR:
             self.xfrsess._request_typestr = 'AXFR'
         else:
             self.xfrsess._request_typestr = 'IXFR'
@@ -278,7 +278,7 @@ class TestXfroutSessionBase(unittest.TestCase):
                                        isc.acl.dns.REQUEST_LOADER.load(
                                            [{"action": "ACCEPT"}]),
                                        {})
-        self.set_request_type(RRType.AXFR()) # test AXFR by default
+        self.set_request_type(RRType.AXFR) # test AXFR by default
         self.mdata = self.create_request_data()
         self.soa_rrset = create_soa(SOA_CURRENT_VERSION)
         # some test replaces a module-wide function.  We should ensure the
@@ -301,7 +301,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.xfrsess._request_data = self.mdata
         self.xfrsess._server.increase_transfers_counter = lambda : False
         XfroutSession._handle(self.xfrsess)
-        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.REFUSED())
+        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.REFUSED)
 
     def test_quota_ok(self):
         '''The default case in terms of the xfrout quota.
@@ -314,7 +314,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         # Replace the data source client to avoid datasrc related exceptions
         self.xfrsess.ClientClass = MockDataSrcClient
         XfroutSession._handle(self.xfrsess)
-        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.FORMERR())
+        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.FORMERR)
 
     def test_exception_from_session(self):
         '''Test the case where the main processing raises an exception.
@@ -331,14 +331,14 @@ class TestXfroutSession(TestXfroutSessionBase):
     def test_parse_query_message(self):
         # Valid AXFR
         [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
-        self.assertEqual(RRType.AXFR(), self.xfrsess._request_type)
+        self.assertEqual(RRType.AXFR, self.xfrsess._request_type)
         self.assertEqual(get_rcode.to_text(), "NOERROR")
 
         # Valid IXFR
         request_data = self.create_request_data(ixfr=2011111801)
         rcode, msg = self.xfrsess._parse_query_message(request_data)
-        self.assertEqual(RRType.IXFR(), self.xfrsess._request_type)
-        self.assertEqual(Rcode.NOERROR(), rcode)
+        self.assertEqual(RRType.IXFR, self.xfrsess._request_type)
+        self.assertEqual(Rcode.NOERROR, rcode)
 
         # Broken request: no question
         self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
@@ -346,7 +346,7 @@ class TestXfroutSession(TestXfroutSessionBase):
 
         # Broken request: invalid RR type (neither AXFR nor IXFR)
         self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
-                          self.create_request_data(qtype=RRType.A()))
+                          self.create_request_data(qtype=RRType.A))
 
         # NOERROR
         request_data = self.create_request_data(ixfr=IXFR_OK_VERSION)
@@ -513,7 +513,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         # should be used.
         self.xfrsess._acl = isc.acl.dns.REQUEST_LOADER.load([
                 {"from": "127.0.0.1", "action": "ACCEPT"}])
-        acl = self.xfrsess._get_transfer_acl(Name('example.com'), RRClass.IN())
+        acl = self.xfrsess._get_transfer_acl(Name('example.com'), RRClass.IN)
         self.assertEqual(acl, self.xfrsess._acl)
 
         # install a per zone config with transfer ACL for example.com.  Then
@@ -526,15 +526,15 @@ class TestXfroutSession(TestXfroutSessionBase):
             com_acl
         self.assertEqual(com_acl,
                          self.xfrsess._get_transfer_acl(Name('example.com'),
-                                                        RRClass.IN()))
+                                                        RRClass.IN))
         self.assertEqual(self.xfrsess._acl,
                          self.xfrsess._get_transfer_acl(Name('example.org'),
-                                                        RRClass.IN()))
+                                                        RRClass.IN))
 
         # Name matching should be case insensitive.
         self.assertEqual(com_acl,
                          self.xfrsess._get_transfer_acl(Name('EXAMPLE.COM'),
-                                                        RRClass.IN()))
+                                                        RRClass.IN))
 
     def test_send_data(self):
         self.xfrsess._send_data(self.sock, self.mdata)
@@ -559,9 +559,9 @@ class TestXfroutSession(TestXfroutSessionBase):
         msg = self.getmsg()
         msg.make_response()
         # SOA record data with different cases
-        soa_rrset = RRset(Name('Example.com.'), RRClass.IN(), RRType.SOA(),
+        soa_rrset = RRset(Name('Example.com.'), RRClass.IN, RRType.SOA,
                                RRTTL(3600))
-        soa_rrset.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+        soa_rrset.add_rdata(Rdata(RRType.SOA, RRClass.IN,
                                   'master.Example.com. admin.exAmple.com. ' +
                                   '2011112001 3600 1800 2419200 7200'))
         msg.add_rrset(Message.SECTION_ANSWER, soa_rrset)
@@ -639,8 +639,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
 
     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_a = RRset(Name("example.com"), RRClass.IN, RRType.A, RRTTL(3600))
+        rrset_a.add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
 
         msg = self.getmsg()
         msg.make_response()
@@ -718,36 +718,36 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.xfrsess.ClientClass = MockDataSrcClient
         # Successful case.  A zone iterator should be set up.
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
         self.assertNotEqual(None, self.xfrsess._iterator)
 
         # Failure cases
         self.assertEqual(self.xfrsess._xfrout_setup(
                 self.getmsg(), Name('notauth.example.com'), TEST_RRCLASS),
-                         Rcode.NOTAUTH())
+                         Rcode.NOTAUTH)
         self.assertEqual(self.xfrsess._xfrout_setup(
                 self.getmsg(), Name('nosoa.example.com'), TEST_RRCLASS),
-                         Rcode.SERVFAIL())
+                         Rcode.SERVFAIL)
         self.assertEqual(self.xfrsess._xfrout_setup(
                 self.getmsg(), Name('multisoa.example.com'), TEST_RRCLASS),
-                         Rcode.SERVFAIL())
+                         Rcode.SERVFAIL)
 
     def test_xfrout_ixfr_setup(self):
         self.xfrsess.ClientClass = MockDataSrcClient
-        self.set_request_type(RRType.IXFR())
+        self.set_request_type(RRType.IXFR)
 
         # Successful case of pure IXFR.  A zone journal reader should be set
         # up.
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
         self.assertNotEqual(None, self.xfrsess._jnl_reader)
 
         # Successful case, but as a result of falling back to AXFR-style
         # IXFR.  A zone iterator should be set up instead of a journal reader.
         self.mdata = self.create_request_data(ixfr=IXFR_NG_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
         self.assertNotEqual(None, self.xfrsess._iterator)
         self.assertEqual(None, self.xfrsess._jnl_reader)
 
@@ -756,7 +756,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         # indicating that the response will contain just one SOA.
         self.mdata = self.create_request_data(ixfr=SOA_CURRENT_VERSION+1)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
         self.assertEqual(None, self.xfrsess._iterator)
         self.assertEqual(None, self.xfrsess._jnl_reader)
 
@@ -764,7 +764,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         # the local SOA.
         self.mdata = self.create_request_data(ixfr=SOA_CURRENT_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
         self.assertEqual(None, self.xfrsess._iterator)
         self.assertEqual(None, self.xfrsess._jnl_reader)
 
@@ -773,7 +773,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         zone_name = Name('maxserial.example.com') # whose SOA is 0xffffffff
         self.mdata = self.create_request_data(ixfr=1, zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                 self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
+                 self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR)
         self.assertEqual(None, self.xfrsess._iterator)
         self.assertEqual(None, self.xfrsess._jnl_reader)
 
@@ -782,7 +782,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR)
         self.assertNotEqual(None, self.xfrsess._iterator)
 
         # Failure cases
@@ -790,42 +790,42 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH)
         # this is a strange case: zone's SOA will be found but the journal
         # reader won't be created due to 'no such zone'.
         zone_name = Name('notauth2.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH)
         zone_name = Name('nosoa.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL)
         zone_name = Name('multisoa.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL)
 
         # query name doesn't match the SOA's owner
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
 
         # query's RR class doesn't match the SOA's class
         zone_name = TEST_ZONE_NAME # make sure the name matches this time
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
-                                              soa_class=RRClass.CH())
+                                              soa_class=RRClass.CH)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
 
         # multiple SOA RRs
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               num_soa=2)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
 
     def test_dns_xfrout_start_formerror(self):
         # formerror
@@ -835,7 +835,7 @@ class TestXfroutSession(TestXfroutSessionBase):
 
     def test_dns_xfrout_start_notauth(self):
         def notauth(msg, name, rrclass):
-            return Rcode.NOTAUTH()
+            return Rcode.NOTAUTH
         self.xfrsess._xfrout_setup = notauth
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         get_msg = self.sock.read_msg()
@@ -846,13 +846,13 @@ class TestXfroutSession(TestXfroutSessionBase):
             raise isc.datasrc.Error('exception for the sake of test')
         self.xfrsess.ClientClass = internal_raise
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
-        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL())
+        self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL)
 
     def test_dns_xfrout_start_unixsocketsenderr(self):
         """This test is for a counter senderr of unixsocket."""
 
         def noerror(msg, name, rrclass):
-            return Rcode.NOERROR()
+            return Rcode.NOERROR
         self.xfrsess._xfrout_setup = noerror
 
         def myreply(msg, sock):
@@ -868,7 +868,7 @@ class TestXfroutSession(TestXfroutSessionBase):
 
     def test_dns_xfrout_start_noerror(self):
         def noerror(msg, name, rrclass):
-            return Rcode.NOERROR()
+            return Rcode.NOERROR
         self.xfrsess._xfrout_setup = noerror
 
         def myreply(msg, sock):
@@ -891,9 +891,9 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
 
     def test_reply_xfrout_query_axfr_with_tsig(self):
-        rrset = RRset(Name('a.example.com'), RRClass.IN(), RRType.A(),
+        rrset = RRset(Name('a.example.com'), RRClass.IN, RRType.A,
                       RRTTL(3600))
-        rrset.add_rdata(Rdata(RRType.A(), RRClass.IN(), '192.0.2.1'))
+        rrset.add_rdata(Rdata(RRType.A, RRClass.IN, '192.0.2.1'))
         global xfrout
 
         def get_rrset_len(rrset):
@@ -981,8 +981,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         algorithm = hmac-md5)
 
         '''
-        soa = RRset(Name('.'), RRClass.IN(), RRType.SOA(), RRTTL(3600))
-        soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(), '. . 0 0 0 0 0'))
+        soa = RRset(Name('.'), RRClass.IN, RRType.SOA, RRTTL(3600))
+        soa.add_rdata(Rdata(RRType.SOA, RRClass.IN, '. . 0 0 0 0 0'))
         self.mdata = self.create_request_data(zone_name=Name('.'))
         self.xfrsess._soa = soa
         if tsig:
@@ -1110,7 +1110,7 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
         self.xfrsess._request_data = self.mdata
         self.xfrsess._server.get_db_file = lambda : TESTDATA_SRCDIR + \
             'test.sqlite3'
-        self.ns_name = 'a.dns.example.com'
+        self.ns_name = 'a.dns.example.com.'
 
     def check_axfr_stream(self, response):
         '''Common checks for AXFR(-style) response for the test zone.
@@ -1141,10 +1141,10 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
                           self.xfrsess._counters.get, 'axfr_running')
         XfroutSession._handle(self.xfrsess)
         response = self.sock.read_msg(Message.PRESERVE_ORDER);
-        self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+        self.assertEqual(Rcode.NOERROR, response.get_rcode())
         self.check_axfr_stream(response)
-        self.assertEqual(self.xfrsess._request_type, RRType.AXFR())
-        self.assertNotEqual(self.xfrsess._request_type, RRType.IXFR())
+        self.assertEqual(self.xfrsess._request_type, RRType.AXFR)
+        self.assertNotEqual(self.xfrsess._request_type, RRType.IXFR)
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self.xfrsess._counters.get, 'ixfr_running')
         self.assertEqual(self.xfrsess._counters.get('axfr_running'), 0)
@@ -1154,10 +1154,10 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
             self.create_request_data(ixfr=IXFR_NG_VERSION)
         XfroutSession._handle(self.xfrsess)
         response = self.sock.read_msg(Message.PRESERVE_ORDER);
-        self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+        self.assertEqual(Rcode.NOERROR, response.get_rcode())
         # This is an AXFR-style IXFR.  So the question section should indicate
         # that it's an IXFR resposne.
-        self.assertEqual(RRType.IXFR(), response.get_question()[0].get_type())
+        self.assertEqual(RRType.IXFR, response.get_question()[0].get_type())
         self.check_axfr_stream(response)
 
     def test_ixfr_normal_session(self):
@@ -1185,8 +1185,8 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
         self.assertEqual(len(expected_records), len(actual_records))
         for (expected_rr, actual_rr) in zip(expected_records, actual_records):
             self.assertTrue(rrsets_equal(expected_rr, actual_rr))
-        self.assertNotEqual(self.xfrsess._request_type, RRType.AXFR())
-        self.assertEqual(self.xfrsess._request_type, RRType.IXFR())
+        self.assertNotEqual(self.xfrsess._request_type, RRType.AXFR)
+        self.assertEqual(self.xfrsess._request_type, RRType.IXFR)
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self.xfrsess._counters.get, 'axfr_running')
         self.assertEqual(self.xfrsess._counters.get('ixfr_running'), 0)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index a9b6e78..d6ef360 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -223,9 +223,9 @@ class XfroutSession():
                                                   self._tsig_key_ring)
             tsig_error = self._tsig_ctx.verify(tsig_record, request_data)
             if tsig_error != TSIGError.NOERROR:
-                return Rcode.NOTAUTH()
+                return Rcode.NOTAUTH
 
-        return Rcode.NOERROR()
+        return Rcode.NOERROR
 
     def _parse_query_message(self, mdata):
         ''' parse query message to [socket,message]'''
@@ -235,11 +235,11 @@ class XfroutSession():
             Message.from_wire(msg, mdata)
         except Exception as err: # Exception is too broad
             logger.error(XFROUT_PARSE_QUERY_ERROR, err)
-            return Rcode.FORMERR(), None
+            return Rcode.FORMERR, None
 
         # TSIG related checks
         rcode = self._check_request_tsig(msg, mdata)
-        if rcode != Rcode.NOERROR():
+        if rcode != Rcode.NOERROR:
             return rcode, msg
 
         # Make sure the question is valid.  This should be ensured by
@@ -253,9 +253,9 @@ class XfroutSession():
 
         # Identify the request type
         self._request_type = question.get_type()
-        if self._request_type == RRType.AXFR():
+        if self._request_type == RRType.AXFR:
             self._request_typestr = 'AXFR'
-        elif self._request_type == RRType.IXFR():
+        elif self._request_type == RRType.IXFR:
             self._request_typestr = 'IXFR'
         else:
             # Likewise, this should be impossible.
@@ -279,7 +279,7 @@ class XfroutSession():
             logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
                          self._request_type, format_addrinfo(self._remote),
                          format_zone_str(zone_name, zone_class))
-            return Rcode.REFUSED(), msg
+            return Rcode.REFUSED, msg
 
         return rcode, msg
 
@@ -347,16 +347,16 @@ class XfroutSession():
         '''
         result, finder = self._datasrc_client.find_zone(zone_name)
         if result != DataSourceClient.SUCCESS:
-            return (Rcode.NOTAUTH(), None)
-        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+            return (Rcode.NOTAUTH, None)
+        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
         if result != ZoneFinder.SUCCESS:
-            return (Rcode.SERVFAIL(), None)
+            return (Rcode.SERVFAIL, None)
         # Especially for database-based zones, a working zone may be in
         # a broken state where it has more than one SOA RR.  We proactively
         # check the condition and abort the xfr attempt if we identify it.
         if soa_rrset.get_rdata_count() != 1:
-            return (Rcode.SERVFAIL(), None)
-        return (Rcode.NOERROR(), soa_rrset)
+            return (Rcode.SERVFAIL, None)
+        return (Rcode.NOERROR, soa_rrset)
 
     def __axfr_setup(self, zone_name):
         '''Setup a zone iterator for AXFR or AXFR-style IXFR.
@@ -375,16 +375,16 @@ class XfroutSession():
             # update get_iterator() API so that we can distinguish "no such
             # zone" and other cases (#1373).  For now we consider all these
             # cases as NOTAUTH.
-            return Rcode.NOTAUTH()
+            return Rcode.NOTAUTH
 
         # If we are an authoritative name server for the zone, but fail
         # to find the zone's SOA record in datasource, xfrout can't
         # provide zone transfer for it.
         self._soa = self._iterator.get_soa()
         if self._soa is None or self._soa.get_rdata_count() != 1:
-            return Rcode.SERVFAIL()
+            return Rcode.SERVFAIL
 
-        return Rcode.NOERROR()
+        return Rcode.NOERROR
 
     def __ixfr_setup(self, request_msg, zone_name, zone_class):
         '''Setup a zone journal reader for IXFR.
@@ -401,21 +401,21 @@ class XfroutSession():
             # Ignore data whose owner name is not the zone apex, and
             # ignore non-SOA or different class of records.
             if auth_rrset.get_name() != zone_name or \
-                    auth_rrset.get_type() != RRType.SOA() or \
+                    auth_rrset.get_type() != RRType.SOA or \
                     auth_rrset.get_class() != zone_class:
                 continue
             if auth_rrset.get_rdata_count() != 1:
                 logger.info(XFROUT_IXFR_MULTIPLE_SOA,
                             format_addrinfo(self._remote))
-                return Rcode.FORMERR()
+                return Rcode.FORMERR
             remote_soa = auth_rrset
         if remote_soa is None:
             logger.info(XFROUT_IXFR_NO_SOA, format_addrinfo(self._remote))
-            return Rcode.FORMERR()
+            return Rcode.FORMERR
 
         # Retrieve the local SOA
         rcode, self._soa = self._get_zone_soa(zone_name)
-        if rcode != Rcode.NOERROR():
+        if rcode != Rcode.NOERROR:
             return rcode
 
         # RFC1995 says "If an IXFR query with the same or newer version
@@ -433,7 +433,7 @@ class XfroutSession():
             logger.info(XFROUT_IXFR_UPTODATE, format_addrinfo(self._remote),
                         format_zone_str(zone_name, zone_class),
                         begin_serial, end_serial)
-            return Rcode.NOERROR()
+            return Rcode.NOERROR
 
         # Set up the journal reader or fall back to AXFR-style IXFR
         try:
@@ -458,12 +458,12 @@ class XfroutSession():
             # between these two operations.  We treat it as NOTAUTH.
             logger.warn(XFROUT_IXFR_NO_ZONE, format_addrinfo(self._remote),
                         format_zone_str(zone_name, zone_class))
-            return Rcode.NOTAUTH()
+            return Rcode.NOTAUTH
 
         # Use the reader as the iterator to generate the response.
         self._iterator = self._jnl_reader
 
-        return Rcode.NOERROR()
+        return Rcode.NOERROR
 
     def _xfrout_setup(self, request_msg, zone_name, zone_class):
         '''Setup a context for xfr responses according to the request type.
@@ -486,7 +486,7 @@ class XfroutSession():
             self._server.get_db_file() + '"}'
         self._datasrc_client = self.ClientClass('sqlite3', datasrc_config)
 
-        if self._request_type == RRType.AXFR():
+        if self._request_type == RRType.AXFR:
             return self.__axfr_setup(zone_name)
         else:
             return self.__ixfr_setup(request_msg, zone_name, zone_class)
@@ -496,17 +496,17 @@ class XfroutSession():
         #TODO. create query message and parse header
         if rcode_ is None: # Dropped by ACL
             return
-        elif rcode_ == Rcode.NOTAUTH() or rcode_ == Rcode.REFUSED():
+        elif rcode_ == Rcode.NOTAUTH or rcode_ == Rcode.REFUSED:
             return self._reply_query_with_error_rcode(msg, sock_fd, rcode_)
-        elif rcode_ != Rcode.NOERROR():
+        elif rcode_ != Rcode.NOERROR:
             return self._reply_query_with_error_rcode(msg, sock_fd,
-                                                      Rcode.FORMERR())
+                                                      Rcode.FORMERR)
         elif not quota_ok:
             logger.warn(XFROUT_QUERY_QUOTA_EXCCEEDED, self._request_typestr,
                         format_addrinfo(self._remote),
                         self._server._max_transfers_out)
             return self._reply_query_with_error_rcode(msg, sock_fd,
-                                                      Rcode.REFUSED())
+                                                      Rcode.REFUSED)
 
         question = msg.get_question()[0]
         zone_name = question.get_name()
@@ -518,15 +518,15 @@ class XfroutSession():
         except Exception as ex:
             logger.error(XFROUT_XFR_TRANSFER_CHECK_ERROR, self._request_typestr,
                          format_addrinfo(self._remote), zone_str, ex)
-            rcode_ = Rcode.SERVFAIL()
-        if rcode_ != Rcode.NOERROR():
+            rcode_ = Rcode.SERVFAIL
+        if rcode_ != Rcode.NOERROR:
             logger.info(XFROUT_XFR_TRANSFER_FAILED, self._request_typestr,
                         format_addrinfo(self._remote), zone_str, rcode_)
             return self._reply_query_with_error_rcode(msg, sock_fd, rcode_)
 
         try:
             # increment Xfr starts by RRType
-            if self._request_type == RRType.AXFR():
+            if self._request_type == RRType.AXFR:
                 self._counters.inc('axfr_running')
             else:
                 self._counters.inc('ixfr_running')
@@ -540,7 +540,7 @@ class XfroutSession():
                     format_addrinfo(self._remote), zone_str, err)
         finally:
             # decrement Xfr starts by RRType
-            if self._request_type == RRType.AXFR():
+            if self._request_type == RRType.AXFR:
                 self._counters.dec('axfr_running')
             else:
                 self._counters.dec('ixfr_running')
@@ -612,7 +612,7 @@ class XfroutSession():
 
             # For AXFR (or AXFR-style IXFR), in which case _jnl_reader is None,
             # we should skip SOAs from the iterator.
-            if self._jnl_reader is None and rrset.get_type() == RRType.SOA():
+            if self._jnl_reader is None and rrset.get_type() == RRType.SOA:
                 continue
 
             # We calculate the maximum size of the RRset (i.e. the
@@ -791,7 +791,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
         """
         sock_fd = recv_fd(request.fileno())
         if sock_fd < 0:
-            logger.warn(XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR)
+            logger.warn(XFROUT_RECEIVE_FD_FAILED)
             return False
 
         # receive request msg.  If it fails we simply terminate the thread;
@@ -1079,7 +1079,7 @@ class XfroutServer:
             zone_name = args.get('zone_name')
             zone_class = args.get('zone_class')
             if not zone_class:
-                zone_class = str(RRClass.IN())
+                zone_class = str(RRClass.IN)
             if zone_name:
                 logger.info(XFROUT_NOTIFY_COMMAND, zone_name, zone_class)
                 if self.send_notify(zone_name, zone_class):
@@ -1139,7 +1139,7 @@ if '__main__' == __name__:
         xfrout_server = XfroutServer()
         xfrout_server.run()
     except KeyboardInterrupt:
-        logger.INFO(XFROUT_STOPPED_BY_KEYBOARD)
+        logger.info(XFROUT_STOPPED_BY_KEYBOARD)
     except SessionError as e:
         logger.error(XFROUT_CC_SESSION_ERROR, str(e))
     except ModuleCCSessionError as e:
@@ -1152,3 +1152,4 @@ if '__main__' == __name__:
     if xfrout_server:
         xfrout_server.shutdown()
 
+    logger.info(XFROUT_EXITING)
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index 311a5f9..d49981d 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -32,6 +32,9 @@ configuration manager b10-cfgmgr is not running.
 The xfrout process encountered an error when installing the configuration at
 startup time.  Details of the error are included in the log message.
 
+% XFROUT_EXITING exiting
+The xfrout daemon is exiting.
+
 % XFROUT_FETCH_REQUEST_ERROR socket error while fetching a request from the auth daemon
 There was a socket error while contacting the b10-auth daemon to
 fetch a transfer request. The auth daemon may have shutdown.
@@ -152,7 +155,7 @@ statistics data should be sent to the stats daemon.
 The xfrout daemon received a shutdown command from the command channel
 and will now shut down.
 
-% XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR error receiving the file descriptor for an XFR connection
+% XFROUT_RECEIVE_FD_FAILED error receiving the file descriptor for an XFR connection
 There was an error receiving the file descriptor for the transfer
 request from b10-auth.  There can be several reasons for this, but
 the most likely cause is that b10-auth terminates for some reason
diff --git a/src/bin/zonemgr/b10-zonemgr.xml b/src/bin/zonemgr/b10-zonemgr.xml
index f859d23..1cb87ff 100644
--- a/src/bin/zonemgr/b10-zonemgr.xml
+++ b/src/bin/zonemgr/b10-zonemgr.xml
@@ -55,8 +55,8 @@
       as the BIND 10 secondary manager, keeps track of timers
       and other information necessary for BIND 10 to act as a DNS slave.
       Normally it is started by the
-      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      boss process.
+      <citerefentry><refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      process.
     </para>
 
     <para>
@@ -74,7 +74,7 @@
 
 <!--
 
-            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param) 
+            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param)
             self._clear_zone_notifier_master(zone_name_class)
         # Send refresh command to xfrin module
         else:
@@ -188,7 +188,7 @@
       <command>shutdown</command> exits <command>b10-zonemgr</command>.
       This has an optional <varname>pid</varname> argument to
       select the process ID to stop.
-      (Note that the BIND 10 boss process may restart this service
+      (Note that the b10-init process may restart this service
       if configured.)
     </para>
 
@@ -243,6 +243,9 @@
         <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-init</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
diff --git a/src/bin/zonemgr/tests/zonemgr_test.py b/src/bin/zonemgr/tests/zonemgr_test.py
index 42ed679..81c5392 100644
--- a/src/bin/zonemgr/tests/zonemgr_test.py
+++ b/src/bin/zonemgr/tests/zonemgr_test.py
@@ -41,23 +41,16 @@ TEST_SQLITE3_DBFILE = os.getenv("TESTDATAOBJDIR") + '/initdb.file'
 class ZonemgrTestException(Exception):
     pass
 
-class MySession():
-    def __init__(self):
-        pass
-
-    def group_sendmsg(self, msg, module_name):
-        if module_name not in ("Auth", "Xfrin"):
-            raise ZonemgrTestException("module name not exist")
-
-    def group_recvmsg(self, nonblock, seq):
-        return None, None
-
 class FakeCCSession(isc.config.ConfigData, MockModuleCCSession):
     def __init__(self):
         module_spec = isc.config.module_spec_from_file(SPECFILE_LOCATION)
         ConfigData.__init__(self, module_spec)
         MockModuleCCSession.__init__(self)
 
+    def rpc_call(self, command, module, instance="*", to="*", params=None):
+        if module not in ("Auth", "Xfrin"):
+            raise ZonemgrTestException("module name not exist")
+
     def get_remote_config_value(self, module_name, identifier):
         if module_name == "Auth" and identifier == "database_file":
             return TEST_SQLITE3_DBFILE, False
@@ -84,8 +77,8 @@ class MyZonemgrRefresh(ZonemgrRefresh):
                 return None
         sqlite3_ds.get_zone_soa = get_zone_soa
 
-        ZonemgrRefresh.__init__(self, MySession(), TEST_SQLITE3_DBFILE,
-                                self._slave_socket, FakeCCSession())
+        ZonemgrRefresh.__init__(self, TEST_SQLITE3_DBFILE, self._slave_socket,
+                                FakeCCSession())
         current_time = time.time()
         self._zonemgr_refresh_info = {
          ('example.net.', 'IN'): {
@@ -619,7 +612,6 @@ class MyZonemgr(Zonemgr):
         self._db_file = TEST_SQLITE3_DBFILE
         self._zone_refresh = None
         self._shutdown_event = threading.Event()
-        self._cc = MySession()
         self._module_cc = FakeCCSession()
         self._config_data = {
                     "lowerbound_refresh" : 10,
@@ -664,8 +656,8 @@ class TestZonemgr(unittest.TestCase):
         self.zonemgr.config_handler(config_data3)
         self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
         # The zone doesn't exist in database, simply skip loading soa for it and log an warning
-        self.zonemgr._zone_refresh = ZonemgrRefresh(None, TEST_SQLITE3_DBFILE,
-                                                    None, FakeCCSession())
+        self.zonemgr._zone_refresh = ZonemgrRefresh(TEST_SQLITE3_DBFILE, None,
+                                                    FakeCCSession())
         config_data1["secondary_zones"] = [{"name": "nonexistent.example",
                                             "class": "IN"}]
         self.assertEqual(self.zonemgr.config_handler(config_data1),
diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in
index 0412e3f..59900c4 100755
--- a/src/bin/zonemgr/zonemgr.py.in
+++ b/src/bin/zonemgr/zonemgr.py.in
@@ -103,8 +103,8 @@ class ZonemgrRefresh:
     can be stopped by calling shutdown() in another thread.
     """
 
-    def __init__(self, cc, db_file, slave_socket, module_cc_session):
-        self._cc = cc
+    def __init__(self, db_file, slave_socket, module_cc_session):
+        self._mccs = module_cc_session
         self._check_sock = slave_socket
         self._db_file = db_file
         self._zonemgr_refresh_info = {}
@@ -277,15 +277,15 @@ class ZonemgrRefresh:
 
     def _send_command(self, module_name, command_name, params):
         """Send command between modules."""
-        msg = create_command(command_name, params)
         try:
-            seq = self._cc.group_sendmsg(msg, module_name)
-            try:
-                answer, env = self._cc.group_recvmsg(False, seq)
-            except isc.cc.session.SessionTimeout:
-                pass        # for now we just ignore the failure
+            self._mccs.rpc_call(command_name, module_name, params=params)
         except socket.error:
+            # FIXME: WTF? Where does socket.error come from? And how do we ever
+            # dare ignore such serious error? It can only be broken link to
+            # msgq, we need to terminate then.
             logger.error(ZONEMGR_SEND_FAIL, module_name)
+        except (isc.cc.session.SessionTimeout, isc.config.RPCError):
+            pass        # for now we just ignore the failure
 
     def _find_need_do_refresh_zone(self):
         """Find the first zone need do refresh, if no zone need
@@ -525,7 +525,7 @@ class Zonemgr:
         self._db_file = self.get_db_file()
         # Create socket pair for communicating between main thread and zonemgr timer thread
         self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
-        self._zone_refresh = ZonemgrRefresh(self._cc, self._db_file, self._slave_socket, self._module_cc)
+        self._zone_refresh = ZonemgrRefresh(self._db_file, self._slave_socket, self._module_cc)
         self._zone_refresh.run_timer()
 
         self._lock = threading.Lock()
@@ -536,7 +536,6 @@ class Zonemgr:
         """Setup two sessions for zonemgr, one(self._module_cc) is used for receiving
         commands and config data sent from other modules, another one (self._cc)
         is used to send commands to proper modules."""
-        self._cc = isc.cc.Session()
         self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                                   self.config_handler,
                                                   self.command_handler)
@@ -625,7 +624,7 @@ class Zonemgr:
         ZONE_NOTIFY_COMMAND is issued by Auth process;
         ZONE_NEW_DATA_READY_CMD and ZONE_XFRIN_FAILED are issued by
         Xfrin process;
-        shutdown is issued by a user or Boss process. """
+        shutdown is issued by a user or Init process. """
         answer = create_answer(0)
         if command == ZONE_NOTIFY_COMMAND:
             """ Handle Auth notify command"""
@@ -714,4 +713,4 @@ if '__main__' == __name__:
     if zonemgrd and zonemgrd.running:
         zonemgrd.shutdown()
 
-    logger.debug(DBG_START_SHUT, ZONEMGR_SHUTDOWN)
+    logger.info(ZONEMGR_SHUTDOWN)
diff --git a/src/bin/zonemgr/zonemgr_messages.mes b/src/bin/zonemgr/zonemgr_messages.mes
index 4f58271..f67b5b9 100644
--- a/src/bin/zonemgr/zonemgr_messages.mes
+++ b/src/bin/zonemgr/zonemgr_messages.mes
@@ -69,7 +69,7 @@ new data.
 
 % ZONEMGR_RECEIVE_SHUTDOWN received SHUTDOWN command
 This is a debug message indicating that the zone manager has received
-a SHUTDOWN command over the command channel from the Boss process.
+a SHUTDOWN command over the command channel from the Init process.
 It will act on this command and shut down.
 
 % ZONEMGR_RECEIVE_UNKNOWN received unknown command '%1'
@@ -114,7 +114,7 @@ connecting to the command channel daemon.  The most usual cause of this
 problem is that the daemon is not running.
 
 % ZONEMGR_SHUTDOWN zone manager has shut down
-A debug message, output when the zone manager has shut down completely.
+The zone manager has shut down completely.
 
 % ZONEMGR_STARTED zonemgr started
 This informational message is output by zonemgr when all initialization
diff --git a/src/lib/asiodns/sync_udp_server.cc b/src/lib/asiodns/sync_udp_server.cc
index 95e1c72..c3f5348 100644
--- a/src/lib/asiodns/sync_udp_server.cc
+++ b/src/lib/asiodns/sync_udp_server.cc
@@ -44,7 +44,7 @@ SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
     output_buffer_(new isc::util::OutputBuffer(0)),
     query_(new isc::dns::Message(isc::dns::Message::PARSE)),
     answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
-    io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
+    checkin_callback_(checkin), lookup_callback_(lookup),
     answer_callback_(answer), stopped_(false)
 {
     if (af != AF_INET && af != AF_INET6) {
diff --git a/src/lib/asiodns/sync_udp_server.h b/src/lib/asiodns/sync_udp_server.h
index ddac1f9..14ec42a 100644
--- a/src/lib/asiodns/sync_udp_server.h
+++ b/src/lib/asiodns/sync_udp_server.h
@@ -118,8 +118,6 @@ private:
     isc::dns::MessagePtr query_, answer_;
     // The socket used for the communication
     std::auto_ptr<asio::ip::udp::socket> socket_;
-    // The event loop we use
-    asio::io_service& io_;
     // Place the socket puts the sender of a packet when it is received
     asio::ip::udp::endpoint sender_;
     // Callbacks
diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc
index 3442de9..397e004 100644
--- a/src/lib/asiodns/tcp_server.cc
+++ b/src/lib/asiodns/tcp_server.cc
@@ -184,7 +184,6 @@ TCPServer::operator()(asio::error_code ec, size_t length) {
         // 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).
diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h
index 46f484b..50e8717 100644
--- a/src/lib/asiodns/tcp_server.h
+++ b/src/lib/asiodns/tcp_server.h
@@ -122,7 +122,6 @@ private:
 
     // 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
diff --git a/src/lib/asiodns/udp_server.cc b/src/lib/asiodns/udp_server.cc
index bdf79a7..cf4b1c4 100644
--- a/src/lib/asiodns/udp_server.cc
+++ b/src/lib/asiodns/udp_server.cc
@@ -61,7 +61,7 @@ struct UDPServer::Data {
      */
     Data(io_service& io_service, const ip::address& addr, const uint16_t port,
         SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
-        io_(io_service), done_(false),
+        io_(io_service), bytes_(0), done_(false),
         checkin_callback_(checkin),lookup_callback_(lookup),
         answer_callback_(answer)
     {
@@ -77,7 +77,7 @@ struct UDPServer::Data {
     }
     Data(io_service& io_service, int fd, int af, SimpleCallback* checkin,
          DNSLookup* lookup, DNSAnswer* answer) :
-         io_(io_service), done_(false),
+         io_(io_service), bytes_(0), done_(false),
          checkin_callback_(checkin),lookup_callback_(lookup),
          answer_callback_(answer)
     {
@@ -104,7 +104,7 @@ struct UDPServer::Data {
      * We also allocate data for receiving the packet here.
      */
     Data(const Data& other) :
-        io_(other.io_), socket_(other.socket_), done_(false),
+        io_(other.io_), socket_(other.socket_), bytes_(0), done_(false),
         checkin_callback_(other.checkin_callback_),
         lookup_callback_(other.lookup_callback_),
         answer_callback_(other.answer_callback_)
@@ -168,7 +168,6 @@ struct UDPServer::Data {
     size_t bytes_;
     bool done_;
 
-
     // Callback functions provided by the caller
     const SimpleCallback* checkin_callback_;
     const DNSLookup* lookup_callback_;
diff --git a/src/lib/asiolink/tests/tcp_socket_unittest.cc b/src/lib/asiolink/tests/tcp_socket_unittest.cc
index 538cf48..20b6cd8 100644
--- a/src/lib/asiolink/tests/tcp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_socket_unittest.cc
@@ -82,7 +82,7 @@ public:
     struct PrivateData {
         PrivateData() :
             error_code_(), length_(0), cumulative_(0), expected_(0), offset_(0),
-            name_(""), queued_(NONE), called_(NONE)
+            name_(""), queued_(NONE), called_(NONE), data_(MIN_SIZE, 0)
         {}
 
         asio::error_code    error_code_;    ///< Completion error code
@@ -93,8 +93,7 @@ public:
         std::string         name_;          ///< Which of the objects this is
         Operation           queued_;        ///< Queued operation
         Operation           called_;        ///< Which callback called
-        uint8_t             data_[MIN_SIZE];  ///< Receive buffer
-
+        std::vector<uint8_t> data_;  ///< Receive buffer
     };
 
     /// \brief Constructor
@@ -169,7 +168,7 @@ public:
 
     /// \brief Get data member
     uint8_t* data() {
-        return (ptr_->data_);
+        return (&ptr_->data_[0]);
     }
 
     /// \brief Get flag to say what was queued
diff --git a/src/lib/cache/local_zone_data.h b/src/lib/cache/local_zone_data.h
index 4bfdb94..fd76a1b 100644
--- a/src/lib/cache/local_zone_data.h
+++ b/src/lib/cache/local_zone_data.h
@@ -29,8 +29,12 @@ namespace cache {
 /// in the zone.
 class LocalZoneData {
 public:
-    LocalZoneData(uint16_t rrset_class) : class_(rrset_class)
-    {}
+    /// \brief Constructor.
+    ///
+    /// The passed parameter is expected to be an RR class value, but is not
+    /// currently unused.  And this library will be quite likely to
+    /// deprecated anyway, so we don't touch it heavily.
+    LocalZoneData(uint16_t) {}
 
     /// \brief Look up one rrset.
     ///
@@ -51,7 +55,6 @@ public:
 
 private:
     std::map<std::string, isc::dns::RRsetPtr> rrsets_map_; // RRsets of the zone
-    uint16_t class_; // The class of the zone
 };
 
 typedef boost::shared_ptr<LocalZoneData> LocalZoneDataPtr;
diff --git a/src/lib/cc/.gitignore b/src/lib/cc/.gitignore
index cb2800f..d1e56df 100644
--- a/src/lib/cc/.gitignore
+++ b/src/lib/cc/.gitignore
@@ -1,4 +1,5 @@
 /cc_messages.cc
 /cc_messages.h
+/proto_defs.h
 /session_config.h
 /session_config.h.pre
diff --git a/src/lib/cc/Makefile.am b/src/lib/cc/Makefile.am
index ec478de..06e9309 100644
--- a/src/lib/cc/Makefile.am
+++ b/src/lib/cc/Makefile.am
@@ -24,9 +24,12 @@ lib_LTLIBRARIES = libb10-cc.la
 libb10_cc_la_SOURCES = data.cc data.h session.cc session.h
 libb10_cc_la_SOURCES += logger.cc logger.h
 nodist_libb10_cc_la_SOURCES = cc_messages.cc cc_messages.h
+libb10_cc_la_SOURCES += proto_defs.cc
+nodist_libb10_cc_la_SOURCES += proto_defs.h
 libb10_cc_la_LIBADD = $(top_builddir)/src/lib/log/libb10-log.la
 
-CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h
+CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h \
+	proto_defs.h
 
 session_config.h: session_config.h.pre
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" session_config.h.pre >$@
@@ -34,6 +37,9 @@ session_config.h: session_config.h.pre
 cc_messages.cc cc_messages.h: cc_messages.mes
 	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/cc/cc_messages.mes
 
-BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h
+BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h proto_defs.h
+
+proto_defs.h: $(top_srcdir)/src/lib/util/python/const2hdr.py proto_defs.cc
+	$(PYTHON) $(top_srcdir)/src/lib/util/python/const2hdr.py $(srcdir)/proto_defs.cc $@
 
 EXTRA_DIST = cc_messages.mes
diff --git a/src/lib/cc/cc_messages.mes b/src/lib/cc/cc_messages.mes
index 94b955a..b561784 100644
--- a/src/lib/cc/cc_messages.mes
+++ b/src/lib/cc/cc_messages.mes
@@ -60,6 +60,10 @@ and its length (2 bytes) is counted in the total length.
 There should be data representing the length of message on the socket, but it
 is not there.
 
+% CC_LNAME_RECEIVED received local name: %1
+Debug message: the local module received its unique identifier (name)
+from msgq on completion of establishing the session with msgq.
+
 % CC_NO_MESSAGE no message ready to be received yet
 The program polled for incoming messages, but there was no message waiting.
 This is a debug message which may happen only after CC_GROUP_RECEIVE.
diff --git a/src/lib/cc/data.cc b/src/lib/cc/data.cc
index 4a37087..af3602a 100644
--- a/src/lib/cc/data.cc
+++ b/src/lib/cc/data.cc
@@ -16,6 +16,7 @@
 
 #include <cc/data.h>
 
+#include <cstring>
 #include <cassert>
 #include <climits>
 #include <map>
@@ -31,7 +32,7 @@
 using namespace std;
 
 namespace {
-const char* WHITESPACE = " \b\f\n\r\t";
+const char* const WHITESPACE = " \b\f\n\r\t";
 } // end anonymous namespace
 
 namespace isc {
@@ -183,7 +184,7 @@ throwJSONError(const std::string& error, const std::string& file, int line,
 }
 
 std::ostream&
-operator<<(std::ostream &out, const Element& e) {
+operator<<(std::ostream& out, const Element& e) {
     return (out << e.str());
 }
 
@@ -240,8 +241,9 @@ Element::createMap() {
 //
 namespace {
 bool
-char_in(const char c, const char *chars) {
-    for (size_t i = 0; i < strlen(chars); ++i) {
+charIn(const int c, const char* chars) {
+    const size_t chars_len = std::strlen(chars);
+    for (size_t i = 0; i < chars_len; ++i) {
         if (chars[i] == c) {
             return (true);
         }
@@ -250,16 +252,16 @@ char_in(const char c, const char *chars) {
 }
 
 void
-skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
-    char c = in.peek();
-    while (char_in(c, chars) && c != EOF) {
+skipChars(std::istream& in, const char* chars, int& line, int& pos) {
+    int c = in.peek();
+    while (charIn(c, chars) && c != EOF) {
         if (c == '\n') {
             ++line;
             pos = 1;
         } else {
             ++pos;
         }
-        in.get();
+        in.ignore();
         c = in.peek();
     }
 }
@@ -270,33 +272,33 @@ skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
 //
 // the character found is left on the stream
 void
-skip_to(std::istream &in, const std::string& file, int& line,
-        int& pos, const char* chars, const char* may_skip="")
+skipTo(std::istream& in, const std::string& file, int& line,
+       int& pos, const char* chars, const char* may_skip="")
 {
-    char c = in.get();
+    int c = in.get();
     ++pos;
     while (c != EOF) {
         if (c == '\n') {
             pos = 1;
             ++line;
         }
-        if (char_in(c, may_skip)) {
+        if (charIn(c, may_skip)) {
             c = in.get();
             ++pos;
-        } else if (char_in(c, chars)) {
-            while(char_in(in.peek(), may_skip)) {
+        } else if (charIn(c, chars)) {
+            while (charIn(in.peek(), may_skip)) {
                 if (in.peek() == '\n') {
                     pos = 1;
                     ++line;
                 }
-                in.get();
+                in.ignore();
                 ++pos;
             }
             in.putback(c);
             --pos;
             return;
         } else {
-            throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
+            throwJSONError(std::string("'") + std::string(1, c) + "' read, one of \"" + chars + "\" expected", file, line, pos);
         }
     }
     throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
@@ -305,12 +307,11 @@ skip_to(std::istream &in, const std::string& file, int& line,
 // TODO: Should we check for all other official escapes here (and
 // error on the rest)?
 std::string
-str_from_stringstream(std::istream &in, const std::string& file, const int line,
-                      int& pos) throw (JSONError)
+strFromStringstream(std::istream& in, const std::string& file,
+                    const int line, int& pos) throw (JSONError)
 {
-    char c;
     std::stringstream ss;
-    c = in.get();
+    int c = in.get();
     ++pos;
     if (c == '"') {
         c = in.get();
@@ -351,10 +352,10 @@ str_from_stringstream(std::istream &in, const std::string& file, const int line,
                 throwJSONError("Bad escape", file, line, pos);
             }
             // drop the escaped char
-            in.get();
+            in.ignore();
             ++pos;
         }
-        ss << c;
+        ss.put(c);
         c = in.get();
         ++pos;
     }
@@ -365,7 +366,7 @@ str_from_stringstream(std::istream &in, const std::string& file, const int line,
 }
 
 std::string
-word_from_stringstream(std::istream &in, int& pos) {
+wordFromStringstream(std::istream& in, int& pos) {
     std::stringstream ss;
     while (isalpha(in.peek())) {
         ss << (char) in.get();
@@ -374,8 +375,8 @@ word_from_stringstream(std::istream &in, int& pos) {
     return (ss.str());
 }
 
-static std::string
-number_from_stringstream(std::istream &in, int& pos) {
+std::string
+numberFromStringstream(std::istream& in, int& pos) {
     std::stringstream ss;
     while (isdigit(in.peek()) || in.peek() == '+' || in.peek() == '-' ||
            in.peek() == '.' || in.peek() == 'e' || in.peek() == 'E') {
@@ -389,13 +390,13 @@ number_from_stringstream(std::istream &in, int& pos) {
 // that can also hold an e value? (and have specific getters if the
 // value is larger than an int can handle)
 ElementPtr
-from_stringstream_number(std::istream &in, int &pos) {
+fromStringstreamNumber(std::istream& in, int& pos) {
     long int i;
     double d = 0.0;
     bool is_double = false;
-    char *endptr;
+    char* endptr;
 
-    std::string number = number_from_stringstream(in, pos);
+    std::string number = numberFromStringstream(in, pos);
 
     i = strtol(number.c_str(), &endptr, 10);
     if (*endptr != '\0') {
@@ -422,10 +423,10 @@ from_stringstream_number(std::istream &in, int &pos) {
 }
 
 ElementPtr
-from_stringstream_bool(std::istream &in, const std::string& file,
-                       const int line, int& pos)
+fromStringstreamBool(std::istream& in, const std::string& file,
+                     const int line, int& pos)
 {
-    const std::string word = word_from_stringstream(in, pos);
+    const std::string word = wordFromStringstream(in, pos);
     if (boost::iequals(word, "True")) {
         return (Element::create(true));
     } else if (boost::iequals(word, "False")) {
@@ -438,10 +439,10 @@ from_stringstream_bool(std::istream &in, const std::string& file,
 }
 
 ElementPtr
-from_stringstream_null(std::istream &in, const std::string& file,
-                       const int line, int& pos)
+fromStringstreamNull(std::istream& in, const std::string& file,
+                     const int line, int& pos)
 {
-    const std::string word = word_from_stringstream(in, pos);
+    const std::string word = wordFromStringstream(in, pos);
     if (boost::iequals(word, "null")) {
         return (Element::create());
     } else {
@@ -451,26 +452,26 @@ from_stringstream_null(std::istream &in, const std::string& file,
 }
 
 ElementPtr
-from_stringstream_string(std::istream& in, const std::string& file, int& line,
-                         int& pos)
+fromStringstreamString(std::istream& in, const std::string& file, int& line,
+                       int& pos)
 {
-    return (Element::create(str_from_stringstream(in, file, line, pos)));
+    return (Element::create(strFromStringstream(in, file, line, pos)));
 }
 
 ElementPtr
-from_stringstream_list(std::istream &in, const std::string& file, int& line,
-                       int& pos)
+fromStringstreamList(std::istream& in, const std::string& file, int& line,
+                     int& pos)
 {
-    char c = 0;
+    int c = 0;
     ElementPtr list = Element::createList();
     ConstElementPtr cur_list_element;
 
-    skip_chars(in, WHITESPACE, line, pos);
+    skipChars(in, WHITESPACE, line, pos);
     while (c != EOF && c != ']') {
         if (in.peek() != ']') {
             cur_list_element = Element::fromJSON(in, file, line, pos);
             list->add(cur_list_element);
-            skip_to(in, file, line, pos, ",]", WHITESPACE);
+            skipTo(in, file, line, pos, ",]", WHITESPACE);
         }
         c = in.get();
         pos++;
@@ -479,37 +480,37 @@ from_stringstream_list(std::istream &in, const std::string& file, int& line,
 }
 
 ElementPtr
-from_stringstream_map(std::istream &in, const std::string& file, int& line,
-                      int& pos)
+fromStringstreamMap(std::istream& in, const std::string& file, int& line,
+                    int& pos)
 {
     ElementPtr map = Element::createMap();
-    skip_chars(in, WHITESPACE, line, pos);
-    char c = in.peek();
+    skipChars(in, WHITESPACE, line, pos);
+    int c = in.peek();
     if (c == EOF) {
         throwJSONError(std::string("Unterminated map, <string> or } expected"), file, line, pos);
     } else if (c == '}') {
         // empty map, skip closing curly
-        c = in.get();
+        in.ignore();
     } else {
         while (c != EOF && c != '}') {
-            std::string key = str_from_stringstream(in, file, line, pos);
+            std::string key = strFromStringstream(in, file, line, pos);
 
-            skip_to(in, file, line, pos, ":", WHITESPACE);
+            skipTo(in, file, line, pos, ":", WHITESPACE);
             // skip the :
-            in.get();
+            in.ignore();
             pos++;
 
             ConstElementPtr value = Element::fromJSON(in, file, line, pos);
             map->set(key, value);
 
-            skip_to(in, file, line, pos, ",}", WHITESPACE);
+            skipTo(in, file, line, pos, ",}", WHITESPACE);
             c = in.get();
             pos++;
         }
     }
     return (map);
 }
-}
+} // unnamed namespace
 
 std::string
 Element::typeToName(Element::types type) {
@@ -575,13 +576,13 @@ Element::fromJSON(std::istream& in, const std::string& file_name)
 }
 
 ElementPtr
-Element::fromJSON(std::istream &in, const std::string& file, int& line,
+Element::fromJSON(std::istream& in, const std::string& file, int& line,
                   int& pos) throw(JSONError)
 {
-    char c = 0;
+    int c = 0;
     ElementPtr element;
     bool el_read = false;
-    skip_chars(in, WHITESPACE, line, pos);
+    skipChars(in, WHITESPACE, line, pos);
     while (c != EOF && !el_read) {
         c = in.get();
         pos++;
@@ -600,7 +601,7 @@ Element::fromJSON(std::istream &in, const std::string& file, int& line,
             case '+':
             case '.':
                 in.putback(c);
-                element = from_stringstream_number(in, pos);
+                element = fromStringstreamNumber(in, pos);
                 el_read = true;
                 break;
             case 't':
@@ -608,32 +609,32 @@ Element::fromJSON(std::istream &in, const std::string& file, int& line,
             case 'f':
             case 'F':
                 in.putback(c);
-                element = from_stringstream_bool(in, file, line, pos);
+                element = fromStringstreamBool(in, file, line, pos);
                 el_read = true;
                 break;
             case 'n':
             case 'N':
                 in.putback(c);
-                element = from_stringstream_null(in, file, line, pos);
+                element = fromStringstreamNull(in, file, line, pos);
                 el_read = true;
                 break;
             case '"':
                 in.putback('"');
-                element = from_stringstream_string(in, file, line, pos);
+                element = fromStringstreamString(in, file, line, pos);
                 el_read = true;
                 break;
             case '[':
-                element = from_stringstream_list(in, file, line, pos);
+                element = fromStringstreamList(in, file, line, pos);
                 el_read = true;
                 break;
             case '{':
-                element = from_stringstream_map(in, file, line, pos);
+                element = fromStringstreamMap(in, file, line, pos);
                 el_read = true;
                 break;
             case EOF:
                 break;
             default:
-                throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
+                throwJSONError(std::string("error: unexpected character ") + std::string(1, c), file, line, pos);
                 break;
         }
     }
@@ -645,12 +646,12 @@ Element::fromJSON(std::istream &in, const std::string& file, int& line,
 }
 
 ElementPtr
-Element::fromJSON(const std::string &in) {
+Element::fromJSON(const std::string& in) {
     std::stringstream ss;
     ss << in;
     int line = 1, pos = 1;
     ElementPtr result(fromJSON(ss, "<string>", line, pos));
-    skip_chars(ss, WHITESPACE, line, pos);
+    skipChars(ss, WHITESPACE, line, pos);
     // ss must now be at end
     if (ss.peek() != EOF) {
         throwJSONError("Extra data", "<string>", line, pos);
diff --git a/src/lib/cc/proto_defs.cc b/src/lib/cc/proto_defs.cc
new file mode 100644
index 0000000..5eb8575
--- /dev/null
+++ b/src/lib/cc/proto_defs.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2013  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 <cc/proto_defs.h>
+
+namespace isc {
+namespace cc {
+
+// Aside from defining the values for the C++ library, this file is also
+// used as direct input of the generator of the python counterpart. Please,
+// keep the syntax here simple and check the generated file
+// (lib/python/isc/cc/proto_defs.py) is correct and sane.
+
+// The constants used in the CC protocol
+// First the header names
+const char* const CC_HEADER_TYPE = "type";
+const char* const CC_HEADER_FROM = "from";
+const char* const CC_HEADER_TO = "to";
+const char* const CC_HEADER_GROUP = "group";
+const char* const CC_HEADER_INSTANCE = "instance";
+const char* const CC_HEADER_SEQ = "seq";
+const char* const CC_HEADER_WANT_ANSWER = "want_answer";
+const char* const CC_HEADER_REPLY = "reply";
+// The commands in the "type" header
+const char* const CC_COMMAND_SEND = "send";
+// The wildcards of some headers
+const char* const CC_TO_WILDCARD = "*";
+const char* const CC_INSTANCE_WILDCARD = "*";
+// Reply codes
+const int CC_REPLY_SUCCESS = 0;
+const int CC_REPLY_NO_RECPT = -1;
+
+}
+}
diff --git a/src/lib/cc/session.cc b/src/lib/cc/session.cc
index 4455b68..da78bd4 100644
--- a/src/lib/cc/session.cc
+++ b/src/lib/cc/session.cc
@@ -30,6 +30,9 @@
 #include <asio/deadline_timer.hpp>
 #include <asio/system_error.hpp>
 
+#include <cc/data.h>
+#include <cc/session.h>
+
 #include <cstdio>
 #include <vector>
 #include <iostream>
@@ -44,9 +47,6 @@
 
 #include <exceptions/exceptions.h>
 
-#include <cc/data.h>
-#include <cc/session.h>
-
 using namespace std;
 using namespace isc::cc;
 using namespace isc::data;
@@ -333,6 +333,7 @@ Session::establish(const char* socket_file) {
     recvmsg(routing, msg, false);
 
     impl_->lname_ = msg->get("lname")->stringValue();
+    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_LNAME_RECEIVED).arg(impl_->lname_);
 
     // At this point there's no risk of resource leak.
     session_holder.clear();
@@ -343,8 +344,8 @@ Session::establish(const char* socket_file) {
 // prefix.
 //
 void
-Session::sendmsg(ConstElementPtr msg) {
-    std::string header_wire = msg->toWire();
+Session::sendmsg(ConstElementPtr header) {
+    std::string header_wire = header->toWire();
     unsigned int length = 2 + header_wire.length();
     unsigned int length_net = htonl(length);
     unsigned short header_length = header_wire.length();
@@ -356,9 +357,9 @@ Session::sendmsg(ConstElementPtr msg) {
 }
 
 void
-Session::sendmsg(ConstElementPtr env, ConstElementPtr msg) {
-    std::string header_wire = env->toWire();
-    std::string body_wire = msg->toWire();
+Session::sendmsg(ConstElementPtr header, ConstElementPtr payload) {
+    std::string header_wire = header->toWire();
+    std::string body_wire = payload->toWire();
     unsigned int length = 2 + header_wire.length() + body_wire.length();
     unsigned int length_net = htonl(length);
     unsigned short header_length = header_wire.length();
@@ -473,20 +474,21 @@ Session::unsubscribe(std::string group, std::string instance) {
 
 int
 Session::group_sendmsg(ConstElementPtr msg, std::string group,
-                       std::string instance, std::string to)
+                       std::string instance, std::string to, bool want_answer)
 {
     LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_SEND).arg(msg->str()).
         arg(group);
     ElementPtr env = Element::createMap();
-    long int nseq = ++impl_->sequence_;
-    
-    env->set("type", Element::create("send"));
-    env->set("from", Element::create(impl_->lname_));
-    env->set("to", Element::create(to));
-    env->set("group", Element::create(group));
-    env->set("instance", Element::create(instance));
-    env->set("seq", Element::create(nseq));
-    //env->set("msg", Element::create(msg->toWire()));
+    const long int nseq = ++impl_->sequence_;
+
+    env->set(CC_HEADER_TYPE,
+             Element::create(CC_COMMAND_SEND));
+    env->set(CC_HEADER_FROM, Element::create(impl_->lname_));
+    env->set(CC_HEADER_TO, Element::create(to));
+    env->set(CC_HEADER_GROUP, Element::create(group));
+    env->set(CC_HEADER_INSTANCE, Element::create(instance));
+    env->set(CC_HEADER_SEQ, Element::create(nseq));
+    env->set(CC_HEADER_WANT_ANSWER, Element::create(want_answer));
 
     sendmsg(env, msg);
     return (nseq);
@@ -513,7 +515,7 @@ Session::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
         arg(newmsg->str());
     ElementPtr env = Element::createMap();
     long int nseq = ++impl_->sequence_;
-    
+
     env->set("type", Element::create("send"));
     env->set("from", Element::create(impl_->lname_));
     env->set("to", Element::create(envelope->get("from")->stringValue()));
diff --git a/src/lib/cc/session.h b/src/lib/cc/session.h
index a818291..63bb41c 100644
--- a/src/lib/cc/session.h
+++ b/src/lib/cc/session.h
@@ -15,14 +15,15 @@
 #ifndef ISC_SESSION_H
 #define ISC_SESSION_H 1
 
-#include <string>
-
-#include <boost/function.hpp>
+#include <cc/data.h>
+#include <cc/session_config.h>
+#include <cc/proto_defs.h>
 
 #include <exceptions/exceptions.h>
 
-#include <cc/data.h>
-#include <cc/session_config.h>
+#include <string>
+
+#include <boost/function.hpp>
 
 namespace asio {
 class io_service;
@@ -81,8 +82,10 @@ namespace isc {
             virtual void disconnect() = 0;
             virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                                       std::string group,
-                                      std::string instance = "*",
-                                      std::string to = "*") = 0;
+                                      std::string instance =
+                                          CC_INSTANCE_WILDCARD,
+                                      std::string to = CC_TO_WILDCARD,
+                                      bool want_answer = false) = 0;
             virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
                                        isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
@@ -128,10 +131,26 @@ namespace isc {
                                    std::string instance = "*");
             virtual void unsubscribe(std::string group,
                              std::string instance = "*");
+
+            /// \brief Send a message to a group.
+            ///
+            /// \todo Can someone explain how the group, instance and to work?
+            ///     What is the desired semantics here?
+            /// \param msg The message to send.
+            /// \param group Part of addressing.
+            /// \param instance Part of addressing.
+            /// \param to Part of addressing.
+            /// \param want_answer Require an answer? If it is true and there's
+            ///     no recipient, the message queue answers by an error
+            ///     instead.
+            /// \return The squence number of the message sent. It can be used
+            ///     to wait for an answer by group_recvmsg.
             virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                                       std::string group,
                                       std::string instance = "*",
-                                      std::string to = "*");
+                                      std::string to = "*",
+                                      bool want_answer = false);
+
             virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
                                        isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
@@ -147,9 +166,14 @@ namespace isc {
             /// @param returns socket descriptor used for session connection
             virtual int getSocketDesc() const;
     private:
-            void sendmsg(isc::data::ConstElementPtr msg);
-            void sendmsg(isc::data::ConstElementPtr env,
-                         isc::data::ConstElementPtr msg);
+            // The following two methods are virtual to allow tests steal and
+            // replace them. It is not expected to be specialized by a derived
+            // class. Actually, it is not expected to inherit from this class
+            // to begin with.
+            virtual void sendmsg(isc::data::ConstElementPtr header);
+            virtual void sendmsg(isc::data::ConstElementPtr header,
+                                 isc::data::ConstElementPtr payload);
+
             bool recvmsg(isc::data::ConstElementPtr& msg,
                          bool nonblock = true,
                          int seq = -1);
diff --git a/src/lib/cc/tests/data_unittests.cc b/src/lib/cc/tests/data_unittests.cc
index 1565418..9f015d2 100644
--- a/src/lib/cc/tests/data_unittests.cc
+++ b/src/lib/cc/tests/data_unittests.cc
@@ -91,6 +91,10 @@ TEST(Element, from_and_to_json) {
     sv.push_back("-1");
     sv.push_back("-1.234");
     sv.push_back("-123.456");
+    // We should confirm that our string handling is 8-bit clean.
+    // At one point we were using char-length data and comparing to EOF,
+    // which means that character '\xFF' would not parse properly.
+    sv.push_back("\"\xFF\"");
 
     BOOST_FOREACH(const std::string& s, sv) {
         // test << operator, which uses Element::str()
diff --git a/src/lib/cc/tests/session_unittests.cc b/src/lib/cc/tests/session_unittests.cc
index 528dda9..fc6e538 100644
--- a/src/lib/cc/tests/session_unittests.cc
+++ b/src/lib/cc/tests/session_unittests.cc
@@ -19,16 +19,28 @@
 // XXX: the ASIO header must be included before others.  See session.cc.
 #include <asio.hpp>
 
+#include <cc/session.h>
+#include <cc/data.h>
+#include <cc/tests/session_unittests_config.h>
+
 #include <gtest/gtest.h>
 #include <boost/bind.hpp>
 
 #include <exceptions/exceptions.h>
 
-#include <cc/session.h>
-#include <cc/data.h>
-#include <session_unittests_config.h>
+#include <utility>
+#include <list>
+#include <string>
+#include <iostream>
 
 using namespace isc::cc;
+using std::pair;
+using std::list;
+using std::string;
+using isc::data::ConstElementPtr;
+using isc::data::Element;
+
+namespace {
 
 TEST(AsioSession, establish) {
     asio::io_service io_service_;
@@ -50,7 +62,6 @@ TEST(AsioSession, establish) {
                        "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
                   ), isc::cc::SessionError
     );
-                  
 }
 
 // This class sets up a domain socket for the session to connect to
@@ -70,18 +81,16 @@ public:
                                boost::bind(&TestDomainSocket::acceptHandler,
                                            this, _1));
     }
-    
+
     ~TestDomainSocket() {
         socket_.close();
         unlink(BIND10_TEST_SOCKET_FILE);
     }
 
-    void
-    acceptHandler(const asio::error_code&) const {
+    void acceptHandler(const asio::error_code&) const {
     }
 
-    void
-    sendmsg(isc::data::ElementPtr& env, isc::data::ElementPtr& msg) {
+    void sendmsg(isc::data::ElementPtr& env, isc::data::ElementPtr& msg) {
         const std::string header_wire = env->toWire();
         const std::string body_wire = msg->toWire();
         const unsigned int length = 2 + header_wire.length() +
@@ -89,7 +98,7 @@ public:
         const unsigned int length_net = htonl(length);
         const unsigned short header_length = header_wire.length();
         const unsigned short header_length_net = htons(header_length);
-    
+
         socket_.send(asio::buffer(&length_net, sizeof(length_net)));
         socket_.send(asio::buffer(&header_length_net,
                                   sizeof(header_length_net)));
@@ -97,8 +106,7 @@ public:
         socket_.send(asio::buffer(body_wire.data(), body_wire.length()));
     }
 
-    void
-    sendLname() {
+    void sendLname() {
         isc::data::ElementPtr lname_answer1 =
             isc::data::Element::fromJSON("{ \"type\": \"lname\" }");
         isc::data::ElementPtr lname_answer2 =
@@ -106,13 +114,12 @@ public:
         sendmsg(lname_answer1, lname_answer2);
     }
 
-    void
-    setSendLname() {
+    void setSendLname() {
         // ignore whatever data we get, send back an lname
         asio::async_read(socket_,  asio::buffer(data_buf, 0),
                          boost::bind(&TestDomainSocket::sendLname, this));
     }
-    
+
 private:
     asio::io_service& io_service_;
     asio::local::stream_protocol::endpoint ep_;
@@ -121,6 +128,38 @@ private:
     char data_buf[1024];
 };
 
+/// \brief Pair holding header and data of a message sent over the connection.
+typedef pair<ConstElementPtr, ConstElementPtr> SentMessage;
+
+// We specialize the tested class a little. We replace some low-level
+// methods so we can examine the rest without relying on real network IO
+class TestSession : public Session {
+public:
+    TestSession(asio::io_service& ioservice) :
+        Session(ioservice)
+    {}
+    // Get first message previously sent by sendmsg and remove it from the
+    // buffer. Expects there's at leas one message in the buffer.
+    SentMessage getSentMessage() {
+        assert(!sent_messages_.empty());
+        const SentMessage result(sent_messages_.front());
+        sent_messages_.pop_front();
+        return (result);
+    }
+private:
+    // Override the sendmsg. They are not sent over the real connection, but
+    // stored locally and can be extracted by getSentMessage()
+    virtual void sendmsg(ConstElementPtr header) {
+        sendmsg(header, ConstElementPtr(new isc::data::NullElement));
+    }
+    virtual void sendmsg(ConstElementPtr header, ConstElementPtr payload) {
+        sent_messages_.push_back(SentMessage(header, payload));
+    }
+
+    // The sendmsg stores data here.
+    list<SentMessage> sent_messages_;
+};
+
 class SessionTest : public ::testing::Test {
 protected:
     SessionTest() : sess(my_io_service), work(my_io_service) {
@@ -134,6 +173,26 @@ protected:
         delete tds;
     }
 
+    // Check the session sent a message with the given header. The
+    // message is hardcoded.
+    void checkSentMessage(const string& expected_hdr, const char* description)
+    {
+        SCOPED_TRACE(description);
+        const SentMessage& msg(sess.getSentMessage());
+        elementsEqual(expected_hdr, msg.first);
+        elementsEqual("{\"test\": 42}", msg.second);
+    }
+
+private:
+    // Check two elements are equal
+    void elementsEqual(const string& expected,
+                       const ConstElementPtr& actual) const
+    {
+        EXPECT_TRUE(Element::fromJSON(expected)->equals(*actual)) <<
+            "Elements differ, expected: " << expected <<
+            ", got: " << actual->toWire();
+    }
+
 public:
     // used in the handler test
     // This handler first reads (and ignores) whatever message caused
@@ -156,7 +215,7 @@ public:
 protected:
     asio::io_service my_io_service;
     TestDomainSocket* tds;
-    Session sess;
+    TestSession sess;
     // Keep run() from stopping right away by informing it it has work to do
     asio::io_service::work work;
 };
@@ -249,3 +308,57 @@ TEST_F(SessionTest, get_socket_descr) {
     // expect actual socket handle to be returned, not 0
     EXPECT_LT(0, socket);
 }
+
+// Test the group_sendmsg sends the correct data.
+TEST_F(SessionTest, group_sendmsg) {
+    // Connect (to set the lname, so we can see it sets the from)
+    tds->setSendLname();
+    sess.establish(BIND10_TEST_SOCKET_FILE);
+    // Eat the "get_lname" message, so it doesn't confuse the
+    // test below.
+    sess.getSentMessage();
+
+    const ConstElementPtr msg(Element::fromJSON("{\"test\": 42}"));
+    sess.group_sendmsg(msg, "group");
+    checkSentMessage("{"
+                     "   \"from\": \"foobar\","
+                     "   \"group\": \"group\","
+                     "   \"instance\": \"*\","
+                     "   \"seq\": 0,"
+                     "   \"to\": \"*\","
+                     "   \"type\": \"send\","
+                     "   \"want_answer\": False"
+                     "}", "No instance");
+    sess.group_sendmsg(msg, "group", "instance", "recipient");
+    checkSentMessage("{"
+                     "   \"from\": \"foobar\","
+                     "   \"group\": \"group\","
+                     "   \"instance\": \"instance\","
+                     "   \"seq\": 1,"
+                     "   \"to\": \"recipient\","
+                     "   \"type\": \"send\","
+                     "   \"want_answer\": False"
+                     "}", "With instance");
+    sess.group_sendmsg(msg, "group", "*", "*", true);
+    checkSentMessage("{"
+                     "   \"from\": \"foobar\","
+                     "   \"group\": \"group\","
+                     "   \"instance\": \"*\","
+                     "   \"seq\": 2,"
+                     "   \"to\": \"*\","
+                     "   \"type\": \"send\","
+                     "   \"want_answer\": True"
+                     "}", "Want answer");
+    sess.group_sendmsg(msg, "group", "*", "*", false);
+    checkSentMessage("{"
+                     "   \"from\": \"foobar\","
+                     "   \"group\": \"group\","
+                     "   \"instance\": \"*\","
+                     "   \"seq\": 3,"
+                     "   \"to\": \"*\","
+                     "   \"type\": \"send\","
+                     "   \"want_answer\": False"
+                     "}", "Doesn't want answer");
+}
+
+}
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 8516d6c..378f2b4 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -341,8 +341,8 @@ getRelatedLoggers(ConstElementPtr loggers) {
         const std::string cur_name = cur_logger->get("name")->stringValue();
         // If name is '*', or starts with '*.', replace * with root
         // logger name.
-        if (cur_name == "*" || cur_name.length() > 1 &&
-            cur_name[0] == '*' && cur_name[1] == '.') {
+        if (cur_name == "*" || (cur_name.length() > 1 &&
+            cur_name[0] == '*' && cur_name[1] == '.')) {
 
             // Substitute the "*" with the root name
             std::string mod_name = cur_name;
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index e07c5a3..2a5e758 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -343,6 +343,7 @@ TEST_F(CCSessionTest, checkCommand) {
     session.addMessage(el("{ \"command\": \"bad_command\" }"), "Spec29", "*");
     result = mccs.checkCommand();
     EXPECT_EQ(0, session.getMsgQueue()->size());
+    EXPECT_EQ(0, result);
 
     session.addMessage(el("{ \"command\": [ \"bad_command\" ] }"),
                        "Spec29", "*");
@@ -627,6 +628,7 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
     EXPECT_EQ(1, session.getMsgQueue()->size());
     result = mccs.checkCommand();
     EXPECT_EQ(0, session.getMsgQueue()->size());
+    EXPECT_EQ(0, result);
 }
 
 TEST_F(CCSessionTest, initializationFail) {
diff --git a/src/lib/config/tests/fake_session.cc b/src/lib/config/tests/fake_session.cc
index 157d4d6..56a30d4 100644
--- a/src/lib/config/tests/fake_session.cc
+++ b/src/lib/config/tests/fake_session.cc
@@ -183,7 +183,7 @@ FakeSession::unsubscribe(std::string group, std::string instance) {
 
 int
 FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
-                           std::string to, std::string)
+                           std::string to, std::string, bool)
 {
     if (throw_on_send_) {
         isc_throw(Exception, "Throw on send is set in FakeSession");
diff --git a/src/lib/config/tests/fake_session.h b/src/lib/config/tests/fake_session.h
index 7d3cfde..0dbaadb 100644
--- a/src/lib/config/tests/fake_session.h
+++ b/src/lib/config/tests/fake_session.h
@@ -61,7 +61,8 @@ public:
     virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                               std::string group,
                               std::string instance = "*",
-                              std::string to = "*");
+                              std::string to = "*",
+                              bool want_answer = false);
     virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
                                isc::data::ConstElementPtr& msg,
                                bool nonblock = true,
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index dc1007a..be79557 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -24,18 +24,16 @@ CLEANFILES += static.zone
 
 lib_LTLIBRARIES = libb10-datasrc.la
 libb10_datasrc_la_SOURCES = data_source.h
-libb10_datasrc_la_SOURCES += rbnode_rrset.h
-libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += exceptions.h
-libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
-libb10_datasrc_la_SOURCES += zone.h zone_finder.cc zone_finder_context.cc
+libb10_datasrc_la_SOURCES += zone.h zone_finder.h zone_finder.cc
+libb10_datasrc_la_SOURCES += zone_finder_context.cc
+libb10_datasrc_la_SOURCES += zone_iterator.h
 libb10_datasrc_la_SOURCES += result.h
 libb10_datasrc_la_SOURCES += logger.h logger.cc
-libb10_datasrc_la_SOURCES += client.h client.cc iterator.h
+libb10_datasrc_la_SOURCES += client.h client.cc
 libb10_datasrc_la_SOURCES += database.h database.cc
 libb10_datasrc_la_SOURCES += factory.h factory.cc
 libb10_datasrc_la_SOURCES += client_list.h client_list.cc
-libb10_datasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
 libb10_datasrc_la_SOURCES += master_loader_callbacks.h
 libb10_datasrc_la_SOURCES += master_loader_callbacks.cc
 libb10_datasrc_la_SOURCES += rrset_collection_base.h rrset_collection_base.cc
@@ -43,7 +41,7 @@ libb10_datasrc_la_SOURCES += zone_loader.h zone_loader.cc
 nodist_libb10_datasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 libb10_datasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
 
-pkglib_LTLIBRARIES =  sqlite3_ds.la memory_ds.la static_ds.la
+pkglib_LTLIBRARIES = sqlite3_ds.la static_ds.la
 
 sqlite3_ds_la_SOURCES = sqlite3_accessor.h sqlite3_accessor.cc
 sqlite3_ds_la_SOURCES += sqlite3_accessor_link.cc
@@ -53,12 +51,8 @@ sqlite3_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 sqlite3_ds_la_LIBADD += libb10-datasrc.la
 sqlite3_ds_la_LIBADD += $(SQLITE_LIBS)
 
-memory_ds_la_SOURCES = memory_datasrc_link.cc
-memory_ds_la_LDFLAGS = -module -avoid-version
-memory_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-memory_ds_la_LIBADD += libb10-datasrc.la
-
 static_ds_la_SOURCES = static_datasrc_link.cc
+static_ds_la_SOURCES += static_datasrc.h
 static_ds_la_LDFLAGS = -module -avoid-version
 static_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 static_ds_la_LIBADD += libb10-datasrc.la
@@ -67,7 +61,7 @@ libb10_datasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
-libb10_datasrc_la_LIBADD += $(builddir)/memory/libdatasrc_memory.la
+libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la
 libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
 
 BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
diff --git a/src/lib/datasrc/client.h b/src/lib/datasrc/client.h
index 607af05..9c5d262 100644
--- a/src/lib/datasrc/client.h
+++ b/src/lib/datasrc/client.h
@@ -21,6 +21,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 /// \file
 /// Datasource clients
@@ -66,7 +67,7 @@
 namespace isc {
 namespace datasrc {
 
-// The iterator.h is not included on purpose, most application won't need it
+// zone_iterator.h is not included on purpose, most application won't need it
 class ZoneIterator;
 typedef boost::shared_ptr<ZoneIterator> ZoneIteratorPtr;
 
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 0b010a4..f6d8252 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -18,7 +18,7 @@
 
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/rrset_collection_base.h>
 
 #include <exceptions/exceptions.h>
@@ -1385,7 +1385,7 @@ DatabaseClient::getIterator(const isc::dns::Name& name,
     return (iterator);
 }
 
-/// \brief datasrc implementation of RRsetCollectionBase.
+/// \brief Database implementation of RRsetCollectionBase.
 class RRsetCollection : public isc::datasrc::RRsetCollectionBase {
 public:
     /// \brief Constructor.
@@ -1393,26 +1393,11 @@ public:
         isc::datasrc::RRsetCollectionBase(updater, rrclass)
     {}
 
-    /// \brief Destructor
-    virtual ~RRsetCollection() {}
-
     /// \brief A wrapper around \c disable() so that it can be used as a
     /// public method. \c disable() is protected.
     void disableWrapper() {
         disable();
     }
-
-protected:
-    // TODO: RRsetCollectionBase::Iter is not implemented and the
-    // following two methods just throw.
-
-    virtual RRsetCollectionBase::IterPtr getBeginning() {
-        isc_throw(NotImplemented, "This method is not implemented.");
-    }
-
-    virtual RRsetCollectionBase::IterPtr getEnd() {
-        isc_throw(NotImplemented, "This method is not implemented.");
-    }
 };
 
 //
@@ -1454,7 +1439,7 @@ public:
 
     virtual ZoneFinder& getFinder() { return (*finder_); }
 
-    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+    virtual isc::dns::RRsetCollectionBase& getRRsetCollection() {
         if (!rrset_collection_) {
             // This is only assigned the first time and remains for the
             // lifetime of the DatabaseUpdater.
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 6ac9db0..2235df8 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -197,6 +197,16 @@ modify the database). This is what the client would do when such RRs
 were given in a DNS response according to RFC2181. The data in
 database should be checked and fixed.
 
+% DATASRC_DATABASE_JOURNALREADER_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6
+This is an error message indicating that a zone's diff is broken and
+the data source library failed to convert it to a valid RRset.  The
+most likely cause of this is that someone has manually modified the
+zone's diff in the database and inserted invalid data as a result.
+The zone's name and class, database name, and the start and end
+serials, and an additional detail of the error are shown in the
+message.  The administrator should examine the diff in the database
+to find any invalid data and fix it.
+
 % DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5
 This is a debug message indicating that the program (successfully)
 reaches the end of sequences of a zone's differences.  The zone's name
@@ -215,16 +225,6 @@ a zone's difference sequences from a database-based data source.  The
 zone's name and class, database name, and the start and end serials
 are shown in the message.
 
-% DATASRC_DATABASE_JOURNALREADER_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6
-This is an error message indicating that a zone's diff is broken and
-the data source library failed to convert it to a valid RRset.  The
-most likely cause of this is that someone has manually modified the
-zone's diff in the database and inserted invalid data as a result.
-The zone's name and class, database name, and the start and end
-serials, and an additional detail of the error are shown in the
-message.  The administrator should examine the diff in the database
-to find any invalid data and fix it.
-
 % DATASRC_DATABASE_NO_MATCH not match for %2/%3/%4 in %1
 No match (not even a wildcard) was found in the named data source for the given
 name/type/class in the data source.
@@ -350,173 +350,6 @@ There's something suspicious in the master file. This is a warning only.
 It may be a problem or it may be harmless, but it should be checked.
 This problem does not stop the zone from being loaded.
 
-% DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
-Debug information. An RRset is being added to the in-memory data source.
-
-% DATASRC_MEM_ADD_WILDCARD adding wildcards for '%1'
-This is a debug message issued during the processing of a wildcard
-name. The internal domain name tree is scanned and some nodes are
-specially marked to allow the wildcard lookup to succeed.
-
-% DATASRC_MEM_ADD_ZONE adding zone '%1/%2'
-Debug information. A zone is being added into the in-memory data source.
-
-% DATASRC_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.
-
-% DATASRC_MEM_CNAME CNAME at the domain '%1'
-Debug information. The requested domain is an alias to a different domain,
-returning the CNAME instead.
-
-% DATASRC_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 other data to CNAME.
-
-% DATASRC_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.
-
-% DATASRC_MEM_CREATE creating zone '%1' in '%2' class
-Debug information. A representation of a zone for the in-memory data source is
-being created.
-
-% DATASRC_MEM_DELEG_FOUND delegation found at '%1'
-Debug information. A delegation point was found above the requested record.
-
-% DATASRC_MEM_DESTROY destroying zone '%1' in '%2' class
-Debug information. A zone from in-memory data source is being destroyed.
-
-% DATASRC_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.
-
-% DATASRC_MEM_DNAME_FOUND DNAME found at '%1'
-Debug information. A DNAME was found instead of the requested information.
-
-% DATASRC_MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%1'
-A request was made 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) and indicates a problem with provided data.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_MEM_FIND find '%1/%2'
-Debug information. A search for the requested RRset is being started.
-
-% DATASRC_MEM_FINDNSEC3 finding NSEC3 for %1, mode %2
-Debug information. A search in an in-memory data source for NSEC3 that
-matches or covers the given name is being started.
-
-% DATASRC_MEM_FINDNSEC3_COVER found a covering NSEC3 for %1: %2
-Debug information. An NSEC3 that covers the given name is found and
-being returned.  The found NSEC3 RRset is also displayed.
-
-% DATASRC_MEM_FINDNSEC3_MATCH found a matching NSEC3 for %1 at label count %2: %3
-Debug information. An NSEC3 that matches (a possibly superdomain of)
-the given name is found and being returned.  When the shown label
-count is smaller than that of the given name, the matching NSEC3 is
-for a superdomain of the given name (see DATASRC_MEM_FINDNSEC3_TRYHASH).
-The found NSEC3 RRset is also displayed.
-
-% DATASRC_MEM_FINDNSEC3_TRYHASH looking for NSEC3 for %1 at label count %2 (hash %3)
-Debug information. In an attempt of finding an NSEC3 for the give name,
-(a possibly superdomain of) the name is hashed and searched for in the
-NSEC3 name space.  When the shown label count is smaller than that of the
-shown name, the search tries the superdomain name that share the shown
-(higher) label count of the shown name (e.g., for
-www.example.com. with shown label count of 3, example.com. is being
-tried).
-
-% DATASRC_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.
-
-% DATASRC_MEM_LOAD loading zone '%1' from file '%2'
-Debug information. The content of master file is being loaded into the memory.
-
-% DATASRC_MEM_NOT_FOUND requested domain '%1' not found
-Debug information. The requested domain does not exist.
-
-% DATASRC_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2
-The in-memory data source has loaded a zone signed with NSEC3 RRs,
-but it doesn't have a NSEC3PARAM RR at the zone origin.  It's likely that
-the zone is somehow broken, but this RR is not necessarily needed for
-handling lookups with NSEC3 in this data source, so it accepts the given
-content of the zone.  Nevertheless the administrator should look into
-the integrity of the zone data.
-
-% DATASRC_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.
-
-% DATASRC_MEM_NXRRSET no such type '%1' at '%2'
-Debug information. The domain exists, but it doesn't hold any record of the
-requested type.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_MEM_SUCCESS query for '%1/%2' successful
-Debug information. The requested record was found.
-
-% DATASRC_MEM_SUPER_STOP stopped as '%1' is superdomain of a zone node, meaning it's empty
-Debug information. The search stopped because the requested domain was
-detected to be a superdomain of some existing node of zone (while there
-was no exact match).  This means that the domain is an empty nonterminal,
-therefore it is treated  as NXRRSET case (eg. the domain exists, but it
-doesn't have the requested record type).
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
-% DATASRC_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.
-
 % DATASRC_META_ADD adding a data source into meta data source
 This is a debug message issued during startup or reconfiguration.
 Another data source is being added into the meta data source.
diff --git a/src/lib/datasrc/factory.cc b/src/lib/datasrc/factory.cc
index 82b4df9..33338db 100644
--- a/src/lib/datasrc/factory.cc
+++ b/src/lib/datasrc/factory.cc
@@ -17,7 +17,6 @@
 #include "data_source.h"
 #include "database.h"
 #include "sqlite3_accessor.h"
-#include "memory_datasrc.h"
 
 #include "datasrc_config.h"
 
diff --git a/src/lib/datasrc/iterator.h b/src/lib/datasrc/iterator.h
deleted file mode 100644
index e1c6929..0000000
--- a/src/lib/datasrc/iterator.h
+++ /dev/null
@@ -1,105 +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 DATASRC_ZONE_ITERATOR_H
-#define DATASRC_ZONE_ITERATOR_H 1
-
-#include <dns/rrset.h>
-
-#include <boost/noncopyable.hpp>
-
-#include <datasrc/zone.h>
-
-namespace isc {
-namespace datasrc {
-
-/**
- * \brief Read-only iterator to a zone.
- *
- * You can get an instance of (descendand of) ZoneIterator from
- * DataSourceClient::getIterator() method. The actual concrete implementation
- * will be different depending on the actual data source used. This is the
- * abstract interface.
- *
- * There's no way to start iterating from the beginning again or return.
- */
-class ZoneIterator : public boost::noncopyable {
-public:
-    /**
-     * \brief Destructor
-     *
-     * Virtual destructor. It is empty, but ensures the right destructor from
-     * descendant is called.
-     */
-    virtual ~ ZoneIterator() { }
-
-    /**
-     * \brief Get next RRset from the zone.
-     *
-     * This returns the next RRset in the zone as a shared pointer. The
-     * shared pointer is used to allow both accessing in-memory data and
-     * automatic memory management.
-     *
-     * Any special order is not guaranteed.
-     *
-     * While this can potentially throw anything (including standard allocation
-     * errors), it should be rare.
-     *
-     * \return Pointer to the next RRset or NULL pointer when the iteration
-     *     gets to the end of the zone.
-     */
-    virtual isc::dns::ConstRRsetPtr getNextRRset() = 0;
-
-    /**
-     * \brief Return the SOA record of the zone in the iterator context.
-     *
-     * This method returns the zone's SOA record (if any, and a valid zone
-     * should have it) in the form of an RRset object.  This SOA is identical
-     * to that (again, if any) contained in the sequence of RRsets returned
-     * by the iterator.  In that sense this method is redundant, but is
-     * provided as a convenient utility for the application of the
-     * iterator; the application may need to know the SOA serial or the
-     * SOA RR itself for the purpose of protocol handling or skipping the
-     * expensive iteration processing.
-     *
-     * If the zone doesn't have an SOA (which is broken, but some data source
-     * may allow that situation), this method returns NULL.  Also, in the
-     * normal and valid case, the SOA should have exactly one RDATA, but
-     * this API does not guarantee it as some data source may accept such an
-     * abnormal condition.  It's up to the caller whether to check the number
-     * of RDATA and how to react to the unexpected case.
-     *
-     * Each concrete derived method must ensure that the SOA returned by this
-     * method is identical to the zone's SOA returned via the iteration.
-     * For example, even if another thread or process updates the SOA while
-     * the iterator is working, the result of this method must not be
-     * affected by the update.  For database based data sources, this can
-     * be done by making the entire iterator operation as a single database
-     * transaction, but the actual implementation can differ.
-     *
-     * \exception None
-     *
-     * \return A shared pointer to an SOA RRset that would be returned
-     * from the iteration.  It will be NULL if the zone doesn't have an SOA.
-     */
-    virtual isc::dns::ConstRRsetPtr getSOA() const = 0;
-};
-
-}
-}
-#endif  // DATASRC_ZONE_ITERATOR_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 72b3273..c0ee688 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -15,6 +15,7 @@ libdatasrc_memory_la_SOURCES += rdataset.h rdataset.cc
 libdatasrc_memory_la_SOURCES += treenode_rrset.h treenode_rrset.cc
 libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc
 libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc
+libdatasrc_memory_la_SOURCES += rrset_collection.h rrset_collection.cc
 libdatasrc_memory_la_SOURCES += segment_object_holder.h
 libdatasrc_memory_la_SOURCES += logger.h logger.cc
 libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 169421f..10e8a81 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -17,7 +17,7 @@
 
 #include <util/memory_segment.h>
 
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/zone_table.h>
 #include <datasrc/memory/zone_data.h>
diff --git a/src/lib/datasrc/memory/memory_messages.mes b/src/lib/datasrc/memory/memory_messages.mes
index 1b67093..f8d5328 100644
--- a/src/lib/datasrc/memory/memory_messages.mes
+++ b/src/lib/datasrc/memory/memory_messages.mes
@@ -88,3 +88,94 @@ 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.
+
+% DATASRC_MEMORY_CHECK_ERROR post-load check of zone %1/%2 failed: %3
+The zone was loaded into the data source successfully, but the content fails
+basic sanity checks. See the message if you want to know what exactly is wrong
+with the data. The data can not be used and previous version, if any, will be
+preserved.
+
+% DATASRC_MEMORY_CHECK_WARNING %1/%2: %3
+The zone was loaded into the data source successfully, but there's some problem
+with the content. The problem does not stop the new version from being used
+(though there may be other problems that do, see DATASRC_MEMORY_CHECK_ERROR),
+but it should still be checked and fixed. See the message to know what exactly
+is wrong with the data.
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_DNAME_FOUND DNAME found at '%1'
+Debug information. A DNAME was found instead of the requested information.
+
+% DATASRC_MEMORY_DELEG_FOUND delegation found at '%1'
+Debug information. A delegation point was found above the requested record.
+
+% DATASRC_MEMORY_SUPER_STOP stopped as '%1' is superdomain of a zone node, meaning it's empty
+Debug information. The search stopped because the requested domain was
+detected to be a superdomain of some existing node of zone (while there
+was no exact match).  This means that the domain is an empty nonterminal,
+therefore it is treated  as NXRRSET case (eg. the domain exists, but it
+doesn't have the requested record type).
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_NOT_FOUND requested domain '%1' not found
+Debug information. The requested domain does not exist.
+
+% DATASRC_MEMORY_FIND_TYPE_AT_ORIGIN origin query for type %1 in in-memory zone %2/%3 successful
+Debug information.  A specific type RRset is requested at a zone origin
+of an in-memory zone and it is found.
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_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.
+
+% DATASRC_MEMORY_SUCCESS query for '%1/%2' successful
+Debug information. The requested record was found.
+
+% DATASRC_MEMORY_CNAME CNAME at the domain '%1'
+Debug information. The requested domain is an alias to a different domain,
+returning the CNAME instead.
+
+% DATASRC_MEMORY_FINDNSEC3 finding NSEC3 for %1, mode %2
+Debug information. A search in an in-memory data source for NSEC3 that
+matches or covers the given name is being started.
+
+% DATASRC_MEMORY_FINDNSEC3_COVER found a covering NSEC3 for %1: %2
+Debug information. An NSEC3 that covers the given name is found and
+being returned.  The found NSEC3 RRset is also displayed.
+
+% DATASRC_MEMORY_FINDNSEC3_MATCH found a matching NSEC3 for %1 at label count %2: %3
+Debug information. An NSEC3 that matches (a possibly superdomain of)
+the given name is found and being returned.  When the shown label
+count is smaller than that of the given name, the matching NSEC3 is
+for a superdomain of the given name (see DATASRC_MEMORY_FINDNSEC3_TRYHASH).
+The found NSEC3 RRset is also displayed.
+
+% DATASRC_MEMORY_FINDNSEC3_TRYHASH looking for NSEC3 for %1 at label count %2 (hash %3)
+Debug information. In an attempt of finding an NSEC3 for the give name,
+(a possibly superdomain of) the name is hashed and searched for in the
+NSEC3 name space.  When the shown label count is smaller than that of the
+shown name, the search tries the superdomain name that share the shown
+(higher) label count of the shown name (e.g., for
+www.example.com. with shown label count of 3, example.com. is being
+tried).
diff --git a/src/lib/datasrc/memory/rrset_collection.cc b/src/lib/datasrc/memory/rrset_collection.cc
new file mode 100644
index 0000000..92319f6
--- /dev/null
+++ b/src/lib/datasrc/memory/rrset_collection.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2013  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/memory/rrset_collection.h>
+#include <datasrc/memory/treenode_rrset.h>
+
+#include <exceptions/exceptions.h>
+
+using namespace isc;
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+ConstRRsetPtr
+RRsetCollection::find(const isc::dns::Name& name,
+                      const isc::dns::RRClass& rrclass,
+                      const isc::dns::RRType& rrtype) const
+{
+    if (rrclass != rrclass_) {
+        // We could throw an exception here, but RRsetCollection is
+        // expected to support an arbitrary collection of RRsets, and it
+        // can be queried just as arbitrarily. So we just return nothing
+        // here.
+        return (ConstRRsetPtr());
+    }
+
+    const ZoneTree& tree = zone_data_.getZoneTree();
+    const ZoneNode *node = NULL;
+    ZoneTree::Result result = tree.find(name, &node);
+    if (result != ZoneTree::EXACTMATCH) {
+        return (ConstRRsetPtr());
+    }
+
+    const RdataSet* rdataset = RdataSet::find(node->getData(), rrtype);
+    if (rdataset == NULL) {
+        return (ConstRRsetPtr());
+    }
+
+    return (ConstRRsetPtr(new TreeNodeRRset(rrclass_, node, rdataset, true)));
+}
+
+} // end of namespace memory
+} // end of namespace datasrc
+} // end of namespace isc
diff --git a/src/lib/datasrc/memory/rrset_collection.h b/src/lib/datasrc/memory/rrset_collection.h
new file mode 100644
index 0000000..e5edd64
--- /dev/null
+++ b/src/lib/datasrc/memory/rrset_collection.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2013  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 RRSET_COLLECTION_DATASRC_MEMORY_H
+#define RRSET_COLLECTION_DATASRC_MEMORY_H 1
+
+#include <dns/rrset_collection_base.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/memory/zone_data.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief In-memory derivation of \c isc::dns::RRsetCollectionBase.
+class RRsetCollection : public isc::dns::RRsetCollectionBase {
+public:
+    /// \brief Constructor.
+    ///
+    /// No reference (count via \c shared_ptr) to the \c ZoneData is
+    /// acquired. The RRsetCollection must not be used after its
+    /// \c ZoneData has been destroyed.
+    ///
+    /// \param zone_data The ZoneData to wrap around.
+    /// \param rrclass The RRClass of the records in the zone.
+    RRsetCollection(ZoneData& zone_data, const isc::dns::RRClass& rrclass) :
+        zone_data_(zone_data),
+        rrclass_(rrclass)
+    {}
+
+    /// \brief Destructor
+    virtual ~RRsetCollection() {}
+
+    /// \brief Find a matching RRset in the collection.
+    ///
+    /// Returns the RRset in the collection that exactly matches the
+    /// given \c name, \c rrclass and \c rrtype.  If no matching RRset
+    /// is found, \c NULL is returned.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if \c find() results in
+    /// some underlying error.
+    ///
+    /// \param name The name of the RRset to search for.
+    /// \param rrclass The class of the RRset to search for.
+    /// \param rrtype The type of the RRset to search for.
+    /// \returns The RRset if found, \c NULL otherwise.
+    virtual isc::dns::ConstRRsetPtr find(const isc::dns::Name& name,
+                                         const isc::dns::RRClass& rrclass,
+                                         const isc::dns::RRType& rrtype) const;
+
+protected:
+    virtual RRsetCollectionBase::IterPtr getBeginning() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
+
+    virtual RRsetCollectionBase::IterPtr getEnd() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
+
+private:
+    ZoneData& zone_data_;
+    isc::dns::RRClass rrclass_;
+};
+
+} // end of namespace memory
+} // end of namespace datasrc
+} // end of namespace isc
+
+#endif  // RRSET_COLLECTION_DATASRC_MEMORY_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc
index e7ed20c..c4e16a6 100644
--- a/src/lib/datasrc/memory/treenode_rrset.cc
+++ b/src/lib/datasrc/memory/treenode_rrset.cc
@@ -59,8 +59,7 @@ TreeNodeRRset::getName() const {
 const RRTTL&
 TreeNodeRRset::getTTL() const {
     if (ttl_ == NULL) {
-        util::InputBuffer ttl_buffer(rdataset_->getTTLData(),
-                                     sizeof(uint32_t));
+        util::InputBuffer ttl_buffer(ttl_data_, sizeof(uint32_t));
         ttl_ = new RRTTL(ttl_buffer);
     }
 
@@ -169,7 +168,7 @@ TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
     // Render the main (non RRSIG) RRs
     const size_t rendered_rdata_count =
         writeRRs(renderer, rdataset_->getRdataCount(), name_labels,
-                 rdataset_->type, rrclass_, rdataset_->getTTLData(), reader,
+                 rdataset_->type, rrclass_, ttl_data_, reader,
                  &RdataReader::iterateRdata);
     if (renderer.isTruncated()) {
         return (rendered_rdata_count);
@@ -180,7 +179,7 @@ TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
     // Render any RRSIGs, if we supposed to do so
     const size_t rendered_rrsig_count = dnssec_ok_ ?
         writeRRs(renderer, rrsig_count_, name_labels, RRType::RRSIG(),
-                 rrclass_, rdataset_->getTTLData(), reader,
+                 rrclass_, ttl_data_, reader,
                  &RdataReader::iterateSingleSig) : 0;
 
     return (rendered_rdata_count + rendered_rrsig_count);
diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h
index 460a704..295a95a 100644
--- a/src/lib/datasrc/memory/treenode_rrset.h
+++ b/src/lib/datasrc/memory/treenode_rrset.h
@@ -112,12 +112,34 @@ public:
                   const RdataSet* rdataset, bool dnssec_ok) :
         node_(node), rdataset_(rdataset),
         rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
-        dnssec_ok_(dnssec_ok), name_(NULL), realname_(NULL), ttl_(NULL)
+        dnssec_ok_(dnssec_ok), name_(NULL), realname_(NULL),
+        ttl_data_(rdataset->getTTLData()), ttl_(NULL)
+    {}
+
+    /// \brief Constructor with a specific TTL.
+    ///
+    /// This constructor is mostly the same as the normal version, but takes
+    /// an extra parameter, \c ttl_data.  It's expected to point to a memory
+    /// region at least for 32 bits, and the corresponding 32-bit data will
+    /// be used as wire-format TTL value of the RRset, instead of the TTL
+    /// associated with \c rdataset.
+    ///
+    /// It's the caller's responsibility to guarantee the memory region is
+    /// valid and intact throughout the lifetime of the RRset.
+    ///
+    /// \throw None
+    TreeNodeRRset(const dns::RRClass& rrclass, const ZoneNode* node,
+                  const RdataSet* rdataset, bool dnssec_ok,
+                  const void* ttl_data) :
+        node_(node), rdataset_(rdataset),
+        rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
+        dnssec_ok_(dnssec_ok), name_(NULL), realname_(NULL),
+        ttl_data_(ttl_data), ttl_(NULL)
     {}
 
     /// \brief Constructor for wildcard-expanded owner name.
     ///
-    /// This constructor is mostly the same as the other version, but takes
+    /// This constructor is mostly the same as the normal version, but takes
     /// an extra parameter, \c realname.  It effectively overrides the owner
     /// name of the RRset; wherever the owner name is used (e.g., in the
     /// \c toWire() method), the specified name will be used instead of
@@ -133,7 +155,7 @@ public:
         node_(node), rdataset_(rdataset),
         rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
         dnssec_ok_(dnssec_ok), name_(NULL), realname_(new dns::Name(realname)),
-	ttl_(NULL)
+	ttl_data_(rdataset->getTTLData()), ttl_(NULL)
     {}
 
     virtual ~TreeNodeRRset() {
@@ -255,6 +277,7 @@ private:
     const bool dnssec_ok_;
     mutable dns::Name* name_;
     const dns::Name* const realname_;
+    const void* const ttl_data_;
     mutable dns::RRTTL* ttl_;
 };
 
diff --git a/src/lib/datasrc/memory/zone_data.cc b/src/lib/datasrc/memory/zone_data.cc
index cc31419..d32fc87 100644
--- a/src/lib/datasrc/memory/zone_data.cc
+++ b/src/lib/datasrc/memory/zone_data.cc
@@ -134,6 +134,31 @@ NSEC3Data::insertName(util::MemorySegment& mem_sgmt, const Name& name,
             result == ZoneTree::ALREADYEXISTS) && node != NULL);
 }
 
+namespace {
+// A helper to convert a TTL value in network byte order and set it in
+// ZoneData::min_ttl_.  We can use util::OutputBuffer, but copy the logic
+// here to guarantee it is exception free.
+// Note: essentially this function is a local (re)implementation of the
+// standard htonl() library function, but we avoid relying on it in case it's
+// not available (it's not in the C++ standard library).
+void
+setTTLInNetOrder(uint32_t val, uint32_t* result) {
+    uint8_t buf[4];
+    buf[0] = static_cast<uint8_t>((val & 0xff000000) >> 24);
+    buf[1] = static_cast<uint8_t>((val & 0x00ff0000) >> 16);
+    buf[2] = static_cast<uint8_t>((val & 0x0000ff00) >> 8);
+    buf[3] = static_cast<uint8_t>(val & 0x000000ff);
+    std::memcpy(result, buf, sizeof(*result));
+}
+}
+
+ZoneData::ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node) :
+    zone_tree_(zone_tree), origin_node_(origin_node),
+    min_ttl_(0)          // tentatively set to silence static checkers
+{
+    setTTLInNetOrder(RRTTL::MAX_TTL().getValue(), &min_ttl_);
+}
+
 ZoneData*
 ZoneData::create(util::MemorySegment& mem_sgmt, const Name& zone_origin) {
     // ZoneTree::insert() and ZoneData allocation can throw.  See also
@@ -178,6 +203,11 @@ ZoneData::insertName(util::MemorySegment& mem_sgmt, const Name& name,
             result == ZoneTree::ALREADYEXISTS) && node != NULL);
 }
 
+void
+ZoneData::setMinTTL(uint32_t min_ttl_val) {
+    setTTLInNetOrder(min_ttl_val, &min_ttl_);
+}
+
 } // namespace memory
 } // namespace datasrc
 } // datasrc isc
diff --git a/src/lib/datasrc/memory/zone_data.h b/src/lib/datasrc/memory/zone_data.h
index 974ce24..c6b3dcc 100644
--- a/src/lib/datasrc/memory/zone_data.h
+++ b/src/lib/datasrc/memory/zone_data.h
@@ -287,7 +287,7 @@ private:
 /// from NSEC to NSEC3 or vice versa, support incremental signing, or support
 /// multiple sets of NSEC3 parameters.
 ///
-/// One last type of meta data is the status of the zone in terms of DNSSEC
+/// One other type of meta data is the status of the zone in terms of DNSSEC
 /// signing.  This class supports the following concepts:
 /// - Whether the zone is signed or not, either with NSEC records or NSEC3
 ///   records.
@@ -315,6 +315,15 @@ private:
 /// because we won't have to change the application code when we implement
 /// the future separation.
 ///
+/// One last type of meta data is the zone's "minimum" TTL.  It's expected
+/// to be a shortcut copy of the minimum field of the zone's SOA RDATA,
+/// and is expected to be used to create an SOA RR for a negative response,
+/// whose RR TTL may have to be set to this value according to RFC2308.
+/// This class is not aware of such usage, however, and only provides a
+/// simple getter and setter method for this value: \c getMinTTLData() and
+/// \c setMinTTL().  The user of this class is responsible for setting the
+/// value with \c setMinTTL() when it loads or updates the SOA RR.
+///
 /// The intended usage of these two status concepts is to implement the
 /// \c ZoneFinder::Context::isNSECSigned() and
 /// \c ZoneFinder::Context::isNSEC3Signed() methods.  A possible implementation
@@ -349,9 +358,7 @@ private:
     /// allocator (\c create()), so the constructor is hidden as private.
     ///
     /// It never throws an exception.
-    ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node) :
-        zone_tree_(zone_tree), origin_node_(origin_node)
-    {}
+    ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node);
 
     // Zone node flags.
 private:
@@ -413,7 +420,7 @@ public:
     ///
     /// The class encapsulation ensures that the origin node always exists at
     /// the same address, so this method always returns a non-NULL valid
-    /// valid pointer.
+    /// pointer.
     ///
     /// \throw none
     const ZoneNode* getOriginNode() const {
@@ -456,6 +463,26 @@ public:
     ///
     /// \throw none
     const NSEC3Data* getNSEC3Data() const { return (nsec3_data_.get()); }
+
+    /// \brief Return a pointer to the zone's minimum TTL data.
+    ///
+    /// The returned pointer points to a memory region that is valid at least
+    /// for 32 bits, storing the zone's minimum TTL in the network byte
+    /// order.  The corresponding 32-bit value as an integer is initially
+    /// set to the value of \c dns::RRTTL::MAX_TTL(), and, once
+    /// \c setMinTTL() is called, set to the value specified at the latest
+    /// call to \c setMinTTL().
+    ///
+    /// It returns opaque data to make it clear that unless the wire
+    /// format data is necessary (e.g., when rendering it in a DNS message),
+    /// it should be converted to, e.g., an \c RRTTL object explicitly.
+    ///
+    /// The returned pointer is valid as long as the \c ZoneData is valid,
+    /// and the corresponding 32-bit data are the same until \c setMinTTL()
+    /// is called.
+    ///
+    /// \throw none
+    const void* getMinTTLData() const { return (&min_ttl_); }
     //@}
 
     ///
@@ -552,12 +579,32 @@ public:
         nsec3_data_ = nsec3_data;
         return (old);
     }
+
+    /// \brief Set the zone's "minimum" TTL.
+    ///
+    /// This method updates the recorded minimum TTL of the zone data.
+    /// It's expected to be identical to the value of the Minimum field
+    /// of the SOA RR at the zone apex, but this method does not check the
+    /// consistency; it's the caller's responsibility.
+    ///
+    /// While RFC2181 specifies the max TTL value to be 2^31-1, this method
+    /// does not check the range; it accepts any unsigned 32-bit integer
+    /// value.  In practice, this shouldn't cause a problem, however, because
+    /// the only expected usage of this value is to use the minimum of this
+    /// value and SOA RR's TTL, and the latter is expected to be in the
+    /// valid range.
+    ///
+    /// \throw None
+    /// \param min_ttl_val The minimum TTL value as unsigned 32-bit integer
+    /// in the host byte order.
+    void setMinTTL(uint32_t min_ttl_val);
     //@}
 
 private:
     const boost::interprocess::offset_ptr<ZoneTree> zone_tree_;
     const boost::interprocess::offset_ptr<ZoneNode> origin_node_;
     boost::interprocess::offset_ptr<NSEC3Data> nsec3_data_;
+    uint32_t min_ttl_;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
index e224224..e3c9c3f 100644
--- a/src/lib/datasrc/memory/zone_data_loader.cc
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -18,11 +18,13 @@
 #include <datasrc/memory/logger.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/util_internal.h>
+#include <datasrc/memory/rrset_collection.h>
 
 #include <dns/master_loader.h>
 #include <dns/rrcollator.h>
 #include <dns/rdataclass.h>
 #include <dns/rrset.h>
+#include <dns/zone_checker.h>
 
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
@@ -148,6 +150,22 @@ ZoneDataLoader::getCurrentName() const {
     return (node_rrsigsets_.begin()->second->getName());
 }
 
+void
+logWarning(const dns::Name* zone_name, const dns::RRClass* rrclass,
+           const std::string& reason)
+{
+    LOG_WARN(logger, DATASRC_MEMORY_CHECK_WARNING).arg(*zone_name).
+        arg(*rrclass).arg(reason);
+}
+
+void
+logError(const dns::Name* zone_name, const dns::RRClass* rrclass,
+         const std::string& reason)
+{
+    LOG_ERROR(logger, DATASRC_MEMORY_CHECK_ERROR).arg(*zone_name).arg(*rrclass).
+        arg(reason);
+}
+
 ZoneData*
 loadZoneDataInternal(util::MemorySegment& mem_sgmt,
                      const isc::dns::RRClass& rrclass,
@@ -172,12 +190,14 @@ loadZoneDataInternal(util::MemorySegment& mem_sgmt,
         }
     }
 
-    // When an empty zone file is loaded, the origin doesn't even have
-    // an SOA RR. This condition should be avoided, and hence load()
-    // should throw when an empty zone is loaded.
-    if (RdataSet::find(rdataset, RRType::SOA()) == NULL) {
-        isc_throw(EmptyZone,
-                  "Won't create an empty zone for: " << zone_name);
+    RRsetCollection collection(*(holder.get()), rrclass);
+    const dns::ZoneCheckerCallbacks
+        callbacks(boost::bind(&logError, &zone_name, &rrclass, _1),
+                  boost::bind(&logWarning, &zone_name, &rrclass, _1));
+    if (!dns::checkZone(zone_name, rrclass, collection, callbacks)) {
+        isc_throw(ZoneValidationError,
+                  "Errors found when validating zone: "
+                  << zone_name << "/" << rrclass);
     }
 
     return (holder.release());
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
index 6b409ec..32ed58b 100644
--- a/src/lib/datasrc/memory/zone_data_loader.h
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -17,7 +17,7 @@
 
 #include <datasrc/exceptions.h>
 #include <datasrc/memory/zone_data.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <util/memory_segment.h>
@@ -26,12 +26,12 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
-/// \brief Zone is empty exception.
+/// \brief Zone is invalid exception.
 ///
-/// This is thrown if an empty zone would be created during
+/// This is thrown if an invalid zone would be created during
 /// \c loadZoneData().
-struct EmptyZone : public ZoneLoaderException {
-    EmptyZone(const char* file, size_t line, const char* what) :
+struct ZoneValidationError : public ZoneLoaderException {
+    ZoneValidationError(const char* file, size_t line, const char* what) :
         ZoneLoaderException(file, line, what)
     {}
 };
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
index 51ec03c..5bde6d4 100644
--- a/src/lib/datasrc/memory/zone_data_updater.cc
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -336,6 +336,17 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
             // "NSEC signed")
             zone_data_.setSigned(true);
         }
+
+        // If we are adding a new SOA at the origin, update zone's min TTL.
+        // Note: if the input is broken and contains multiple SOAs, the load
+        // or update will be rejected higher level.  We just always (though
+        // this should be only once in normal cases) update the TTL.
+        if (rrset && rrtype == RRType::SOA() && is_origin) {
+            // Our own validation ensures the RRset is not empty.
+            zone_data_.setMinTTL(
+                dynamic_cast<const generic::SOA&>(
+                    rrset->getRdataIterator()->getCurrent()).getMinimum());
+        }
     }
 }
 
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 7f57d8e..5acc5be 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -17,15 +17,18 @@
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/rdata_serialization.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/data_source.h>
 #include <dns/labelsequence.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
+#include <dns/rrttl.h>
 #include <dns/nsec3hash.h>
 
-#include <datasrc/logger.h>
+#include <datasrc/memory/logger.h>
+
+#include <util/buffer.h>
 
 #include <boost/scoped_ptr.hpp>
 #include <boost/bind.hpp>
@@ -104,14 +107,19 @@ createTreeNodeRRset(const ZoneNode* node,
                     const RdataSet* rdataset,
                     const RRClass& rrclass,
                     ZoneFinder::FindOptions options,
-                    const Name* realname = NULL)
+                    const Name* realname = NULL,
+                    const void* ttl_data = NULL)
 {
     const bool dnssec = ((options & ZoneFinder::FIND_DNSSEC) != 0);
-    if (node != NULL && rdataset != NULL) {
-        if (realname != NULL) {
+    if (node && rdataset) {
+        if (realname) {
             return (TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass,
                                                        node, rdataset,
                                                        dnssec)));
+        } else if (ttl_data) {
+            assert(!realname);  // these two cases should be mixed in our use
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
+                                                       dnssec, ttl_data)));
         } else {
             return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
                                                        dnssec)));
@@ -160,7 +168,7 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
                                                  RRType::DNAME());
 
     if (found_dname != NULL) {
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
+        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEMORY_DNAME_ENCOUNTERED);
         state->dname_node_ = &node;
         state->rdataset_ = found_dname;
         return (true);
@@ -175,7 +183,7 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
             return (false);
         }
 
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
+        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEMORY_NS_ENCOUNTERED);
 
         // BIND 9 checks if this node is not the origin.  That's probably
         // because it can support multiple versions for dynamic updates
@@ -229,6 +237,12 @@ createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
                                 ZoneFinder::FIND_DNSSEC));
 }
 
+inline RRTTL
+createTTLFromData(const void* ttl_data) {
+    util::InputBuffer b(ttl_data, sizeof(uint32_t));
+    return (RRTTL(b));
+}
+
 // convenience function to fill in the final details
 //
 // Set up ZoneFinderResultContext object as a return value of find(),
@@ -250,7 +264,8 @@ createFindResult(const RRClass& rrclass,
                  const RdataSet* rdataset,
                  ZoneFinder::FindOptions options,
                  bool wild = false,
-                 const Name* qname = NULL)
+                 const Name* qname = NULL,
+                 bool use_minttl = false)
 {
     ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
     const Name* rename = NULL;
@@ -268,6 +283,15 @@ createFindResult(const RRClass& rrclass,
         }
     }
 
+    if (use_minttl && rdataset &&
+        createTTLFromData(zone_data.getMinTTLData()) <
+        createTTLFromData(rdataset->getTTLData())) {
+        return (ZoneFinderResultContext(
+                    code,
+                    createTreeNodeRRset(node, rdataset, rrclass, options,
+                                        rename, zone_data.getMinTTLData()),
+                    flags, zone_data, node, rdataset));
+    }
     return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rdataset,
                                                               rrclass, options,
                                                               rename),
@@ -459,13 +483,13 @@ FindNodeResult findNode(const ZoneData& zone_data,
     } else if (result == ZoneTree::PARTIALMATCH) {
         assert(node != NULL);
         if (state.dname_node_ != NULL) { // DNAME
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_DNAME_FOUND).
                 arg(state.dname_node_->getName());
             return (FindNodeResult(ZoneFinder::DNAME, state.dname_node_,
                                    state.rdataset_));
         }
         if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_DELEG_FOUND).
                 arg(state.zonecut_node_->getName());
             return (FindNodeResult(ZoneFinder::DELEGATION,
                                    state.zonecut_node_,
@@ -474,7 +498,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
         if (node_path.getLastComparisonResult().getRelation() ==
             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
             LOG_DEBUG(logger, DBG_TRACE_DATA,
-                      DATASRC_MEM_SUPER_STOP).arg(name_labels);
+                      DATASRC_MEMORY_SUPER_STOP).arg(name_labels);
             ConstNodeRRset nsec_rrset = getClosestNSEC(zone_data, node_path,
                                                        options);
             return (FindNodeResult(ZoneFinder::NXRRSET, nsec_rrset.first,
@@ -492,7 +516,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
                 // baz.foo.wild.example. The common ancestor, foo.wild.example,
                 // should cancel wildcard.  Treat it as NXDOMAIN.
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_WILDCARD_CANCEL).arg(name_labels);
+                          DATASRC_MEMORY_WILDCARD_CANCEL).arg(name_labels);
                 ConstNodeRRset nsec_rrset = getClosestNSEC(zone_data,
                                                            node_path,
                                                            options);
@@ -522,7 +546,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
                         FindNodeResult::FIND_WILDCARD | zonecut_flag));
         }
 
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_NOT_FOUND).
             arg(name_labels);
         ConstNodeRRset nsec_rrset = getClosestNSEC(zone_data, node_path,
                                                    options);
@@ -549,6 +573,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
 /// For (successful) type ANY query, found_node points to the
 /// corresponding zone node, which is recorded within this specialized
 /// context.
+// cppcheck-suppress noConstructor
 class InMemoryZoneFinder::Context : public ZoneFinder::Context {
 public:
     Context(InMemoryZoneFinder& finder, ZoneFinder::FindOptions options,
@@ -721,8 +746,8 @@ InMemoryZoneFinder::Context::findAdditional(
 
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::find(const isc::dns::Name& name,
-                const isc::dns::RRType& type,
-                const FindOptions options)
+                         const isc::dns::RRType& type,
+                         const FindOptions options)
 {
     return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
                                              findInternal(name, type,
@@ -731,8 +756,8 @@ InMemoryZoneFinder::find(const isc::dns::Name& name,
 
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::findAll(const isc::dns::Name& name,
-        std::vector<isc::dns::ConstRRsetPtr>& target,
-        const FindOptions options)
+                            std::vector<isc::dns::ConstRRsetPtr>& target,
+                            const FindOptions options)
 {
     return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
                                              findInternal(name,
@@ -741,6 +766,44 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
                                                           options))));
 }
 
+// The implementation is a special case of the generic findInternal: we know
+// the qname should have an "exact match" and its node is accessible via
+// getOriginNode(); and, since there should be at least SOA RR at the origin
+// the case of CNAME can be eliminated (these should be guaranteed at the load
+// or update time, but even if they miss a corner case and allows a CNAME to
+// be added at origin, the zone is broken anyway, so we'd just let this
+// method return garbage, too).  As a result, there can be only too cases
+// for the result codes: SUCCESS if the requested type of RR exists; NXRRSET
+// otherwise.  Due to its simplicity we implement it separately, rather than
+// sharing the code with findInternal.
+boost::shared_ptr<ZoneFinder::Context>
+InMemoryZoneFinder::findAtOrigin(const isc::dns::RRType& type,
+                                 bool use_minttl,
+                                 const FindOptions options)
+{
+    const ZoneNode* const node = zone_data_.getOriginNode();
+    const RdataSet* const found = RdataSet::find(node->getData(), type);
+
+    if (found != NULL) {
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_FIND_TYPE_AT_ORIGIN).
+            arg(type).arg(getOrigin()).arg(rrclass_);
+        return (ZoneFinderContextPtr(
+                    new Context(*this, options, rrclass_,
+                                createFindResult(rrclass_, zone_data_, SUCCESS,
+                                                 node, found, options, false,
+                                                 NULL, use_minttl))));
+    }
+    return (ZoneFinderContextPtr(
+                    new Context(*this, options, rrclass_,
+                                createFindResult(rrclass_, zone_data_, NXRRSET,
+                                                 node,
+                                                 getNSECForNXRRSET(zone_data_,
+                                                                   options,
+                                                                   node),
+                                                 options, false, NULL,
+                                                 use_minttl))));
+}
+
 ZoneFinderResultContext
 InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
                                  const isc::dns::RRType& type,
@@ -768,7 +831,7 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
     // 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).
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_DOMAIN_EMPTY).
             arg(name);
         ConstNodeRRset nsec_rrset = getClosestNSEC(zone_data_, node_path,
                                                    options);
@@ -791,7 +854,7 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
         found = RdataSet::find(node->getData(), RRType::NS());
         if (found != NULL) {
             LOG_DEBUG(logger, DBG_TRACE_DATA,
-                      DATASRC_MEM_EXACT_DELEGATION).arg(name);
+                      DATASRC_MEMORY_EXACT_DELEGATION).arg(name);
             return (createFindResult(rrclass_, zone_data_, DELEGATION,
                                      node, found, options, wild, &name));
         }
@@ -803,10 +866,11 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
         const RdataSet* cur_rds = node->getData();
         while (cur_rds != NULL) {
             target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
-                                                  options, &name));
+                                                  options,
+                                                  wild ? &name : NULL));
             cur_rds = cur_rds->getNext();
         }
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_ANY_SUCCESS).
             arg(name);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, node, NULL,
                                  options, wild, &name));
@@ -815,7 +879,7 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
     found = RdataSet::find(node->getData(), type);
     if (found != NULL) {
         // Good, it is here
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_SUCCESS).arg(name).
             arg(type);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, node, found,
                                  options, wild, &name));
@@ -824,20 +888,24 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
         found = RdataSet::find(node->getData(), RRType::CNAME());
         if (found != NULL) {
 
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
+            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_CNAME).arg(name);
             return (createFindResult(rrclass_, zone_data_, CNAME, node, found,
                                      options, wild, &name));
         }
     }
     // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
+    // Note that we don't have to provide the "real name" even if this is
+    // a wildcard; if NSEC is needed its owner name shouldn't be subject to
+    // wildcard substitution; if NSEC isn't needed the "real name" doesn't
+    // matter anyway.
     return (createFindResult(rrclass_, zone_data_, NXRRSET, node,
                              getNSECForNXRRSET(zone_data_, options, node),
-                             options, wild, &name));
+                             options, wild));
 }
 
 isc::datasrc::ZoneFinder::FindNSEC3Result
 InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_FINDNSEC3).arg(name).
         arg(recursive ? "recursive" : "non-recursive");
 
     uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
@@ -904,7 +972,7 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
                              name : name.split(qlabels - labels, labels));
         const std::string hlabel = hash->calculate(hname);
 
-        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
+        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_FINDNSEC3_TRYHASH).
             arg(name).arg(labels).arg(hlabel);
 
         node = NULL;
@@ -927,7 +995,7 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
             }
 
             LOG_DEBUG(logger, DBG_TRACE_BASIC,
-                      DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
+                      DATASRC_MEMORY_FINDNSEC3_MATCH).arg(name).arg(labels).
                 arg(*closest);
 
             return (FindNSEC3Result(true, labels, closest, next));
@@ -946,7 +1014,7 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
                     closest = createNSEC3RRset(covering_node, getClass());
 
                     LOG_DEBUG(logger, DBG_TRACE_BASIC,
-                              DATASRC_MEM_FINDNSEC3_COVER).
+                              DATASRC_MEMORY_FINDNSEC3_COVER).
                         arg(name).arg(*closest);
                 }
 
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
index c95b5bc..f4f411a 100644
--- a/src/lib/datasrc/memory/zone_finder.h
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -18,7 +18,7 @@
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/treenode_rrset.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
@@ -60,6 +60,16 @@ public:
         const isc::dns::RRType& type,
         const FindOptions options = FIND_DEFAULT);
 
+    /// \brief Search for an RRset of given RR type at the zone origin
+    /// specialized for in-memory data source.
+    ///
+    /// This specialized version exploits internal data structure to find
+    /// RRsets at the zone origin and (if \c use_minttl is true) extract
+    /// the SOA Minimum TTL much more efficiently.
+    virtual boost::shared_ptr<ZoneFinder::Context> findAtOrigin(
+        const isc::dns::RRType& type, bool use_minttl,
+        FindOptions options);
+
     /// \brief Version of find that returns all types at once
     ///
     /// It acts the same as find, just that when the correct node is found,
@@ -108,3 +118,7 @@ private:
 } // namespace isc
 
 #endif // DATASRC_MEMORY_ZONE_FINDER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
deleted file mode 100644
index 686dd94..0000000
--- a/src/lib/datasrc/memory_datasrc.cc
+++ /dev/null
@@ -1,2043 +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 <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/nsec3hash.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/masterload.h>
-
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/rbtree.h>
-#include <datasrc/rbnode_rrset.h>
-#include <datasrc/logger.h>
-#include <datasrc/iterator.h>
-#include <datasrc/data_source.h>
-#include <datasrc/factory.h>
-
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-
-#include <algorithm>
-#include <map>
-#include <utility>
-#include <cctype>
-#include <cassert>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using boost::scoped_ptr;
-
-namespace isc {
-namespace datasrc {
-
-using namespace internal;
-
-namespace {
-// Some type aliases
-
-// A functor type used for loading.
-typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
-
-// RRset specified for this implementation
-typedef boost::shared_ptr<internal::RBNodeRRset> RBNodeRRsetPtr;
-typedef boost::shared_ptr<const internal::RBNodeRRset> ConstRBNodeRRsetPtr;
-
-/*
- * Each domain consists of some RRsets. They will be looked up by the
- * RRType.
- *
- * The use of map is questionable with regard to performance - there'll
- * be usually only few RRsets in the domain, so the log n benefit isn't
- * much and a vector/array might be faster due to its simplicity and
- * continuous memory location. But this is unlikely to be a performance
- * critical place and map has better interface for the lookups, so we use
- * that.
- */
-typedef map<RRType, ConstRBNodeRRsetPtr> Domain;
-typedef Domain::value_type DomainPair;
-typedef boost::shared_ptr<Domain> DomainPtr;
-// The tree stores domains
-typedef RBTree<Domain> DomainTree;
-typedef RBNode<Domain> DomainNode;
-
-// In the following dedicated namespace we define a few application-specific
-// RBNode flags.  We use a separate namespace so we can consolidate the
-// definition in a single place, which would hopefully reduce the risk of
-// collisions.
-// (Note: it's within an unnamed namespace, so effectively private.)
-namespace domain_flag {
-// This flag indicates the node is at a "wildcard level" (in short, it means
-// one of the node's immediate child is a wildcard).  See addWildcards()
-// for more details.
-const DomainNode::Flags WILD = DomainNode::FLAG_USER1;
-
-// This flag is used for additional record shortcut.  If a node has this
-// flag, it's under a zone cut for a delegation to a child zone.
-// Note: for a statically built zone this information is stable, but if we
-// change the implementation to be dynamically modifiable, it may not be
-// realistic to keep this flag update for all affected nodes, and we may
-// have to reconsider the mechanism.
-const DomainNode::Flags GLUE = DomainNode::FLAG_USER2;
-
-// This flag indicates the node is generated as a result of wildcard
-// expansion.  In this implementation, this flag can be set only in
-// the separate auxiliary tree of ZoneData (see the structure description).
-const DomainNode::Flags WILD_EXPANDED = DomainNode::FLAG_USER3;
-};
-
-// Separate storage for NSEC3 RRs (and their RRSIGs).  It's an STL map
-// from string to the NSEC3 RRset.  The map key is the first label
-// (upper cased) of the owner name of the corresponding NSEC3 (i.e., map
-// value).  We can use  the standard string comparison (if the comparison
-// target is also upper cased) due to the nature of NSEC3 owner names.
-//
-// Note: We maintain the RRsets in the form of RBNodeRRset even if they are
-// not stored in the RB tree.  The reason is because comparison can be
-// more efficient if we make sure all RRsets returned from this module are
-// of the same type.
-typedef map<string, ConstRBNodeRRsetPtr> NSEC3Map;
-typedef NSEC3Map::value_type NSEC3Pair;
-
-// Actual zone data: Essentially a set of zone's RRs.  This is defined as
-// a separate structure so that it'll be replaceable on reload.
-struct ZoneData {
-    // Note: this code is not entirely exception safe; domains_storage_ could
-    // leak if the constructor throws.  But since it's an intermediate version
-    // toward a full revision and the actual risk of leak should be very small
-    // in practice, we leave it open for now.
-    ZoneData(const Name& origin) :
-        domains_storage_(DomainTree::create(local_mem_sgmt_, true)),
-        domains_(*domains_storage_),
-        aux_wild_domains_(NULL),
-        origin_data_(NULL),
-        nsec_signed_(false)
-    {
-        // We create the node for origin (it needs to exist anyway in future)
-        domains_.insert(local_mem_sgmt_, origin, &origin_data_);
-        DomainPtr origin_domain(new Domain);
-        origin_data_->setData(origin_domain);
-    }
-
-    ~ZoneData() {
-        DomainTree::destroy(local_mem_sgmt_, domains_storage_);
-        if (aux_wild_domains_ != NULL) {
-            DomainTree::destroy(local_mem_sgmt_, aux_wild_domains_);
-        }
-
-        // The assert may be too harsh, but we assume we'll discard (rewrite)
-        // this code soon enough.  Until then this would be a good way to
-        // detect any memory leak.  Also, at that point we shouldn't use
-        // a single separate memory segment for each zone tree; normally
-        // zone data for multiple zones will be managed in a single segment.
-        assert(local_mem_sgmt_.allMemoryDeallocated());
-    }
-
-    // Memory segment to allocate/deallocate memory for the tree and the nodes.
-    // (This will eventually have to be abstract; for now we hardcode the
-    // specific derived segment class).
-    util::MemorySegmentLocal local_mem_sgmt_;
-
-    // The main data (name + RRsets).  We use domains_ as a reference to
-    // domains_storage_ so we don't have to update the rest of the code;
-    // it will eventually have to be revised substantially, at which point
-    // we should clean this up, too.
-    DomainTree* domains_storage_;
-    DomainTree& domains_;
-
-    // An auxiliary tree for wildcard expanded data used in additional data
-    // processing.  It contains names like "ns.wild.example" in the following
-    // example:
-    // child.wild.example. NS ns.wild.example.
-    // *.wild.example IN AAAA 2001:db8::1234
-    // (and there's no exact ns.wild.example. in the zone).  This tree contains
-    // such names with a copy of the RRsets of the matching wildcard name
-    // with its owner name expanded, e.g.:
-    // ns.wild.example. IN AAAA 2001:db8::1234
-    // In theory, this tree could have many such wildcard-expandable names,
-    // each of which has a copy of the original list of RRsets.  In practice,
-    // however, it should be very rare that names for additional section
-    // processing are subject to wildcard expansion, so in most cases this tree
-    // should be even empty, and even if it has content it should be very
-    // small.
-private:
-    DomainTree* aux_wild_domains_;
-public:
-    DomainTree& getAuxWildDomains() {
-        if (aux_wild_domains_ == NULL) {
-            aux_wild_domains_ = DomainTree::create(local_mem_sgmt_);
-        }
-        return (*aux_wild_domains_);
-    }
-
-    // Shortcut to the origin node, which should always exist
-    DomainNode* origin_data_;
-
-    // The optional NSEC3 related data
-    struct NSEC3Data {
-        NSEC3Data(const generic::NSEC3PARAM& nsec3param) :
-            hash_(NSEC3Hash::create(nsec3param))
-        {}
-        NSEC3Data(const generic::NSEC3& nsec3) :
-            hash_(NSEC3Hash::create(nsec3))
-        {}
-        NSEC3Map map_;    // Actual NSEC3 RRs
-        const scoped_ptr<NSEC3Hash> hash_; // hash parameter/calculator
-    };
-    scoped_ptr<NSEC3Data> nsec3_data_; // non NULL only when it's NSEC3 signed
-    bool nsec_signed_; // True if there's at least one NSEC record
-
-    // This templated structure encapsulates the find result of findNode()
-    // method (also templated) below.
-    // The template parameter is expected to be either 'const DomainNode' or
-    // 'DomainNode' (to avoid misuse the template definition itself is kept
-    // private - we only expose expected typedefs).  The former is expected
-    // to be used for lookups, and the latter is expected to be used for
-    // constructing the zone.
-private:
-    template <typename NodeType>
-    struct FindNodeResultBase {
-        // Bitwise flags to represent supplemental information of the
-        // search result:
-        // Search resulted in a wildcard match.
-        static const unsigned int FIND_WILDCARD = 1;
-        // Search encountered a zone cut due to NS but continued to look for
-        // a glue.
-        static const unsigned int FIND_ZONECUT = 2;
-
-        FindNodeResultBase(ZoneFinder::Result code_param,
-                           NodeType* node_param,
-                           ConstRBNodeRRsetPtr rrset_param,
-                           unsigned int flags_param = 0) :
-            code(code_param), node(node_param), rrset(rrset_param),
-            flags(flags_param)
-        {}
-        const ZoneFinder::Result code;
-        NodeType* const node;
-        ConstRBNodeRRsetPtr const rrset;
-        const unsigned int flags;
-    };
-public:
-    typedef FindNodeResultBase<const DomainNode> FindNodeResult;
-    typedef FindNodeResultBase<DomainNode> FindMutableNodeResult;
-
-    // Identify the RBTree node that best matches the given name.
-    // See implementation notes below.
-    //
-    // The caller should pass an empty node_path, and it will contain the
-    // search context (all ancestor nodes that the underlying RBTree search
-    // traverses, and how the search stops) for possible later use at the
-    // caller side.
-    template <typename ResultType>
-    ResultType findNode(const Name& name,
-                        RBTreeNodeChain<Domain>& node_path,
-                        ZoneFinder::FindOptions options) const;
-
-    // A helper method for NSEC-signed zones.  It searches the zone for
-    // the "closest" NSEC corresponding to the search context stored in
-    // node_path (it should contain sufficient information to identify the
-    // previous name of the query name in the zone).  In some cases the
-    // immediate closest name may not have NSEC (when it's under a zone cut
-    // for glue records, or even when the zone is partly broken), so this
-    // method continues the search until it finds a name that has NSEC,
-    // and returns the one found first.  Due to the prerequisite (see below),
-    // it should always succeed.
-    //
-    // node_path must store valid search context (in practice, it's expected
-    // to be set by findNode()); otherwise the underlying RBTree implementation
-    // throws.
-    //
-    // If the zone is not considered NSEC-signed or DNSSEC records were not
-    // required in the original search context (specified in options), this
-    // method doesn't bother to find NSEC, and simply returns NULL.  So, by
-    // definition of "NSEC-signed", when it really tries to find an NSEC it
-    // should succeed; there should be one at least at the zone origin.
-    ConstRBNodeRRsetPtr
-    getClosestNSEC(RBTreeNodeChain<Domain>& node_path,
-                   ZoneFinder::FindOptions options) const;
-};
-
-ConstRBNodeRRsetPtr
-ZoneData::getClosestNSEC(RBTreeNodeChain<Domain>& node_path,
-                         ZoneFinder::FindOptions options) const
-{
-    if (!nsec_signed_ || (options & ZoneFinder::FIND_DNSSEC) == 0) {
-        return (ConstRBNodeRRsetPtr());
-    }
-
-    const DomainNode* prev_node;
-    while ((prev_node = domains_.previousNode(node_path)) != NULL) {
-        if (!prev_node->isEmpty()) {
-            const Domain::const_iterator found =
-                prev_node->getData()->find(RRType::NSEC());
-            if (found != prev_node->getData()->end()) {
-                return (found->second);
-            }
-        }
-    }
-    // This must be impossible and should be an internal bug.
-    // See the description at the method declaration.
-    assert(false);
-    // Even though there is an assert here, strict compilers
-    // will still need some return value.
-    return (ConstRBNodeRRsetPtr());
-}
-
-/// Maintain intermediate data specific to the search context used in
-/// \c find().
-///
-/// It will be passed to \c cutCallback() (see below) and record a possible
-/// zone cut node and related RRset (normally NS or DNAME).
-struct FindState {
-    FindState(bool glue_ok) :
-        zonecut_node_(NULL),
-        dname_node_(NULL),
-        glue_ok_(glue_ok)
-    {}
-
-    // These will be set to a domain node of the highest delegation point,
-    // if any.  In fact, we could use a single variable instead of both.
-    // But then we would need to distinquish these two cases by something
-    // else and it seemed little more confusing when this was written.
-    const DomainNode* zonecut_node_;
-    const DomainNode* dname_node_;
-
-    // Delegation RRset (NS or DNAME), if found.
-    ConstRBNodeRRsetPtr rrset_;
-
-    // Whether to continue search below a delegation point.
-    // Set at construction time.
-    const bool glue_ok_;
-};
-
-// A callback called from possible zone cut nodes and nodes with DNAME.
-// This will be passed from findNode() to \c RBTree::find().
-bool cutCallback(const DomainNode& node, FindState* state) {
-    // We need to look for DNAME first, there's allowed case where
-    // DNAME and NS coexist in the apex. DNAME is the one to notice,
-    // the NS is authoritative, not delegation (corner case explicitly
-    // allowed by section 3 of 2672)
-    const Domain::const_iterator found_dname(node.getData()->find(
-                                                 RRType::DNAME()));
-    if (found_dname != node.getData()->end()) {
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
-        state->dname_node_ = &node;
-        state->rrset_ = found_dname->second;
-        // No more processing below the DNAME (RFC 2672, section 3
-        // forbids anything to exist below it, so there's no need
-        // to actually search for it). This is strictly speaking
-        // a different way than described in 4.1 of that RFC,
-        // but because of the assumption in section 3, it has the
-        // same behaviour.
-        return (true);
-    }
-
-    // Look for NS
-    const Domain::const_iterator found_ns(node.getData()->find(RRType::NS()));
-    if (found_ns != node.getData()->end()) {
-        // We perform callback check only for the highest zone cut in the
-        // rare case of nested zone cuts.
-        if (state->zonecut_node_ != NULL) {
-            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
-        // the apex and the DNAME doesn't exist for a particular version.
-        // It cannot happen for us (at least for now), so we don't do
-        // that check.
-        state->zonecut_node_ = &node;
-        state->rrset_ = found_ns->second;
-
-        // Unless glue is allowed the search stops here, so we return
-        // false; otherwise return true to continue the search.
-        return (!state->glue_ok_);
-    }
-
-    // This case should not happen because we enable callback only
-    // when we add an RR searched for above.
-    assert(0);
-    // This is here to avoid warning (therefore compilation error)
-    // in case assert is turned off. Otherwise we could get "Control
-    // reached end of non-void function".
-    return (false);
-}
-
-// Implementation notes: this method identifies an RBT node that best matches
-// the give name in terms of DNS query handling.  In many cases,
-// DomainTree::find() will result in EXACTMATCH or PARTIALMATCH (note that
-// the given name is generally expected to be contained in the zone, so
-// even if it doesn't exist, it should at least match the zone origin).
-// If it finds an exact match, that's obviously the best one.  The partial
-// match case is more complicated.
-//
-// We first need to consider the case where search hits a delegation point,
-// either due to NS or DNAME.  They are indicated as either dname_node_ or
-// zonecut_node_ being non NULL.  Usually at most one of them will be
-// something else than NULL (it might happen both are NULL, in which case we
-// consider it NOT FOUND). There's one corner case when both might be
-// something else than NULL and it is in case there's a DNAME under a zone
-// cut and we search in glue OK mode ‒ in that case we don't stop on the
-// domain with NS and ignore it for the answer, but it gets set anyway. Then
-// we find the DNAME and we need to act by it, therefore we first check for
-// DNAME and then for NS. In all other cases it doesn't matter, as at least
-// one of them is NULL.
-//
-// Next, we need to check if the RBTree search stopped at a node for a
-// subdomain of the search name (so the comparison result that stopped the
-// search is "SUPERDOMAIN"), it means the stopping node is an empty
-// non-terminal node.  In this case the search name is considered to exist
-// but no data should be found there.
-//
-// If none of above is the case, we then consider whether there's a matching
-// wildcard.  DomainTree::find() records the node if it encounters a
-// "wildcarding" node, i.e., the immediate ancestor of a wildcard name
-// (e.g., wild.example.com for *.wild.example.com), and returns it if it
-// doesn't find any node that better matches the query name.  In this case
-// we'll check if there's indeed a wildcard below the wildcarding node.
-//
-// Note, first, that the wildcard is checked after the empty
-// non-terminal domain case above, because if that one triggers, it
-// means we should not match according to 4.3.3 of RFC 1034 (the query
-// name is known to exist).
-//
-// Before we try to find a wildcard, we should check whether there's
-// an existing node that would cancel the wildcard match.  If
-// DomainTree::find() stopped at a node which has a common ancestor
-// with the query name, it might mean we are comparing with a
-// non-wildcard node. In that case, we check which part is common. If
-// we have something in common that lives below the node we got (the
-// one above *), then we should cancel the match according to section
-// 4.3.3 of RFC 1034 (as the name between the wildcard domain and the
-// query name is known to exist).
-//
-// If there's no node below the wildcarding node that shares a common ancestor
-// of the query name, we can conclude the wildcard is the best match.
-// We'll then identify the wildcard node via an incremental search.  Note that
-// there's no possibility that the query name is at an empty non terminal
-// node below the wildcarding node at this stage; that case should have been
-// caught above.
-//
-// If none of the above succeeds, we conclude the name doesn't exist in
-// the zone.
-template <typename ResultType>
-ResultType
-ZoneData::findNode(const Name& name, RBTreeNodeChain<Domain>& node_path,
-                   ZoneFinder::FindOptions options) const
-{
-    DomainNode* node = NULL;
-    FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
-
-    const DomainTree::Result result =
-        domains_.find(LabelSequence(name), &node, node_path,
-                      cutCallback, &state);
-    const unsigned int zonecut_flag =
-        (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
-    if (result == DomainTree::EXACTMATCH) {
-        return (ResultType(ZoneFinder::SUCCESS, node, state.rrset_,
-                           zonecut_flag));
-    } else if (result == DomainTree::PARTIALMATCH) {
-        assert(node != NULL);
-        if (state.dname_node_ != NULL) { // DNAME
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
-                arg(state.rrset_->getName());
-            return (ResultType(ZoneFinder::DNAME, NULL, state.rrset_));
-        }
-        if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
-                arg(state.rrset_->getName());
-            return (ResultType(ZoneFinder::DELEGATION, NULL, state.rrset_));
-        }
-        if (node_path.getLastComparisonResult().getRelation() ==
-            NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
-            return (ResultType(ZoneFinder::NXRRSET, node,
-                               getClosestNSEC(node_path, options)));
-        }
-        if (node->getFlag(domain_flag::WILD) && // maybe a wildcard, check only
-            (options & ZoneFinder::NO_WILDCARD) == 0) { // if not disabled.
-            if (node_path.getLastComparisonResult().getRelation() ==
-                NameComparisonResult::COMMONANCESTOR) {
-                // This means, e.g., we have *.wild.example and
-                // bar.foo.wild.example and are looking for
-                // baz.foo.wild.example. The common ancestor, foo.wild.example,
-                // should cancel wildcard.  Treat it as NXDOMAIN.
-                LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_WILDCARD_CANCEL).arg(name);
-                return (ResultType(ZoneFinder::NXDOMAIN, NULL,
-                                   getClosestNSEC(node_path, options)));
-            }
-            // Now the wildcard should be the best match.
-            const Name wildcard(Name("*").concatenate(
-                                    node_path.getAbsoluteName()));
-
-            // Clear the node_path so that we don't keep incorrect (NSEC)
-            // context
-            node_path.clear();
-            DomainTree::Result result(domains_.find(wildcard, &node,
-                                                    node_path));
-            // Otherwise, why would the domain_flag::WILD be there if
-            // there was no wildcard under it?
-            assert(result == DomainTree::EXACTMATCH);
-            return (ResultType(ZoneFinder::SUCCESS, node, state.rrset_,
-                               FindNodeResult::FIND_WILDCARD |
-                               zonecut_flag));
-        }
-        // Nothing really matched.
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
-        return (ResultType(ZoneFinder::NXDOMAIN, node,
-                           getClosestNSEC(node_path, options)));
-    } else {
-        // If the name is neither an exact or partial match, it is
-        // out of bailiwick, which is considered an error.
-        isc_throw(OutOfZone, name.toText() << " not in " <<
-                             origin_data_->getName());
-    }
-}
-} // unnamed namespace
-
-namespace internal {
-
-/// \brief An encapsulation type for a pointer of an additional node
-/// associated with an \c RBNodeRRset object.
-///
-/// Currently this is defined as a structure only so that it can declared
-/// in rbnode_rrset.h; this is essentially a pointer to \c DomainNode.
-/// In future, however, this structure may have other attributes.
-struct AdditionalNodeInfo {
-    explicit AdditionalNodeInfo(DomainNode* node) : node_(node) {}
-    DomainNode* node_;
-};
-
-//
-// RBNodeRRset details
-//
-struct RBNodeRRsetImpl {
-public:
-    RBNodeRRsetImpl(const ConstRRsetPtr& rrset) : rrset_(rrset)
-    {}
-
-    ConstRRsetPtr rrset_;     ///< Underlying RRset
-    scoped_ptr<vector<AdditionalNodeInfo> > additionals_;
-};
-
-RBNodeRRset::RBNodeRRset(const ConstRRsetPtr& rrset) :
-    impl_(new RBNodeRRsetImpl(rrset))
-{
-}
-
-RBNodeRRset::~RBNodeRRset() {
-    delete impl_;
-}
-
-unsigned int
-RBNodeRRset::getRdataCount() const {
-    return (impl_->rrset_->getRdataCount());
-}
-
-const Name&
-RBNodeRRset::getName() const {
-    return (impl_->rrset_->getName());
-}
-
-const RRClass&
-RBNodeRRset::getClass() const {
-    return (impl_->rrset_->getClass());
-}
-
-const RRType&
-RBNodeRRset::getType() const {
-    return (impl_->rrset_->getType());
-}
-
-const RRTTL&
-RBNodeRRset::getTTL() const {
-    return (impl_->rrset_->getTTL());
-}
-
-void
-RBNodeRRset::setName(const Name&) {
-    isc_throw(isc::NotImplemented, "RBNodeRRset::setName() not supported");
-}
-
-void
-RBNodeRRset::setTTL(const RRTTL&) {
-    isc_throw(isc::NotImplemented, "RBNodeRRset::setTTL() not supported");
-}
-
-string
-RBNodeRRset::toText() const {
-    return (impl_->rrset_->toText());
-}
-
-unsigned int
-RBNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
-    return (impl_->rrset_->toWire(renderer));
-}
-
-unsigned int
-RBNodeRRset::toWire(isc::util::OutputBuffer& buffer) const {
-    return (impl_->rrset_->toWire(buffer));
-}
-
-void
-RBNodeRRset::addRdata(ConstRdataPtr) {
-    isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
-}
-
-void
-RBNodeRRset::addRdata(const Rdata&) {
-    isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
-}
-
-RdataIteratorPtr
-RBNodeRRset::getRdataIterator() const {
-    return (impl_->rrset_->getRdataIterator());
-}
-
-RRsetPtr
-RBNodeRRset::getRRsig() const {
-    return (impl_->rrset_->getRRsig());
-}
-
-unsigned int
-RBNodeRRset::getRRsigDataCount() const {
-    return (impl_->rrset_->getRRsigDataCount());
-}
-
-void
-RBNodeRRset::addRRsig(const ConstRdataPtr& rdata) {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->addRRsig(rdata);
-}
-
-void
-RBNodeRRset::addRRsig(const RdataPtr& rdata) {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->addRRsig(rdata);
-}
-
-void
-RBNodeRRset::addRRsig(const AbstractRRset& sigs) {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->addRRsig(sigs);
-}
-
-void
-RBNodeRRset::addRRsig(const ConstRRsetPtr& sigs) {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->addRRsig(sigs);
-}
-
-void
-RBNodeRRset::addRRsig(const RRsetPtr& sigs) {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->addRRsig(sigs);
-}
-
-void
-RBNodeRRset::removeRRsig() {
-    AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
-    p->removeRRsig();
-}
-
-ConstRRsetPtr
-RBNodeRRset::getUnderlyingRRset() const {
-    return (impl_->rrset_);
-}
-
-void
-RBNodeRRset::addAdditionalNode(const AdditionalNodeInfo& additional) {
-    // Lazy initialization
-    if (!impl_->additionals_) {
-        impl_->additionals_.reset(new vector<AdditionalNodeInfo>);
-    }
-    impl_->additionals_->push_back(additional);
-}
-
-const vector<AdditionalNodeInfo>*
-RBNodeRRset::getAdditionalNodes() const {
-    return (impl_->additionals_.get());
-}
-
-void
-RBNodeRRset::copyAdditionalNodes(RBNodeRRset& dst) const {
-    if (impl_->additionals_) {
-        dst.impl_->additionals_.reset(
-            new vector<AdditionalNodeInfo>(impl_->additionals_->begin(),
-                                           impl_->additionals_->end()));
-    }
-}
-
-} // end of internal
-
-namespace {
-/*
- * Prepares a rrset to be return as a result.
- *
- * If rename is false, it returns the one provided. If it is true, it
- * creates a new rrset with the same data but with provided name.
- * In addition, if DNSSEC records are required by the original caller of
- * find(), it also creates expanded RRSIG based on the RRSIG of the
- * wildcard RRset.
- * It is designed for wildcard case, where we create the rrsets
- * dynamically.
- */
-ConstRBNodeRRsetPtr
-prepareRRset(const Name& name, const ConstRBNodeRRsetPtr& rrset, bool rename,
-             ZoneFinder::FindOptions options)
-{
-    if (rename) {
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
-            arg(rrset->getName()).arg(name);
-        RRsetPtr result_base(new RRset(name, rrset->getClass(),
-                                       rrset->getType(), rrset->getTTL()));
-        for (RdataIteratorPtr i(rrset->getRdataIterator()); !i->isLast();
-             i->next()) {
-            result_base->addRdata(i->getCurrent());
-        }
-        if ((options & ZoneFinder::FIND_DNSSEC) != 0) {
-            ConstRRsetPtr sig_rrset = rrset->getRRsig();
-            if (sig_rrset) {
-                RRsetPtr result_sig(new RRset(name, sig_rrset->getClass(),
-                                              RRType::RRSIG(),
-                                              sig_rrset->getTTL()));
-                for (RdataIteratorPtr i(sig_rrset->getRdataIterator());
-                     !i->isLast();
-                     i->next())
-                {
-                    result_sig->addRdata(i->getCurrent());
-                }
-                result_base->addRRsig(result_sig);
-            }
-        }
-        RBNodeRRsetPtr result(new RBNodeRRset(result_base));
-        rrset->copyAdditionalNodes(*result);
-        return (result);
-    } else {
-        ConstRRsetPtr sig_rrset = rrset->getRRsig();
-        if (sig_rrset &&
-            ((options & ZoneFinder::FIND_DNSSEC) == 0)) {
-            RRsetPtr result_base(new RRset(name, rrset->getClass(),
-                                           rrset->getType(),
-                                           rrset->getTTL()));
-            for (RdataIteratorPtr i(rrset->getRdataIterator());
-                 !i->isLast();
-                 i->next()) {
-                result_base->addRdata(i->getCurrent());
-            }
-
-            RBNodeRRsetPtr result(new RBNodeRRset(result_base));
-            rrset->copyAdditionalNodes(*result);
-            return (result);
-        } else {
-            return (rrset);
-        }
-    }
-}
-
-// Specialized version of ZoneFinder::ResultContext, which specifically
-// holds rrset in the form of RBNodeRRset.
-struct RBNodeResultContext {
-    /// \brief Constructor
-    ///
-    /// The first three parameters correspond to those of
-    /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
-    /// found RBNode in the search.
-    RBNodeResultContext(ZoneFinder::Result code_param,
-                        ConstRBNodeRRsetPtr rrset_param,
-                        ZoneFinder::FindResultFlags flags_param,
-                        const DomainNode* node) :
-        code(code_param), rrset(rrset_param), flags(flags_param),
-        found_node(node)
-    {}
-
-    const ZoneFinder::Result code;
-    const ConstRBNodeRRsetPtr rrset;
-    const ZoneFinder::FindResultFlags flags;
-    const DomainNode* const found_node;
-};
-}
-
-class InMemoryZoneFinder::Context : public ZoneFinder::Context {
-public:
-    /// \brief Constructor.
-    ///
-    /// Note that we don't have a specific constructor for the findAll() case.
-    /// For (successful) type ANY query, found_node points to the
-    /// corresponding RB node, which is recorded within this specialized
-    /// context.
-    Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
-            const RBNodeResultContext& result) :
-        ZoneFinder::Context(options,
-                            ResultContext(result.code, result.rrset,
-                                          result.flags)),
-        finder_(finder), rrset_(result.rrset), found_node_(result.found_node)
-    {}
-
-protected:
-    virtual ZoneFinder* getFinder() { return (&finder_); }
-
-    virtual const std::vector<isc::dns::ConstRRsetPtr>* getAllRRsets() const {
-        return (NULL);
-    }
-
-    virtual void getAdditionalImpl(const vector<RRType>& requested_types,
-                                   vector<ConstRRsetPtr>& result)
-    {
-        if (!rrset_) {
-            // In this case this context should encapsulate the result of
-            // findAll() and found_node_ should point to a valid answer node.
-            if (found_node_ == NULL || found_node_->isEmpty()) {
-                isc_throw(isc::Unexpected,
-                          "Invalid call to in-memory getAdditional: caller's "
-                          "bug or broken zone");
-            }
-            BOOST_FOREACH(const DomainPair& dom_it, *found_node_->getData()) {
-                getAdditionalForRRset(*dom_it.second, requested_types,
-                                      result, options_);
-            }
-        } else {
-            getAdditionalForRRset(*rrset_, requested_types, result, options_);
-        }
-    }
-
-private:
-    // Retrieve additional RRsets for a given RRset associated in the context.
-    // The process is straightforward: it examines the link to
-    // AdditionalNodeInfo vector (if set), and find RRsets of the requested
-    // type for each node.
-    static void getAdditionalForRRset(const RBNodeRRset& rrset,
-                                      const vector<RRType>& requested_types,
-                                      vector<ConstRRsetPtr>& result,
-                                      ZoneFinder::FindOptions options)
-    {
-        const vector<AdditionalNodeInfo>* additionals_ =
-            rrset.getAdditionalNodes();
-        if (additionals_ == NULL) {
-            return;
-        }
-        const bool glue_ok = (rrset.getType() == RRType::NS());
-        BOOST_FOREACH(const AdditionalNodeInfo& additional, *additionals_) {
-            assert(additional.node_ != NULL);
-            if (additional.node_->isEmpty()) {
-                continue;
-            }
-            if (!glue_ok && additional.node_->getFlag(domain_flag::GLUE)) {
-                continue;
-            }
-            const bool wild_expanded =
-                additional.node_->getFlag(domain_flag::WILD_EXPANDED);
-            BOOST_FOREACH(const RRType& rrtype, requested_types) {
-                Domain::const_iterator found =
-                    additional.node_->getData()->find(rrtype);
-                if (found != additional.node_->getData()->end()) {
-                    // If the additional node was generated as a result of
-                    // wildcard expansion, we return the underlying RRset,
-                    // in case the caller has the same RRset but as a result
-                    // of normal find() and needs to know they are of the same
-                    // kind; otherwise we simply use the stored RBNodeRRset.
-                    ConstRRsetPtr rp;
-                    if (wild_expanded) {
-                        rp = found->second->getUnderlyingRRset();
-                    } else {
-                        rp = found->second;
-                    }
-                    result.push_back(ZoneFinder::stripRRsigs(rp, options));
-                }
-            }
-        }
-    }
-
-    ZoneFinder& finder_;
-    const ConstRBNodeRRsetPtr rrset_;
-    const DomainNode* const found_node_;
-};
-
-// Private data and hidden methods of InMemoryZoneFinder
-struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
-    // Constructor
-    InMemoryZoneFinderImpl(const RRClass& zone_class, const Name& origin) :
-        zone_class_(zone_class), origin_(origin),
-        zone_data_(new ZoneData(origin_))
-    {}
-
-    // Information about the zone
-    RRClass zone_class_;
-    Name origin_;
-    string file_name_;
-
-    // The actual zone data
-    scoped_ptr<ZoneData> zone_data_;
-
-    // Common process for zone load.
-    // rrset_installer is a functor that takes another functor as an argument,
-    // and expected to call the latter for each RRset of the zone.  How the
-    // sequence of the RRsets is generated depends on the internal
-    // details  of the loader: either from a textual master file or from
-    // another data source.
-    // filename is the file name of the master file or empty if the zone is
-    // loaded from another data source.
-    void load(const string& filename,
-              boost::function<void(LoadCallback)> rrset_installer);
-
-    // Add the necessary magic for any wildcard contained in 'name'
-    // (including itself) to be found in the zone.
-    //
-    // In order for wildcard matching to work correctly in find(),
-    // we must ensure that a node for the wildcarding level exists in the
-    // backend RBTree.
-    // E.g. if the wildcard name is "*.sub.example." then we must ensure
-    // that "sub.example." exists and is marked as a wildcard level.
-    // Note: the "wildcarding level" is for the parent name of the wildcard
-    // name (such as "sub.example.").
-    //
-    // We also perform the same trick for empty wild card names possibly
-    // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
-    void addWildcards(util::MemorySegment& mem_sgmt, DomainTree& domains,
-                      const Name& name)
-    {
-        Name wname(name);
-        const unsigned int labels(wname.getLabelCount());
-        const unsigned int origin_labels(origin_.getLabelCount());
-        for (unsigned int l = labels;
-             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;
-                DomainTree::Result result(domains.insert(mem_sgmt,
-                                                         wname.split(1),
-                                                         &node));
-                assert(result == DomainTree::SUCCESS ||
-                       result == DomainTree::ALREADYEXISTS);
-                node->setFlag(domain_flag::WILD);
-
-                // Ensure a separate level exists for the wildcard name.
-                // Note: for 'name' itself we do this later anyway, but the
-                // overhead should be marginal because wildcard names should
-                // be rare.
-                result = domains.insert(mem_sgmt, wname, &node);
-                assert(result == DomainTree::SUCCESS ||
-                       result == DomainTree::ALREADYEXISTS);
-            }
-        }
-    }
-
-    // A helper predicate used in contextCheck() to check if a given domain
-    // name has a RRset of type different than NSEC.
-    static bool isNotNSEC(const DomainPair& element) {
-        return (element.second->getType() != RRType::NSEC());
-    }
-
-    /*
-     * Does some checks in context of the data that are already in the zone.
-     * Currently checks for forbidden combinations of RRsets in the same
-     * domain (CNAME+anything, DNAME+NS).
-     *
-     * If such condition is found, it throws AddError.
-     */
-    void contextCheck(const AbstractRRset& rrset, const Domain& domain) const {
-        // Ensure CNAME and other type of RR don't coexist for the same
-        // owner name except with NSEC, which is the only RR that can coexist
-        // with CNAME (and also RRSIG, which is handled separately)
-        if (rrset.getType() == RRType::CNAME()) {
-            if (find_if(domain.begin(), domain.end(), isNotNSEC)
-                != domain.end()) {
-                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 (rrset.getType() != RRType::NSEC() &&
-                   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());
-        }
-
-        /*
-         * Similar with DNAME, but it must not coexist only with NS and only in
-         * non-apex domains.
-         * RFC 2672 section 3 mentions that it is implied from it and RFC 2181
-         */
-        if (rrset.getName() != origin_ &&
-            // Adding DNAME, NS already there
-            ((rrset.getType() == RRType::DNAME() &&
-            domain.find(RRType::NS()) != domain.end()) ||
-            // Adding NS, DNAME already there
-            (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());
-        }
-    }
-
-    // Validate rrset before adding it to the zone.  If something is wrong
-    // it throws an exception.  It doesn't modify the zone, and provides
-    // the strong exception guarantee.
-    void addValidation(const ConstRRsetPtr rrset) {
-        if (!rrset) {
-            isc_throw(NullRRset, "The rrset provided is NULL");
-        }
-        if (rrset->getRdataCount() == 0) {
-            isc_throw(AddError, "The rrset provided is empty: " <<
-                      rrset->getName() << "/" << rrset->getType());
-        }
-        // Check for singleton RRs. It should probably handled at a different
-        // layer in future.
-        if ((rrset->getType() == RRType::CNAME() ||
-            rrset->getType() == RRType::DNAME()) &&
-            rrset->getRdataCount() > 1)
-        {
-            // 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());
-        }
-        // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
-        // implementation requests it be so at the moment.
-        if ((rrset->getType() == RRType::NSEC3() ||
-             rrset->getType() == RRType::NSEC3PARAM()) &&
-            rrset->getRdataCount() > 1) {
-            isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
-                      << rrset->getName() << " which isn't supported");
-        }
-
-        NameComparisonResult compare(origin_.compare(rrset->getName()));
-        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_);
-        }
-
-        // Some RR types do not really work well with a wildcard.
-        // Even though the protocol specifically doesn't completely ban such
-        // usage, we refuse to load a zone containing such RR in order to
-        // keep the lookup logic simpler and more predictable.
-        // See RFC4592 and (for DNAME) draft-ietf-dnsext-rfc2672bis-dname
-        // for more technical background.  Note also that BIND 9 refuses
-        // NS at a wildcard, so in that sense we simply provide compatible
-        // 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());
-            }
-        }
-
-        // Owner names of NSEC3 have special format as defined in RFC5155,
-        // and cannot be a wildcard name or must be one label longer than
-        // the zone origin.  While the RFC doesn't prohibit other forms of
-        // names, no sane zone would have such names for NSEC3.
-        // BIND 9 also refuses NSEC3 at wildcard.
-        if (rrset->getType() == RRType::NSEC3() &&
-            (rrset->getName().isWildcard() ||
-             rrset->getName().getLabelCount() !=
-             origin_.getLabelCount() + 1)) {
-            LOG_ERROR(logger, DATASRC_BAD_NSEC3_NAME).
-                arg(rrset->getName());
-            isc_throw(AddError, "Invalid NSEC3 owner name: " <<
-                      rrset->getName());
-        }
-    }
-
-    result::Result addRRsig(const ConstRRsetPtr sig_rrset, ZoneData& zone_data)
-    {
-        // Check consistency of the type covered.
-        // We know the RRset isn't empty, so the following check is safe.
-        RdataIteratorPtr rit = sig_rrset->getRdataIterator();
-        const RRType covered = dynamic_cast<const generic::RRSIG&>(
-            rit->getCurrent()).typeCovered();
-        for (rit->next(); !rit->isLast(); rit->next()) {
-            if (dynamic_cast<const generic::RRSIG&>(
-                    rit->getCurrent()).typeCovered() != covered) {
-                isc_throw(AddError, "RRSIG contains mixed covered types: "
-                          << sig_rrset->toText());
-            }
-        }
-
-        // Find the RRset to be covered; if not found, treat it as an error
-        // for now.
-        ConstRRsetPtr covered_rrset;
-        if (covered != RRType::NSEC3()) {
-            DomainNode* node = NULL;
-            if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
-                DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
-                isc_throw(AddError,
-                          "RRSIG is being added, but no RR to be covered: "
-                          << sig_rrset->getName());
-            }
-            const Domain::const_iterator it = node->getData()->find(covered);
-            if (it != node->getData()->end()) {
-                covered_rrset = it->second;
-            }
-        } else {
-            // In case of NSEC3 if something is found it must be NSEC3 RRset
-            // under the assumption of our current implementation.
-            if (zone_data.nsec3_data_) {
-                // Convert the first label to upper-cased text.  Note that
-                // for a valid NSEC3 RR the label should only consist of
-                // positive 8-bit char values, so using toupper(int) should be
-                // safe (if it's a bogus label for NSEC3 the zone won't work
-                // anyway).  Also note the '::' below: g++'s STL implementation
-                // seems to require it to toupper to make this compile.
-                string fst_label =
-                    sig_rrset->getName().split(0, 1).toText(true);
-                transform(fst_label.begin(), fst_label.end(),
-                          fst_label.begin(), ::toupper);
-
-                NSEC3Map::const_iterator found =
-                    zone_data.nsec3_data_->map_.find(fst_label);
-                if (found != zone_data.nsec3_data_->map_.end()) {
-                    covered_rrset = found->second;
-                    assert(covered_rrset->getType() == covered);
-                }
-            }
-        }
-        if (!covered_rrset) {
-            isc_throw(AddError, "RRSIG is being added, but no RR of "
-                      "covered type found: " << sig_rrset->toText());
-        }
-
-        // The current implementation doesn't allow an existing RRSIG to be
-        // overridden (or updated with additional ones).
-        if (covered_rrset->getRRsig()) {
-            isc_throw(AddError,
-                      "RRSIG is being added to override an existing one: "
-                      << sig_rrset->toText());
-        }
-
-        // All okay, setting the RRSIG.
-        // XXX: we break const-ness of the covered RRsets.  In practice the
-        // ownership of these RRsets would have been given to us so it should
-        // be safe, but it's still a very bad practice.
-        // We'll fix this problem anyway when we update the underlying
-        // representation so that it's more space efficient.
-        // Note: there's a slight chance of getting an exception.
-        // As noted in add(), we give up strong exception guarantee in such
-        // cases.
-        boost::const_pointer_cast<AbstractRRset>(covered_rrset)->addRRsig(sig_rrset);
-
-        return (result::SUCCESS);
-    }
-
-    result::Result addNSEC3(const ConstRRsetPtr rrset, ZoneData& zone_data) {
-        // We know rrset has exactly one RDATA
-        const generic::NSEC3& nsec3_rdata =
-            dynamic_cast<const generic::NSEC3&>(
-                rrset->getRdataIterator()->getCurrent());
-
-        // If we've not done any NSEC3 setup for the zone, do it now;
-        // otherwise check parameter consistency.
-        if (!zone_data.nsec3_data_) {
-            zone_data.nsec3_data_.reset(new ZoneData::NSEC3Data(nsec3_rdata));
-        } else if (!zone_data.nsec3_data_->hash_->match(nsec3_rdata)) {
-            isc_throw(AddError, "NSEC3 with inconsistent parameters: " <<
-                      rrset->toText());
-        }
-
-        string fst_label = rrset->getName().split(0, 1).toText(true);
-        transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
-                  ::toupper);
-
-        // Our current implementation doesn't allow an existing NSEC3 to be
-        // updated/overridden.
-        if (zone_data.nsec3_data_->map_.find(fst_label) !=
-            zone_data.nsec3_data_->map_.end()) {
-            return (result::EXIST);
-        }
-
-        zone_data.nsec3_data_->map_.insert(
-            NSEC3Pair(fst_label, ConstRBNodeRRsetPtr(new RBNodeRRset(rrset))));
-        return (result::SUCCESS);
-    }
-
-    /*
-     * Implementation of longer methods. We put them here, because the
-     * access is without the impl_-> and it will get inlined anyway.
-     */
-    // Implementation of InMemoryZoneFinder::add
-    result::Result add(const ConstRRsetPtr& rawrrset, ZoneData& zone_data,
-                       vector<RBNodeRRset*>* need_additionals)
-    {
-        // Sanitize input.  This will cause an exception to be thrown
-        // if the input RRset is empty.
-        addValidation(rawrrset);
-
-        // OK, can add the RRset.
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
-            arg(rawrrset->getName()).arg(rawrrset->getType()).arg(origin_);
-
-        // ... although instead of loading the RRset directly, we encapsulate
-        // it within an RBNodeRRset.  This contains additional information that
-        // speeds up queries.
-        RBNodeRRsetPtr rrset(new RBNodeRRset(rawrrset));
-
-        if (rrset->getType() == RRType::NSEC3()) {
-            return (addNSEC3(rrset, zone_data));
-        }
-
-        // RRSIGs are special in various points, so we handle it in a
-        // separate dedicated method.
-        if (rrset->getType() == RRType::RRSIG()) {
-            return (addRRsig(rrset, zone_data));
-        }
-
-        // Add wildcards possibly contained in the owner name to the domain
-        // tree.
-        // Note: this can throw an exception, breaking strong exception
-        // guarantee.  (see also the note for contextCheck() below).
-        addWildcards(zone_data.local_mem_sgmt_, zone_data.domains_,
-                     rrset->getName());
-
-        // Get the node
-        DomainNode* node;
-        DomainTree::Result result =
-            zone_data.domains_.insert(zone_data.local_mem_sgmt_,
-                                      rrset->getName(), &node);
-        // Just check it returns reasonable results
-        assert((result == DomainTree::SUCCESS ||
-                result == DomainTree::ALREADYEXISTS) && node!= NULL);
-
-        // Now get the domain
-        DomainPtr domain;
-        // It didn't exist yet, create it
-        if (node->isEmpty()) {
-            domain.reset(new Domain);
-            node->setData(domain);
-        } else { // Get existing one
-            domain = node->getData();
-        }
-
-        // Checks related to the surrounding data.
-        // Note: when the check fails and the exception is thrown, it may
-        // break strong exception guarantee.  At the moment we prefer
-        // code simplicity and don't bother to introduce complicated
-        // recovery code.
-        contextCheck(*rrset, *domain);
-
-        // Try inserting the rrset there
-        if (domain->insert(DomainPair(rrset->getType(), rrset)).second) {
-            // Ok, we just put it in
-
-            // If this RRset creates a zone cut at this node, mark the node
-            // indicating the need for callback in find().
-            if (rrset->getType() == RRType::NS() &&
-                rrset->getName() != origin_) {
-                node->setFlag(DomainNode::FLAG_CALLBACK);
-                // If it is DNAME, we have a callback as well here
-            } else if (rrset->getType() == RRType::DNAME()) {
-                node->setFlag(DomainNode::FLAG_CALLBACK);
-            }
-
-            if (need_additionals != NULL &&
-                (rrset->getType() == RRType::NS() ||
-                 rrset->getType() == RRType::MX())) {
-                need_additionals->push_back(rrset.get());
-            }
-
-            // If we've added NSEC3PARAM at zone origin, set up NSEC3 specific
-            // data or check consistency with already set up parameters.
-            if (rrset->getType() == RRType::NSEC3PARAM() &&
-                rrset->getName() == origin_) {
-                // We know rrset has exactly one RDATA
-                const generic::NSEC3PARAM& param =
-                    dynamic_cast<const generic::NSEC3PARAM&>(
-                        rrset->getRdataIterator()->getCurrent());
-
-                if (!zone_data.nsec3_data_) {
-                    zone_data.nsec3_data_.reset(
-                        new ZoneData::NSEC3Data(param));
-                } else if (!zone_data.nsec3_data_->hash_->match(param)) {
-                    isc_throw(AddError, "NSEC3PARAM with inconsistent "
-                              "parameters: " << rrset->toText());
-                }
-            } else if (rrset->getType() == RRType::NSEC()) {
-                // If it is NSEC signed zone, so we put a flag there
-                // (flag is enough)
-                zone_data.nsec_signed_ = true;
-            }
-            return (result::SUCCESS);
-        } else {
-            // The RRSet of given type was already there
-            return (result::EXIST);
-        }
-    }
-
-    /*
-     * Same as above, but it checks the return value and if it already exists,
-     * it throws.
-     */
-    void addFromLoad(const ConstRRsetPtr& set, ZoneData* zone_data,
-                     vector<RBNodeRRset*>* need_additionals)
-    {
-        switch (add(set, *zone_data, need_additionals)) {
-        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:
-            return;
-        default:
-            assert(0);
-        }
-    }
-
-    // A helper function for the NXRRSET case in find().  If the zone is
-    // NSEC-signed and DNSSEC records are requested, try to find NSEC
-    // on the given node, and return it if found; return NULL for all other
-    // cases.
-    ConstRBNodeRRsetPtr getNSECForNXRRSET(FindOptions options,
-                                          const DomainNode& node) const
-    {
-        if (zone_data_->nsec_signed_ &&
-            (options & ZoneFinder::FIND_DNSSEC) != 0) {
-            const Domain::const_iterator found =
-                node.getData()->find(RRType::NSEC());
-            if (found != node.getData()->end()) {
-                return (found->second);
-            }
-        }
-        return (ConstRBNodeRRsetPtr());
-    }
-
-    // Set up FindContext object as a return value of find(), taking into
-    // account wildcard matches and DNSSEC information.  We set the NSEC/NSEC3
-    // flag when applicable regardless of the find option; the caller would
-    // simply ignore these when they didn't request DNSSEC related results.
-    // When the optional parameter 'node' is given (in which case it should be
-    // non NULL), it means it's a result of ANY query and the context should
-    // remember the matched node.
-    RBNodeResultContext createFindResult(Result code,
-                                         ConstRBNodeRRsetPtr rrset,
-                                         bool wild = false,
-                                         const DomainNode* node = NULL) const
-    {
-        FindResultFlags flags = RESULT_DEFAULT;
-        if (wild) {
-            flags = flags | RESULT_WILDCARD;
-        }
-        if (code == NXRRSET || code == NXDOMAIN || wild) {
-            if (zone_data_->nsec3_data_) {
-                flags = flags | RESULT_NSEC3_SIGNED;
-            }
-            if (zone_data_->nsec_signed_) {
-                flags = flags | RESULT_NSEC_SIGNED;
-            }
-        }
-        return (RBNodeResultContext(code, rrset, flags, node));
-    }
-
-    // Implementation of InMemoryZoneFinder::find
-    RBNodeResultContext find(const Name& name, RRType type,
-                             std::vector<ConstRRsetPtr>* target,
-                             const FindOptions options) const
-    {
-        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
-            arg(type);
-
-        // Get the node.  All other cases than an exact match are handled
-        // in findNode().  We simply construct a result structure and return.
-        RBTreeNodeChain<Domain> node_path; // findNode will fill in this
-        const ZoneData::FindNodeResult node_result =
-            zone_data_->findNode<ZoneData::FindNodeResult>(name, node_path,
-                                                           options);
-        if (node_result.code != SUCCESS) {
-            return (createFindResult(node_result.code, node_result.rrset));
-        }
-
-        // We've found an exact match, may or may not be a result of wildcard.
-        const DomainNode* node = node_result.node;
-        assert(node != NULL);
-        const bool rename = ((node_result.flags &
-                              ZoneData::FindNodeResult::FIND_WILDCARD) != 0);
-
-        // 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 (createFindResult(NXRRSET,
-                                     zone_data_->getClosestNSEC(node_path,
-                                                                options),
-                                     rename));
-        }
-
-        Domain::const_iterator found;
-
-        // If the node callback is enabled, this may be a zone cut.  If it
-        // has a NS RR, we should return a delegation, but not in the apex.
-        // There is one exception: the case for DS query, which should always
-        // be considered in-zone lookup.
-        if (node->getFlag(DomainNode::FLAG_CALLBACK) &&
-            node != zone_data_->origin_data_ && type != RRType::DS()) {
-            found = node->getData()->find(RRType::NS());
-            if (found != node->getData()->end()) {
-                LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_EXACT_DELEGATION).arg(name);
-                return (createFindResult(DELEGATION,
-                                         prepareRRset(name, found->second,
-                                                      rename, options)));
-            }
-        }
-
-        // handle type any query
-        if (target != NULL && !node->getData()->empty()) {
-            // Empty domain will be handled as NXRRSET by normal processing
-            for (found = node->getData()->begin();
-                 found != node->getData()->end(); ++found)
-            {
-                target->push_back(prepareRRset(name, found->second, rename,
-                                               options));
-            }
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
-                arg(name);
-            return (createFindResult(SUCCESS, ConstRBNodeRRsetPtr(), rename,
-                                     node));
-        }
-
-        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 (createFindResult(SUCCESS, prepareRRset(name,
-                                                           found->second,
-                                                           rename, options),
-                                     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 (createFindResult(CNAME,
-                                          prepareRRset(name, found->second,
-                                                       rename, options),
-                                          rename));
-            }
-        }
-        // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
-        return (createFindResult(NXRRSET, getNSECForNXRRSET(options, *node),
-                                 rename));
-    }
-};
-
-InMemoryZoneFinder::InMemoryZoneFinder(const RRClass& zone_class,
-                                       const Name& origin) :
-    impl_(new InMemoryZoneFinderImpl(zone_class, origin))
-{
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_CREATE).arg(origin).
-        arg(zone_class);
-}
-
-InMemoryZoneFinder::~InMemoryZoneFinder() {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_DESTROY).arg(getOrigin()).
-        arg(getClass());
-    delete impl_;
-}
-
-Name
-InMemoryZoneFinder::getOrigin() const {
-    return (impl_->origin_);
-}
-
-RRClass
-InMemoryZoneFinder::getClass() const {
-    return (impl_->zone_class_);
-}
-
-ZoneFinderContextPtr
-InMemoryZoneFinder::find(const Name& name, const RRType& type,
-                         const FindOptions options)
-{
-    return (ZoneFinderContextPtr(
-                new Context(*this, options, impl_->find(name, type, NULL,
-                                                        options))));
-}
-
-ZoneFinderContextPtr
-InMemoryZoneFinder::findAll(const Name& name,
-                            std::vector<ConstRRsetPtr>& target,
-                            const FindOptions options)
-{
-    return (ZoneFinderContextPtr(
-                new Context(*this, options, impl_->find(name, RRType::ANY(),
-                                                        &target, options))));
-}
-
-ZoneFinder::FindNSEC3Result
-InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
-        arg(recursive ? "recursive" : "non-recursive");
-
-    if (!impl_->zone_data_->nsec3_data_) {
-        isc_throw(DataSourceError,
-                  "findNSEC3 attempt for non NSEC3 signed zone: " <<
-                  impl_->origin_ << "/" << impl_->zone_class_);
-    }
-    const NSEC3Map& map = impl_->zone_data_->nsec3_data_->map_;
-    if (map.empty()) {
-        isc_throw(DataSourceError,
-                  "findNSEC3 attempt but zone has no NSEC3 RR: " <<
-                  impl_->origin_ << "/" << impl_->zone_class_);
-    }
-    const NameComparisonResult cmp_result = name.compare(impl_->origin_);
-    if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
-        cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
-        isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
-                  << name << ", zone: " << impl_->origin_ << "/"
-                  << impl_->zone_class_);
-    }
-
-    // Convenient shortcuts
-    const NSEC3Hash& nsec3hash = *impl_->zone_data_->nsec3_data_->hash_;
-    const unsigned int olabels = impl_->origin_.getLabelCount();
-    const unsigned int qlabels = name.getLabelCount();
-
-    ConstRBNodeRRsetPtr covering_proof; // placeholder of the next closer proof
-    // Examine all names from the query name to the origin name, stripping
-    // the deepest label one by one, until we find a name that has a matching
-    // NSEC3 hash.
-    for (unsigned int labels = qlabels; labels >= olabels; --labels) {
-        const string hlabel = nsec3hash.calculate(
-            labels == qlabels ? name : name.split(qlabels - labels, labels));
-        NSEC3Map::const_iterator found = map.lower_bound(hlabel);
-        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
-            arg(name).arg(labels).arg(hlabel);
-
-        // If the given hash is larger than the largest stored hash or
-        // the first label doesn't match the target, identify the "previous"
-        // hash value and remember it as the candidate next closer proof.
-        if (found == map.end() || found->first != hlabel) {
-            // If the given hash is larger or smaller than everything,
-            // the covering proof is the NSEC3 that has the largest hash.
-            // Note that we know the map isn't empty, so rbegin() is
-            // safe.
-            if (found == map.end() || found == map.begin()) {
-                covering_proof = map.rbegin()->second;
-            } else {
-                // Otherwise, H(found_entry-1) < given_hash < H(found_entry).
-                // The covering proof is the first one (and it's valid
-                // because found is neither begin nor end)
-                covering_proof = (--found)->second;
-            }
-            if (!recursive) {   // in non recursive mode, we are done.
-                LOG_DEBUG(logger, DBG_TRACE_BASIC,
-                          DATASRC_MEM_FINDNSEC3_COVER).
-                    arg(name).arg(*covering_proof);
-                return (FindNSEC3Result(false, labels, covering_proof,
-                                        ConstRRsetPtr()));
-            }
-        } else {                // found an exact match.
-                LOG_DEBUG(logger, DBG_TRACE_BASIC,
-                          DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
-                    arg(*found->second);
-            return (FindNSEC3Result(true, labels, found->second,
-                                    covering_proof));
-        }
-    }
-
-    isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely "
-              "a broken NSEC3 zone: " << impl_->origin_ << "/"
-              << impl_->zone_class_);
-}
-
-result::Result
-InMemoryZoneFinder::add(const ConstRRsetPtr& rrset) {
-    return (impl_->add(rrset, *impl_->zone_data_, NULL));
-}
-
-namespace {
-// This should eventually be more generalized.
-const Name
-getAdditionalName(RRType rrtype, const rdata::Rdata& rdata) {
-    if (rrtype == RRType::NS()) {
-        const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
-        return (ns.getNSName());
-    } else {
-        // In our usage the only other possible case is MX.
-        assert(rrtype == RRType::MX());
-        const generic::MX& mx = dynamic_cast<const generic::MX&>(rdata);
-        return (mx.getMXName());
-    }
-}
-
-void
-convertAndInsert(const DomainPair& rrset_item, DomainPtr dst_domain,
-                 const Name* dstname)
-{
-    // We copy RRSIGs, too, if they are attached in case we need it in
-    // getAdditional().
-    dst_domain->insert(DomainPair(rrset_item.first,
-                                  prepareRRset(*dstname, rrset_item.second,
-                                               true,
-                                               ZoneFinder::FIND_DNSSEC)));
-}
-
-void
-addAdditional(RBNodeRRset* rrset, ZoneData* zone_data,
-              vector<RBNodeRRset*>* wild_rrsets)
-{
-    RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    bool match_wild = false;    // will be true if wildcard match is found
-    RBTreeNodeChain<Domain> node_path;  // placeholder for findNode()
-    for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
-        // For each domain name that requires additional section processing
-        // in each RDATA, search the tree for the name and remember it if
-        // found.  If the name is under a zone cut (for a delegation to a
-        // child zone), mark the node as "GLUE", so we can selectively
-        // include/exclude them when we use it.
-
-        const Name& name = getAdditionalName(rrset->getType(),
-                                             rdata_iterator->getCurrent());
-        // if the name is not in or below this zone, skip it
-        const NameComparisonResult::NameRelation reln =
-            name.compare(zone_data->origin_data_->getName()).getRelation();
-        if (reln != NameComparisonResult::SUBDOMAIN &&
-            reln != NameComparisonResult::EQUAL) {
-            continue;
-        }
-        node_path.clear();
-        const ZoneData::FindMutableNodeResult result =
-            zone_data->findNode<ZoneData::FindMutableNodeResult>(
-                name, node_path, ZoneFinder::FIND_GLUE_OK);
-        if (result.code != ZoneFinder::SUCCESS) {
-            // We are not interested in anything but a successful match.
-            continue;
-        }
-        DomainNode* node = result.node;
-        assert(node != NULL);
-        if ((result.flags & ZoneData::FindNodeResult::FIND_ZONECUT) != 0 ||
-            (node->getFlag(DomainNode::FLAG_CALLBACK) &&
-             node->getData()->find(RRType::NS()) != node->getData()->end())) {
-            // The node is under or at a zone cut; mark it as a glue.
-            node->setFlag(domain_flag::GLUE);
-        }
-
-        // A rare case: the additional name may have to be expanded with a
-        // wildcard.  We'll store the name in a separate auxiliary tree,
-        // copying all RRsets of the original wildcard node with expanding
-        // the owner name.  This is costly in terms of memory, but this case
-        // should be pretty rare.  On the other hand we won't have to worry
-        // about wildcard expansion in getAdditional, which is quite
-        // performance sensitive.
-        DomainNode* wildnode = NULL;
-        if ((result.flags & ZoneData::FindNodeResult::FIND_WILDCARD) != 0) {
-            // Wildcard and glue shouldn't coexist.  Make it sure here.
-            assert(!node->getFlag(domain_flag::GLUE));
-
-            if (zone_data->getAuxWildDomains().insert(
-                    zone_data->local_mem_sgmt_, name, &wildnode)
-                == DomainTree::SUCCESS) {
-                // If we first insert the node, copy the RRsets.  If the
-                // original node was empty, we add empty data so
-                // addWildAdditional() can get an exactmatch for this name.
-                DomainPtr dst_domain(new Domain);
-                if (!node->isEmpty()) {
-                    for_each(node->getData()->begin(), node->getData()->end(),
-                             boost::bind(convertAndInsert, _1, dst_domain,
-                                         &name));
-                }
-                wildnode->setData(dst_domain);
-                // Mark the node as "wildcard expanded" so it can be
-                // distinguished at lookup time.
-                wildnode->setFlag(domain_flag::WILD_EXPANDED);
-            }
-            match_wild = true;
-            node = wildnode;
-        }
-
-        // If this name wasn't subject to wildcard substitution, we can add
-        // the additional information to the RRset now; otherwise I'll defer
-        // it until the entire auxiliary tree is built (pointers may be
-        // invalidated as we build it).
-        if (wildnode == NULL) {
-            // Note that node may be empty.  We should keep it in the list
-            // in case we dynamically update the tree and it becomes non empty
-            // (which is not supported yet)
-            rrset->addAdditionalNode(AdditionalNodeInfo(node));
-        }
-    }
-
-    if (match_wild) {
-        wild_rrsets->push_back(rrset);
-    }
-}
-
-void
-addWildAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
-    // Similar to addAdditional(), but due to the first stage we know that
-    // the rrset should contain a name stored in the auxiliary trees, and
-    // that it should be found as an exact match.  The RRset may have other
-    // names that didn't require wildcard expansion, but we can simply ignore
-    // them in this context.  (Note that if we find an exact match in the
-    // auxiliary tree, it shouldn't be in the original zone; otherwise it
-    // shouldn't have resulted in wildcard in the first place).
-
-    RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
-        const Name& name = getAdditionalName(rrset->getType(),
-                                             rdata_iterator->getCurrent());
-        DomainNode* wildnode = NULL;
-        if (zone_data->getAuxWildDomains().find(name, &wildnode) ==
-            DomainTree::EXACTMATCH) {
-            rrset->addAdditionalNode(AdditionalNodeInfo(wildnode));
-        }
-    }
-}
-}
-
-void
-InMemoryZoneFinder::InMemoryZoneFinderImpl::load(
-    const string& filename,
-    boost::function<void(LoadCallback)> rrset_installer)
-{
-    vector<RBNodeRRset*> need_additionals;
-    scoped_ptr<ZoneData> tmp(new ZoneData(origin_));
-
-    rrset_installer(boost::bind(&InMemoryZoneFinderImpl::addFromLoad, this,
-                                _1, tmp.get(), &need_additionals));
-
-    vector<RBNodeRRset*> wild_additionals;
-    for_each(need_additionals.begin(), need_additionals.end(),
-             boost::bind(addAdditional, _1, tmp.get(), &wild_additionals));
-    for_each(wild_additionals.begin(), wild_additionals.end(),
-             boost::bind(addWildAdditional, _1, tmp.get()));
-
-    // If the zone is NSEC3-signed, check if it has NSEC3PARAM
-    if (tmp->nsec3_data_) {
-        // Note: origin_data_ is set on creation of ZoneData, and the load
-        // process only adds new nodes (and their data), so this assertion
-        // should hold.
-        assert(tmp->origin_data_ != NULL && !tmp->origin_data_->isEmpty());
-        if (tmp->origin_data_->getData()->find(RRType::NSEC3PARAM()) ==
-            tmp->origin_data_->getData()->end()) {
-            LOG_WARN(logger, DATASRC_MEM_NO_NSEC3PARAM).
-                arg(origin_).arg(zone_class_);
-        }
-    }
-
-    // If it went well, put it inside
-    file_name_ = filename;
-    tmp.swap(zone_data_);
-    // And let the old data die with tmp
-}
-
-namespace {
-// A wrapper for dns::masterLoad used by load() below.  Essentially it
-// converts the two callback types.  Note the mostly redundant wrapper of
-// boost::bind.  It converts function<void(ConstRRsetPtr)> to
-// function<void(RRsetPtr)> (masterLoad() expects the latter).  SunStudio
-// doesn't seem to do this conversion if we just pass 'callback'.
-void
-masterLoadWrapper(const char* const filename, const Name& origin,
-                  const RRClass& zone_class, LoadCallback callback)
-{
-    masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
-}
-
-// The installer called from Impl::load() for the iterator version of load().
-void
-generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
-    ConstRRsetPtr rrset;
-    vector<ConstRRsetPtr> rrsigs; // placeholder for RRSIGs until "commitable".
-
-    // The current internal implementation assumes an RRSIG is always added
-    // after the RRset they cover.  So we store any RRSIGs in 'rrsigs' until
-    // it's safe to add them; based on our assumption if the owner name
-    // changes, all covered RRsets of the previous name should have been
-    // installed and any pending RRSIGs can be added at that point.  RRSIGs
-    // of the last name from the iterator must be added separately.
-    while ((rrset = iterator->getNextRRset()) != NULL) {
-        if (!rrsigs.empty() && rrset->getName() != rrsigs[0]->getName()) {
-            BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
-                callback(sig_rrset);
-            }
-            rrsigs.clear();
-        }
-        if (rrset->getType() == RRType::RRSIG()) {
-            rrsigs.push_back(rrset);
-        } else {
-            callback(rrset);
-        }
-    }
-
-    BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
-        callback(sig_rrset);
-    }
-}
-}
-
-void
-InMemoryZoneFinder::load(const std::string& filename) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
-        arg(filename);
-
-    impl_->load(filename,
-                boost::bind(masterLoadWrapper, filename.c_str(), getOrigin(),
-                            getClass(), _1));
-}
-
-void
-InMemoryZoneFinder::load(ZoneIterator& iterator) {
-    impl_->load(string(),
-                boost::bind(generateRRsetFromIterator, &iterator, _1));
-}
-
-void
-InMemoryZoneFinder::swap(InMemoryZoneFinder& zone_finder) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
-        arg(zone_finder.getOrigin());
-    std::swap(impl_, zone_finder.impl_);
-}
-
-const string
-InMemoryZoneFinder::getFileName() const {
-    return (impl_->file_name_);
-}
-
-/// Implementation details for \c InMemoryClient hidden from the public
-/// interface.
-///
-/// For now, \c InMemoryClient only contains a \c ZoneTable object, which
-/// consists of (pointers to) \c InMemoryZoneFinder objects, we may add more
-/// member variables later for new features.
-class InMemoryClient::InMemoryClientImpl {
-public:
-    InMemoryClientImpl() : zone_count(0),
-                           zone_table(ZoneTable::create(local_mem_sgmt))
-    {}
-    ~InMemoryClientImpl() {
-        ZoneTable::destroy(local_mem_sgmt, zone_table);
-
-        // see above for the assert().
-        assert(local_mem_sgmt.allMemoryDeallocated());
-    }
-
-    // Memory segment to allocate/deallocate memory for the zone table.
-    // (This will eventually have to be abstract; for now we hardcode the
-    // specific derived segment class).
-    util::MemorySegmentLocal local_mem_sgmt;
-    unsigned int zone_count;
-    ZoneTable* zone_table;
-};
-
-InMemoryClient::InMemoryClient() : impl_(new InMemoryClientImpl)
-{}
-
-InMemoryClient::~InMemoryClient() {
-    delete impl_;
-}
-
-unsigned int
-InMemoryClient::getZoneCount() const {
-    return (impl_->zone_count);
-}
-
-result::Result
-InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
-    if (!zone_finder) {
-        isc_throw(InvalidParameter,
-                  "Null pointer is passed to InMemoryClient::addZone()");
-    }
-
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
-        arg(zone_finder->getOrigin()).arg(zone_finder->getClass().toText());
-
-    const result::Result result =
-        impl_->zone_table->addZone(impl_->local_mem_sgmt, zone_finder);
-    if (result == result::SUCCESS) {
-        ++impl_->zone_count;
-    }
-    return (result);
-}
-
-InMemoryClient::FindResult
-InMemoryClient::findZone(const isc::dns::Name& name) const {
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
-    ZoneTable::FindResult result(impl_->zone_table->findZone(name));
-    return (FindResult(result.code, result.zone));
-}
-
-namespace {
-
-class MemoryIterator : public ZoneIterator {
-private:
-    RBTreeNodeChain<Domain> chain_;
-    Domain::const_iterator dom_iterator_;
-    const DomainTree& tree_;
-    const DomainNode* node_;
-    // Only used when separate_rrs_ is true
-    RdataIteratorPtr rdata_iterator_;
-    bool separate_rrs_;
-    bool ready_;
-public:
-    MemoryIterator(const DomainTree& tree, const Name& origin, bool separate_rrs) :
-        tree_(tree),
-        separate_rrs_(separate_rrs),
-        ready_(true)
-    {
-        // Find the first node (origin) and preserve the node chain for future
-        // searches
-        DomainTree::Result result(tree_.find(origin, &node_, chain_));
-        // It can't happen that the origin is not in there
-        if (result != DomainTree::EXACTMATCH) {
-            isc_throw(Unexpected,
-                      "In-memory zone corrupted, missing origin node");
-        }
-        // Initialize the iterator if there's somewhere to point to
-        if (node_ != NULL && node_->getData() != DomainPtr()) {
-            dom_iterator_ = node_->getData()->begin();
-            if (separate_rrs_ && dom_iterator_ != node_->getData()->end()) {
-                rdata_iterator_ = dom_iterator_->second->getRdataIterator();
-            }
-        }
-    }
-
-    virtual ConstRRsetPtr getNextRRset() {
-        if (!ready_) {
-            isc_throw(Unexpected, "Iterating past the zone end");
-        }
-        /*
-         * This cycle finds the first nonempty node with yet unused RRset.
-         * If it is NULL, we run out of nodes. If it is empty, it doesn't
-         * contain any RRsets. If we are at the end, just get to next one.
-         */
-        while (node_ != NULL && (node_->getData() == DomainPtr() ||
-                                 dom_iterator_ == node_->getData()->end())) {
-            node_ = tree_.nextNode(chain_);
-            // If there's a node, initialize the iterator and check next time
-            // if the map is empty or not
-            if (node_ != NULL && node_->getData() != NULL) {
-                dom_iterator_ = node_->getData()->begin();
-                // New RRset, so get a new rdata iterator
-                if (separate_rrs_) {
-                    rdata_iterator_ = dom_iterator_->second->getRdataIterator();
-                }
-            }
-        }
-        if (node_ == NULL) {
-            // That's all, folks
-            ready_ = false;
-            return (ConstRRsetPtr());
-        }
-
-        if (separate_rrs_) {
-            // For separate rrs, reconstruct a new RRset with just the
-            // 'current' rdata
-            RRsetPtr result(new RRset(dom_iterator_->second->getName(),
-                                      dom_iterator_->second->getClass(),
-                                      dom_iterator_->second->getType(),
-                                      dom_iterator_->second->getTTL()));
-            result->addRdata(rdata_iterator_->getCurrent());
-            rdata_iterator_->next();
-            if (rdata_iterator_->isLast()) {
-                // all used up, next.
-                ++dom_iterator_;
-                // New RRset, so get a new rdata iterator, but only if this
-                // was not the final RRset in the chain
-                if (dom_iterator_ != node_->getData()->end()) {
-                    rdata_iterator_ = dom_iterator_->second->getRdataIterator();
-                }
-            }
-            return (result);
-        } else {
-            // The iterator points to the next yet unused RRset now
-            ConstRRsetPtr result(dom_iterator_->second);
-
-            // This one is used, move it to the next time for next call
-            ++dom_iterator_;
-
-            return (result);
-        }
-    }
-
-    virtual ConstRRsetPtr getSOA() const {
-        isc_throw(NotImplemented, "Not imelemented");
-    }
-};
-
-} // End of anonymous namespace
-
-ZoneIteratorPtr
-InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
-    ZoneTable::FindResult result(impl_->zone_table->findZone(name));
-    if (result.code != result::SUCCESS) {
-        isc_throw(DataSourceError, "No such zone: " + name.toText());
-    }
-
-    const InMemoryZoneFinder*
-        zone(dynamic_cast<const InMemoryZoneFinder*>(result.zone.get()));
-    if (zone == NULL) {
-        /*
-         * TODO: This can happen only during some of the tests and only as
-         * a temporary solution. This should be fixed by #1159 and then
-         * this cast and check shouldn't be necessary. We don't have
-         * test for handling a "can not happen" condition.
-         */
-        isc_throw(Unexpected, "The zone at " + name.toText() +
-                  " is not InMemoryZoneFinder");
-    }
-    return (ZoneIteratorPtr(new MemoryIterator(
-                                zone->impl_->zone_data_->domains_, name,
-                                separate_rrs)));
-}
-
-ZoneUpdaterPtr
-InMemoryClient::getUpdater(const isc::dns::Name&, bool, bool) const {
-    isc_throw(isc::NotImplemented, "Update attempt on in memory data source");
-}
-
-pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
-InMemoryClient::getJournalReader(const isc::dns::Name&, uint32_t,
-                                 uint32_t) const
-{
-    isc_throw(isc::NotImplemented, "Journaling isn't supported for "
-              "in memory data source");
-}
-
-} // end of namespace datasrc
-} // end of namespace isc
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
deleted file mode 100644
index 4e277e0..0000000
--- a/src/lib/datasrc/memory_datasrc.h
+++ /dev/null
@@ -1,366 +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 MEMORY_DATA_SOURCE_H
-#define MEMORY_DATA_SOURCE_H 1
-
-#include <string>
-
-#include <boost/noncopyable.hpp>
-
-#include <datasrc/zonetable.h>
-#include <datasrc/client.h>
-
-#include <cc/data.h>
-
-namespace isc {
-namespace dns {
-class Name;
-class RRsetList;
-};
-
-namespace datasrc {
-
-/// A derived zone finder class intended to be used with the memory data source.
-///
-/// Conceptually this "finder" maintains a local in-memory copy of all RRs
-/// of a single zone from some kind of source (right now it's a textual
-/// master file, but it could also be another data source with a database
-/// backend).  This is why the class has methods like \c load() or \c add().
-///
-/// This class is non copyable.
-class InMemoryZoneFinder : boost::noncopyable, public ZoneFinder {
-    ///
-    /// \name Constructors and Destructor.
-public:
-    /// \brief Constructor from zone parameters.
-    ///
-    /// This constructor internally involves resource allocation, and if
-    /// it fails, a corresponding standard exception will be thrown.
-    /// It never throws an exception otherwise.
-    ///
-    /// \param rrclass The RR class of the zone.
-    /// \param origin The origin name of the zone.
-    InMemoryZoneFinder(const isc::dns::RRClass& rrclass,
-                       const isc::dns::Name& origin);
-
-    /// The destructor.
-    virtual ~InMemoryZoneFinder();
-    //@}
-
-    /// \brief Returns the origin of the zone.
-    virtual isc::dns::Name getOrigin() const;
-
-    /// \brief Returns the class of the zone.
-    virtual isc::dns::RRClass getClass() const;
-
-    /// \brief Find an RRset in the datasource
-    virtual ZoneFinderContextPtr find(const isc::dns::Name& name,
-                                      const isc::dns::RRType& type,
-                                      const FindOptions options =
-                                      FIND_DEFAULT);
-
-    /// \brief Version of find that returns all types at once
-    ///
-    /// It acts the same as find, just that when the correct node is found,
-    /// all the RRsets are filled into the target parameter instead of being
-    /// returned by the result.
-    virtual ZoneFinderContextPtr findAll(
-        const isc::dns::Name& name,
-        std::vector<isc::dns::ConstRRsetPtr>& target,
-        const FindOptions options = FIND_DEFAULT);
-
-    /// Look for NSEC3 for proving (non)existence of given name.
-    ///
-    /// See documentation in \c Zone.
-    virtual FindNSEC3Result
-    findNSEC3(const isc::dns::Name& name, bool recursive);
-
-    /// \brief Inserts an rrset into the zone.
-    ///
-    /// It puts another RRset into the zone.
-    ///
-    /// In the current implementation, this method doesn't allow an existing
-    /// RRset to be updated or overridden.  So the caller must make sure that
-    /// all RRs of the same type and name must be given in the form of a
-    /// single RRset.  The current implementation will also require that
-    /// when an RRSIG is added the RRset to be covered has already been
-    /// added.  These restrictions are probably too strict when this data
-    /// source accepts various forms of input, so they should be revisited
-    /// later.
-    ///
-    /// Except for NullRRset and OutOfZone, this method does not guarantee
-    /// strong exception safety (it is currently not needed, if it is needed
-    /// in future, it should be implemented).
-    ///
-    /// \throw NullRRset \c rrset is a NULL pointer.
-    /// \throw OutOfZone The owner name of \c rrset is outside of the
-    /// origin of the zone.
-    /// \throw AddError Other general errors.
-    /// \throw Others This method might throw standard allocation exceptions.
-    ///
-    /// \param rrset The set to add.
-    /// \return SUCCESS or EXIST (if an rrset for given name and type already
-    ///    exists).
-    result::Result add(const isc::dns::ConstRRsetPtr& rrset);
-
-    /// \brief RRset is NULL exception.
-    ///
-    /// This is thrown if the provided RRset parameter is NULL.
-    struct NullRRset : public InvalidParameter {
-        NullRRset(const char* file, size_t line, const char* what) :
-            InvalidParameter(file, line, what)
-        { }
-    };
-
-    /// \brief General failure exception for \c add().
-    ///
-    /// This is thrown against general error cases in adding an RRset
-    /// to the zone.
-    ///
-    /// Note: this exception would cover cases for \c OutOfZone or
-    /// \c NullRRset.  We'll need to clarify and unify the granularity
-    /// of exceptions eventually.  For now, exceptions are added as
-    /// developers see the need for it.
-    struct AddError : public InvalidParameter {
-        AddError(const char* file, size_t line, const char* what) :
-            InvalidParameter(file, line, what)
-        { }
-    };
-
-    /// Return the master file name of the zone
-    ///
-    /// This method returns the name of the zone's master file to be loaded.
-    /// The returned string will be an empty unless the zone finder has
-    /// successfully loaded a zone.
-    ///
-    /// This method should normally not throw an exception.  But the creation
-    /// of the return string may involve a resource allocation, and if it
-    /// fails, the corresponding standard exception will be thrown.
-    ///
-    /// \return The name of the zone file loaded in the zone finder, or an empty
-    /// string if the zone hasn't loaded any file.
-    const std::string getFileName() const;
-
-    /// \brief Load zone from masterfile.
-    ///
-    /// This loads data from masterfile specified by filename. It replaces
-    /// current content. The masterfile parsing ability is kind of limited,
-    /// see isc::dns::masterLoad.
-    ///
-    /// This throws isc::dns::MasterLoadError if there is problem with loading
-    /// (missing file, malformed, it contains different zone, etc - see
-    /// isc::dns::masterLoad for details).
-    ///
-    /// In case of internal problems, OutOfZone, NullRRset or AssertError could
-    /// be thrown, but they should not be expected. Exceptions caused by
-    /// allocation may be thrown as well.
-    ///
-    /// If anything is thrown, the previous content is preserved (so it can
-    /// be used to update the data, but if user makes a typo, the old one
-    /// is kept).
-    ///
-    /// \param filename The master file to load.
-    ///
-    /// \todo We may need to split it to some kind of build and commit/abort.
-    ///     This will probably be needed when a better implementation of
-    ///     configuration reloading is written.
-    void load(const std::string& filename);
-
-    /// \brief Load zone from another data source.
-    ///
-    /// This is similar to the other version, but zone's RRsets are provided
-    /// by an iterator of another data source.  On successful load, the
-    /// internal filename will be cleared.
-    ///
-    /// This implementation assumes the iterator produces combined RRsets,
-    /// that is, there should exactly one RRset for the same owner name and
-    /// RR type.  This means the caller is expected to create the iterator
-    /// with \c separate_rrs being \c false.  This implementation also assumes
-    /// RRsets of different names are not mixed; so if the iterator produces
-    /// an RRset of a different name than that of the previous RRset, that
-    /// previous name must never appear in the subsequent sequence of RRsets.
-    /// Note that the iterator API does not ensure this.  If the underlying
-    /// implementation does not follow it, load() will fail.  Note, however,
-    /// that this whole interface is tentative.  in-memory zone loading will
-    /// have to be revisited fundamentally, and at that point this restriction
-    /// probably won't matter.
-    void load(ZoneIterator& iterator);
-
-    /// Exchanges the content of \c this zone finder with that of the given
-    /// \c zone_finder.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param zone_finder Another \c InMemoryZone object which is to
-    /// be swapped with \c this zone finder.
-    void swap(InMemoryZoneFinder& zone_finder);
-
-private:
-    /// \name Hidden private data
-    //@{
-    struct InMemoryZoneFinderImpl;
-    InMemoryZoneFinderImpl* impl_;
-    //@}
-    // The friend here is for InMemoryClient::getIterator. The iterator
-    // needs to access the data inside the zone, so the InMemoryClient
-    // extracts the pointer to data and puts it into the iterator.
-    // The access is read only.
-    friend class InMemoryClient;
-
-    /// \brief In-memory version of finder context.
-    ///
-    /// The implementation (and any specialized interface) is completely local
-    /// to the InMemoryZoneFinder class, so it's defined as private
-    class Context;
-};
-
-/// \brief A data source client that holds all necessary data in memory.
-///
-/// The \c InMemoryClient class provides an access to a conceptual data
-/// source that maintains all necessary data in a memory image, thereby
-/// allowing much faster lookups.  The in memory data is a copy of some
-/// real physical source - in the current implementation a list of zones
-/// are populated as a result of \c addZone() calls; zone data is given
-/// in a standard master file (but there's a plan to use database backends
-/// as a source of the in memory data).
-///
-/// Although every data source client is assumed to be of the same RR class,
-/// the \c InMemoryClient class does not enforce the assumption through
-/// its interface.
-/// For example, the \c addZone() method does not check if the new zone is of
-/// the same RR class as that of the others already in memory.
-/// It is caller's responsibility to ensure this assumption.
-///
-/// <b>Notes to developer:</b>
-///
-/// The addZone() method takes a (Boost) shared pointer because it would be
-/// inconvenient to require the caller to maintain the ownership of zones,
-/// while it wouldn't be safe to delete unnecessary zones inside the dedicated
-/// backend.
-///
-/// The findZone() method takes a domain name and returns the best matching
-/// \c InMemoryZoneFinder in the form of (Boost) shared pointer, so that it can
-/// provide the general interface for all data sources.
-class InMemoryClient : public DataSourceClient {
-public:
-    ///
-    /// \name Constructors and Destructor.
-    ///
-    //@{
-
-    /// Default constructor.
-    ///
-    /// This constructor internally involves resource allocation, and if
-    /// it fails, a corresponding standard exception will be thrown.
-    /// It never throws an exception otherwise.
-    InMemoryClient();
-
-    /// The destructor.
-    ~InMemoryClient();
-    //@}
-
-    /// Return the number of zones stored in the client.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \return The number of zones stored in the client.
-    virtual unsigned int getZoneCount() const;
-
-    /// Add a zone (in the form of \c ZoneFinder) to the \c InMemoryClient.
-    ///
-    /// \c zone_finder must not be associated with a NULL pointer; otherwise
-    /// an exception of class \c InvalidParameter will be thrown.
-    /// If internal resource allocation fails, a corresponding standard
-    /// exception will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// \param zone_finder A \c ZoneFinder object to be added.
-    /// \return \c result::SUCCESS If the zone_finder is successfully
-    /// added to the client.
-    /// \return \c result::EXIST The memory data source already
-    /// stores a zone that has the same origin.
-    result::Result addZone(ZoneFinderPtr zone_finder);
-
-    /// Returns a \c ZoneFinder for a zone_finder that best matches the given
-    /// name.
-    ///
-    /// This derived version of the method never throws an exception.
-    /// For other details see \c DataSourceClient::findZone().
-    virtual FindResult findZone(const isc::dns::Name& name) const;
-
-    /// \brief Implementation of the getIterator method
-    virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
-                                        bool separate_rrs = false) const;
-
-    /// In-memory data source is read-only, so this derived method will
-    /// result in a NotImplemented exception.
-    ///
-    /// \note We plan to use a database-based data source as a backend
-    /// persistent storage for an in-memory data source.  When it's
-    /// implemented we may also want to allow the user of the in-memory client
-    /// to update via its updater (this may or may not be a good idea and
-    /// is subject to further discussions).
-    virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name& name,
-                                      bool replace, bool journaling = false)
-        const;
-
-    virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
-    getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
-                     uint32_t end_serial) const;
-
-private:
-    // TODO: Do we still need the PImpl if nobody should manipulate this class
-    // directly any more (it should be handled through DataSourceClient)?
-    class InMemoryClientImpl;
-    InMemoryClientImpl* impl_;
-};
-
-/// \brief Creates an instance of the Memory datasource client
-///
-/// Currently the configuration passed here must be a MapElement, formed as
-/// follows:
-/// \code
-/// { "type": string ("memory"),
-///   "class": string ("IN"/"CH"/etc),
-///   "zones": list
-/// }
-/// Zones list is a list of maps:
-/// { "origin": string,
-///   "file": string
-/// }
-/// \endcode
-/// (i.e. the configuration that was used prior to the datasource refactor)
-///
-/// This configuration setup is currently under discussion and will change in
-/// the near future.
-///
-/// \param config The configuration for the datasource instance
-/// \param error This string will be set to an error message if an error occurs
-///              during initialization
-/// \return An instance of the memory datasource client, or NULL if there was
-///         an error
-extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
-                                            std::string& error);
-
-/// \brief Destroy the instance created by createInstance()
-extern "C" void destroyInstance(DataSourceClient* instance);
-
-
-}
-}
-#endif  // MEMORY_DATA_SOURCE_H
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/memory_datasrc_link.cc b/src/lib/datasrc/memory_datasrc_link.cc
deleted file mode 100644
index 857223f..0000000
--- a/src/lib/datasrc/memory_datasrc_link.cc
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright (C) 2012  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 <cc/data.h>
-
-#include <dns/rrclass.h>
-
-#include <datasrc/client.h>
-#include <datasrc/factory.h>
-#include <datasrc/memory_datasrc.h>
-
-#include <exceptions/exceptions.h>
-
-#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
-
-#include <string>
-
-using namespace isc::dns;
-using namespace isc::data;
-
-namespace isc {
-namespace datasrc {
-
-/// This exception is raised if there is an error in the configuration
-/// that has been passed; missing information, duplicate values, etc.
-class InMemoryConfigError : public isc::Exception {
-public:
-    InMemoryConfigError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-namespace {
-// convencience function to add an error message to a list of those
-// (TODO: move functions like these to some util lib?)
-void
-addError(ElementPtr errors, const std::string& error) {
-    if (errors != ElementPtr() && errors->getType() == Element::list) {
-        errors->add(Element::create(error));
-    }
-}
-
-/// Check if the given element exists in the map, and if it is a string
-bool
-checkConfigElementString(ConstElementPtr config, const std::string& name,
-                         ElementPtr errors)
-{
-    if (!config->contains(name)) {
-        addError(errors,
-                 "Config for memory backend does not contain a '"
-                 +name+
-                 "' value");
-        return (false);
-    } else if (!config->get(name) ||
-               config->get(name)->getType() != Element::string) {
-        addError(errors, "value of " + name +
-                 " in memory backend config is not a string");
-        return (false);
-    } else {
-        return (true);
-    }
-}
-
-bool
-checkZoneConfig(ConstElementPtr config, ElementPtr errors) {
-    bool result = true;
-    if (!config || config->getType() != Element::map) {
-        addError(errors, "Elements in memory backend's zone list must be maps");
-        result = false;
-    } else {
-        if (!checkConfigElementString(config, "origin", errors)) {
-            result = false;
-        }
-        if (!checkConfigElementString(config, "file", errors)) {
-            result = false;
-        }
-        // we could add some existence/readabilty/parsability checks here
-        // if we want
-    }
-    return result;
-}
-
-bool
-checkConfig(ConstElementPtr config, ElementPtr errors) {
-    /* Specific configuration is under discussion, right now this accepts
-     * the 'old' configuration, see [TODO]
-     * So for memory datasource, we get a structure like this:
-     * { "type": string ("memory"),
-     *   "class": string ("IN"/"CH"/etc),
-     *   "zones": list
-     * }
-     * Zones list is a list of maps:
-     * { "origin": string,
-     *     "file": string
-     * }
-     *
-     * At this moment we cannot be completely sure of the contents of the
-     * structure, so we have to do some more extensive tests than should
-     * strictly be necessary (e.g. existence and type of elements)
-     */
-    bool result = true;
-
-    if (!config || config->getType() != Element::map) {
-        addError(errors, "Base config for memory backend must be a map");
-        result = false;
-    } else {
-        if (!checkConfigElementString(config, "type", errors)) {
-            result = false;
-        } else {
-            if (config->get("type")->stringValue() != "memory") {
-                addError(errors,
-                         "Config for memory backend is not of type \"memory\"");
-                result = false;
-            }
-        }
-        if (config->contains("class")) {
-            if (!checkConfigElementString(config, "class", errors)) {
-                result = false;
-            } else {
-                try {
-                    RRClass(config->get("class")->stringValue());
-                } catch (const isc::Exception& rrce) {
-                    addError(errors,
-                             "Error parsing class config for memory backend: " +
-                             std::string(rrce.what()));
-                    result = false;
-                }
-            }
-        }
-        if (!config->contains("zones")) {
-            // Assume empty list of zones
-        } else if (!config->get("zones") ||
-                   config->get("zones")->getType() != Element::list) {
-            addError(errors,
-                     "'zones' element in memory backend config is not a list");
-            result = false;
-        } else {
-            BOOST_FOREACH(ConstElementPtr zone_config,
-                          config->get("zones")->listValue()) {
-                if (!checkZoneConfig(zone_config, errors)) {
-                    result = false;
-                }
-            }
-        }
-    }
-
-    return (result);
-}
-
-// Apply the given config to the just-initialized client
-// client must be freshly allocated, and config_value should have been
-// checked by the caller
-void
-applyConfig(isc::datasrc::InMemoryClient& client,
-            isc::data::ConstElementPtr config_value)
-{
-    // XXX: We have lost the context to get to the default values here,
-    // as a temporary workaround we hardcode the IN class here.
-    isc::dns::RRClass rrclass = RRClass::IN();
-    if (config_value->contains("class")) {
-        rrclass = RRClass(config_value->get("class")->stringValue());
-    }
-    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");
-        const std::string origin_txt = origin ? origin->stringValue() : "";
-        if (origin_txt.empty()) {
-            isc_throw(InMemoryConfigError, "Missing zone origin");
-        }
-        ConstElementPtr file = zone_config->get("file");
-        const std::string file_txt = file ? file->stringValue() : "";
-        if (file_txt.empty()) {
-            isc_throw(InMemoryConfigError, "Missing zone file for zone: "
-                      << origin_txt);
-        }
-
-        // We support the traditional text type and SQLite3 backend.  For the
-        // latter we create a client for the underlying SQLite3 data source,
-        // and build the in-memory zone using an iterator of the underlying
-        // zone.
-        ConstElementPtr filetype = zone_config->get("filetype");
-        const std::string filetype_txt = filetype ? filetype->stringValue() :
-            "text";
-        boost::scoped_ptr<DataSourceClientContainer> container;
-        if (filetype_txt == "sqlite3") {
-            container.reset(new DataSourceClientContainer(
-                                "sqlite3",
-                                Element::fromJSON("{\"database_file\": \"" +
-                                                  file_txt + "\"}")));
-        } else if (filetype_txt != "text") {
-            isc_throw(InMemoryConfigError, "Invalid filetype for zone "
-                      << origin_txt << ": " << filetype_txt);
-        }
-
-        // Note: we don't want to have such small try-catch blocks for each
-        // specific error.  We may eventually want to introduce some unified
-        // error handling framework as we have more configuration parameters.
-        // See bug #1627 for the relevant discussion.
-        InMemoryZoneFinder* imzf = NULL;
-        try {
-            imzf = new InMemoryZoneFinder(rrclass, Name(origin_txt));
-        } catch (const isc::dns::NameParserException& ex) {
-            isc_throw(InMemoryConfigError, "unable to parse zone's origin: " <<
-                      ex.what());
-        }
-
-        boost::shared_ptr<InMemoryZoneFinder> zone_finder(imzf);
-        const result::Result result = client.addZone(zone_finder);
-        if (result == result::EXIST) {
-            isc_throw(InMemoryConfigError, "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.
-         */
-        if (filetype_txt == "text") {
-            zone_finder->load(file_txt);
-        } else {
-            zone_finder->load(*container->getInstance().getIterator(
-                                  Name(origin_txt)));
-        }
-    }
-}
-
-} // end unnamed namespace
-
-DataSourceClient *
-createInstance(isc::data::ConstElementPtr config, std::string& error) {
-    ElementPtr errors(Element::createList());
-    if (!checkConfig(config, errors)) {
-        error = "Configuration error: " + errors->str();
-        return (NULL);
-    }
-    try {
-        std::auto_ptr<InMemoryClient> client(new isc::datasrc::InMemoryClient());
-        applyConfig(*client, config);
-        return (client.release());
-    } catch (const isc::Exception& isce) {
-        error = isce.what();
-        return (NULL);
-    } catch (const std::exception& exc) {
-        error = std::string("Error creating memory datasource: ") + exc.what();
-        return (NULL);
-    } catch (...) {
-        error = std::string("Error creating memory datasource, "
-                            "unknown exception");
-        return (NULL);
-    }
-}
-
-void destroyInstance(DataSourceClient* instance) {
-    delete instance;
-}
-
-} // end of namespace datasrc
-} // end of namespace isc
diff --git a/src/lib/datasrc/rbnode_rrset.h b/src/lib/datasrc/rbnode_rrset.h
deleted file mode 100644
index cbb1b71..0000000
--- a/src/lib/datasrc/rbnode_rrset.h
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (C) 2012  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 RBNODE_RRSET_H
-#define RBNODE_RRSET_H
-
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrttl.h>
-#include <dns/rrtype.h>
-#include <util/buffer.h>
-
-#include <string>
-#include <vector>
-
-namespace isc {
-namespace datasrc {
-namespace internal {
-
-/// \brief The actual content of \c RBNodeRRset
-///
-///  This is defined in the namespace-scope (not hidden in the main class)
-/// so that the In-memory data source implementation can refer to it.
-struct RBNodeRRsetImpl;
-
-// Forward declaration of an opaque data type defined and used within the
-// implementation.  This is public only because it needs to be used within
-// the in-memory data source implementation, but conceptually this is a
-// private type for the in-memory data source implementation.
-// Note that the definition of the structure is still hidden within the
-// implementation, so, basically, a normal application should never be able
-// to use it directly even if it peeks into the "internal" namespace.
-struct AdditionalNodeInfo;
-
-/// \brief Special RRset for optimizing memory datasource requirement
-///
-/// To speed up the performance of the in-memory data source, at load time
-/// associate relevant "additional section" data with each RRset in the
-/// data source.
-///
-/// This class, derived from AbstractRRset, holds a "const" pointer to the
-/// underlying RRset object.  All calls to methods on the class are passed to
-/// the underlying object.  However, there are some restrictions:
-///
-/// - Calls to methods that change attributes of the underlying RRset (such as
-///   TTL or Name) cause an exception to be thrown.  The in-memory data source
-///   does not allow modification of these attributes.  In theory, it is a bad
-///   practice in that it doesn't preserve the assumed behavior of the base
-///   class.  In practice, however, it should be acceptable because this
-///   class is effectively hidden from applications and will only be given
-///   to them as a const pointer to the base class via find() variants.
-///   So the application cannot call non const methods anyway unless it
-///   intentionally breaks the constness.
-///
-/// - Calls that add the pointer to the associated RRSIG to the RRset are
-///   allowed (even though the pointer is to a "const" RRset).  The reason here
-///   is that RRSIGs are added to the in-memory data source after the
-///   RBNodeRRset objects have been created.  Thus there has to be the
-///   capability of modifying this information.
-///
-/// The class is not derived from RRset itself to simplify coding: part of the
-/// loading of the memory data source is handled in the BIND 10 "libdns++"
-/// code, which creates RRsets and passes them to the data source code.  This
-/// does not have to be altered if encapsulation, rather than inheritance, is
-/// used.
-///
-/// \note This class is exposed in this separate header file so that test code
-/// can refer to its definition, and only for that purpose.  Otherwise this is
-/// essentially a private class of the in-memory data source implementation,
-/// and an application shouldn't directly refer to this class.
-///
-// Note: non-Doxygen-documented methods are documented in the base class.
-
-class RBNodeRRset : public isc::dns::AbstractRRset {
-
-private:
-    // Note: The copy constructor and the assignment operator are intentionally
-    // defined as private as we would normally not duplicate a RBNodeRRset.
-    // (We use the "private" method instead of inheriting from
-    // boost::noncopyable so as to avoid multiple inheritance.)
-    RBNodeRRset(const RBNodeRRset& source);
-    RBNodeRRset& operator=(const RBNodeRRset& source);
-
-public:
-    /// \brief Usual Constructor
-    ///
-    /// Creates an RBNodeRRset from the pointer to the RRset passed to it.
-    ///
-    /// \param rrset Pointer to underlying RRset encapsulated by this object.
-    explicit RBNodeRRset(const isc::dns::ConstRRsetPtr& rrset);
-
-    /// \brief Destructor
-    virtual ~RBNodeRRset();
-
-    // Getter and Setter Methods
-    //
-    // The getter methods pass the call through to the underlying RRset.  The
-    // setter methods thrown an exception - this specialisation of the RRset
-    // object does not expect the underlying RRset to be modified.
-
-    virtual unsigned int getRdataCount() const;
-
-    virtual const isc::dns::Name& getName() const;
-
-    virtual const isc::dns::RRClass& getClass() const;
-
-    virtual const isc::dns::RRType& getType() const;
-
-    virtual const isc::dns::RRTTL& getTTL() const;
-
-    virtual void setName(const isc::dns::Name&);
-
-    virtual void setTTL(const isc::dns::RRTTL&);
-
-    virtual std::string toText() const;
-
-    virtual bool isSameKind(const AbstractRRset& other) const {
-        // This code is an optimisation for comparing
-        // RBNodeRRsets. However, in doing this optimisation,
-        // semantically the code is not "is same kind" but is instead
-        // "is identical object" in the case where RBNodeRRsets are compared.
-
-        const RBNodeRRset* rb = dynamic_cast<const RBNodeRRset*>(&other);
-        if (rb != NULL) {
-            return (this == rb);
-        } else {
-            return (AbstractRRset::isSameKind(other));
-        }
-    }
-
-    virtual unsigned int toWire(
-        isc::dns::AbstractMessageRenderer& renderer) const;
-
-    virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
-
-    virtual void addRdata(isc::dns::rdata::ConstRdataPtr);
-
-    virtual void addRdata(const isc::dns::rdata::Rdata&);
-
-    virtual isc::dns::RdataIteratorPtr getRdataIterator() const;
-
-    virtual isc::dns::RRsetPtr getRRsig() const;
-
-    virtual unsigned int getRRsigDataCount() const;
-
-    // With all the RRsig methods, we have the problem that we store the
-    // underlying RRset using a ConstRRsetPtr - a pointer to a "const" RRset -
-    // but we need to modify it by adding or removing an RRSIG.  We overcome
-    // this by temporarily violating the "const" nature of the RRset to add the
-    // data.
-
-    virtual void addRRsig(const isc::dns::rdata::ConstRdataPtr& rdata);
-
-    virtual void addRRsig(const isc::dns::rdata::RdataPtr& rdata);
-
-    virtual void addRRsig(const AbstractRRset& sigs);
-
-    virtual void addRRsig(const isc::dns::ConstRRsetPtr& sigs);
-
-    virtual void addRRsig(const isc::dns::RRsetPtr& sigs);
-
-    virtual void removeRRsig();
-
-    /// \brief Associate a link to an RB node of the additional record.
-    ///
-    /// This method adds a given opaque object that holds a link to an RB node
-    /// of the underlying in-memory data source that is corresponding to an
-    /// RDATA of this RRset.
-    ///
-    /// This method is exposed as public so it can be used within the in-memory
-    /// data source implementation, and only for that purpose.
-    ///
-    /// \param additional An opaque \c AdditionalNodeInfo object to be
-    /// associated with this RRset.
-    void addAdditionalNode(const AdditionalNodeInfo& additional);
-
-    /// \brief Return a pointer to the list (vector) of additional RB nodes.
-    ///
-    /// This method returns a pointer to a vector storing the opaque
-    /// \c AdditionalNodeInfo object that may be possibly set in this RRset.
-    /// Not all RRsets are associated with additional nodes; if no
-    /// such node is stored, this method returns NULL.
-    ///
-    /// Like \c addAdditionalNode(), this method is exposed as public only for
-    /// the in-memory data source implementation.
-    ///
-    /// \return A pointer to the associated vector of \c AdditionalNodeInfo;
-    /// NULL if no additional nodes are associated to this RRset.
-    const std::vector<AdditionalNodeInfo>* getAdditionalNodes() const;
-
-    /// \brief Copy the list of additional RB nodes to another RRset.
-    ///
-    /// This method copies the internal list (an STL vector in the actual
-    /// implementation) of additional RB nodes for this RRset to another
-    /// \c RBNodeRRset object.  The copy destination is generally expected to
-    /// be newly created and have an empty list, but this method does not
-    /// check the condition.  If the destination already has a non empty list,
-    /// the existing entries will be lost.
-    ///
-    /// \param dst The \c RBNodeRRset object to which the additional
-    /// RB node list is to be copied.
-    void copyAdditionalNodes(RBNodeRRset& dst) const;
-
-    /// \brief Return underlying RRset pointer
-    ///
-    /// ... mainly for testing.
-    isc::dns::ConstRRsetPtr getUnderlyingRRset() const;
-
-private:
-    RBNodeRRsetImpl* impl_;
-};
-
-}   // namespace internal
-}   // namespace datasrc
-}   // namespace isc
-
-#endif  // RBNODE_RRSET_H
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
deleted file mode 100644
index d0efa0a..0000000
--- a/src/lib/datasrc/rbtree.h
+++ /dev/null
@@ -1,1993 +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 RBTREE_H
-#define RBTREE_H 1
-
-//! \file datasrc/rbtree.h
-///
-/// \note The purpose of the RBTree is to provide a generic map with
-///     domain names as the key that can be used by various BIND 10 modules or
-///     even by other applications.  However, because of some unresolved design
-///     issue, the design and interface are not fixed, and RBTree isn't ready
-///     to be used as a base data structure by other modules.
-
-#include <exceptions/exceptions.h>
-#include <util/memory_segment.h>
-#include <dns/name.h>
-#include <dns/labelsequence.h>
-
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/interprocess/offset_ptr.hpp>
-#include <boost/static_assert.hpp>
-
-#include <ostream>
-#include <algorithm>
-#include <cassert>
-
-namespace isc {
-namespace datasrc {
-
-/// Forward declare RBTree class here is convinent for following friend
-/// class declare inside RBNode and RBTreeNodeChain
-template <typename T>
-class RBTree;
-
-/// \brief \c RBNode is used by RBTree to store any data related to one domain
-///     name.
-///
-/// This is meant to be used only from RBTree. It is meaningless to inherit it
-/// or create instances of it from elsewhere. For that reason, the constructor
-/// (and the allocator, see below) is private.
-///
-/// It serves three roles. One is to keep structure of the \c RBTree as a
-/// red-black tree. For that purpose, it has left, right and parent pointers
-/// and color member. These are private and accessed only from within the tree.
-///
-/// The second one is to store data for one domain name. The data related
-/// functions can be used to access and set the data.
-///
-/// The third role is to keep the hierarchy of domains. The down pointer
-/// points to a subtree of subdomains. The parent pointer of a subtree's
-/// root node points to the parent leaf of the upper tree.
-///
-/// One special kind of node is non-terminal node. It has subdomains with
-/// RRsets, but doesn't have any RRsets itself.
-///
-/// In order to keep memory footprint as small as possible, the node data
-/// are heavily packed.  Specifically, some internal node properties (such as
-/// the node color) are encoded as part of "flags", some of the flag bits
-/// can also be set by the user application.  Each node is associated with
-/// a sequence of domain name labels, which is essentially the search/insert
-/// key for the node (see also the description of RBTree).  This is encoded
-/// as opaque binary immediately following the main node object.  The size
-/// of the allocated space for the labels data is encoded by borrowing some
-/// bits of the "flags" field.
-template <typename T>
-class RBNode : public boost::noncopyable {
-private:
-    /// The RBNode is meant for use from within RBTree, so it has access to
-    /// it.
-    friend class RBTree<T>;
-
-    /// \brief Just a type alias
-    ///
-    /// We are going to use a lot of these offset pointers here and they
-    /// have a long name.
-    typedef boost::interprocess::offset_ptr<RBNode<T> > RBNodePtr;
-
-    /// \name Constructors
-    ///
-    /// \note The existence of a RBNode without a RBTree is meaningless.
-    ///     Therefore the constructors are private.
-    //@{
-
-    /// \brief Constructor from normal nodes.
-    RBNode(size_t labels_capacity);
-
-    /// \brief Destructor
-    ~RBNode();
-
-    //@}
-
-    /// \brief Accessor to the memory region for node labels.
-    ///
-    /// The only valid usage of the returned pointer is to pass it to the
-    /// corresponding constructor of \c dns::LabelSequence.
-    const void* getLabelsData() const { return (this + 1); }
-
-    /// \brief Accessor to the memory region for node labels, mutable version.
-    ///
-    /// The only valid usage of the returned pointer is to pass it to
-    /// \c LabelSequence::serialize() with the node's labels_capacity_ member
-    /// (which should be sufficiently large for the \c LabelSequence in that
-    /// context).
-    void* getLabelsData() { return (this + 1); }
-
-    /// \brief Allocate and construct \c RBNode
-    ///
-    /// This static method allocates memory for a new \c RBNode object
-    /// from the given memory segment, constructs the object, and returns
-    /// a pointer to it.
-    ///
-    /// \throw std::bad_alloc Memory allocation fails.
-    ///
-    /// \param mem_sgmt A \c MemorySegment from which memory for the new
-    /// \c RBNode is allocated.
-    static RBNode<T>* create(util::MemorySegment& mem_sgmt,
-                             const dns::LabelSequence& labels)
-    {
-        const size_t labels_len = labels.getSerializedLength();
-        void* p = mem_sgmt.allocate(sizeof(RBNode<T>) + labels_len);
-        RBNode<T>* node = new(p) RBNode<T>(labels_len);
-        labels.serialize(node->getLabelsData(), labels_len);
-        return (node);
-    }
-
-    /// \brief Destruct and deallocate \c RBNode
-    ///
-    /// \throw none
-    ///
-    /// \param mem_sgmt The \c MemorySegment that allocated memory for
-    /// \c rbnode.
-    /// \param rbnode A non NULL pointer to a valid \c RBNode object
-    /// that was originally created by the \c create() method (the behavior
-    /// is undefined if this condition isn't met).
-    static void destroy(util::MemorySegment& mem_sgmt, RBNode<T>* rbnode) {
-        const size_t labels_capacity = rbnode->labels_capacity_;
-        rbnode->~RBNode<T>();
-        mem_sgmt.deallocate(rbnode, sizeof(RBNode<T>) + labels_capacity);
-    }
-
-    /// \brief Reset node's label sequence to a new one.
-    ///
-    /// The new labels must be a sub sequence of the current label sequence;
-    /// otherwise the serialize() method will throw an exception.
-    void resetLabels(const dns::LabelSequence& labels) {
-        labels.serialize(getLabelsData(), labels_capacity_);
-    }
-
-public:
-    /// \brief Alias for shared pointer to the data.
-    typedef boost::shared_ptr<T> NodeDataPtr;
-
-    /// Node flags.
-    ///
-    /// Each flag value defines a non default property for a specific node.
-    /// These are defined as bitmask type values for the convenience of
-    /// internal implementation, but applications are expected to use
-    /// each flag separately via the enum definitions.
-    ///
-    /// All (settable) flags are off by default; they must be explicitly
-    /// set to on by the \c setFlag() method.
-    enum Flags {
-        FLAG_CALLBACK = 1, ///< Callback enabled. See \ref callback
-        FLAG_RED = 2, ///< Node color; 1 if node is red, 0 if node is black.
-        FLAG_SUBTREE_ROOT = 4, ///< Set if the node is the root of a subtree
-        FLAG_USER1 = 0x400000U, ///< Application specific flag
-        FLAG_USER2 = 0x200000U, ///< Application specific flag
-        FLAG_USER3 = 0x100000U, ///< Application specific flag
-        FLAG_MAX = 0x400000U    // for integrity check
-    };
-private:
-    // Some flag values are expected to be used for internal purposes
-    // (e.g., representing the node color) in future versions, so we
-    // limit the settable flags via the \c setFlag() method to those
-    // explicitly defined in \c Flags.  This constant represents all
-    // such flags.
-    static const uint32_t SETTABLE_FLAGS = (FLAG_CALLBACK | FLAG_USER1 |
-                                            FLAG_USER2 | FLAG_USER3);
-
-public:
-
-    /// \name Getter functions.
-    //@{
-    /// \brief Return the name of current node.
-    ///
-    /// It's relative to its containing node.
-    ///
-    /// To get the absolute name of one node, the node path from the top node
-    /// to current node has to be recorded.
-    ///
-    /// \note We should eventually deprecate this method and revise all its
-    /// usage with \c getLabels().  At this point the only user of this method
-    /// is getAbsoluteName()::getAbsoluteName(), which would have to be revised
-    /// using \c LabelSequence.  Until then we keep this interface as a
-    /// simplest form of wrapper; it's not efficient, but should be replaced
-    /// before we need to worry about that.
-    const isc::dns::Name getName() const {
-        return (dns::Name(dns::LabelSequence(getLabelsData()).toText()));
-    }
-
-    /// \brief Return the label sequence of the node.
-    ///
-    /// This method returns the label sequence corresponding to this node
-    /// in the form of \c dns::LabelSequence object.  Any modification to
-    /// the tree can invalidate the returned \c LabelSequence object or copy
-    /// of it; in general, it's expected to be used in a very limited scope.
-    dns::LabelSequence getLabels() const {
-        return (dns::LabelSequence(getLabelsData()));
-    }
-
-    /// \brief Return the absolute label sequence of the node.
-    ///
-    /// This method returns the label sequence corresponding to the full
-    /// name of the node; i.e. the entire name as it appears in the zone.
-    ///
-    /// It takes the (partial) name of the node itself, and extends it
-    /// with all upper nodes.
-    ///
-    /// \note Care must be taken with the buffer that is used here; this
-    /// method overwrites its data, so it should not be associated with
-    /// any other LabelSequence during the lifetime of the LabelSequence
-    /// returned by this method. See LabelSequence::extend(), which is used
-    /// by this method.
-    ///
-    /// \param buf A data buffer where the label sequence will be built.
-    ///            The data in this buffer will be overwritten by this call.
-    /// \return A LabelSequence with the absolute name of this node.
-    isc::dns::LabelSequence getAbsoluteLabels(
-        uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const;
-
-    /// \brief Return the data stored in this node.
-    ///
-    /// You should not delete the data, it is handled by shared pointers.
-    NodeDataPtr& getData() { return (data_); }
-    /// \brief Return the data stored in this node.
-    const NodeDataPtr& getData() const { return (data_); }
-
-    /// \brief return whether the node has related data.
-    ///
-    /// There can be empty nodes inside the RBTree. They are usually the
-    /// non-terminal domains, but it is possible (yet probably meaningless)
-    /// empty nodes anywhere.
-    bool isEmpty() const { return (data_.get() == NULL); }
-    //@}
-
-    /// \name Setter functions.
-    //@{
-    /// \brief Set the data stored in the node.
-    void setData(const NodeDataPtr& data) { data_ = data; }
-    //@}
-
-    /// \name Node flag manipulation methods
-    //@{
-    /// Get the status of a node flag.
-    ///
-    /// This method returns whether the given node flag is set (enabled)
-    /// on the node.  The \c flag parameter is expected to be one of the
-    /// defined \c Flags constants.  For simplicity, the method interface
-    /// does not prohibit passing an undefined flag or combined flags, but
-    /// the return value in such a case will be meaningless for the caller
-    /// (an application would have to use an ugly cast for such an unintended
-    /// form of call, which will hopefully avoid accidental misuse).
-    ///
-    /// \exception None
-    /// \param flag The flag to be tested.
-    /// \return \c true if the \c flag is set; \c false otherwise.
-    bool getFlag(Flags flag) const {
-        return ((flags_ & flag) != 0);
-    }
-
-    /// Set or clear a node flag.
-    ///
-    /// This method changes the status of the specified node flag to either
-    /// "on" (enabled) or "off" (disabled).  The new status is specified by
-    /// the \c on parameter.
-    /// Like the \c getFlag() method, \c flag is expected to be one of the
-    /// defined \c Flags constants.  If an undefined or unsettable flag is
-    /// specified, \c isc::InvalidParameter exception will be thrown.
-    ///
-    /// \exception isc::InvalidParameter Unsettable flag is specified
-    /// \exception None otherwise
-    /// \param flag The node flag to be changed.
-    /// \param on If \c true, set the flag to on; otherwise set it to off.
-    void setFlag(Flags flag, bool on = true) {
-        if ((flag & ~SETTABLE_FLAGS) != 0) {
-            isc_throw(isc::InvalidParameter,
-                      "Unsettable RBTree flag is being set");
-        }
-        if (on) {
-            flags_ |= flag;
-        } else {
-            flags_ &= ~flag;
-        }
-    }
-    //@}
-
-private:
-    /// \name Callback related methods
-    ///
-    /// See the description of \c RBTree<T>::find() at \ref callback
-    /// about callbacks.
-    ///
-    /// These methods never throw an exception.
-    //@{
-    /// Return if callback is enabled at the node.
-    //@}
-
-
-    /// \brief Define rbnode color
-    enum RBNodeColor {BLACK, RED};
-
-    /// \brief Returns the color of this node
-    RBNodeColor getColor() const {
-        if ((flags_ & FLAG_RED) != 0) {
-            return (RED);
-        } else {
-            return (BLACK);
-        }
-    }
-
-    /// \brief Sets the color of this node
-    void setColor(const RBNodeColor color) {
-        if (color == RED) {
-            flags_ |= FLAG_RED;
-        } else {
-            flags_ &= ~FLAG_RED;
-        }
-    }
-
-    void setSubTreeRoot(bool root) {
-        if (root) {
-            flags_ |= FLAG_SUBTREE_ROOT;
-        } else {
-            flags_ &= ~FLAG_SUBTREE_ROOT;
-        }
-    }
-
-    bool isSubTreeRoot() const {
-        return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
-    }
-
-public:
-    /// \brief returns the parent of the root of its subtree
-    ///
-    /// This method takes a node and returns the parent of the root of
-    /// its subtree (i.e, it returns the node's immediate ancestor in
-    /// the tree-of-tree hierarchy). If the node is at the top level
-    /// (which should be absolute), it will return \c NULL.
-    ///
-    /// This method never throws an exception.
-    const RBNode<T>* getUpperNode() const;
-
-private:
-    /// \brief return the next node which is bigger than current node
-    /// in the same subtree
-    ///
-    /// The next successor for this node is the next bigger node in terms of
-    /// the DNSSEC order relation within the same single subtree.
-    /// Note that it may NOT be the next bigger node in the entire RBTree;
-    ///  RBTree is a tree in tree, and the real next node may reside in
-    /// an upper or lower subtree of the subtree where this node belongs.
-    /// For example, if this node has a sub domain, the real next node is
-    /// the smallest node in the sub domain tree.
-    ///
-    /// If this node is the biggest node within the subtree, this method
-    /// returns \c NULL.
-    ///
-    /// This method never throws an exception.
-    const RBNode<T>* successor() const;
-
-    /// \brief return the next node which is smaller than current node
-    /// in the same subtree
-    ///
-    /// The predecessor for this node is the next smaller node in terms of
-    /// the DNSSEC order relation within the same single subtree.
-    /// Note that it may NOT be the next smaller node in the entire RBTree;
-    /// RBTree is a tree in tree, and the real next node may reside in
-    /// an upper or lower subtree of the subtree where this node belongs.
-    /// For example, if the predecessor node has a sub domain, the real next
-    /// node is the largest node in the sub domain tree.
-    ///
-    /// If this node is the smallest node within the subtree, this method
-    /// returns \c NULL.
-    ///
-    /// This method never throws an exception.
-    const RBNode<T>* predecessor() const;
-
-    /// \brief private shared implementation of successor and predecessor
-    ///
-    /// As the two mentioned functions are merely mirror images of each other,
-    /// it makes little sense to keep both versions. So this is the body of the
-    /// functions and we call it with the correct pointers.
-    ///
-    /// Not to be called directly, not even by friends.
-    ///
-    /// The overhead of the member pointers should be optimised out, as this
-    /// will probably get completely inlined into predecessor and successor
-    /// methods.
-    const RBNode<T>*
-        abstractSuccessor(typename RBNode<T>::RBNodePtr RBNode<T>::*left,
-                          typename RBNode<T>::RBNodePtr RBNode<T>::*right)
-        const;
-
-    /// \name Data to maintain the rbtree structure.
-    ///
-    /// We keep them as offset pointers. This is part of a future plan, when we
-    /// want to share the image of the tree between multiple processes.
-    /// However, whenever we have a chance, we switch to bare pointers during
-    /// the processing. The pointers on stack are never shared and the offset
-    /// pointers have non-trivial performance impact.
-    //@{
-    RBNodePtr parent_;
-    /// \brief Access the parent_ as bare pointer.
-    RBNode<T>* getParent() {
-        return (parent_.get());
-    }
-    /// \brief Access the parent_ as bare pointer, const.
-    const RBNode<T>* getParent() const {
-        return (parent_.get());
-    }
-    RBNodePtr left_;
-    /// \brief Access the left_ as bare pointer.
-    RBNode<T>* getLeft() {
-        return (left_.get());
-    }
-    /// \brief Access the left_ as bare pointer, const.
-    const RBNode<T>* getLeft() const {
-        return (left_.get());
-    }
-    RBNodePtr right_;
-    /// \brief Access the right_ as bare pointer.
-    RBNode<T>* getRight() {
-        return (right_.get());
-    }
-    /// \brief Access the right_ as bare pointer, const.
-    const RBNode<T>* getRight() const {
-        return (right_.get());
-    }
-    //@}
-
-    /// \brief Data stored here.
-    NodeDataPtr       data_;
-
-    /// \brief The subdomain tree.
-    ///
-    /// This points to the root node of trees of subdomains of this domain.
-    ///
-    /// \par Adding down pointer to \c RBNode has two purposes:
-    /// \li Accelerate the search process, with sub domain tree, it splits the
-    ///     big flat tree into several hierarchy trees.
-    /// \li It saves memory usage as it allows storing only relative names,
-    ///     avoiding storage of the same domain labels multiple times.
-    RBNodePtr down_;
-    /// \brief Access the down_ as bare pointer.
-    RBNode<T>* getDown() {
-        return (down_.get());
-    }
-    /// \brief Access the down_ as bare pointer, const.
-    const RBNode<T>* getDown() const {
-        return (down_.get());
-    }
-
-    /// \brief Internal or user-configurable flags of node's properties.
-    ///
-    /// See the \c Flags enum for available flags.
-    ///
-    /// For memory efficiency reasons, we only use a subset of the 32-bit
-    /// space, and use the rest to store the allocated size for the node's
-    /// label sequence data.
-    uint32_t flags_ : 23;          // largest flag being 0x400000
-    BOOST_STATIC_ASSERT((1 << 23) > FLAG_MAX); // assumption check
-
-    const uint32_t labels_capacity_ : 9; // size for labelseq; range is 0..511
-    // Make sure the reserved space for labels_capacity_ is sufficiently
-    // large.  In effect, we use the knowledge of the implementation of the
-    // serialization, but we still only use its public interface, and the
-    // public interface of this class doesn't rely on this assumption.
-    // So we can change this implementation without affecting its users if
-    // a future change to LabelSequence breaks this assumption.
-    BOOST_STATIC_ASSERT((1 << 9) > dns::LabelSequence::MAX_SERIALIZED_LENGTH);
-};
-
-template <typename T>
-RBNode<T>::RBNode(size_t labels_capacity) :
-    parent_(NULL),
-    left_(NULL),
-    right_(NULL),
-    down_(NULL),
-    flags_(FLAG_RED | FLAG_SUBTREE_ROOT),
-    labels_capacity_(labels_capacity)
-{
-}
-
-template <typename T>
-RBNode<T>::~RBNode() {
-}
-
-template <typename T>
-const RBNode<T>*
-RBNode<T>::getUpperNode() const {
-    const RBNode<T>* current = this;
-
-    // current would never be equal to NULL here (in a correct tree
-    // implementation)
-    while (!current->isSubTreeRoot()) {
-        current = current->getParent();
-    }
-
-    return (current->getParent());
-}
-
-template <typename T>
-isc::dns::LabelSequence
-RBNode<T>::getAbsoluteLabels(
-    uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const
-{
-    isc::dns::LabelSequence result(getLabels(), buf);
-    const RBNode<T>* upper = getUpperNode();
-    while (upper != NULL) {
-        result.extend(upper->getLabels(), buf);
-        upper = upper->getUpperNode();
-    }
-
-    return (result);
-}
-
-template <typename T>
-const RBNode<T>*
-RBNode<T>::abstractSuccessor(typename RBNode<T>::RBNodePtr RBNode<T>::*left,
-                             typename RBNode<T>::RBNodePtr RBNode<T>::*right)
-    const
-{
-    // This function is written as a successor. It becomes predecessor if
-    // the left and right pointers are swapped. So in case of predecessor,
-    // the left pointer points to right and vice versa. Don't get confused
-    // by the idea, just imagine the pointers look into a mirror.
-
-    const RBNode<T>* current = this;
-    // If it has right node, the successor is the left-most node of the right
-    // subtree.
-    if ((current->*right).get() != NULL) {
-        current = (current->*right).get();
-        const RBNode<T>* left_n;
-        while ((left_n = (current->*left).get()) != NULL) {
-            current = left_n;
-        }
-        return (current);
-    }
-
-    // Otherwise go up until we find the first left branch on our path to
-    // root.  If found, the parent of the branch is the successor.
-    // Otherwise, we return the null node
-    const RBNode<T>* parent = current->getParent();
-    while ((!current->isSubTreeRoot()) &&
-           (current == (parent->*right).get())) {
-        current = parent;
-        parent = parent->getParent();
-    }
-
-    if (!current->isSubTreeRoot()) {
-        return (parent);
-    } else {
-        return (NULL);
-    }
-}
-
-template <typename T>
-const RBNode<T>*
-RBNode<T>::successor() const {
-    return (abstractSuccessor(&RBNode<T>::left_, &RBNode<T>::right_));
-}
-
-template <typename T>
-const RBNode<T>*
-RBNode<T>::predecessor() const {
-    // Swap the left and right pointers for the abstractSuccessor
-    return (abstractSuccessor(&RBNode<T>::right_, &RBNode<T>::left_));
-}
-
-/// \brief RBTreeNodeChain stores detailed information of \c RBTree::find()
-/// result.
-///
-/// - The \c RBNode that was last compared with the search name, and
-///   the comparison result at that point in the form of
-///   \c isc::dns::NameComparisonResult.
-/// - A sequence of nodes that forms a path to the found node.
-///
-/// The comparison result can be used to handle some rare cases such as
-/// empty node processing.
-/// The node sequence keeps track of the nodes to reach any given node from
-/// the root of RBTree.
-///
-/// Currently, RBNode does not have "up" pointers in them (i.e., back pointers
-/// from the root of one level of tree of trees to the node in the parent
-/// tree whose down pointer points to that root node) for memory usage
-/// reasons, so there is no other way to find the path back to the root from
-/// any given RBNode.
-///
-/// \note This design may change in future versions.  In particular, it's
-/// quite likely we want to have that pointer if we want to optimize name
-/// compression by exploiting the structure of the zone.  If and when that
-/// happens we should also revisit the need for the chaining.
-/// Also, the class name may not be appropriate now that it contains other
-/// information than a node "chain", and the chain itself may even be
-/// deprecated.  Something like "RBTreeFindContext" may be a better name.
-/// This point should be revisited later.
-///
-/// RBTreeNodeChain is constructed and manipulated only inside the \c RBTree
-/// class.
-/// \c RBTree uses it as an inner data structure to iterate over the whole
-/// RBTree.
-/// This is the reason why manipulation methods such as \c push() and \c pop()
-/// are private (and not shown in the doxygen document).
-template <typename T>
-class RBTreeNodeChain {
-    /// RBTreeNodeChain is initialized by RBTree, only RBTree has
-    /// knowledge to manipulate it.
-    friend class RBTree<T>;
-public:
-    /// \name Constructors and Assignment Operator.
-    ///
-    /// \note The copy constructor and the assignment operator are
-    /// intentionally defined as private, making this class non copyable.
-    /// This may have to be changed in a future version with newer need.
-    /// For now we explicitly disable copy to avoid accidental copy happens
-    /// unintentionally.
-    //{@
-    /// The default constructor.
-    ///
-    /// \exception None
-    RBTreeNodeChain() : node_count_(0), last_compared_(NULL),
-                        // XXX: meaningless initial values:
-                        last_comparison_(0, 0,
-                                         isc::dns::NameComparisonResult::EQUAL)
-    {}
-
-private:
-    RBTreeNodeChain(const RBTreeNodeChain<T>&);
-    RBTreeNodeChain<T>& operator=(const RBTreeNodeChain<T>&);
-    //@}
-
-public:
-    /// Clear the state of the chain.
-    ///
-    /// This method re-initializes the internal state of the chain so that
-    /// it can be reused for subsequent operations.
-    ///
-    /// \exception None
-    void clear() {
-        node_count_ = 0;
-        last_compared_ = NULL;
-    }
-
-    /// Return the \c RBNode that was last compared in \c RBTree::find().
-    ///
-    /// If this chain has been passed to \c RBTree::find() and there has
-    /// been name comparison against the search name, the last compared
-    /// \c RBNode is recorded within the chain.  This method returns that
-    /// node.
-    /// If \c RBTree::find() hasn't been called with this chain or name
-    /// comparison hasn't taken place (which is possible if the tree is empty),
-    /// this method returns \c NULL.
-    ///
-    /// \exception None
-    const RBNode<T>* getLastComparedNode() const {
-        return (last_compared_);
-    }
-
-    /// Return the result of last name comparison in \c RBTree::find().
-    ///
-    /// Like \c getLastComparedNode(), \c RBTree::find() records the result
-    /// of the last name comparison in the chain.  This method returns the
-    /// result.
-    /// The return value of this method is only meaningful when comparison
-    /// has taken place, i.e, when \c getLastComparedNode() would return a
-    /// non \c NULL value.
-    ///
-    /// \exception None
-    const isc::dns::NameComparisonResult& getLastComparisonResult() const {
-        return (last_comparison_);
-    }
-
-    /// \brief Return the number of levels stored in the chain.
-    ///
-    /// It's equal to the number of nodes in the chain; for an empty
-    /// chain, 0 will be returned.
-    ///
-    /// \exception None
-    unsigned int getLevelCount() const { return (node_count_); }
-
-    /// \brief return the absolute name for the node which this
-    /// \c RBTreeNodeChain currently refers to.
-    ///
-    /// The chain must not be empty.
-    ///
-    /// \exception isc::BadValue the chain is empty.
-    /// \exception std::bad_alloc memory allocation for the new name fails.
-    isc::dns::Name getAbsoluteName() const {
-        if (isEmpty()) {
-            isc_throw(isc::BadValue,
-                      "RBTreeNodeChain::getAbsoluteName is called on an empty "
-                      "chain");
-        }
-
-        const RBNode<T>* top_node = top();
-        isc::dns::Name absolute_name = top_node->getName();
-        int node_count = node_count_ - 1;
-        while (node_count > 0) {
-            top_node = nodes_[node_count - 1];
-            absolute_name = absolute_name.concatenate(top_node->getName());
-            --node_count;
-        }
-        return (absolute_name);
-    }
-
-private:
-    // the following private functions check invariants about the internal
-    // state using assert() instead of exception.  The state of a chain
-    // can only be modified by operations within this file, so if any of the
-    // assumptions fails it means an internal bug.
-
-    /// \brief return whether node chain has node in it.
-    ///
-    /// \exception None
-    bool isEmpty() const { return (node_count_ == 0); }
-
-    /// \brief return the top node for the node chain
-    ///
-    /// RBTreeNodeChain store all the nodes along top node to
-    /// root node of RBTree
-    ///
-    /// \exception None
-    const RBNode<T>* top() const {
-        assert(!isEmpty());
-        return (nodes_[node_count_ - 1]);
-    }
-
-    /// \brief pop the top node from the node chain
-    ///
-    /// After pop, up/super node of original top node will be
-    /// the top node
-    ///
-    /// \exception None
-    void pop() {
-        assert(!isEmpty());
-        --node_count_;
-    }
-
-    /// \brief add the node into the node chain
-    ///
-    /// If the node chain isn't empty, the node should be
-    /// the sub domain of the original top node in node chain
-    /// otherwise the node should be the root node of RBTree.
-    ///
-    /// \exception None
-    void push(const RBNode<T>* node) {
-        assert(node_count_ < RBT_MAX_LEVEL);
-        nodes_[node_count_++] = node;
-    }
-
-private:
-    // The max label count for one domain name is Name::MAX_LABELS (128).
-    // Since each node in rbtree stores at least one label, it's also equal
-    // to the possible maximum level.
-    const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
-
-    int node_count_;
-    const RBNode<T>* nodes_[RBT_MAX_LEVEL];
-    const RBNode<T>* last_compared_;
-    isc::dns::NameComparisonResult last_comparison_;
-};
-
-
-// note: the following class description is documented using multiline comments
-// because the verbatim diagram contain a backslash, which could be interpreted
-// as escape of newline in singleline comment.
-/**
- *  \brief \c RBTree class represents all the domains with the same suffix.
- *      It can be used to store the domains in one zone, for example.
- *
- *  RBTree is a generic map from domain names to any kind of data. Internally,
- *  it uses a red-black tree. However, it isn't one tree containing everything.
- *  Subdomains are trees, so this structure is recursive - trees inside trees.
- *  But, from the interface point of view, it is opaque data structure.
- *
- *  \c RBTree splits the domain space into hierarchy red black trees; nodes
- * in one tree has the same base name. The benefit of this struct is that:
- *  - Enhances the query performace compared with one big flat red black tree.
- *  - Decreases the memory footprint, as it doesn't store the suffix labels
- *      multiple times.
- *
- * Depending on different usage, rbtree will support different search policies.
- * Whether to return an empty node to end user is one policy among them.
- * The default policy is to NOT return an empty node to end user;
- * to change the behavior, specify \c true for the constructor parameter
- * \c returnEmptyNode.
- * \note The search policy only affects the \c find() behavior of RBTree.
- * When inserting one name into RBTree, if the node with the name already
- * exists in the RBTree and it's an empty node which doesn't have any data,
- * the \c insert() method will still return \c ALREADYEXISTS regardless of
- * the search policy.
- *
- * \anchor diagram
- *
- * with the following names:
- *  - a
- *  - b
- *  - c
- *  - x.d.e.f
- *  - z.d.e.f
- *  - g.h
- *  - o.w.y.d.e.f
- *  - p.w.y.d.e.f
- *  - q.w.y.d.e.f
- *
- * the tree will look like:
- *  \verbatim
-                                .
-                                |
-                                b
-                              /   \
-                             a    d.e.f
-                                    /|\
-                                   c | g.h
-                                     |
-                                    w.y
-                                    /|\
-                                   x | z
-                                     |
-                                     p
-                                    / \
-                                   o   q
-   \endverbatim
- *  \todo
- *  - add remove interface
- */
-template <typename T>
-class RBTree : public boost::noncopyable {
-    friend class RBNode<T>;
-public:
-    /// \brief The return value for the \c find() and insert() methods
-    enum Result {
-        SUCCESS,    ///< Insert was successful
-        /// \brief The node returned from find mathes exactly the name given
-        EXACTMATCH,
-        PARTIALMATCH, ///< A superdomain node was found
-        NOTFOUND,   ///< Not even any superdomain was found
-        /// \brief Returned by insert() if a node of the name already exists
-        ALREADYEXISTS,
-    };
-
-    /// \brief Allocate and construct \c RBTree
-    ///
-    /// This static method allocates memory for a new \c RBTree object
-    /// from the given memory segment, constructs the object, and returns
-    /// a pointer to it.
-    ///
-    /// \throw std::bad_alloc Memory allocation fails.
-    ///
-    /// \param mem_sgmt A \c MemorySegment from which memory for the new
-    /// \c RBTree is allocated.
-    static RBTree* create(util::MemorySegment& mem_sgmt,
-                          bool return_empty_node = false)
-    {
-        void* p = mem_sgmt.allocate(sizeof(RBTree<T>));
-        return (new(p) RBTree<T>(return_empty_node));
-    }
-
-    /// \brief Destruct and deallocate \c RBTree
-    ///
-    /// This method also destroys and deallocates all nodes inserted to the
-    /// tree.
-    ///
-    /// \note The memory segment (\c mem_sgmt) must be the same one that
-    /// was originally used to allocate memory for the tree (and for all
-    /// nodes inserted to the tree, due to the requirement of \c insert()),
-    /// since the tree itself doesn't maintain a reference to the segment.
-    /// This is not a robust interface, but since we plan to share the tree
-    /// structure by multiple processes via shared memory or possibly allow
-    /// the memory image to be dumped to a file for later reload, there
-    /// doesn't seem to be an easy way to store such reference in the data
-    /// itself.  We should probably consider a wrapper interface that
-    /// encapsulates the corresponding segment and always use it for any
-    /// allocation/deallocation of tree related data (the tree itself, their
-    /// nodes, and node data) to keep the usage as safe as possible.
-    ///
-    /// \throw none
-    ///
-    /// \param mem_sgmt The \c MemorySegment that allocated memory for
-    /// \c rbtree and for all nodes inserted to the tree.
-    /// \param rbtree A non NULL pointer to a valid \c RBTree object
-    /// that was originally created by the \c create() method (the behavior
-    /// is undefined if this condition isn't met).
-    static void destroy(util::MemorySegment& mem_sgmt, RBTree<T>* rbtree) {
-        rbtree->deleteAllNodes(mem_sgmt);
-        rbtree->~RBTree<T>();
-        mem_sgmt.deallocate(rbtree, sizeof(RBTree<T>));
-    }
-
-private:
-    /// \name Constructor and Destructor
-    //@{
-    /// \brief The constructor.
-    ///
-    /// An object of this class is always expected to be created by the
-    /// allocator (\c create()), so the constructor is hidden as private.
-    ///
-    /// It never throws an exception.
-    explicit RBTree(bool returnEmptyNode = false);
-
-    /// \brief The destructor.
-    ///
-    /// An object of this class is always expected to be destroyed explicitly
-    /// by \c destroy(), so the constructor is hidden as private.
-    ///
-    /// \note RBTree is not intended to be inherited so the destructor
-    /// is not virtual
-    ~RBTree();
-    //@}
-
-public:
-
-    /// \name Find methods
-    ///
-    /// \brief Find the node that gives a longest match against the given name.
-    ///
-    /// \anchor find
-    ///
-    /// These methods search the RBTree for a node whose name is longest
-    /// against name. The found node, if any, is returned via the node pointer.
-    ///
-    /// By default, nodes that don't have data (see RBNode::isEmpty) are
-    /// ignored and the result can be NOTFOUND even if there's a node whose
-    /// name matches.  If the \c RBTree is constructed with its
-    /// \c returnEmptyNode parameter being \c true, empty nodes will also
-    /// be match candidates.
-    ///
-    /// \note Even when \c returnEmptyNode is \c true, not all empty nodes
-    /// in terms of the DNS protocol may necessarily be found by this method.
-    /// For example, in the \ref diagram shown in the class description,
-    /// the name y.d.e.f is logically contained in the tree as part of the
-    /// node w.y, but the \c find() variants cannot find the former for
-    /// the search key of y.d.e.f, no matter how the \c RBTree is constructed.
-    /// The caller of this method must use a different way to identify the
-    /// hidden match when necessary.
-    ///
-    /// These methods involve operations on names that can throw an exception.
-    /// If that happens the exception will be propagated to the caller.
-    /// The callback function should generally not throw an exception, but
-    /// if it throws, the exception will be propagated to the caller.
-    ///
-    /// The \c name parameter says what should be found. The node parameter
-    /// is output-only, and in case of EXACTMATCH or PARTIALMATCH, it is set
-    /// to a pointer to the found node.
-    ///
-    /// They return:
-    ///  - EXACTMATCH when a node with the same name as requested exists.
-    ///  - PARTIALMATCH when a node with the same name does not exist (or is
-    ///    empty), but there's a (nonempty) superdomain of the requested one.
-    ///    The superdomain with longest name is returned through the node
-    ///    parameter. Beware that if you store a zone in the tree, you may get
-    ///    PARTIALMATCH with zone apex when the given domain name is not there.
-    ///    You should not try to delegate into another zone in that case.
-    ///  - NOTFOUND if there's no node with the same name nor any superdomain
-    ///    of it. In that case, node parameter is left intact.
-    //@{
-
-    /// \brief Simple find.
-    ///
-    /// Acts as described in the \ref find section.
-    Result find(const isc::dns::Name& name, RBNode<T>** node) const {
-        RBTreeNodeChain<T> node_path;
-        const isc::dns::LabelSequence ls(name);
-        return (find<void*>(ls, node, node_path, NULL, NULL));
-    }
-
-    /// \brief Simple find returning immutable node.
-    ///
-    /// Acts as described in the \ref find section, but returns immutable node
-    /// pointer.
-    Result find(const isc::dns::Name& name, const RBNode<T>** node) const {
-        RBTreeNodeChain<T> node_path;
-        RBNode<T> *target_node = NULL;
-        const isc::dns::LabelSequence ls(name);
-        Result ret = (find<void*>(ls, &target_node, node_path, NULL, NULL));
-        if (ret != NOTFOUND) {
-            *node = target_node;
-        }
-        return (ret);
-    }
-
-    /// \brief Simple find, with node_path tracking
-    ///
-    /// Acts as described in the \ref find section.
-    Result find(const isc::dns::Name& name, RBNode<T>** node,
-                RBTreeNodeChain<T>& node_path) const
-    {
-        const isc::dns::LabelSequence ls(name);
-        return (find<void*>(ls, node, node_path, NULL, NULL));
-    }
-
-    /// \brief Simple find returning immutable node, with node_path tracking
-    ///
-    /// Acts as described in the \ref find section, but returns immutable node
-    /// pointer.
-    Result find(const isc::dns::Name& name, const RBNode<T>** node,
-                RBTreeNodeChain<T>& node_path) const
-    {
-        RBNode<T> *target_node = NULL;
-        const isc::dns::LabelSequence ls(name);
-        Result ret = (find<void*>(ls, &target_node, node_path, NULL, NULL));
-        if (ret != NOTFOUND) {
-            *node = target_node;
-        }
-        return (ret);
-    }
-
-    /// \brief Simple find returning immutable node.
-    ///
-    /// Acts as described in the \ref find section, but returns immutable
-    /// node pointer.
-    template <typename CBARG>
-    Result find(const isc::dns::Name& name,
-                const RBNode<T>** node,
-                RBTreeNodeChain<T>& node_path,
-                bool (*callback)(const RBNode<T>&, CBARG),
-                CBARG callback_arg) const
-    {
-        RBNode<T>* target_node = NULL;
-        const isc::dns::LabelSequence ls(name);
-        Result ret = find(ls, &target_node, node_path, callback,
-                          callback_arg);
-        if (ret != NOTFOUND) {
-            *node = target_node;
-        }
-        return (ret);
-    }
-
-    /// \brief Find with callback and node chain
-    /// \anchor callback
-    ///
-    /// This version of \c find() is specifically designed for the backend
-    /// of the \c InMemoryZoneFinder class, and implements all necessary
-    /// features for that purpose.  Other applications shouldn't need these
-    /// additional features, and should normally use the simpler versions.
-    ///
-    /// This version of \c find() calls the callback whenever traversing (on
-    /// the way from root down the tree) a marked node on the way down through
-    /// the domain namespace (see \c RBNode::FLAG_CALLBACK).
-    ///
-    /// Also, this version takes a \c LabelSequence object, not a \c Name
-    /// object to be as efficient as possible; operations on the former
-    /// needed for the search are generally much more efficient than those
-    /// for the latter.  Since \c Name objects are more commonly used
-    /// in other parts of the implementation, other versions take a \c Name
-    /// and convert it to \c LabelSequence.  This conversion is cheap,
-    /// while the other direction isn't, and since there would be cases
-    /// where an implementation primarily handles \c LabelSequence objects
-    /// as an efficient representation of names, it would make most sense
-    /// to provide the interface that takes \c LabelSequence.
-    ///
-    /// If you return true from the callback, the search is stopped and a
-    /// PARTIALMATCH is returned with the given node. Note that this node
-    /// doesn't really need to be the one with longest possible match.
-    ///
-    /// The callback is not called for the node which matches exactly
-    /// (EXACTMATCH is returned). This is typically the last node in the
-    /// traversal during a successful search.
-    ///
-    /// This callback mechanism was designed with zone cut (delegation)
-    /// processing in mind. The marked nodes would be the ones at delegation
-    /// points. It is not expected that any other applications would need
-    /// callbacks; they should use the versions of find without callbacks.
-    /// The callbacks are not general functors for the same reason - we don't
-    /// expect it to be needed.
-    ///
-    /// Another special feature of this version is the ability to record
-    /// more detailed information regarding the search result.
-    ///
-    /// This information will be returned via the \c node_path parameter,
-    /// which is an object of class \c RBTreeNodeChain.
-    /// The passed parameter must be empty.
-    ///
-    /// On success, the node sequence stored in \c node_path will contain all
-    /// the ancestor nodes from the found node towards the root.
-    /// For example, if we look for o.w.y.d.e.f in the example \ref diagram,
-    /// \c node_path will contain w.y and d.e.f; the \c top() node of the
-    /// chain will be o, w.y and d.e.f will be stored below it.
-    ///
-    /// This feature can be used to get the absolute name for a node;
-    /// to do so, we need to travel upside from the node toward the root,
-    /// concatenating all ancestor labels.  A node chain can also be used to
-    /// find the next and previous nodes of a given node in the entire RBTree;
-    /// the \c nextNode() and \c previousNode() methods take a node
-    /// chain as a parameter.
-    ///
-    /// \exception isc::BadValue node_path is not empty.
-    ///
-    /// \param target_labels_orig Target to be found
-    /// \param node On success (either \c EXACTMATCH or \c PARTIALMATCH)
-    ///     it will store a pointer to the matching node
-    /// \param node_path Other search details will be stored (see the
-    ///        description)
-    /// \param callback If non- \c NULL, a call back function to be called
-    ///     at marked nodes (see the description).
-    /// \param callback_arg A caller supplied argument to be passed to
-    ///     \c callback.
-    ///
-    /// \return As in the description, but in case of callback returning
-    ///     \c true, it returns immediately with the current node.
-    template <typename CBARG>
-    Result find(const isc::dns::LabelSequence& target_labels_orig,
-                RBNode<T>** node,
-                RBTreeNodeChain<T>& node_path,
-                bool (*callback)(const RBNode<T>&, CBARG),
-                CBARG callback_arg) const;
-
-    /// \brief Simple find returning immutable node.
-    ///
-    /// Acts as described in the \ref find section, but returns immutable
-    /// node pointer.
-    template <typename CBARG>
-    Result find(const isc::dns::LabelSequence& target_labels,
-                const RBNode<T>** node,
-                RBTreeNodeChain<T>& node_path,
-                bool (*callback)(const RBNode<T>&, CBARG),
-                CBARG callback_arg) const
-    {
-        RBNode<T>* target_node = NULL;
-        Result ret = find(target_labels, &target_node, node_path,
-                          callback, callback_arg);
-        if (ret != NOTFOUND) {
-            *node = target_node;
-        }
-        return (ret);
-    }
-    //@}
-
-    /// \brief return the next bigger node in DNSSEC order from a given node
-    /// chain.
-    ///
-    /// This method identifies the next bigger node of the node currently
-    /// referenced in \c node_path and returns it.
-    /// This method also updates the passed \c node_path so that it will store
-    /// the path for the returned next node.
-    /// It will be convenient when we want to iterate over the all nodes
-    /// of \c RBTree; we can do this by calling this method repeatedly
-    /// starting from the root node.
-    ///
-    /// \note \c nextNode() will iterate over all the nodes in RBTree including
-    /// empty nodes. If empty node isn't desired, it's easy to add logic to
-    /// check return node and keep invoking \c nextNode() until the non-empty
-    /// node is retrieved.
-    ///
-    /// \exception isc::BadValue node_path is empty.
-    ///
-    /// \param node_path A node chain that stores all the nodes along the path
-    /// from root to node.
-    ///
-    /// \return An \c RBNode that is next bigger than \c node; if \c node is
-    /// the largest, \c NULL will be returned.
-    const RBNode<T>* nextNode(RBTreeNodeChain<T>& node_path) const;
-
-    /// \brief return the next smaller node in DNSSEC order from a node
-    ///     searched by RBTree::find().
-    ///
-    /// This acts similarly to \c nextNode(), but it walks in the other
-    /// direction. But unlike \c nextNode(), this can start even if the
-    /// node requested by \c find() was not found. In that case, it will
-    /// identify the node that is previous to the queried name.
-    ///
-    /// \note \c previousNode() will iterate over all the nodes in RBTree
-    /// including empty nodes. If empty node isn't desired, it's easy to add
-    /// logic to check return node and keep invoking \c previousNode() until the
-    /// non-empty node is retrieved.
-    ///
-    /// \exception isc::BadValue node_path is empty.
-    ///
-    /// \param node_path A node chain that stores all the nodes along the path
-    /// from root to node and the result of \c find(). This will get modified.
-    /// You should not use the node_path again except for repetitive calls
-    /// of this method.
-    ///
-    /// \return An \c RBNode that is next smaller than \c node; if \c node is
-    /// the smallest, \c NULL will be returned.
-    const RBNode<T>* previousNode(RBTreeNodeChain<T>& node_path) const;
-
-    /// \brief Get the total number of nodes in the tree
-    ///
-    /// It includes nodes internally created as a result of adding a domain
-    /// name that is a subdomain of an existing node of the tree.
-    /// This function is mainly intended to be used for debugging.
-    int getNodeCount() const { return (node_count_); }
-
-    /// \name Debug function
-    //@{
-    /// \brief Print the nodes in the trees.
-    ///
-    /// \param os A \c std::ostream object to which the tree is printed.
-    /// \param depth A factor of the initial indentation.  Each line
-    /// will begin with space character repeating <code>5 * depth</code>
-    /// times.
-    void dumpTree(std::ostream& os, unsigned int depth = 0) const;
-
-    /// \brief Print the nodes in the trees for processing with
-    /// Graphviz's dot.
-    ///
-    /// \param os A \c std::ostream object to which the tree is printed.
-    /// \param show_pointers Show node and parent pointers in the node
-    void dumpDot(std::ostream& os, bool show_pointers = false) const;
-    //@}
-
-    /// \name Modify functions
-    //@{
-    /// \brief Insert the domain name into the tree.
-    ///
-    /// It either finds an already existing node of the given name, or inserts
-    /// a new one if none exists yet. In any case, the \c inserted_node parameter
-    /// is set to point to that node. You can fill data into it or modify it.
-    /// So, if you don't know if a node exists or not and you need to modify
-    /// it, just call insert and act by the result.
-    ///
-    /// Please note that the tree can add some empty nodes by itself, so don't
-    /// assume that if you didn't insert a node of that name it doesn't exist.
-    ///
-    /// This method normally involves resource allocation.  If it fails
-    /// the corresponding standard exception will be thrown.
-    ///
-    /// This method does not provide the strong exception guarantee in its
-    /// strict sense; if an exception is thrown in the middle of this
-    /// method, the internal structure may change.  However, it should
-    /// still retain the same property as a mapping container before this
-    /// method is called.  For example, the result of \c find() should be
-    /// the same.  This method provides the weak exception guarantee in its
-    /// normal sense.
-    ///
-    /// \param mem_sgmt A \c MemorySegment object for allocating memory of
-    /// a new node to be inserted.  Must be the same segment as that used
-    /// for creating the tree itself.
-    /// \param name The name to be inserted into the tree.
-    /// \param inserted_node This is an output parameter and is set to the
-    ///     node.
-    ///
-    /// \return
-    ///  - SUCCESS The node was added.
-    ///  - ALREADYEXISTS There was already a node of that name, so it was not
-    ///     added.
-    Result insert(util::MemorySegment& mem_sgmt, const isc::dns::Name& name,
-                  RBNode<T>** inserted_node);
-
-    /// \brief Delete all tree nodes.
-    ///
-    /// \throw none.
-    ///
-    /// \param mem_sgmt The \c MemorySegment object used to insert the nodes
-    /// (which was also used for creating the tree due to the requirement of
-    /// \c inert()).
-    void deleteAllNodes(util::MemorySegment& mem_sgmt);
-
-    /// \brief Swaps two tree's contents.
-    ///
-    /// This and \c other trees must have been created with the same
-    /// memory segment (see the discussion in \c create()); otherwise the
-    /// behavior is undefined.
-    ///
-    /// This acts the same as many std::*.swap functions, exchanges the
-    /// contents. This doesn't throw anything.
-    void swap(RBTree<T>& other) {
-        std::swap(root_, other.root_);
-        std::swap(node_count_, other.node_count_);
-    }
-    //@}
-
-private:
-    /// \name RBTree balance functions
-    //@{
-    void insertRebalance(typename RBNode<T>::RBNodePtr* root, RBNode<T>* node);
-    RBNode<T>* rightRotate(typename RBNode<T>::RBNodePtr* root,
-                           RBNode<T>* node);
-    RBNode<T>* leftRotate(typename RBNode<T>::RBNodePtr* root,
-                          RBNode<T>* node);
-    //@}
-
-    /// \name Helper functions
-    //@{
-    /// \brief delete tree whose root is equal to node
-    void deleteHelper(util::MemorySegment& mem_sgmt, RBNode<T> *node);
-
-    /// \brief Print the information of given RBNode.
-    void dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
-                        unsigned int depth) const;
-
-    /// \brief Print the information of given RBNode for dot.
-    int dumpDotHelper(std::ostream& os, const RBNode<T>* node,
-                      int* nodecount, bool show_pointers) const;
-
-    /// \brief Indentation helper function for dumpTree
-    static void indent(std::ostream& os, unsigned int depth);
-
-    /// Split one node into two nodes for "prefix" and "suffix" parts of
-    /// the labels of the original node, respectively.  The given node
-    /// will hold the prefix, while a newly created node will hold the prefix.
-    /// Note that the original node still represents the same domain name in
-    /// the entire tree.  This ensures that a pointer to a node keeps its
-    /// semantics even if the tree structure is changed (as long as the node
-    /// itself remains valid).
-    void nodeFission(util::MemorySegment& mem_sgmt, RBNode<T>& node,
-                     const isc::dns::LabelSequence& new_prefix,
-                     const isc::dns::LabelSequence& new_suffix);
-    //@}
-
-    typename RBNode<T>::RBNodePtr root_;
-    /// the node count of current tree
-    unsigned int node_count_;
-    /// search policy for rbtree
-    const bool needsReturnEmptyNode_;
-};
-
-template <typename T>
-RBTree<T>::RBTree(bool returnEmptyNode) :
-    root_(NULL),
-    node_count_(0),
-    needsReturnEmptyNode_(returnEmptyNode)
-{
-}
-
-template <typename T>
-RBTree<T>::~RBTree() {
-    assert(node_count_ == 0);
-}
-
-template <typename T>
-void
-RBTree<T>::deleteHelper(util::MemorySegment& mem_sgmt, RBNode<T>* root) {
-    while (root != NULL) {
-        // If there is a left, right or down node, walk into it and
-        // iterate.
-        if (root->getLeft() != NULL) {
-            RBNode<T>* node = root;
-            root = root->getLeft();
-            node->left_ = NULL;
-        } else if (root->getRight() != NULL) {
-            RBNode<T>* node = root;
-            root = root->getRight();
-            node->right_ = NULL;
-        } else if (root->getDown() != NULL) {
-            RBNode<T>* node = root;
-            root = root->getDown();
-            node->down_ = NULL;
-        } else {
-            // There are no left, right or down nodes, so we can
-            // free this one and go back to its parent.
-            RBNode<T>* node = root;
-            root = root->getParent();
-            RBNode<T>::destroy(mem_sgmt, node);
-            --node_count_;
-        }
-    }
-}
-
-template <typename T>
-template <typename CBARG>
-typename RBTree<T>::Result
-RBTree<T>::find(const isc::dns::LabelSequence& target_labels_orig,
-                RBNode<T>** target,
-                RBTreeNodeChain<T>& node_path,
-                bool (*callback)(const RBNode<T>&, CBARG),
-                CBARG callback_arg) const
-{
-    if (!node_path.isEmpty()) {
-        isc_throw(isc::BadValue, "RBTree::find is given a non empty chain");
-    }
-
-    RBNode<T>* node = root_.get();
-    Result ret = NOTFOUND;
-    dns::LabelSequence target_labels(target_labels_orig);
-
-    while (node != NULL) {
-        node_path.last_compared_ = node;
-        node_path.last_comparison_ = target_labels.compare(node->getLabels());
-        const isc::dns::NameComparisonResult::NameRelation relation =
-            node_path.last_comparison_.getRelation();
-
-        if (relation == isc::dns::NameComparisonResult::EQUAL) {
-            if (needsReturnEmptyNode_ || !node->isEmpty()) {
-                node_path.push(node);
-                *target = node;
-                ret = EXACTMATCH;
-            }
-            break;
-        } else if (relation == isc::dns::NameComparisonResult::NONE) {
-            // If the two labels have no hierarchical relationship in terms
-            // of matching, we should continue the binary search.
-            node = (node_path.last_comparison_.getOrder() < 0) ?
-                node->getLeft() : node->getRight();
-        } else {
-            if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
-                if (needsReturnEmptyNode_ || !node->isEmpty()) {
-                    ret = PARTIALMATCH;
-                    *target = node;
-                    if (callback != NULL &&
-                        node->getFlag(RBNode<T>::FLAG_CALLBACK)) {
-                        if ((callback)(*node, callback_arg)) {
-                            break;
-                        }
-                    }
-                }
-                node_path.push(node);
-                target_labels.stripRight(
-                    node_path.last_comparison_.getCommonLabels());
-                node = node->getDown();
-            } else {
-                break;
-            }
-        }
-    }
-
-    return (ret);
-}
-
-template <typename T>
-const RBNode<T>*
-RBTree<T>::nextNode(RBTreeNodeChain<T>& node_path) const {
-    if (node_path.isEmpty()) {
-        isc_throw(isc::BadValue, "RBTree::nextNode is given an empty chain");
-    }
-
-    const RBNode<T>* node = node_path.top();
-    // if node has sub domain, the next domain is the smallest
-    // domain in sub domain tree
-    const RBNode<T>* down = node->getDown();
-    if (down != NULL) {
-        const RBNode<T>* left_most = down;
-        while (left_most->getLeft() != NULL) {
-            left_most = left_most->getLeft();
-        }
-        node_path.push(left_most);
-        return (left_most);
-    }
-
-    // try to find a successor.
-    // if no successor found move to up level, the next successor
-    // is the successor of up node in the up level tree, if
-    // up node doesn't have successor we gonna keep moving to up
-    // level
-    while (!node_path.isEmpty()) {
-        const RBNode<T>* up_node_successor = node_path.top()->successor();
-        node_path.pop();
-        if (up_node_successor != NULL) {
-            node_path.push(up_node_successor);
-            return (up_node_successor);
-        }
-    }
-
-    return (NULL);
-}
-
-template <typename T>
-const RBNode<T>*
-RBTree<T>::previousNode(RBTreeNodeChain<T>& node_path) const {
-    if (getNodeCount() == 0) {
-        // Special case for empty trees. It would look every time like
-        // we didn't search, because the last compared is empty. This is
-        // a slight hack and not perfect, but this is better than throwing
-        // on empty tree. And we probably won't meet an empty tree in practice
-        // anyway.
-        return (NULL);
-    }
-    if (node_path.last_compared_ == NULL) {
-        isc_throw(isc::BadValue,
-                  "RBTree::previousNode() called before find()");
-    }
-
-    // If the relation isn't EQUAL, it means the find was called previously
-    // and didn't find the exact node. Therefore we need to locate the place
-    // to start iterating the chain of domains.
-    //
-    // The logic here is not too complex, we just need to take care to handle
-    // all the cases and decide where to go from there.
-    switch (node_path.last_comparison_.getRelation()) {
-        case dns::NameComparisonResult::COMMONANCESTOR:
-        case dns::NameComparisonResult::NONE:
-            // We compared with a leaf in the tree and wanted to go to one of
-            // the children. But the child was not there. It now depends on the
-            // direction in which we wanted to go.
-            if (node_path.last_comparison_.getOrder() < 0) {
-                // We wanted to go left. So the one we compared with is
-                // the one higher than we wanted. If we just put it into
-                // the node_path, then the following algorithm below will find
-                // the smaller one.
-                //
-                // This is exactly the same as with superdomain below.
-                // Therefore, we just fall through to the next case.
-            } else {
-                // We wanted to go right. That means we want to output the
-                // one which is the largest in the tree defined by the
-                // compared one (it is either the compared one, or some
-                // subdomain of it). There probably is not an easy trick
-                // for this, so we just find the correct place.
-                const RBNode<T>* current(node_path.last_compared_);
-                while (current != NULL) {
-                    node_path.push(current);
-                    // Go a level down and as much right there as possible
-                    current = current->getDown();
-                    if (current != NULL) {
-                        const RBNode<T>* right;
-                        while ((right = current->getRight()) != NULL) {
-                            current = right;
-                        }
-                    }
-                }
-                // Now, the one on top of the path is the one we want. We
-                // return it now and leave it there, so we can search for
-                // previous of it the next time we'are called.
-                node_path.last_comparison_ =
-                    dns::NameComparisonResult(0, 0,
-                                              dns::NameComparisonResult::EQUAL);
-                return (node_path.top());
-            }
-            // No break; here - we want to fall through. See above.
-        case dns::NameComparisonResult::SUPERDOMAIN:
-            // This is the case there's a "compressed" node and we looked for
-            // only part of it. The node itself is larger than we wanted, but
-            // if we put it to the node_path and then go one step left from it,
-            // we get the correct result.
-            node_path.push(node_path.last_compared_);
-            // Correct the comparison result, so we won't trigger this case
-            // next time previousNode is called. We already located the correct
-            // place to start. The value is partly nonsense, but that doesn't
-            // matter any more.
-            node_path.last_comparison_ =
-                dns::NameComparisonResult(0, 0,
-                                          dns::NameComparisonResult::EQUAL);
-            break;
-        case dns::NameComparisonResult::SUBDOMAIN:
-            // A subdomain means we returned the one above the searched one
-            // already and it is on top of the stack. This is was smaller
-            // than the one already, but we want to return yet smaller one.
-            // So we act as if it was EQUAL.
-            break;
-        case dns::NameComparisonResult::EQUAL:
-            // The find gave us an exact match or the previousNode was called
-            // already, which located the exact node. The rest of the function
-            // goes one domain left and returns it for us.
-            break;
-    }
-
-    // So, the node_path now contains the path to a node we want previous for.
-    // We just need to go one step left.
-
-    if (node_path.isEmpty()) {
-        // We got past the first one. So, we're returning NULL from
-        // now on.
-        return (NULL);
-    }
-
-    const RBNode<T>* node(node_path.top());
-
-    // Try going left in this tree
-    node = node->predecessor();
-    if (node == NULL) {
-        // We are the smallest ones in this tree. We go one level
-        // up. That one is the smaller one than us.
-
-        node_path.pop();
-        if (node_path.isEmpty()) {
-            // We're past the first one
-            return (NULL);
-        } else {
-            return (node_path.top());
-        }
-    }
-
-    // Exchange the node at the top of the path, as we move horizontaly
-    // through the domain tree
-    node_path.pop();
-    node_path.push(node);
-
-    // Try going as deep as possible, keeping on the right side of the trees
-    const RBNode<T>* down;
-    while ((down = node->getDown()) != NULL) {
-        // Move to the tree below
-        node = down;
-        if (node != NULL) {
-            // And get as much to the right of the tree as possible
-            const RBNode<T>* right;
-            while ((right = node->getRight()) != NULL) {
-                node = right;
-            }
-        }
-        // Now, we found the right-most node in the sub-tree, we need to
-        // include it in the path
-        node_path.push(node);
-    }
-
-    // Now, if the current node has no down_ pointer any more, it's the
-    // correct one.
-    return (node);
-}
-
-template <typename T>
-typename RBTree<T>::Result
-RBTree<T>::insert(util::MemorySegment& mem_sgmt,
-                  const isc::dns::Name& target_name, RBNode<T>** new_node)
-{
-    RBNode<T>* parent = NULL;
-    RBNode<T>* current = root_.get();
-    RBNode<T>* up_node = NULL;
-    isc::dns::LabelSequence target_labels(target_name);
-
-    int order = -1;
-    // For possible LabelSequence serialization we always store labels data
-    // in the separate local buffer.
-    uint8_t labels_buf[dns::LabelSequence::MAX_SERIALIZED_LENGTH];
-    while (current != NULL) {
-        const dns::LabelSequence current_labels(
-            dns::LabelSequence(current->getLabels(), labels_buf));
-        const isc::dns::NameComparisonResult compare_result =
-            target_labels.compare(current_labels);
-        const isc::dns::NameComparisonResult::NameRelation relation =
-            compare_result.getRelation();
-        if (relation == isc::dns::NameComparisonResult::EQUAL) {
-            if (new_node != NULL) {
-                *new_node = current;
-            }
-            return (ALREADYEXISTS);
-        } else if (relation == isc::dns::NameComparisonResult::NONE) {
-            parent = current;
-            order = compare_result.getOrder();
-            current = order < 0 ? current->getLeft() : current->getRight();
-        } else if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
-            // insert sub domain to sub tree
-            parent = NULL;
-            up_node = current;
-            target_labels.stripRight(compare_result.getCommonLabels());
-            current = current->getDown();
-        } else {
-            // The number of labels in common is fewer than the number of
-            // labels at the current node, so the current node must be
-            // adjusted to have just the common suffix, and a down pointer
-            // made to a new tree.
-            dns::LabelSequence common_ancestor = target_labels;
-            common_ancestor.stripLeft(target_labels.getLabelCount() -
-                                      compare_result.getCommonLabels());
-            dns::LabelSequence new_prefix = current_labels;
-            new_prefix.stripRight(compare_result.getCommonLabels());
-            nodeFission(mem_sgmt, *current, new_prefix, common_ancestor);
-            current = current->getParent();
-        }
-    }
-
-    typename RBNode<T>::RBNodePtr* current_root = (up_node != NULL) ?
-        &(up_node->down_) : &root_;
-    // Once a new node is created, no exception will be thrown until the end
-    // of the function, so we can simply create and hold a new node pointer.
-    RBNode<T>* node = RBNode<T>::create(mem_sgmt, target_labels);
-    node->parent_ = parent;
-    if (parent == NULL) {
-        *current_root = node;
-        // node is the new root of sub tree, so its init color is BLACK
-        node->setColor(RBNode<T>::BLACK);
-        node->setSubTreeRoot(true);
-        node->parent_ = up_node;
-    } else if (order < 0) {
-        node->setSubTreeRoot(false);
-        parent->left_ = node;
-    } else {
-        node->setSubTreeRoot(false);
-        parent->right_ = node;
-    }
-    insertRebalance(current_root, node);
-    if (new_node != NULL) {
-        *new_node = node;
-    }
-
-    ++node_count_;
-    return (SUCCESS);
-}
-
-template <typename T>
-void
-RBTree<T>::deleteAllNodes(util::MemorySegment& mem_sgmt) {
-    deleteHelper(mem_sgmt, root_.get());
-    root_ = NULL;
-}
-
-template <typename T>
-void
-RBTree<T>::nodeFission(util::MemorySegment& mem_sgmt, RBNode<T>& node,
-                       const isc::dns::LabelSequence& new_prefix,
-                       const isc::dns::LabelSequence& new_suffix)
-{
-    // Create and reset the labels.
-    // Once a new node is created, no exception will be thrown until
-    // the end of the function, and it will keep consistent behavior
-    // (i.e., a weak form of strong exception guarantee) even if code
-    // after the call to this function throws an exception.
-    RBNode<T>* up_node = RBNode<T>::create(mem_sgmt, new_suffix);
-    node.resetLabels(new_prefix);
-
-    up_node->parent_ = node.getParent();
-    if (node.getParent() != NULL) {
-        if (node.getParent()->getLeft() == &node) {
-            node.getParent()->left_ = up_node;
-        } else if (node.getParent()->getRight() == &node) {
-            node.getParent()->right_ = up_node;
-        } else {
-            node.getParent()->down_ = up_node;
-        }
-    } else {
-        this->root_ = up_node;
-    }
-
-    up_node->down_ = &node;
-    node.parent_ = up_node;
-
-    // inherit the left/right pointers from the original node, and set
-    // the original node's left/right pointers to NULL.
-    up_node->left_ = node.getLeft();
-    if (node.getLeft() != NULL) {
-        node.getLeft()->parent_ = up_node;
-    }
-    up_node->right_ = node.getRight();
-    if (node.getRight() != NULL) {
-        node.getRight()->parent_ = up_node;
-    }
-    node.left_ = NULL;
-    node.right_ = NULL;
-
-    // set color of both nodes; the initial subtree node color is BLACK
-    up_node->setColor(node.getColor());
-    node.setColor(RBNode<T>::BLACK);
-
-    // set the subtree root flag of both nodes
-    up_node->setSubTreeRoot(node.isSubTreeRoot());
-    node.setSubTreeRoot(true);
-
-    ++node_count_;
-}
-
-
-template <typename T>
-void
-RBTree<T>::insertRebalance(typename RBNode<T>::RBNodePtr* root,
-                           RBNode<T>* node)
-{
-    RBNode<T>* uncle;
-    RBNode<T>* parent;
-    while (node != (*root).get() &&
-           (parent = node->getParent())->getColor() == RBNode<T>::RED) {
-        // Here, node->parent_ is not NULL and it is also red, so
-        // node->parent_->parent_ is also not NULL.
-        if (parent == parent->getParent()->getLeft()) {
-            uncle = parent->getParent()->getRight();
-
-            if (uncle != NULL && uncle->getColor() == RBNode<T>::RED) {
-                parent->setColor(RBNode<T>::BLACK);
-                uncle->setColor(RBNode<T>::BLACK);
-                parent->getParent()->setColor(RBNode<T>::RED);
-                node = parent->getParent();
-            } else {
-                if (node == parent->getRight()) {
-                    node = parent;
-                    leftRotate(root, node);
-                    parent = node->getParent();
-                }
-                parent->setColor(RBNode<T>::BLACK);
-                parent->getParent()->setColor(RBNode<T>::RED);
-                rightRotate(root, parent->getParent());
-            }
-        } else {
-            uncle = parent->getParent()->getLeft();
-            if (uncle != NULL && uncle->getColor() == RBNode<T>::RED) {
-                parent->setColor(RBNode<T>::BLACK);
-                uncle->setColor(RBNode<T>::BLACK);
-                parent->getParent()->setColor(RBNode<T>::RED);
-                node = parent->getParent();
-            } else {
-                if (node == parent->getLeft()) {
-                    node = parent;
-                    rightRotate(root, node);
-                    parent = node->getParent();
-                }
-                parent->setColor(RBNode<T>::BLACK);
-                parent->getParent()->setColor(RBNode<T>::RED);
-                leftRotate(root, parent->getParent());
-            }
-        }
-    }
-
-    (*root)->setColor(RBNode<T>::BLACK);
-}
-
-
-template <typename T>
-RBNode<T>*
-RBTree<T>::leftRotate(typename RBNode<T>::RBNodePtr* root, RBNode<T>* node) {
-    RBNode<T>* const right = node->getRight();
-    RBNode<T>* const rleft = right->getLeft();
-    node->right_ = rleft;
-    if (rleft != NULL) {
-        rleft->parent_ = node;
-    }
-
-    RBNode<T>* const parent = node->getParent();
-    right->parent_ = parent;
-
-    if (!node->isSubTreeRoot()) {
-        right->setSubTreeRoot(false);
-        if (node == parent->getLeft()) {
-            parent->left_ = right;
-        } else  {
-            parent->right_ = right;
-        }
-    } else {
-        right->setSubTreeRoot(true);
-        *root = right;
-    }
-
-    right->left_ = node;
-    node->parent_ = right;
-    node->setSubTreeRoot(false);
-    return (node);
-}
-
-template <typename T>
-RBNode<T>*
-RBTree<T>::rightRotate(typename RBNode<T>::RBNodePtr* root, RBNode<T>* node) {
-    RBNode<T>* const left = node->getLeft();
-    RBNode<T>* const lright = left->getRight();
-    node->left_ = lright;
-    if (lright != NULL) {
-        lright->parent_ = node;
-    }
-
-    RBNode<T>* const parent = node->getParent();
-    left->parent_ = parent;
-
-    if (!node->isSubTreeRoot()) {
-        left->setSubTreeRoot(false);
-        if (node == parent->getRight()) {
-            parent->right_ = left;
-        } else  {
-            parent->left_ = left;
-        }
-    } else {
-        left->setSubTreeRoot(true);
-        *root = left;
-    }
-    left->right_ = node;
-    node->parent_ = left;
-    node->setSubTreeRoot(false);
-
-    return (node);
-}
-
-
-template <typename T>
-void
-RBTree<T>::dumpTree(std::ostream& os, unsigned int depth) const {
-    indent(os, depth);
-    os << "tree has " << node_count_ << " node(s)\n";
-    dumpTreeHelper(os, root_.get(), depth);
-}
-
-template <typename T>
-void
-RBTree<T>::dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
-                          unsigned int depth) const
-{
-    if (node == NULL) {
-        indent(os, depth);
-        os << "NULL\n";
-        return;
-    }
-
-    indent(os, depth);
-    os << node->getLabels() << " ("
-       << ((node->getColor() == RBNode<T>::BLACK) ? "black" : "red")
-       << ")";
-    if (node->isEmpty()) {
-        os << " [invisible]";
-    }
-    if (node->isSubTreeRoot()) {
-        os << " [subtreeroot]";
-    }
-    os << "\n";
-
-    const RBNode<T>* down = node->getDown();
-    if (down != NULL) {
-        indent(os, depth + 1);
-        os << "begin down from " << node->getLabels() << "\n";
-        dumpTreeHelper(os, down, depth + 1);
-        indent(os, depth + 1);
-        os << "end down from " << node->getLabels() << "\n";
-    }
-    dumpTreeHelper(os, node->getLeft(), depth + 1);
-    dumpTreeHelper(os, node->getRight(), depth + 1);
-}
-
-template <typename T>
-void
-RBTree<T>::indent(std::ostream& os, unsigned int depth) {
-    static const unsigned int INDENT_FOR_EACH_DEPTH = 5;
-    os << std::string(depth * INDENT_FOR_EACH_DEPTH, ' ');
-}
-
-template <typename T>
-void
-RBTree<T>::dumpDot(std::ostream& os, bool show_pointers) const {
-    int nodecount = 0;
-
-    os << "digraph g {\n";
-    os << "node [shape = record,height=.1];\n";
-    dumpDotHelper(os, root_.get(), &nodecount, show_pointers);
-    os << "}\n";
-}
-
-template <typename T>
-int
-RBTree<T>::dumpDotHelper(std::ostream& os, const RBNode<T>* node,
-                         int* nodecount, bool show_pointers) const
-{
-    if (node == NULL) {
-        return 0;
-    }
-
-    int l = dumpDotHelper(os, node->getLeft(), nodecount, show_pointers);
-    int r = dumpDotHelper(os, node->getRight(), nodecount, show_pointers);
-    int d = dumpDotHelper(os, node->getDown(), nodecount, show_pointers);
-
-    *nodecount += 1;
-
-    os << "node" << *nodecount <<
-          "[label = \"<f0> |<f1> " << node->getLabels() <<
-          "|<f2>";
-    if (show_pointers) {
-        os << "|<f3> n=" << node << "|<f4> p=" << node->getParent();
-    }
-    os << "\"] [";
-
-    if (node->getColor() == RBNode<T>::RED) {
-        os << "color=red";
-    } else {
-        os << "color=black";
-    }
-
-    if (node->isSubTreeRoot()) {
-        os << ",penwidth=3";
-    }
-
-    if (node->isEmpty()) {
-        os << ",style=filled,fillcolor=lightgrey";
-    }
-
-    os << "];\n";
-
-    if (node->getLeft() != NULL) {
-        os << "\"node" << *nodecount << "\":f0 -> \"node" << l << "\":f1;\n";
-    }
-
-    if (node->getDown() != NULL) {
-        os << "\"node" << *nodecount << "\":f1 -> \"node" << d << "\":f1 [penwidth=5];\n";
-    }
-
-    if (node->getRight() != NULL) {
-        os << "\"node" << *nodecount << "\":f2 -> \"node" << r << "\":f1;\n";
-    }
-
-    return (*nodecount);
-}
-
-}
-}
-
-#endif  // RBTREE_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/rrset_collection_base.cc b/src/lib/datasrc/rrset_collection_base.cc
index b19f62e..9da4075 100644
--- a/src/lib/datasrc/rrset_collection_base.cc
+++ b/src/lib/datasrc/rrset_collection_base.cc
@@ -14,6 +14,7 @@
 
 #include <datasrc/rrset_collection_base.h>
 #include <datasrc/zone_loader.h>
+#include <datasrc/zone_finder.h>
 #include <exceptions/exceptions.h>
 
 using namespace isc;
diff --git a/src/lib/datasrc/rrset_collection_base.h b/src/lib/datasrc/rrset_collection_base.h
index c02df9a..66b5825 100644
--- a/src/lib/datasrc/rrset_collection_base.h
+++ b/src/lib/datasrc/rrset_collection_base.h
@@ -22,14 +22,33 @@
 namespace isc {
 namespace datasrc {
 
-/// \brief A forward declaration
-class ZoneUpdater;
-
 /// \brief datasrc derivation of \c isc::dns::RRsetCollectionBase.
 ///
-/// This is an abstract class that adds datasrc related detail to
-/// \c isc::dns::RRsetCollectionBase. Derived classes need to complete
-/// the implementation (add iterator support, etc.) before using it.
+/// This is a default datasrc implementation of
+/// \c isc::dns::RRsetCollectionBase that adds datasrc related detail.
+///
+/// While it is a concrete class to be used along with a \c ZoneUpdater,
+/// specific \c ZoneUpdater implementations may derive from it and add
+/// additional detail. Unless you are implementing a \c ZoneUpdater, you
+/// must not use the constructor directly. Instead use the
+/// \c ZoneUpdater::getRRsetCollection() method to get a reference to
+/// the \c RRsetCollectionBase object for that \c ZoneUpdater. This is
+/// usually a singleton object and the API is designed with this in
+/// mind, because multiple \c RRsetCollectionBase objects cannot be used
+/// at the same time in most kinds of database implementations
+/// (esp. where iterators are in use). Specific \c ZoneUpdaters that can
+/// allow multiple \c RRsetCollection objects may provide additional
+/// API, but that is unspecified here.
+///
+/// There are some restrictions on when an \c RRsetCollection may be
+/// used. Though code may have a reference to an \c RRsetCollection
+/// object, it is not always valid to use it. Implementations of
+/// \c ZoneUpdater may disable an \c RRsetCollection previously returned
+/// by \c ZoneUpdater::getRRsetCollection() after \c commit() is called
+/// on the \c ZoneUpdater. An \c isc::dns::RRsetCollectionError
+/// exception will be thrown if an \c RRsetCollection is used when
+/// disabled. Please see the \c ZoneUpdater methods' documentation for
+/// more detail.
 class RRsetCollectionBase : public isc::dns::RRsetCollectionBase {
 public:
     /// \brief Constructor.
@@ -90,18 +109,18 @@ protected:
     /// \brief See \c isc::dns::RRsetCollectionBase::getBeginning() for
     /// documentation.
     ///
-    /// \throw isc::dns::RRsetCollectionError if using the iterator
-    /// results in some underlying datasrc error, or if \c disable() was
-    /// called.
-    virtual IterPtr getBeginning() = 0;
+    /// \throw isc::NotImplemented as it's not implemented currently.
+    virtual IterPtr getBeginning() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
 
     /// \brief See \c isc::dns::RRsetCollectionBase::getEnd() for
     /// documentation.
     ///
-    /// \throw isc::dns::RRsetCollectionError if using the iterator
-    /// results in some underlying datasrc error, or if \c disable() was
-    /// called.
-    virtual IterPtr getEnd() = 0;
+    /// \throw isc::NotImplemented as it's not implemented currently.
+    virtual IterPtr getEnd() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
 
 private:
     ZoneUpdater& updater_;
@@ -109,13 +128,6 @@ private:
     bool disabled_;
 };
 
-/// \brief A pointer-like type pointing to an
-/// \c isc::datasrc::RRsetCollectionBase object.
-///
-/// This type is used to handle RRsetCollections in a polymorphic manner
-/// in libdatasrc.
-typedef boost::shared_ptr<isc::datasrc::RRsetCollectionBase> RRsetCollectionPtr;
-
 } // end of namespace datasrc
 } // end of namespace isc
 
diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc
index bd71544..a858028 100644
--- a/src/lib/datasrc/sqlite3_accessor.cc
+++ b/src/lib/datasrc/sqlite3_accessor.cc
@@ -44,7 +44,7 @@ namespace {
 // program may not be taking advantage of features (possibly performance
 // improvements) added to the database.
 const int SQLITE_SCHEMA_MAJOR_VERSION = 2;
-const int SQLITE_SCHEMA_MINOR_VERSION = 1;
+const int SQLITE_SCHEMA_MINOR_VERSION = 2;
 }
 
 namespace isc {
@@ -338,7 +338,7 @@ public:
 const char* const SCHEMA_LIST[] = {
     "CREATE TABLE schema_version (version INTEGER NOT NULL, "
         "minor INTEGER NOT NULL DEFAULT 0)",
-    "INSERT INTO schema_version VALUES (2, 1)",
+    "INSERT INTO schema_version VALUES (2, 2)",
     "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
     "name TEXT NOT NULL COLLATE NOCASE, "
     "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
@@ -358,6 +358,7 @@ const char* const SCHEMA_LIST[] = {
     // defining a separate index for rdtype only doesn't work either; SQLite3
     // would then create a temporary B-tree for "ORDER BY").
     "CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
+    "CREATE INDEX records_byrname_and_rdtype ON records (rname, rdtype)",
     "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
         "hash TEXT NOT NULL COLLATE NOCASE, "
         "owner TEXT NOT NULL COLLATE NOCASE, "
@@ -681,6 +682,8 @@ convertToPlainChar(const unsigned char* ucp, sqlite3 *db) {
 }
 
 }
+
+// cppcheck-suppress noConstructor
 class SQLite3Accessor::Context : public DatabaseAccessor::IteratorContext {
 public:
     // Construct an iterator for all records. When constructed this
@@ -886,6 +889,7 @@ SQLite3Accessor::getAllRecords(int id) const {
 /// This iterator is used to search through the differences table for the
 /// resouce records making up an IXFR between two versions of a zone.
 
+// cppcheck-suppress noConstructor
 class SQLite3Accessor::DiffContext : public DatabaseAccessor::IteratorContext {
 public:
 
diff --git a/src/lib/datasrc/sqlite3_accessor_link.cc b/src/lib/datasrc/sqlite3_accessor_link.cc
index c064e0f..56e0c2f 100644
--- a/src/lib/datasrc/sqlite3_accessor_link.cc
+++ b/src/lib/datasrc/sqlite3_accessor_link.cc
@@ -47,12 +47,12 @@ checkConfig(ConstElementPtr config, ElementPtr errors) {
     bool result = true;
 
     if (!config || config->getType() != Element::map) {
-        addError(errors, "Base config for SQlite3 backend must be a map");
+        addError(errors, "Base config for SQLite3 backend must be a map");
         result = false;
     } else {
         if (!config->contains(CONFIG_ITEM_DATABASE_FILE)) {
             addError(errors,
-                     "Config for SQlite3 backend does not contain a '" +
+                     "Config for SQLite3 backend does not contain a '" +
                      string(CONFIG_ITEM_DATABASE_FILE) +
                      "' value");
             result = false;
@@ -89,11 +89,11 @@ createInstance(isc::data::ConstElementPtr config, std::string& error) {
             new SQLite3Accessor(dbfile, "IN")); // XXX: avoid hardcode RR class
         return (new DatabaseClient(isc::dns::RRClass::IN(), sqlite3_accessor));
     } catch (const std::exception& exc) {
-        error = std::string("Error creating sqlite3 datasource: ") +
+        error = std::string("Error creating SQLite3 datasource: ") +
             exc.what();
         return (NULL);
     } catch (...) {
-        error = std::string("Error creating sqlite3 datasource, "
+        error = std::string("Error creating SQLite3 datasource, "
                             "unknown exception");
         return (NULL);
     }
diff --git a/src/lib/datasrc/static_datasrc.h b/src/lib/datasrc/static_datasrc.h
new file mode 100644
index 0000000..d5d8875
--- /dev/null
+++ b/src/lib/datasrc/static_datasrc.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2013  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_STATIC_H
+#define DATASRC_STATIC_H
+
+#include <datasrc/database.h>
+#include <cc/data.h>
+
+#include <string>
+
+namespace isc {
+namespace datasrc {
+
+/// \brief Creates an instance of the static datasource client
+///
+/// Currently the configuration passed here must be a StringElement,
+/// containing the path to a zone file for the BIND./CH zone.
+///
+/// \param config The configuration for the datasource instance (see above)
+/// \param error This string will be set to an error message if an error occurs
+///              during initialization
+/// \return An instance of the static datasource client, or NULL if there was
+///         an error
+extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
+                                            std::string& error);
+
+/// \brief Destroy the instance created by createInstance()
+extern "C" void destroyInstance(DataSourceClient* instance);
+
+}
+}
+
+#endif  // DATASRC_STATIC_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/static_datasrc_link.cc b/src/lib/datasrc/static_datasrc_link.cc
index 789580d..1b767a4 100644
--- a/src/lib/datasrc/static_datasrc_link.cc
+++ b/src/lib/datasrc/static_datasrc_link.cc
@@ -13,7 +13,9 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include "client.h"
-#include "memory_datasrc.h"
+#include "static_datasrc.h"
+#include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_table_segment.h>
 
 #include <cc/data.h>
 #include <dns/rrclass.h>
@@ -32,16 +34,20 @@ namespace datasrc {
 DataSourceClient*
 createInstance(ConstElementPtr config, string& error) {
     try {
+        // FIXME: Fix the config that should be passed to
+        // ZoneTableSegment::create() when it actually uses the config
+        // to do something.
+        shared_ptr<memory::ZoneTableSegment> ztable_segment(
+            memory::ZoneTableSegment::create(isc::data::NullElement(),
+                                             RRClass::CH()));
         // Create the data source
-        auto_ptr<InMemoryClient> client(new InMemoryClient());
-        // Hardcode the origin and class
-        shared_ptr<InMemoryZoneFinder>
-            finder(new InMemoryZoneFinder(RRClass::CH(), Name("BIND")));
+        auto_ptr<memory::InMemoryClient> client
+            (new memory::InMemoryClient(ztable_segment, RRClass::CH()));
+
         // Fill it with data
         const string path(config->stringValue());
-        finder->load(path);
-        // And put the zone inside
-        client->addZone(finder);
+        client->load(Name("BIND"), path);
+
         return (client.release());
     }
     catch (const std::exception& e) {
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 7c61826..7960963 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -48,14 +48,11 @@ common_ldadd += $(GTEST_LDADD) $(SQLITE_LIBS)
 run_unittests_SOURCES = $(common_sources)
 
 run_unittests_SOURCES += test_client.h test_client.cc
-run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += client_unittest.cc
-run_unittests_SOURCES += database_unittest.cc
+run_unittests_SOURCES += database_unittest.h database_unittest.cc
+run_unittests_SOURCES += database_sqlite3_unittest.cc
 run_unittests_SOURCES += sqlite3_accessor_unittest.cc
-run_unittests_SOURCES += memory_datasrc_unittest.cc
-run_unittests_SOURCES += rbnode_rrset_unittest.cc
-run_unittests_SOURCES += zonetable_unittest.cc
 run_unittests_SOURCES += zone_finder_context_unittest.cc
 run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
 run_unittests_SOURCES += client_list_unittest.cc
@@ -118,5 +115,6 @@ EXTRA_DIST += testdata/new_minor_schema.sqlite3
 EXTRA_DIST += testdata/newschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/static.zone
+EXTRA_DIST += testdata/static-bad.zone
 EXTRA_DIST += testdata/novalidate.zone
 EXTRA_DIST += testdata/checkwarn.zone
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 6769e9b..0838fb6 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/data_source.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
@@ -77,7 +77,7 @@ public:
     };
     class Iterator : public ZoneIterator {
     public:
-        Iterator(const Name& origin, bool include_ns) :
+        Iterator(const Name& origin, bool include_a) :
             origin_(origin),
             soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
                            RRTTL(3600)))
@@ -89,12 +89,21 @@ public:
                                                0, 0, 0, 0, 0));
             rrsets_.push_back(soa_);
 
-            if (include_ns) {
-                ns_.reset(new RRset(origin_, RRClass::IN(), RRType::NS(),
-                                    RRTTL(3600)));
-                ns_->addRdata(rdata::generic::NS(Name::ROOT_NAME()));
-                rrsets_.push_back(ns_);
+            RRsetPtr rrset(new RRset(origin_, RRClass::IN(), RRType::NS(),
+                                     RRTTL(3600)));
+            rrset->addRdata(rdata::generic::NS(Name::ROOT_NAME()));
+            rrsets_.push_back(rrset);
+
+            if (include_a) {
+                 // Dummy A rrset. This is used for checking zone data
+                 // after reload.
+                 rrset.reset(new RRset(Name("tstzonedata").concatenate(origin_),
+                                       RRClass::IN(), RRType::A(),
+                                       RRTTL(3600)));
+                 rrset->addRdata(rdata::in::A("192.0.2.1"));
+                 rrsets_.push_back(rrset);
             }
+
             rrsets_.push_back(ConstRRsetPtr());
 
             it_ = rrsets_.begin();
@@ -110,13 +119,12 @@ public:
     private:
         const Name origin_;
         const RRsetPtr soa_;
-        RRsetPtr ns_;
         std::vector<ConstRRsetPtr> rrsets_;
         std::vector<ConstRRsetPtr>::const_iterator it_;
     };
     // Constructor from a list of zones.
     MockDataSourceClient(const char* zone_names[]) :
-        have_ns_(true), use_baditerator_(true)
+        have_a_(true), use_baditerator_(true)
     {
         for (const char** zone(zone_names); *zone; ++zone) {
             zones.insert(Name(*zone));
@@ -128,7 +136,7 @@ public:
                          const ConstElementPtr& configuration) :
         type_(type),
         configuration_(configuration),
-        have_ns_(true), use_baditerator_(true)
+        have_a_(true), use_baditerator_(true)
     {
         EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
             "and it never should be created as a data source client";
@@ -176,19 +184,19 @@ public:
         } else {
             FindResult result(findZone(name));
             if (result.code == isc::datasrc::result::SUCCESS) {
-                return (ZoneIteratorPtr(new Iterator(name, have_ns_)));
+                return (ZoneIteratorPtr(new Iterator(name, have_a_)));
             } else {
                 isc_throw(DataSourceError, "No such zone");
             }
         }
     }
-    void disableNS() { have_ns_ = false; }
+    void disableA() { have_a_ = false; }
     void disableBadIterator() { use_baditerator_ = false; }
     const string type_;
     const ConstElementPtr configuration_;
 private:
     set<Name> zones;
-    bool have_ns_; // control the iterator behavior wrt whether to include NS
+    bool have_a_; // control the iterator behavior whether to include A record
     bool use_baditerator_; // whether to use bogus zone iterators for tests
 };
 
@@ -285,7 +293,7 @@ public:
         MockDataSourceClient mock_client(zones);
         // Disable some default features of the mock to distinguish the
         // temporary case from normal case.
-        mock_client.disableNS();
+        mock_client.disableA();
         mock_client.disableBadIterator();
 
         // Create cache from the temporary data source, and push it to the
@@ -925,14 +933,19 @@ TYPED_TEST(ReloadTest, reloadSuccess) {
     this->list_->configure(this->config_elem_zones_, true);
     const Name name("example.org");
     this->prepareCache(0, name);
-    // The cache currently contains a tweaked version of zone, which doesn't
-    // have apex NS.  So the lookup should result in NXRRSET.
-    EXPECT_EQ(ZoneFinder::NXRRSET,
-              this->list_->find(name).finder_->find(name, RRType::NS())->code);
+    // The cache currently contains a tweaked version of zone, which
+    // doesn't have "tstzonedata" A record.  So the lookup should result
+    // in NXDOMAIN.
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              this->list_->find(name).finder_->
+                  find(Name("tstzonedata").concatenate(name),
+                       RRType::A())->code);
     // Now reload the full zone. It should be there now.
     EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS, this->doReload(name));
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              this->list_->find(name).finder_->find(name, RRType::NS())->code);
+              this->list_->find(name).finder_->
+                  find(Name("tstzonedata").concatenate(name),
+                       RRType::A())->code);
 }
 
 // The cache is not enabled. The load should be rejected.
@@ -941,14 +954,18 @@ TYPED_TEST(ReloadTest, reloadNotEnabled) {
     const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the thing.
     this->prepareCache(0, name);
-    // See the reloadSuccess test.  This should result in NXRRSET.
-    EXPECT_EQ(ZoneFinder::NXRRSET,
-              this->list_->find(name).finder_->find(name, RRType::NS())->code);
+    // See the reloadSuccess test.  This should result in NXDOMAIN.
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              this->list_->find(name).finder_->
+                  find(Name("tstzonedata").concatenate(name),
+                       RRType::A())->code);
     // Now reload. It should reject it.
     EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, this->doReload(name));
     // Nothing changed here
-    EXPECT_EQ(ZoneFinder::NXRRSET,
-              this->list_->find(name).finder_->find(name, RRType::NS())->code);
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              this->list_->find(name).finder_->
+                  find(Name("tstzonedata").concatenate(name),
+                       RRType::A())->code);
 }
 
 // Test several cases when the zone does not exist
@@ -974,10 +991,11 @@ TYPED_TEST(ReloadTest, reloadNoSuchZone) {
               this->list_->find(Name("example.cz")).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
               this->list_->find(Name("sub.example.com"), true).dsrc_client_);
-    // Not reloaded, so NS shouldn't be visible yet.
-    EXPECT_EQ(ZoneFinder::NXRRSET,
+    // Not reloaded, so A record shouldn't be visible yet.
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
               this->list_->find(Name("example.com")).finder_->
-              find(Name("example.com"), RRType::NS())->code);
+                  find(Name("tstzonedata.example.com"),
+                       RRType::A())->code);
 }
 
 // Check we gracefuly throw an exception when a zone disappeared in
diff --git a/src/lib/datasrc/tests/database_sqlite3_unittest.cc b/src/lib/datasrc/tests/database_sqlite3_unittest.cc
new file mode 100644
index 0000000..0dd356a
--- /dev/null
+++ b/src/lib/datasrc/tests/database_sqlite3_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2013  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/tests/database_unittest.h>
+
+#include <datasrc/database.h>
+#include <datasrc/sqlite3_accessor.h>
+
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <cstdlib>
+#include <string>
+
+using std::string;
+
+using namespace isc::datasrc;
+using namespace isc::datasrc::test;
+
+namespace {
+boost::shared_ptr<DatabaseAccessor>
+createSQLite3Accessor() {
+    // To make sure we always have empty diffs table at the beginning of
+    // each test, we re-install the writable data source here.
+    const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_COMMONDIR
+        "/rwtest.sqlite3 " TEST_DATA_BUILDDIR "/rwtest.sqlite3.copied";
+    if (std::system(install_cmd) != 0) {
+        // any exception will do, this is failure in test setup, but nice
+        // to show the command that fails, and shouldn't be caught
+        isc_throw(isc::Unexpected,
+                  "Error setting up; command failed: " << install_cmd);
+    }
+
+    // The SQLite accessor implements all API, so we can use the generic
+    // loadTestDataGeneric once accessor is created.
+    boost::shared_ptr<DatabaseAccessor> accessor(
+        new SQLite3Accessor(TEST_DATA_BUILDDIR "/rwtest.sqlite3.copied",
+                            "IN"));
+    loadTestDataGeneric(*accessor);
+
+    return (accessor);
+}
+
+// The test parameter for the SQLite3 accessor.  We can use enableNSEC3Generic
+// as this accessor fully supports NSEC3 related APIs.
+const DatabaseClientTestParam sqlite3_param = { createSQLite3Accessor,
+                                                enableNSEC3Generic };
+
+INSTANTIATE_TEST_CASE_P(SQLite3, DatabaseClientTest,
+                        ::testing::Values(&sqlite3_param));
+
+INSTANTIATE_TEST_CASE_P(SQLite3, RRsetCollectionTest,
+                        ::testing::Values(&sqlite3_param));
+}
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 9f5ade4..83ff004 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -12,9 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "faked_nsec3.h"
-
-#include <exceptions/exceptions.h>
+#include <datasrc/tests/database_unittest.h>
+#include <datasrc/tests/faked_nsec3.h>
 
 #include <dns/masterload.h>
 #include <dns/name.h>
@@ -25,9 +24,9 @@
 
 #include <datasrc/database.h>
 #include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
-#include <datasrc/sqlite3_accessor.h>
+#include <datasrc/zone_iterator.h>
 
 #include <testutils/dnsmessage_test.h>
 
@@ -37,8 +36,8 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
-#include <cstdlib>
 #include <map>
+#include <string>
 #include <vector>
 
 using namespace isc::datasrc;
@@ -51,207 +50,62 @@ using namespace isc::dns;
 using namespace isc::testutils;
 using namespace isc::datasrc::test;
 
-namespace {
+namespace isc {
+namespace datasrc {
+namespace test {
+/// Single journal entry in the mock database.
+///
+/// All the members there are public for simplicity, as it only stores data.
+/// We use the implicit constructor and operator. The members can't be const
+/// because of the assignment operator (used in the vectors).
+struct JournalEntry {
+    JournalEntry(int id, uint32_t serial,
+                 DatabaseAccessor::DiffOperation operation,
+                 const std::string (&data)[DatabaseAccessor::DIFF_PARAM_COUNT])
+        : id_(id), serial_(serial), operation_(operation)
+    {
+        data_[DatabaseAccessor::DIFF_NAME] = data[DatabaseAccessor::DIFF_NAME];
+        data_[DatabaseAccessor::DIFF_TYPE] = data[DatabaseAccessor::DIFF_TYPE];
+        data_[DatabaseAccessor::DIFF_TTL] = data[DatabaseAccessor::DIFF_TTL];
+        data_[DatabaseAccessor::DIFF_RDATA] =
+            data[DatabaseAccessor::DIFF_RDATA];
+    }
+    JournalEntry(int id, uint32_t serial,
+                 DatabaseAccessor::DiffOperation operation,
+                 const std::string& name, const std::string& type,
+                 const std::string& ttl, const std::string& rdata):
+        id_(id), serial_(serial), operation_(operation)
+    {
+        data_[DatabaseAccessor::DIFF_NAME] = name;
+        data_[DatabaseAccessor::DIFF_TYPE] = type;
+        data_[DatabaseAccessor::DIFF_TTL] = ttl;
+        data_[DatabaseAccessor::DIFF_RDATA] = rdata;
+    }
+    int id_;
+    uint32_t serial_;
+    DatabaseAccessor::DiffOperation operation_;
+    std::string data_[DatabaseAccessor::DIFF_PARAM_COUNT];
+    bool operator==(const JournalEntry& other) const {
+        for (size_t i = 0; i < DatabaseAccessor::DIFF_PARAM_COUNT; ++ i) {
+            if (data_[i] != other.data_[i]) {
+                return false;
+            }
+        }
+        // No need to check data here, checked above
+        return (id_ == other.id_ && serial_ == other.serial_ &&
+                operation_ == other.operation_);
+    }
+};
+}
+}
+}
 
+namespace {
 // Imaginary zone IDs used in the mock accessor below.
 const int READONLY_ZONE_ID = 42;
 const int NEW_ZONE_ID = 420;
 const int WRITABLE_ZONE_ID = 4200;
 
-// Commonly used test data
-const char* const TEST_RECORDS[][5] = {
-    // some plain data
-    {"www.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"www.example.org.", "AAAA", "3600", "", "2001:db8::1"},
-    {"www.example.org.", "AAAA", "3600", "", "2001:db8::2"},
-    {"www.example.org.", "NSEC", "3600", "", "www2.example.org. A AAAA NSEC RRSIG"},
-    {"www.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    {"www2.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"www2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
-    {"www2.example.org.", "A", "3600", "", "192.0.2.2"},
-
-    {"cname.example.org.", "CNAME", "3600", "", "www.example.org."},
-
-    // some DNSSEC-'signed' data
-    {"signed1.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
-    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::1"},
-    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::2"},
-    {"signed1.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    {"signedcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
-    {"signedcname1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    // special case might fail; sig is for cname, which isn't there (should be ignored)
-    // (ignoring of 'normal' other type is done above by www.)
-    {"acnamesig1.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"acnamesig1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"acnamesig1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    // let's pretend we have a database that is not careful
-    // about the order in which it returns data
-    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::2"},
-    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
-    {"signed2.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"signed2.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
-
-    {"signedcname2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"signedcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
-
-    {"acnamesig2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"acnamesig2.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"acnamesig2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    {"acnamesig3.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"acnamesig3.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"acnamesig3.example.org.", "A", "3600", "", "192.0.2.1"},
-
-    {"ttldiff1.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"ttldiff1.example.org.", "A", "360", "", "192.0.2.2"},
-
-    {"ttldiff2.example.org.", "A", "360", "", "192.0.2.1"},
-    {"ttldiff2.example.org.", "A", "3600", "", "192.0.2.2"},
-
-    // also add some intentionally bad data
-    {"badcname1.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"badcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
-
-    {"badcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
-    {"badcname2.example.org.", "A", "3600", "", "192.0.2.1"},
-
-    {"badcname3.example.org.", "CNAME", "3600", "", "www.example.org."},
-    {"badcname3.example.org.", "CNAME", "3600", "", "www.example2.org."},
-
-    {"badrdata.example.org.", "A", "3600", "", "bad"},
-
-    {"badtype.example.org.", "BAD_TYPE", "3600", "", "192.0.2.1"},
-
-    {"badttl.example.org.", "A", "badttl", "", "192.0.2.1"},
-
-    {"badsig.example.org.", "A", "badttl", "", "192.0.2.1"},
-    {"badsig.example.org.", "RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    {"badsigtype.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"badsigtype.example.org.", "RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    // Data for testing delegation (with NS and DNAME)
-    {"delegation.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"delegation.example.org.", "NS", "3600", "",
-     "ns.delegation.example.org."},
-    {"delegation.example.org.", "DS", "3600", "", "1 1 2 abcd"},
-    {"delegation.example.org.", "RRSIG", "3600", "", "NS 5 3 3600 "
-     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"delegation.example.org.", "RRSIG", "3600", "", "DS 5 3 3600 "
-     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"ns.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"deep.below.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
-
-    {"dname.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"dname.example.org.", "DNAME", "3600", "", "dname.example.com."},
-    {"dname.example.org.", "RRSIG", "3600", "",
-     "DNAME 5 3 3600 20000101000000 20000201000000 12345 "
-     "example.org. FAKEFAKEFAKE"},
-
-    {"below.dname.example.org.", "A", "3600", "", "192.0.2.1"},
-
-    // Insecure delegation (i.e., no DS at the delegation point)
-    {"insecdelegation.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"insecdelegation.example.org.", "NSEC", "3600", "",
-     "dummy.example.org. NS NSEC"},
-    // and a DS under the zone cut. Such an RR shouldn't exist in a sane zone,
-    // but it could by error or some malicious attempt.  It shouldn't confuse
-    // the implementation)
-    {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
-     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    // Delegation NS and other ordinary type of RR coexist at the same
-    // name.  This is deviant (except for some special cases like the other
-    // RR could be used for addressing the NS name), but as long as the
-    // other records are hidden behind the delegation for normal queries
-    // it's not necessarily harmful. (so "broken" may be too strong, but we
-    // keep the name since it could be in a chain of sorted names for DNSSEC
-    // processing and renaming them may have other bad effects for tests).
-    {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
-
-    // Now double DNAME, to test failure mode
-    {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
-    {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
-
-    // Put some data into apex (including NS) so we can check our NS
-    // doesn't break anything
-    {"example.org.", "SOA", "3600", "", "ns1.example.org. admin.example.org. "
-     "1234 3600 1800 2419200 7200" },
-    {"example.org.", "NS", "3600", "", "ns.example.com."},
-    {"example.org.", "A", "3600", "", "192.0.2.1"},
-    // Note that the RDATA text is "normalized", i.e., identical to what
-    // Rdata::toText() would produce.  some tests rely on that behavior.
-    {"example.org.", "NSEC", "3600", "",
-     "acnamesig1.example.org. A NS RRSIG NSEC"},
-    {"example.org.", "RRSIG", "3600", "", "SOA 5 3 3600 20000101000000 "
-              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 "
-              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"example.org.", "RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
-              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
-
-    // This is because of empty domain test
-    {"a.b.example.org.", "A", "3600", "", "192.0.2.1"},
-
-    // Something for wildcards
-    {"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
-    {"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
-    {"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
-    {"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
-    {"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
-    {"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
-    {"wild.*.foo.*.bar.example.org.", "NSEC", "3600", "",
-     "brokenns1.example.org. A NSEC"},
-    {"bao.example.org.", "NSEC", "3600", "", "wild.*.foo.*.bar.example.org. NSEC"},
-    {"*.cnamewild.example.org.", "CNAME", "3600", "", "www.example.org."},
-    {"*.dnamewild.example.org.", "DNAME", "3600", "", "dname.example.com."},
-    {"*.nswild.example.org.", "NS", "3600", "", "ns.example.com."},
-    // For NSEC empty non-terminal
-    {"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
-    {"empty.nonterminal.example.org.", "A", "3600", "", "192.0.2.1"},
-    // Invalid rdata
-    {"invalidrdata.example.org.", "A", "3600", "", "Bunch of nonsense"},
-    {"invalidrdata2.example.org.", "A", "3600", "", "192.0.2.1"},
-    {"invalidrdata2.example.org.", "RRSIG", "3600", "", "Nonsense"},
-
-    {NULL, NULL, NULL, NULL, NULL},
-};
-
-// NSEC3PARAM at the zone origin and its RRSIG.  These will be added
-// separately for some NSEC3 related tests.
-const char* TEST_NSEC3PARAM_RECORDS[][5] = {
-    {"example.org.", "NSEC3PARAM", "3600", "", "1 0 12 aabbccdd"},
-    {"example.org.", "RRSIG", "3600", "", "NSEC3PARAM 5 3 3600 20000101000000 "
-     "20000201000000 12345 example.org. FAKEFAKEFAKE"},
-    {NULL, NULL, NULL, NULL, NULL}
-};
-
-// FIXME: Taken from a different test. Fill with proper data when creating a test.
-const char* TEST_NSEC3_RECORDS[][5] = {
-    {apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
-    {apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
-    {ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
-    {ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
-    {w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
-    {w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
-    {zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
-    {zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
-    {NULL, NULL, NULL, NULL, NULL}
-};
-
 /*
  * An accessor with minimum implementation, keeping the original
  * "NotImplemented" methods.
@@ -358,52 +212,6 @@ private:
     std::map<std::string, int> zones_;
 };
 
-/**
- * Single journal entry in the mock database.
- *
- * All the members there are public for simplicity, as it only stores data.
- * We use the implicit constructor and operator. The members can't be const
- * because of the assignment operator (used in the vectors).
- */
-struct JournalEntry {
-    JournalEntry(int id, uint32_t serial,
-                 DatabaseAccessor::DiffOperation operation,
-                 const std::string (&data)[DatabaseAccessor::DIFF_PARAM_COUNT])
-        : id_(id), serial_(serial), operation_(operation)
-    {
-        data_[DatabaseAccessor::DIFF_NAME] = data[DatabaseAccessor::DIFF_NAME];
-        data_[DatabaseAccessor::DIFF_TYPE] = data[DatabaseAccessor::DIFF_TYPE];
-        data_[DatabaseAccessor::DIFF_TTL] = data[DatabaseAccessor::DIFF_TTL];
-        data_[DatabaseAccessor::DIFF_RDATA] =
-            data[DatabaseAccessor::DIFF_RDATA];
-    }
-    JournalEntry(int id, uint32_t serial,
-                 DatabaseAccessor::DiffOperation operation,
-                 const std::string& name, const std::string& type,
-                 const std::string& ttl, const std::string& rdata):
-        id_(id), serial_(serial), operation_(operation)
-    {
-        data_[DatabaseAccessor::DIFF_NAME] = name;
-        data_[DatabaseAccessor::DIFF_TYPE] = type;
-        data_[DatabaseAccessor::DIFF_TTL] = ttl;
-        data_[DatabaseAccessor::DIFF_RDATA] = rdata;
-    }
-    int id_;
-    uint32_t serial_;
-    DatabaseAccessor::DiffOperation operation_;
-    std::string data_[DatabaseAccessor::DIFF_PARAM_COUNT];
-    bool operator==(const JournalEntry& other) const {
-        for (size_t i = 0; i < DatabaseAccessor::DIFF_PARAM_COUNT; ++ i) {
-            if (data_[i] != other.data_[i]) {
-                return false;
-            }
-        }
-        // No need to check data here, checked above
-        return (id_ == other.id_ && serial_ == other.serial_ &&
-                operation_ == other.operation_);
-    }
-};
-
 /*
  * A virtual database accessor that pretends it contains single zone --
  * example.org.
@@ -1132,328 +940,470 @@ public:
         }
     }
 };
+}
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+const char* const TEST_RECORDS[][5] = {
+    // some plain data
+    {"www.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"www.example.org.", "AAAA", "3600", "", "2001:db8::1"},
+    {"www.example.org.", "AAAA", "3600", "", "2001:db8::2"},
+    {"www.example.org.", "NSEC", "3600", "", "www2.example.org. A AAAA NSEC RRSIG"},
+    {"www.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    {"www2.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"www2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
+    {"www2.example.org.", "A", "3600", "", "192.0.2.2"},
+
+    {"cname.example.org.", "CNAME", "3600", "", "www.example.org."},
+
+    // some DNSSEC-'signed' data
+    {"signed1.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
+    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::1"},
+    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::2"},
+    {"signed1.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    {"signedcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
+    {"signedcname1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    // special case might fail; sig is for cname, which isn't there (should be ignored)
+    // (ignoring of 'normal' other type is done above by www.)
+    {"acnamesig1.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"acnamesig1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"acnamesig1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    // let's pretend we have a database that is not careful
+    // about the order in which it returns data
+    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::2"},
+    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
+    {"signed2.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"signed2.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
+
+    {"signedcname2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"signedcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
+
+    {"acnamesig2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"acnamesig2.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"acnamesig2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    {"acnamesig3.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"acnamesig3.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"acnamesig3.example.org.", "A", "3600", "", "192.0.2.1"},
+
+    {"ttldiff1.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"ttldiff1.example.org.", "A", "360", "", "192.0.2.2"},
+
+    {"ttldiff2.example.org.", "A", "360", "", "192.0.2.1"},
+    {"ttldiff2.example.org.", "A", "3600", "", "192.0.2.2"},
+
+    // also add some intentionally bad data
+    {"badcname1.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"badcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
+
+    {"badcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
+    {"badcname2.example.org.", "A", "3600", "", "192.0.2.1"},
+
+    {"badcname3.example.org.", "CNAME", "3600", "", "www.example.org."},
+    {"badcname3.example.org.", "CNAME", "3600", "", "www.example2.org."},
+
+    {"badrdata.example.org.", "A", "3600", "", "bad"},
+
+    {"badtype.example.org.", "BAD_TYPE", "3600", "", "192.0.2.1"},
+
+    {"badttl.example.org.", "A", "badttl", "", "192.0.2.1"},
+
+    {"badsig.example.org.", "A", "badttl", "", "192.0.2.1"},
+    {"badsig.example.org.", "RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    {"badsigtype.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"badsigtype.example.org.", "RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    // Data for testing delegation (with NS and DNAME)
+    {"delegation.example.org.", "NS", "3600", "", "ns.example.com."},
+    {"delegation.example.org.", "NS", "3600", "",
+     "ns.delegation.example.org."},
+    {"delegation.example.org.", "DS", "3600", "", "1 1 2 abcd"},
+    {"delegation.example.org.", "RRSIG", "3600", "", "NS 5 3 3600 "
+     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"delegation.example.org.", "RRSIG", "3600", "", "DS 5 3 3600 "
+     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"ns.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"deep.below.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
+
+    {"dname.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"dname.example.org.", "DNAME", "3600", "", "dname.example.com."},
+    {"dname.example.org.", "RRSIG", "3600", "",
+     "DNAME 5 3 3600 20000101000000 20000201000000 12345 "
+     "example.org. FAKEFAKEFAKE"},
+
+    {"below.dname.example.org.", "A", "3600", "", "192.0.2.1"},
+
+    // Insecure delegation (i.e., no DS at the delegation point)
+    {"insecdelegation.example.org.", "NS", "3600", "", "ns.example.com."},
+    {"insecdelegation.example.org.", "NSEC", "3600", "",
+     "dummy.example.org. NS NSEC"},
+    // and a DS under the zone cut. Such an RR shouldn't exist in a sane zone,
+    // but it could by error or some malicious attempt.  It shouldn't confuse
+    // the implementation)
+    {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
+     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    // Delegation NS and other ordinary type of RR coexist at the same
+    // name.  This is deviant (except for some special cases like the other
+    // RR could be used for addressing the NS name), but as long as the
+    // other records are hidden behind the delegation for normal queries
+    // it's not necessarily harmful. (so "broken" may be too strong, but we
+    // keep the name since it could be in a chain of sorted names for DNSSEC
+    // processing and renaming them may have other bad effects for tests).
+    {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
+
+    // Now double DNAME, to test failure mode
+    {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
+    {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
+
+    // Put some data into apex (including NS) so we can check our NS
+    // doesn't break anything
+    {"example.org.", "SOA", "3600", "", "ns1.example.org. admin.example.org. "
+     "1234 3600 1800 2419200 7200" },
+    {"example.org.", "NS", "3600", "", "ns.example.com."},
+    {"example.org.", "A", "3600", "", "192.0.2.1"},
+    // Note that the RDATA text is "normalized", i.e., identical to what
+    // Rdata::toText() would produce.  some tests rely on that behavior.
+    {"example.org.", "NSEC", "3600", "",
+     "acnamesig1.example.org. A NS RRSIG NSEC"},
+    {"example.org.", "RRSIG", "3600", "", "SOA 5 3 3600 20000101000000 "
+              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 "
+              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"example.org.", "RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
+              "20000201000000 12345 example.org. FAKEFAKEFAKE"},
+
+    // This is because of empty domain test
+    {"a.b.example.org.", "A", "3600", "", "192.0.2.1"},
+
+    // Something for wildcards
+    {"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
+    {"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
+    {"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
+    {"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
+    {"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
+    {"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
+    {"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
+    {"wild.*.foo.*.bar.example.org.", "NSEC", "3600", "",
+     "brokenns1.example.org. A NSEC"},
+    {"bao.example.org.", "NSEC", "3600", "", "wild.*.foo.*.bar.example.org. NSEC"},
+    {"*.cnamewild.example.org.", "CNAME", "3600", "", "www.example.org."},
+    {"*.dnamewild.example.org.", "DNAME", "3600", "", "dname.example.com."},
+    {"*.nswild.example.org.", "NS", "3600", "", "ns.example.com."},
+    // For NSEC empty non-terminal
+    {"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
+    {"empty.nonterminal.example.org.", "A", "3600", "", "192.0.2.1"},
+    // Invalid rdata
+    {"invalidrdata.example.org.", "A", "3600", "", "Bunch of nonsense"},
+    {"invalidrdata2.example.org.", "A", "3600", "", "192.0.2.1"},
+    {"invalidrdata2.example.org.", "RRSIG", "3600", "", "Nonsense"},
+
+    {NULL, NULL, NULL, NULL, NULL},
+};
+
+const char* TEST_NSEC3PARAM_RECORDS[][5] = {
+    {"example.org.", "NSEC3PARAM", "3600", "", "1 0 12 aabbccdd"},
+    {"example.org.", "RRSIG", "3600", "", "NSEC3PARAM 5 3 3600 20000101000000 "
+     "20000201000000 12345 example.org. FAKEFAKEFAKE"},
+    {NULL, NULL, NULL, NULL, NULL}
+};
 
-// This tests the default getRecords behaviour, throwing NotImplemented
-TEST(DatabaseConnectionTest, getRecords) {
-    EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
-                 isc::NotImplemented);
-}
+const char* TEST_NSEC3_RECORDS[][5] = {
+    {apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {NULL, NULL, NULL, NULL, NULL}
+};
 
-// This tests the default getAllRecords behaviour, throwing NotImplemented
-TEST(DatabaseConnectionTest, getAllRecords) {
-    // The parameters don't matter
-    EXPECT_THROW(NopAccessor().getAllRecords(1),
-                 isc::NotImplemented);
+DatabaseClientTest::DatabaseClientTest() :
+    zname_("example.org"), qname_("www.example.org"),
+    qclass_(dns::RRClass::IN()),
+    qtype_(dns::RRType::A()),
+    rrttl_(3600)
+{
+    // Test IN/A RDATA to be added in update tests.  Intentionally using
+    // different data than the initial data configured in the MockAccessor.
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(),
+                                        rrset_->getClass(), "192.0.2.2"));
+    soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
+                                      "ns1.example.org. admin.example.org. "
+                                      "1234 3600 1800 2419200 7200"));
+
+    // And its RRSIG.  Also different from the configured one.
+    rrsigset_.reset(new RRset(qname_, qclass_, RRType::RRSIG(),
+                              rrttl_));
+    rrsigset_->addRdata(rdata::createRdata(rrsigset_->getType(),
+                                           rrsigset_->getClass(),
+                                           "A 5 3 0 20000101000000 "
+                                           "20000201000000 0 example.org. "
+                                           "FAKEFAKEFAKE"));
 }
 
-// This test fixture is templated so that we can share (most of) the test
-// cases with different types of data sources.  Note that in test cases
-// we need to use 'this' to refer to member variables of the test class.
-template <typename ACCESSOR_TYPE>
-class DatabaseClientTest : public ::testing::Test {
-public:
-    DatabaseClientTest() : zname_("example.org"), qname_("www.example.org"),
-                           qclass_(RRClass::IN()), qtype_(RRType::A()),
-                           rrttl_(3600)
-    {
-        createClient();
-
-        // set up the commonly used finder.
-        DataSourceClient::FindResult zone(client_->findZone(zname_));
-        assert(zone.code == result::SUCCESS);
-        finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
-            zone.zone_finder);
-
-        // Test IN/A RDATA to be added in update tests.  Intentionally using
-        // different data than the initial data configured in the MockAccessor.
-        rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
-        rrset_->addRdata(rdata::createRdata(rrset_->getType(),
-                                            rrset_->getClass(), "192.0.2.2"));
-        soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
-        soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
-                                         "ns1.example.org. admin.example.org. "
-                                         "1234 3600 1800 2419200 7200"));
+void
+DatabaseClientTest::createClient(const DatabaseClientTestParam* test_param) {
+    current_accessor_ = test_param->accessor_creator();
+    is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_.get()) != NULL);
+    client_.reset(new DatabaseClient(qclass_, current_accessor_));
+
+    // set up the commonly used finder.
+    const DataSourceClient::FindResult result(client_->findZone(zname_));
+    assert(result.code == result::SUCCESS);
+    finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
+        result.zone_finder);
+}
 
-        // And its RRSIG.  Also different from the configured one.
-        rrsigset_.reset(new RRset(qname_, qclass_, RRType::RRSIG(),
-                                  rrttl_));
-        rrsigset_->addRdata(rdata::createRdata(rrsigset_->getType(),
-                                               rrsigset_->getClass(),
-                                               "A 5 3 0 20000101000000 "
-                                               "20000201000000 0 example.org. "
-                                               "FAKEFAKEFAKE"));
+void
+DatabaseClientTest::checkZoneFinder(const DataSourceClient::FindResult& zone) {
+    ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
+    boost::shared_ptr<DatabaseClient::Finder> finder(
+        boost::dynamic_pointer_cast<DatabaseClient::Finder>(
+            zone.zone_finder));
+    ASSERT_NE(boost::shared_ptr<DatabaseClient::Finder>(), finder) <<
+        "Wrong type of finder";
+    if (is_mock_) {
+        EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
     }
+    EXPECT_EQ(current_accessor_.get(), &finder->getAccessor());
+}
 
-    ~ DatabaseClientTest() {
-        // Make sure we return the default creator no matter if we set it or not
-        setNSEC3HashCreator(NULL);
+boost::shared_ptr<DatabaseClient::Finder>
+DatabaseClientTest::getFinder() {
+    DataSourceClient::FindResult zone(client_->findZone(zname_));
+    EXPECT_EQ(result::SUCCESS, zone.code);
+    boost::shared_ptr<DatabaseClient::Finder> finder(
+        boost::dynamic_pointer_cast<DatabaseClient::Finder>(
+            zone.zone_finder));
+    if (is_mock_) {
+        EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
     }
 
-    /*
-     * We initialize the client from a function, so we can call it multiple
-     * times per test.
-     */
-    void createClient() {
-        // To make sure we always have empty diffs table at the beginning of
-        // each test, we re-install the writable data source here.
-        // Note: this is SQLite3 specific and a waste (though otherwise
-        // harmless) for other types of data sources.  If and when we support
-        // more types of data sources in this test framework, we should
-        // probably move this to some specialized templated method specific
-        // to SQLite3 (or for even a longer term we should add an API to
-        // purge the diffs table).
-        const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_COMMONDIR
-            "/rwtest.sqlite3 " TEST_DATA_BUILDDIR
-            "/rwtest.sqlite3.copied";
-        if (system(install_cmd) != 0) {
-            // any exception will do, this is failure in test setup, but nice
-            // to show the command that fails, and shouldn't be caught
-            isc_throw(isc::Exception,
-                      "Error setting up; command failed: " << install_cmd);
-        }
+    return (finder);
+}
 
-        current_accessor_ = new ACCESSOR_TYPE();
-        is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_) != NULL);
-        client_.reset(new DatabaseClient(qclass_,
-                                         boost::shared_ptr<ACCESSOR_TYPE>(
-                                             current_accessor_)));
+bool
+DatabaseClientTest::isRollbacked(bool expected) const {
+    if (is_mock_) {
+        const MockAccessor& mock_accessor =
+            dynamic_cast<const MockAccessor&>(*update_accessor_);
+        return (mock_accessor.isRollbacked());
+    } else {
+        return (expected);
     }
+}
 
-    /**
-     * Check the zone finder is a valid one and references the zone ID and
-     * database available here.
-     */
-    void checkZoneFinder(const DataSourceClient::FindResult& zone) {
-        ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
-        boost::shared_ptr<DatabaseClient::Finder> finder(
-            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
-        ASSERT_NE(boost::shared_ptr<DatabaseClient::Finder>(), finder) <<
-            "Wrong type of finder";
-        if (is_mock_) {
-            EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
+void
+DatabaseClientTest::checkLastAdded(const char* const expected[]) const {
+    if (is_mock_) {
+        const MockAccessor* mock_accessor =
+            dynamic_cast<const MockAccessor*>(current_accessor_.get());
+        for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
+            EXPECT_EQ(expected[i],
+                      mock_accessor->getLatestClone()->getLastAdded()[i]);
         }
-        EXPECT_EQ(current_accessor_, &finder->getAccessor());
     }
+}
 
-    boost::shared_ptr<DatabaseClient::Finder> getFinder() {
-        DataSourceClient::FindResult zone(client_->findZone(zname_));
-        EXPECT_EQ(result::SUCCESS, zone.code);
-        boost::shared_ptr<DatabaseClient::Finder> finder(
-            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
-        if (is_mock_) {
-            EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
-        }
-
-        return (finder);
+void
+DatabaseClientTest::setUpdateAccessor() {
+    if (is_mock_) {
+        const MockAccessor* mock_accessor =
+            dynamic_cast<const MockAccessor*>(current_accessor_.get());
+        update_accessor_ = mock_accessor->getLatestClone();
     }
+}
 
-    // Helper methods for update tests
-    bool isRollbacked(bool expected = false) const {
-        if (is_mock_) {
-            const MockAccessor& mock_accessor =
-                dynamic_cast<const MockAccessor&>(*update_accessor_);
-            return (mock_accessor.isRollbacked());
-        } else {
-            return (expected);
+void
+DatabaseClientTest::checkJournal(const std::vector<JournalEntry>& expected) {
+    if (is_mock_) {
+        const MockAccessor* mock_accessor =
+            dynamic_cast<const MockAccessor*>(current_accessor_.get());
+        mock_accessor->checkJournal(expected);
+    } else {
+        // For other generic databases, retrieve the diff using the
+        // reader class and compare the resulting sequence of RRset.
+        // For simplicity we only consider the case where the expected
+        // sequence is not empty.
+        ASSERT_FALSE(expected.empty());
+        const Name zone_name(expected.front().
+                             data_[DatabaseAccessor::DIFF_NAME]);
+        ZoneJournalReaderPtr jnl_reader =
+            client_->getJournalReader(zone_name,
+                                      expected.front().serial_,
+                                      expected.back().serial_).second;
+        ASSERT_TRUE(jnl_reader);
+        ConstRRsetPtr rrset;
+        std::vector<JournalEntry>::const_iterator it = expected.begin();
+        for (rrset = jnl_reader->getNextDiff();
+             rrset && it != expected.end();
+             rrset = jnl_reader->getNextDiff(), ++it) {
+            typedef DatabaseAccessor Accessor;
+            RRsetPtr expected_rrset(
+                new RRset(Name((*it).data_[Accessor::DIFF_NAME]),
+                          qclass_,
+                          RRType((*it).data_[Accessor::DIFF_TYPE]),
+                          RRTTL((*it).data_[Accessor::DIFF_TTL])));
+            expected_rrset->addRdata(
+                rdata::createRdata(expected_rrset->getType(),
+                                   expected_rrset->getClass(),
+                                   (*it).data_[Accessor::DIFF_RDATA]));
+            rrsetCheck(expected_rrset, rrset);
         }
+        // We should have examined all entries of both expected and
+        // actual data.
+        EXPECT_TRUE(it == expected.end());
+        ASSERT_FALSE(rrset);
     }
+}
 
-    void checkLastAdded(const char* const expected[]) const {
-        if (is_mock_) {
-            const MockAccessor* mock_accessor =
-                dynamic_cast<const MockAccessor*>(current_accessor_);
-            for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
-                EXPECT_EQ(expected[i],
-                          mock_accessor->getLatestClone()->getLastAdded()[i]);
-            }
-        }
+void
+DatabaseClientTest::allowMoreTransaction(bool is_allowed) {
+    if (is_mock_) {
+        // Use a separate variable for MockAccessor&; some compilers
+        // would be confused otherwise.
+        MockAccessor& mock_accessor =
+            dynamic_cast<MockAccessor&>(*current_accessor_);
+        mock_accessor.allowMoreTransaction(is_allowed);
     }
+}
 
-    void setUpdateAccessor() {
-        if (is_mock_) {
-            const MockAccessor* mock_accessor =
-                dynamic_cast<const MockAccessor*>(current_accessor_);
-            update_accessor_ = mock_accessor->getLatestClone();
-        }
+void
+loadTestDataGeneric(DatabaseAccessor& accessor) {
+    accessor.startUpdateZone("example.org.", true);
+    string columns[DatabaseAccessor::ADD_COLUMN_COUNT];
+    for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
+        columns[DatabaseAccessor::ADD_NAME] = TEST_RECORDS[i][0];
+        columns[DatabaseAccessor::ADD_REV_NAME] =
+            Name(columns[DatabaseAccessor::ADD_NAME]).reverse().toText();
+        columns[DatabaseAccessor::ADD_TYPE] = TEST_RECORDS[i][1];
+        columns[DatabaseAccessor::ADD_TTL] = TEST_RECORDS[i][2];
+        columns[DatabaseAccessor::ADD_SIGTYPE] = TEST_RECORDS[i][3];
+        columns[DatabaseAccessor::ADD_RDATA] = TEST_RECORDS[i][4];
+
+        accessor.addRecordToZone(columns);
     }
+    // We don't add NSEC3s until we are explicitly told we need them
+    // in enableNSEC3(); these would break some non NSEC3 tests.
+    accessor.commit();
+}
 
-    void checkJournal(const vector<JournalEntry>& expected) {
-        if (is_mock_) {
-            const MockAccessor* mock_accessor =
-                dynamic_cast<const MockAccessor*>(current_accessor_);
-            mock_accessor->checkJournal(expected);
-        } else {
-            // For other generic databases, retrieve the diff using the
-            // reader class and compare the resulting sequence of RRset.
-            // For simplicity we only consider the case where the expected
-            // sequence is not empty.
-            ASSERT_FALSE(expected.empty());
-            const Name zone_name(expected.front().
-                                 data_[DatabaseAccessor::DIFF_NAME]);
-            ZoneJournalReaderPtr jnl_reader =
-                client_->getJournalReader(zone_name,
-                                          expected.front().serial_,
-                                          expected.back().serial_).second;
-            ASSERT_TRUE(jnl_reader);
-            ConstRRsetPtr rrset;
-            vector<JournalEntry>::const_iterator it = expected.begin();
-            for (rrset = jnl_reader->getNextDiff();
-                 rrset && it != expected.end();
-                 rrset = jnl_reader->getNextDiff(), ++it) {
-                typedef DatabaseAccessor Accessor;
-                RRsetPtr expected_rrset(
-                    new RRset(Name((*it).data_[Accessor::DIFF_NAME]),
-                              qclass_,
-                              RRType((*it).data_[Accessor::DIFF_TYPE]),
-                              RRTTL((*it).data_[Accessor::DIFF_TTL])));
-                expected_rrset->addRdata(
-                    rdata::createRdata(expected_rrset->getType(),
-                                       expected_rrset->getClass(),
-                                       (*it).data_[Accessor::DIFF_RDATA]));
-                rrsetCheck(expected_rrset, rrset);
-            }
-            // We should have examined all entries of both expected and
-            // actual data.
-            EXPECT_TRUE(it == expected.end());
-            ASSERT_FALSE(rrset);
-        }
+void
+enableNSEC3Generic(DatabaseAccessor& accessor) {
+    accessor.startUpdateZone("example.org.", false);
+
+    // Add NSECPARAM at the zone origin
+    for (int i = 0; TEST_NSEC3PARAM_RECORDS[i][0] != NULL; ++i) {
+        const string param_columns[DatabaseAccessor::ADD_COLUMN_COUNT] = {
+            TEST_NSEC3PARAM_RECORDS[i][0], // name
+            Name(param_columns[DatabaseAccessor::ADD_NAME]).reverse().toText(),
+            // revname
+            TEST_NSEC3PARAM_RECORDS[i][2],   // TTL
+            TEST_NSEC3PARAM_RECORDS[i][1],   // RR type
+            TEST_NSEC3PARAM_RECORDS[i][3],   // sigtype
+            TEST_NSEC3PARAM_RECORDS[i][4] }; // RDATA
+        accessor.addRecordToZone(param_columns);
     }
 
-    // Mock-only; control whether to allow subsequent transaction.
-    void allowMoreTransaction(bool is_allowed) {
-        if (is_mock_) {
-            // Use a separate variable for MockAccessor&; some compilers
-            // would be confused otherwise.
-            MockAccessor& mock_accessor =
-                dynamic_cast<MockAccessor&>(*current_accessor_);
-            mock_accessor.allowMoreTransaction(is_allowed);
-        }
+    // Add NSEC3s
+    for (int i = 0; TEST_NSEC3_RECORDS[i][0] != NULL; ++i) {
+        const string nsec3_columns[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT] =
+            {
+                TEST_NSEC3_RECORDS[i][0], // Hash
+                TEST_NSEC3_RECORDS[i][2], // TTL
+                TEST_NSEC3_RECORDS[i][1], // RR type
+                TEST_NSEC3_RECORDS[i][4]  // RDATA
+            };
+        accessor.addNSEC3RecordToZone(nsec3_columns);
     }
 
-    // Some tests only work for MockAccessor.  We remember whether our accessor
-    // is of that type.
-    bool is_mock_;
-
-    // Will be deleted by client_, just keep the current value for comparison.
-    ACCESSOR_TYPE* current_accessor_;
-    boost::shared_ptr<DatabaseClient> client_;
-    const std::string database_name_;
+    accessor.commit();
+}
 
-    // The zone finder of the test zone commonly used in various tests.
-    boost::shared_ptr<DatabaseClient::Finder> finder_;
-
-    // Some shortcut variables for commonly used test parameters
-    const Name zname_; // the zone name stored in the test data source
-    const Name qname_; // commonly used name to be found
-    const RRClass qclass_;      // commonly used RR class used with qname
-    const RRType qtype_;        // commonly used RR type used with qname
-    const RRTTL rrttl_;         // commonly used RR TTL
-    RRsetPtr rrset_;            // for adding/deleting an RRset
-    RRsetPtr rrsigset_;         // for adding/deleting an RRset
-    RRsetPtr soa_;              // for adding/deleting an RRset
-
-    // update related objects to be tested
-    ZoneUpdaterPtr updater_;
-    boost::shared_ptr<const DatabaseAccessor> update_accessor_;
-
-    // placeholders
-    const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
-    std::vector<std::string> expected_rdatas_;
-    std::vector<std::string> expected_sig_rdatas_;
-
-    // A creator for use in several NSEC3 related tests.
-    TestNSEC3HashCreator test_nsec3_hash_creator_;
-};
+} // namespace test
+} // namespace datasrc
+} // namespace isc
 
-class TestSQLite3Accessor : public SQLite3Accessor {
-public:
-    TestSQLite3Accessor() : SQLite3Accessor(
-        TEST_DATA_BUILDDIR "/rwtest.sqlite3.copied", "IN")
-    {
-        startUpdateZone("example.org.", true);
-        string columns[ADD_COLUMN_COUNT];
-        for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
-            columns[ADD_NAME] = TEST_RECORDS[i][0];
-            columns[ADD_REV_NAME] = Name(columns[ADD_NAME]).reverse().toText();
-            columns[ADD_TYPE] = TEST_RECORDS[i][1];
-            columns[ADD_TTL] = TEST_RECORDS[i][2];
-            columns[ADD_SIGTYPE] = TEST_RECORDS[i][3];
-            columns[ADD_RDATA] = TEST_RECORDS[i][4];
-
-            addRecordToZone(columns);
-        }
-        // We don't add NSEC3s until we are explicitly told we need them
-        // in enableNSEC3(); these would break some non NSEC3 tests.
-        commit();
-    }
+namespace {
+// This tests the default getRecords behaviour, throwing NotImplemented
+TEST(DatabaseConnectionTest, getRecords) {
+    EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
+                 isc::NotImplemented);
+}
 
-    void enableNSEC3() {
-        startUpdateZone("example.org.", false);
+// This tests the default getAllRecords behaviour, throwing NotImplemented
+TEST(DatabaseConnectionTest, getAllRecords) {
+    // The parameters don't matter
+    EXPECT_THROW(NopAccessor().getAllRecords(1),
+                 isc::NotImplemented);
+}
 
-        // Add NSECPARAM at the zone origin
-        for (int i = 0; TEST_NSEC3PARAM_RECORDS[i][0] != NULL; ++i) {
-            const string param_columns[ADD_COLUMN_COUNT] = {
-                TEST_NSEC3PARAM_RECORDS[i][0], // name
-                Name(param_columns[ADD_NAME]).reverse().toText(), // revname
-                TEST_NSEC3PARAM_RECORDS[i][2],   // TTL
-                TEST_NSEC3PARAM_RECORDS[i][1],   // RR type
-                TEST_NSEC3PARAM_RECORDS[i][3],   // sigtype
-                TEST_NSEC3PARAM_RECORDS[i][4] }; // RDATA
-            addRecordToZone(param_columns);
-        }
+// The following two lines instantiate test cases with concrete accessor
+// classes to be tested.
 
-        // Add NSEC3s
-        for (int i = 0; TEST_NSEC3_RECORDS[i][0] != NULL; ++i) {
-            const string nsec3_columns[ADD_NSEC3_COLUMN_COUNT] = {
-                Name(TEST_NSEC3_RECORDS[i][0]).split(0, 1).toText(true),
-                TEST_NSEC3_RECORDS[i][2], // TTL
-                TEST_NSEC3_RECORDS[i][1], // RR type
-                TEST_NSEC3_RECORDS[i][4] }; // RDATA
-            addNSEC3RecordToZone(nsec3_columns);
-        }
+boost::shared_ptr<DatabaseAccessor>
+createMockAccessor() {
+    return (boost::shared_ptr<DatabaseAccessor>(new MockAccessor()));
+}
 
-        commit();
-    }
-};
+void
+mockEnableNSEC3(DatabaseAccessor& accessor) {
+    dynamic_cast<MockAccessor&>(accessor).enableNSEC3();
+}
 
-// The following two lines instantiate test cases with concrete accessor
-// classes to be tested.
-// XXX: clang++ installed on our FreeBSD buildbot cannot complete compiling
-// this file, seemingly due to the size of the code.  We'll consider more
-// complete workaround, but for a short term workaround we'll reduce the
-// number of tested accessor classes (thus reducing the amount of code
-// to be compiled) for this particular environment.
-#if defined(__clang__) && defined(__FreeBSD__)
-typedef ::testing::Types<MockAccessor> TestAccessorTypes;
-#else
-typedef ::testing::Types<MockAccessor, TestSQLite3Accessor> TestAccessorTypes;
-#endif
+const DatabaseClientTestParam mock_param = { createMockAccessor,
+                                             mockEnableNSEC3 };
 
-TYPED_TEST_CASE(DatabaseClientTest, TestAccessorTypes);
+INSTANTIATE_TEST_CASE_P(, DatabaseClientTest, ::testing::Values(&mock_param));
 
-// In some cases the entire test fixture is for the mock accessor only.
-// We use the usual TEST_F for them with the corresponding specialized class
-// to make the code simpler.
-typedef DatabaseClientTest<MockAccessor> MockDatabaseClientTest;
+// This inherit the DatabaseClientTest cases except for the parameterized
+// setup; it's intended to be used selected test cases that only work for mock
+// data sources.
+class MockDatabaseClientTest : public DatabaseClientTest {
+protected:
+    // Override SetUp() to avoid parameterized setup
+    virtual void SetUp() {
+        createClient(&mock_param);
+    }
+};
 
-TYPED_TEST(DatabaseClientTest, zoneNotFound) {
-    DataSourceClient::FindResult zone(
-        this->client_->findZone(Name("example.com")));
-    EXPECT_EQ(result::NOTFOUND, zone.code);
+TEST_P(DatabaseClientTest, zoneNotFound) {
+    EXPECT_EQ(result::NOTFOUND, client_->findZone(Name("example.com")).code);
 }
 
-TYPED_TEST(DatabaseClientTest, exactZone) {
-    DataSourceClient::FindResult zone(
-        this->client_->findZone(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, zone.code);
-    this->checkZoneFinder(zone);
+TEST_P(DatabaseClientTest, exactZone) {
+    const DataSourceClient::FindResult result =
+        client_->findZone(Name("example.org"));
+    EXPECT_EQ(result::SUCCESS, result.code);
+    checkZoneFinder(result);
 }
 
-TYPED_TEST(DatabaseClientTest, superZone) {
-    DataSourceClient::FindResult zone(this->client_->findZone(Name(
-        "sub.example.org")));
-    EXPECT_EQ(result::PARTIALMATCH, zone.code);
-    this->checkZoneFinder(zone);
+TEST_P(DatabaseClientTest, superZone) {
+    const DataSourceClient::FindResult result =
+        client_->findZone(Name("sub.example.org"));
+    EXPECT_EQ(result::PARTIALMATCH, result.code);
+    checkZoneFinder(result);
 }
 
 // This test doesn't depend on derived accessor class, so we use TEST().
@@ -1466,9 +1416,8 @@ TEST(GenericDatabaseClientTest, noAccessorException) {
 }
 
 // If the zone doesn't exist, exception is thrown
-TYPED_TEST(DatabaseClientTest, noZoneIterator) {
-    EXPECT_THROW(this->client_->getIterator(Name("example.com")),
-                 DataSourceError);
+TEST_P(DatabaseClientTest, noZoneIterator) {
+    EXPECT_THROW(client_->getIterator(Name("example.com")), DataSourceError);
 }
 
 // If the zone doesn't exist and iteration is not implemented, it still throws
@@ -1491,14 +1440,14 @@ TEST(GenericDatabaseClientTest, notImplementedIterator) {
 // Pretend a bug in the connection and pass NULL as the context
 // Should not crash, but gracefully throw.  Works for the mock accessor only.
 TEST_F(MockDatabaseClientTest, nullIteratorContext) {
-    EXPECT_THROW(this->client_->getIterator(Name("null.example.org")),
+    EXPECT_THROW(client_->getIterator(Name("null.example.org")),
                  isc::Unexpected);
 }
 
 // It doesn't crash or anything if the zone is completely empty.
 // Works for the mock accessor only.
 TEST_F(MockDatabaseClientTest, emptyIterator) {
-    ZoneIteratorPtr it(this->client_->getIterator(Name("empty.example.org")));
+    ZoneIteratorPtr it(client_->getIterator(Name("empty.example.org")));
     EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
     // This is past the end, it should throw
     EXPECT_THROW(it->getNextRRset(), isc::Unexpected);
@@ -1524,13 +1473,13 @@ checkRRset(isc::dns::ConstRRsetPtr rrset,
 }
 
 // Iterate through a zone, common case
-TYPED_TEST(DatabaseClientTest, iterator) {
-    ZoneIteratorPtr it(this->client_->getIterator(Name("example.org")));
+TEST_P(DatabaseClientTest, iterator) {
+    ZoneIteratorPtr it(client_->getIterator(Name("example.org")));
     ConstRRsetPtr rrset(it->getNextRRset());
     ASSERT_NE(ConstRRsetPtr(), rrset);
 
     // The first name should be the zone origin.
-    EXPECT_EQ(this->zname_, rrset->getName());
+    EXPECT_EQ(zname_, rrset->getName());
 }
 
 // Supplemental structure used in the couple of tests below.  It represents
@@ -1631,19 +1580,18 @@ TEST_F(MockDatabaseClientTest, iteratorSeparateRRs) {
 // the data is handled in rdata itself).  Works for the mock accessor only.
 TEST_F(MockDatabaseClientTest, badIterator) {
     // It should not throw, but get the lowest one of them
-    ZoneIteratorPtr it(this->client_->getIterator(Name("bad.example.org")));
+    ZoneIteratorPtr it(client_->getIterator(Name("bad.example.org")));
     EXPECT_EQ(it->getNextRRset()->getTTL(), isc::dns::RRTTL(300));
 }
 
-TYPED_TEST(DatabaseClientTest, getSOAFromIterator) {
+TEST_P(DatabaseClientTest, getSOAFromIterator) {
     vector<string> soa_data;
     soa_data.push_back("ns1.example.org. admin.example.org. "
                        "1234 3600 1800 2419200 7200");
 
-    ZoneIteratorPtr it(this->client_->getIterator(this->zname_));
+    ZoneIteratorPtr it(client_->getIterator(zname_));
     ASSERT_TRUE(it);
-    checkRRset(it->getSOA(), this->zname_, this->qclass_, RRType::SOA(),
-               this->rrttl_, soa_data);
+    checkRRset(it->getSOA(), zname_, qclass_, RRType::SOA(), rrttl_, soa_data);
 
     // Iterate over the zone until we find an SOA.  Although there's a broken
     // RDATA that would trigger an exception in getNextRRset(), we should
@@ -1659,19 +1607,19 @@ TYPED_TEST(DatabaseClientTest, getSOAFromIterator) {
     rrsetCheck(it->getSOA(), rrset);
 }
 
-TYPED_TEST(DatabaseClientTest, noSOAFromIterator) {
+TEST_P(DatabaseClientTest, noSOAFromIterator) {
     // First, empty the zone.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->commit();
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->commit();
 
     // Then getSOA() should return NULL.
-    ZoneIteratorPtr it(this->client_->getIterator(this->zname_));
+    ZoneIteratorPtr it(client_->getIterator(zname_));
     ASSERT_TRUE(it);
     EXPECT_FALSE(it->getSOA());
 }
 
-TYPED_TEST(DatabaseClientTest, iterateThenUpdate) {
-    ZoneIteratorPtr it(this->client_->getIterator(this->zname_));
+TEST_P(DatabaseClientTest, iterateThenUpdate) {
+    ZoneIteratorPtr it(client_->getIterator(zname_));
     ASSERT_TRUE(it);
 
     // Try to empty the zone after getting the iterator.  Depending on the
@@ -1679,12 +1627,12 @@ TYPED_TEST(DatabaseClientTest, iterateThenUpdate) {
     // transaction for the iterator.  In either case the integrity of the
     // iterator result should be reserved.
     try {
-        this->updater_ = this->client_->getUpdater(this->zname_, true);
-        this->updater_->commit();
+        updater_ = client_->getUpdater(zname_, true);
+        updater_->commit();
 
         // Confirm at least it doesn't contain any SOA
         EXPECT_EQ(ZoneFinder::NXDOMAIN,
-                  this->getFinder()->find(this->zname_, RRType::SOA())->code);
+                  getFinder()->find(zname_, RRType::SOA())->code);
     } catch (const DataSourceError&) {}
 
     ConstRRsetPtr rrset;
@@ -1697,89 +1645,137 @@ TYPED_TEST(DatabaseClientTest, iterateThenUpdate) {
     rrsetCheck(it->getSOA(), rrset);
 }
 
-TYPED_TEST(DatabaseClientTest, updateThenIterateThenUpdate) {
+TEST_P(DatabaseClientTest, updateThenIterateThenUpdate) {
     // First clear the zone.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->commit();
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->commit();
 
     // Then iterate over it.  It should immediately reach the end, at which
     // point the transaction should be committed.
-    ZoneIteratorPtr it(this->client_->getIterator(this->zname_));
+    ZoneIteratorPtr it(client_->getIterator(zname_));
     ASSERT_TRUE(it);
     EXPECT_FALSE(it->getNextRRset());
 
     // So another update attempt should succeed, too.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->commit();
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->commit();
 }
 
-TYPED_TEST(DatabaseClientTest, updateAfterDeleteIterator) {
+TEST_P(DatabaseClientTest, updateAfterDeleteIterator) {
     // Similar to the previous case, but we delete the iterator in the
     // middle of zone.  The transaction should be canceled (actually no
     // different from commit though) at that point.
-    ZoneIteratorPtr it(this->client_->getIterator(this->zname_));
+    ZoneIteratorPtr it(client_->getIterator(zname_));
     ASSERT_TRUE(it);
     EXPECT_TRUE(it->getNextRRset());
     it.reset();
 
     // So another update attempt should succeed.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->commit();
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->commit();
 }
 
 void
-doFindTest(ZoneFinder& finder,
-           const isc::dns::Name& name,
-           const isc::dns::RRType& type,
-           const isc::dns::RRType& expected_type,
-           const isc::dns::RRTTL expected_ttl,
-           ZoneFinder::Result expected_result,
-           const std::vector<std::string>& expected_rdatas,
-           const std::vector<std::string>& expected_sig_rdatas,
-           ZoneFinder::FindResultFlags expected_flags =
-           ZoneFinder::RESULT_DEFAULT,
-           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
-           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
+findTestCommon(ZoneFinder& finder, const isc::dns::Name& name,
+               const isc::dns::RRType& type,
+               ConstZoneFinderContextPtr actual_result,
+               const isc::dns::RRType& expected_type,
+               const isc::dns::RRTTL expected_ttl,
+               ZoneFinder::Result expected_result,
+               const std::vector<string>& expected_rdatas,
+               const std::vector<string>& expected_sig_rdatas,
+               ZoneFinder::FindResultFlags expected_flags,
+               const isc::dns::Name& expected_name,
+               const ZoneFinder::FindOptions options)
 {
-    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
-    ConstZoneFinderContextPtr result = finder.find(name, type, options);
-    ASSERT_EQ(expected_result, result->code) << name << " " << type;
+    ASSERT_EQ(expected_result, actual_result->code) << name << " " << type;
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-              result->isWildcard());
+              actual_result->isWildcard());
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
-              result->isNSECSigned());
+              actual_result->isNSECSigned());
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
-              result->isNSEC3Signed());
-    if (!expected_rdatas.empty() && result->rrset) {
-        checkRRset(result->rrset, expected_name != Name(".") ? expected_name :
+              actual_result->isNSEC3Signed());
+    if (!expected_rdatas.empty() && actual_result->rrset) {
+        checkRRset(actual_result->rrset,
+                   expected_name != Name::ROOT_NAME() ? expected_name :
                    name, finder.getClass(), expected_type, expected_ttl,
                    expected_rdatas);
         if ((options & ZoneFinder::FIND_DNSSEC) == ZoneFinder::FIND_DNSSEC) {
-            if (!expected_sig_rdatas.empty() && result->rrset->getRRsig()) {
-                checkRRset(result->rrset->getRRsig(),
-                           expected_name != Name(".") ? expected_name : name,
-                           finder.getClass(),
+            if (!expected_sig_rdatas.empty() &&
+                actual_result->rrset->getRRsig()) {
+                checkRRset(actual_result->rrset->getRRsig(),
+                           expected_name != Name::ROOT_NAME() ?
+                           expected_name : name, finder.getClass(),
                            isc::dns::RRType::RRSIG(), expected_ttl,
                            expected_sig_rdatas);
             } else if (expected_sig_rdatas.empty()) {
-                EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
-                    "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
+                EXPECT_EQ(isc::dns::RRsetPtr(),
+                          actual_result->rrset->getRRsig()) <<
+                    "Unexpected RRSIG: " <<
+                    actual_result->rrset->getRRsig()->toText();
             } else {
                 ADD_FAILURE() << "Missing RRSIG";
             }
-        } else if (result->rrset->getRRsig()) {
-            EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
-                "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
+        } else if (actual_result->rrset->getRRsig()) {
+            EXPECT_EQ(isc::dns::RRsetPtr(), actual_result->rrset->getRRsig())
+                << "Unexpected RRSIG: "
+                << actual_result->rrset->getRRsig()->toText();
         }
     } else if (expected_rdatas.empty()) {
-        EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset) <<
-            "Unexpected RRset: " << result->rrset->toText();
+        EXPECT_EQ(isc::dns::RRsetPtr(), actual_result->rrset) <<
+            "Unexpected RRset: " << actual_result->rrset->toText();
     } else {
         ADD_FAILURE() << "Missing result";
     }
 }
 
 void
+doFindTest(ZoneFinder& finder,
+           const isc::dns::Name& name,
+           const isc::dns::RRType& type,
+           const isc::dns::RRType& expected_type,
+           const isc::dns::RRTTL expected_ttl,
+           ZoneFinder::Result expected_result,
+           const std::vector<std::string>& expected_rdatas,
+           const std::vector<std::string>& expected_sig_rdatas,
+           ZoneFinder::FindResultFlags expected_flags =
+           ZoneFinder::RESULT_DEFAULT,
+           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
+           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
+{
+    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
+    ConstZoneFinderContextPtr result = finder.find(name, type, options);
+    findTestCommon(finder, name, type, result, expected_type, expected_ttl,
+                   expected_result, expected_rdatas, expected_sig_rdatas,
+                   expected_flags, expected_name, options);
+}
+
+void
+doFindAtOriginTest(ZoneFinder& finder,
+                   const isc::dns::Name& origin,
+                   const isc::dns::RRType& type,
+                   const isc::dns::RRType& expected_type,
+                   const isc::dns::RRTTL expected_ttl,
+                   ZoneFinder::Result expected_result,
+                   const std::vector<std::string>& expected_rdatas,
+                   const std::vector<std::string>& expected_sig_rdatas,
+                   bool use_minttl = false,
+                   ZoneFinder::FindResultFlags expected_flags =
+                   ZoneFinder::RESULT_DEFAULT,
+                   const isc::dns::Name& expected_name =
+                   isc::dns::Name::ROOT_NAME(),
+                   const ZoneFinder::FindOptions options =
+                   ZoneFinder::FIND_DEFAULT)
+{
+    SCOPED_TRACE("doFindOriginTest " + origin.toText() + " " + type.toText());
+    ConstZoneFinderContextPtr result =
+        finder.findAtOrigin(type, use_minttl, options);
+    findTestCommon(finder, origin, type, result, expected_type, expected_ttl,
+                   expected_result, expected_rdatas, expected_sig_rdatas,
+                   expected_flags, expected_name, options);
+}
+
+void
 doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
                     ZoneFinder::Result expected_result,
                     const isc::dns::RRType expected_type,
@@ -1826,14 +1822,14 @@ doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
 // When asking for an RRset where RRs somehow have different TTLs, it should
 // convert to the lowest one.
 TEST_F(MockDatabaseClientTest, ttldiff) {
-    ZoneIteratorPtr it(this->client_->getIterator(Name("example.org")));
+    ZoneIteratorPtr it(client_->getIterator(Name("example.org")));
     // Walk through the full iterator, we should see 1 rrset with name
     // ttldiff1.example.org., and two rdatas. Same for ttldiff2
-    Name name("ttldiff.example.org.");
+    const Name name("ttldiff.example.org.");
     bool found = false;
     //bool found2 = false;
     ConstRRsetPtr rrset = it->getNextRRset();
-    while(rrset != ConstRRsetPtr()) {
+    while (rrset != ConstRRsetPtr()) {
         if (rrset->getName() == name) {
             ASSERT_FALSE(found);
             ASSERT_EQ(2, rrset->getRdataCount());
@@ -1848,15 +1844,15 @@ TEST_F(MockDatabaseClientTest, ttldiff) {
 // Unless we ask for individual RRs in our iterator request. In that case
 // every RR should go into its own 'rrset'
 TEST_F(MockDatabaseClientTest, ttldiff_separate_rrs) {
-    ZoneIteratorPtr it(this->client_->getIterator(Name("example.org"), true));
+    ZoneIteratorPtr it(client_->getIterator(Name("example.org"), true));
 
     // Walk through the full iterator, we should see 1 rrset with name
     // ttldiff1.example.org., and two rdatas. Same for ttldiff2
-    Name name("ttldiff.example.org.");
+    const Name name("ttldiff.example.org.");
     int found1 = false;
     int found2 = false;
     ConstRRsetPtr rrset = it->getNextRRset();
-    while(rrset != ConstRRsetPtr()) {
+    while (rrset != ConstRRsetPtr()) {
         if (rrset->getName() == name) {
             ASSERT_EQ(1, rrset->getRdataCount());
             // We should find 1 'rrset' with TTL 300 and one with TTL 600
@@ -1877,613 +1873,741 @@ TEST_F(MockDatabaseClientTest, ttldiff_separate_rrs) {
     ASSERT_TRUE(found2);
 }
 
-TYPED_TEST(DatabaseClientTest, find) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, find) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
     doFindTest(*finder, isc::dns::Name("www.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(*finder, isc::dns::Name("www2.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::1");
-    this->expected_rdatas_.push_back("2001:db8::2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_rdatas_.push_back("2001:db8::2");
     doFindTest(*finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_,
-               ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
-               this->rrttl_,
-               ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::NXRRSET,
+               expected_rdatas_, expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
     doFindTest(*finder, isc::dns::Name("cname.example.org."),
-               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
-               ZoneFinder::CNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               qtype_, isc::dns::RRType::CNAME(), rrttl_,
+               ZoneFinder::CNAME, expected_rdatas_,
+               expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
     doFindTest(*finder, isc::dns::Name("cname.example.org."),
                isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("doesnotexist.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+               qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN,
+               expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12346 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signed1.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::1");
-    this->expected_rdatas_.push_back("2001:db8::2");
-    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_rdatas_.push_back("2001:db8::2");
+    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signed1.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("signed1.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
-               ZoneFinder::NXRRSET, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
-    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
+    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signedcname1.example.org."),
-               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
-               ZoneFinder::CNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+               qtype_, isc::dns::RRType::CNAME(), rrttl_,
+               ZoneFinder::CNAME, expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12346 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signed2.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::2");
-    this->expected_rdatas_.push_back("2001:db8::1");
-    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::2");
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signed2.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("signed2.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
-               ZoneFinder::NXRRSET, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
-    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
+    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("signedcname2.example.org."),
-               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
-               ZoneFinder::CNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               qtype_, isc::dns::RRType::CNAME(), rrttl_,
+               ZoneFinder::CNAME, expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("acnamesig1.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("acnamesig2.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("acnamesig3.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(*finder, isc::dns::Name("ttldiff1.example.org."),
-               this->qtype_, this->qtype_, isc::dns::RRTTL(360),
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+               qtype_, qtype_, isc::dns::RRTTL(360),
+               ZoneFinder::SUCCESS, expected_rdatas_, expected_sig_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(*finder, isc::dns::Name("ttldiff2.example.org."),
-               this->qtype_, this->qtype_, isc::dns::RRTTL(360),
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               qtype_, qtype_, isc::dns::RRTTL(360),
+               ZoneFinder::SUCCESS, expected_rdatas_, expected_sig_rdatas_);
 
     EXPECT_THROW(finder->find(isc::dns::Name("badcname1.example.org."),
-                                              this->qtype_,
+                                              qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badcname2.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badcname2.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badcname3.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badcname3.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badrdata.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badrdata.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badtype.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badtype.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badttl.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badttl.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("badsig.example.org."),
-                                              this->qtype_,
+    EXPECT_THROW(finder->find(isc::dns::Name("badsig.example.org."), qtype_,
                                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
 
     // Trigger the hardcoded exceptions and see if find() has cleaned up
-    if (this->is_mock_) {
-        EXPECT_THROW(finder->find(Name("dsexception.example.org."),
-                                  this->qtype_,
+    if (is_mock_) {
+        EXPECT_THROW(finder->find(Name("dsexception.example.org."), qtype_,
                                   ZoneFinder::FIND_DEFAULT),
                      DataSourceError);
-        EXPECT_THROW(finder->find(Name("iscexception.example.org."),
-                                  this->qtype_,
+        EXPECT_THROW(finder->find(Name("iscexception.example.org."), qtype_,
                                   ZoneFinder::FIND_DEFAULT),
                      isc::Exception);
-        EXPECT_THROW(finder->find(Name("basicexception.example.org."),
-                                  this->qtype_,
+        EXPECT_THROW(finder->find(Name("basicexception.example.org."), qtype_,
                                   ZoneFinder::FIND_DEFAULT),
                      std::exception);
         EXPECT_THROW(finder->find(Name("dsexception.getnext.example.org"),
-                                  this->qtype_,
-                                  ZoneFinder::FIND_DEFAULT),
+                                  qtype_, ZoneFinder::FIND_DEFAULT),
                      DataSourceError);
         EXPECT_THROW(finder->find(Name("iscexception.getnext.example.org."),
-                                  this->qtype_,
-                                  ZoneFinder::FIND_DEFAULT),
+                                  qtype_, ZoneFinder::FIND_DEFAULT),
                      isc::Exception);
         EXPECT_THROW(finder->find(Name("basicexception.getnext.example.org."),
-                                  this->qtype_,
-                                  ZoneFinder::FIND_DEFAULT),
+                                  qtype_, ZoneFinder::FIND_DEFAULT),
                      std::exception);
     }
 
     // This RRSIG has the wrong sigtype field, which should be
     // an error if we decide to keep using that field
     // Right now the field is ignored, so it does not error
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("badsigtype.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+}
+
+TEST_P(DatabaseClientTest, findAtOrigin) {
+    ZoneFinderPtr finder(getFinder());
+
+    // Specified type of RR exists, no DNSSEC
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    doFindAtOriginTest(*finder, zname_, RRType::NS(), RRType::NS(),
+                       rrttl_, ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_);
+
+    // Specified type of RR exists, with DNSSEC
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, zname_, RRType::NS(), RRType::NS(),
+                       rrttl_, ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_DEFAULT, zname_,
+                       ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, no DNSSEC
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    doFindAtOriginTest(*finder, zname_, RRType::TXT(), qtype_,
+                       rrttl_, ZoneFinder::NXRRSET,
+                       expected_rdatas_, expected_sig_rdatas_);
+
+    // Specified type of RR doesn't exist, with DNSSEC
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("acnamesig1.example.org. A NS RRSIG NSEC");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, zname_, RRType::TXT(), RRType::NSEC(),
+                       rrttl_, ZoneFinder::NXRRSET,
+                       expected_rdatas_, expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_NSEC_SIGNED,
+                       zname_, ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, with DNSSEC, enabling NSEC3
+    (GetParam()->enable_nsec3_fn)(*current_accessor_);
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    doFindAtOriginTest(*finder, zname_, RRType::TXT(), RRType::TXT(),
+                       rrttl_, ZoneFinder::NXRRSET,
+                       expected_rdatas_, expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_NSEC3_SIGNED,
+                       zname_, ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, findOutOfZone) {
+TEST_P(DatabaseClientTest, findAtOriginWithMinTTL) {
+    // First, replace the SOA of the test zone so that its RR TTL is larger
+    // than MINTTL (the original data are used in many places, so replacing
+    // them just for this doesn't make sense).
+    RRsetPtr old_soa(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+
+    const string new_soa_rdata = "ns1.example.org. admin.example.org. "
+        "1234 3600 1800 2419200 1200";
+    RRsetPtr new_soa(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    new_soa->addRdata(rdata::createRdata(RRType::SOA(), qclass_,
+                                         new_soa_rdata));
+
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*old_soa);
+    updater_->addRRset(*new_soa);
+    updater_->commit();
+
+    ZoneFinderPtr finder = getFinder();
+
+    // Specify the use of min TTL, then the resulting TTL should be derived
+    // from the SOA MINTTL (which is smaller).
+    expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_, true);
+
+    // If DNSSEC is requested, TTL of the RRSIG should also be the min.
+    expected_sig_rdatas_.push_back(
+        "SOA 5 3 3600 20000101000000 "
+        "20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_DEFAULT, zname_,
+                       ZoneFinder::FIND_DNSSEC);
+
+    // Not really intended usage, but specify the use of min TTL for non SOA.
+    // It should still work as specified.
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    doFindAtOriginTest(*finder, zname_, RRType::NS(), RRType::NS(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_, true);
+
+    // If we don't request the use of min TTL, the original TTL will be used.
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, zname_, RRType::SOA(), RRType::SOA(),
+                       rrttl_, ZoneFinder::SUCCESS,
+                       expected_rdatas_, expected_sig_rdatas_);
+
+    // If no RRset is returned, use_minttl doesn't matter (it shouldn't cause
+    // disruption)
+    expected_rdatas_.clear();
+    doFindAtOriginTest(*finder, zname_, RRType::TXT(), qtype_,
+                       rrttl_, ZoneFinder::NXRRSET,
+                       expected_rdatas_, expected_sig_rdatas_, true);
+
+    // If it results in NXRRSET with NSEC, and if we specify the use of min
+    // TTL, the NSEC and RRSIG should have the min TTL (again, though, this
+    // use case is not really the intended one)
+    expected_rdatas_.push_back("acnamesig1.example.org. A NS RRSIG NSEC");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, zname_, RRType::TXT(), RRType::NSEC(),
+                       RRTTL(1200), ZoneFinder::NXRRSET,
+                       expected_rdatas_, expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_NSEC_SIGNED,
+                       zname_, ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_P(DatabaseClientTest, findAtOriginWithMinTTLBroken) {
+    // Similar to the previous case, but we intentionally remove the SOA
+    // (assuming the underlying data source doesn't complain about it).
+    // This will cause exception in subsequent findAtOrigin() with use_minttl
+    // being true.
+    RRsetPtr old_soa(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*old_soa);
+    updater_->commit();
+
+    EXPECT_THROW(getFinder()->findAtOrigin(RRType::NS(), true,
+                                           ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+}
+
+TEST_P(DatabaseClientTest, findOutOfZone) {
     // If the query name is out-of-zone it should result in an exception
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
     vector<ConstRRsetPtr> target;
 
     // Superdomain
-    EXPECT_THROW(finder->find(Name("org"), this->qtype_), OutOfZone);
+    EXPECT_THROW(finder->find(Name("org"), qtype_), OutOfZone);
     EXPECT_THROW(finder->findAll(Name("org"), target), OutOfZone);
 
     // sharing a common ancestor
-    EXPECT_THROW(finder->find(Name("noexample.org"), this->qtype_), OutOfZone);
+    EXPECT_THROW(finder->find(Name("noexample.org"), qtype_), OutOfZone);
     EXPECT_THROW(finder->findAll(Name("noexample.org"), target), OutOfZone);
 
     // totally unrelated domain, smaller number of labels
-    EXPECT_THROW(finder->find(Name("com"), this->qtype_), OutOfZone);
+    EXPECT_THROW(finder->find(Name("com"), qtype_), OutOfZone);
     EXPECT_THROW(finder->findAll(Name("com"), target), OutOfZone);
 
     // totally unrelated domain, same number of labels
-    EXPECT_THROW(finder->find(Name("example.com"), this->qtype_), OutOfZone);
+    EXPECT_THROW(finder->find(Name("example.com"), qtype_), OutOfZone);
     EXPECT_THROW(finder->findAll(Name("example.com"), target), OutOfZone);
 
     // totally unrelated domain, larger number of labels
-    EXPECT_THROW(finder->find(Name("more.example.com"), this->qtype_),
-                 OutOfZone);
+    EXPECT_THROW(finder->find(Name("more.example.com"), qtype_), OutOfZone);
     EXPECT_THROW(finder->findAll(Name("more.example.com"), target), OutOfZone);
 }
 
-TYPED_TEST(DatabaseClientTest, findDelegation) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, findDelegation) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // The apex should not be considered delegation point and we can access
     // data
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
     doFindTest(*finder, isc::dns::Name("example.org."),
-               this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               qtype_, qtype_,
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com.");
-    this->expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("example.org."),
                isc::dns::RRType::NS(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
     // Check when we ask for something below delegation point, we get the NS
     // (Both when the RRset there exists and doesn't)
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com.");
-    this->expected_rdatas_.push_back("ns.delegation.example.org.");
-    this->expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.push_back("ns.delegation.example.org.");
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("ns.delegation.example.org."),
-               this->qtype_, isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, isc::dns::RRType::NS(),
+               rrttl_, ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegation.example.org."));
     doFindTest(*finder, isc::dns::Name("ns.delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegation.example.org."));
     doFindTest(*finder, isc::dns::Name("deep.below.delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegation.example.org."));
 
     // Even when we check directly at the delegation point, we should get
     // the NS
     doFindTest(*finder, isc::dns::Name("delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_);
 
     // And when we ask directly for the NS, we should still get delegation
     doFindTest(*finder, isc::dns::Name("delegation.example.org."),
                isc::dns::RRType::NS(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_);
 
     // Now test delegation. If it is below the delegation point, we should get
     // the DNAME (the one with data under DNAME is invalid zone, but we test
     // the behaviour anyway just to make sure)
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("dname.example.com.");
-    this->expected_sig_rdatas_.clear();
-    this->expected_sig_rdatas_.push_back("DNAME 5 3 3600 20000101000000 "
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("dname.example.com.");
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back("DNAME 5 3 3600 20000101000000 "
                                   "20000201000000 12345 example.org. "
                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
-               this->qtype_, isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, isc::dns::RRType::DNAME(),
+               rrttl_, ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."));
     doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."));
     // below.dname.example.org. has an A record
     doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."));
     doFindTest(*finder, isc::dns::Name("really.deep.below.dname.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."));
 
     // Asking directly for DNAME should give SUCCESS
     doFindTest(*finder, isc::dns::Name("dname.example.org."),
                isc::dns::RRType::DNAME(), isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
 
     // But we don't delegate at DNAME point
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("dname.example.org."),
-               this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
-    this->expected_rdatas_.clear();
+               qtype_, qtype_,
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
+    expected_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("dname.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXRRSET, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               rrttl_, ZoneFinder::NXRRSET, expected_rdatas_,
+               expected_sig_rdatas_);
 
     // This is broken dname, it contains two targets
     EXPECT_THROW(finder->find(isc::dns::Name("below.baddname.example.org."),
-                              this->qtype_,
+                              qtype_,
                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
 
     // NS and other type coexist: deviant and not necessarily harmful.
     // It should normally just result in DELEGATION; if GLUE_OK is specified,
     // the other RR should be visible.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com");
-    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
-               RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
-               this->expected_rdatas_, this->empty_rdatas_,
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    doFindTest(*finder, Name("brokenns1.example.org"), qtype_,
+               RRType::NS(), rrttl_, ZoneFinder::DELEGATION,
+               expected_rdatas_, empty_rdatas_,
                ZoneFinder::RESULT_DEFAULT);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->empty_rdatas_,
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(*finder, Name("brokenns1.example.org"), qtype_,
+               qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, empty_rdatas_,
                ZoneFinder::RESULT_DEFAULT, Name("brokenns1.example.org"),
                ZoneFinder::FIND_GLUE_OK);
 }
 
-TYPED_TEST(DatabaseClientTest, findDS) {
+TEST_P(DatabaseClientTest, findDS) {
     // Type DS query is an exception to the general delegation case; the NS
     // should be ignored and it should be treated just like normal
     // authoritative data.
 
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // DS exists at the delegation point.  It should be returned with result
     // code of SUCCESS.
-    this->expected_rdatas_.push_back("1 1 2 abcd"),
-    this->expected_sig_rdatas_.push_back("DS 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("1 1 2 abcd"),
+    expected_sig_rdatas_.push_back("DS 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, Name("delegation.example.org."),
-               RRType::DS(), RRType::DS(), this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               RRType::DS(), RRType::DS(), rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_DEFAULT);
 
     // DS doesn't exist at the delegation point.  The result should be
     // NXRRSET, and if DNSSEC is requested and the zone is NSEC-signed,
     // the corresponding NSEC should be returned (normally with its RRSIG,
     // but in this simplified test setup it's omitted in the test data).
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("dummy.example.org. NS NSEC");
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("dummy.example.org. NS NSEC");
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, Name("insecdelegation.example.org."),
-               RRType::DS(), RRType::NSEC(), this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               RRType::DS(), RRType::NSEC(), rrttl_, ZoneFinder::NXRRSET,
+               expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_NSEC_SIGNED,
                Name("insecdelegation.example.org."), ZoneFinder::FIND_DNSSEC);
 
     // Some insane case: DS under a zone cut.  It's included in the DB, but
     // shouldn't be visible via finder.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
     doFindTest(*finder, Name("child.insecdelegation.example.org"),
-               RRType::DS(), RRType::NS(), this->rrttl_,
-               ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               RRType::DS(), RRType::NS(), rrttl_,
+               ZoneFinder::DELEGATION, expected_rdatas_,
+               empty_rdatas_, ZoneFinder::RESULT_DEFAULT,
                Name("insecdelegation.example.org."), ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, emptyDomain) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, emptyDomain) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // This domain doesn't exist, but a subdomain of it does.
     // Therefore we should pretend the domain is there, but contains no RRsets
-    doFindTest(*finder, isc::dns::Name("b.example.org."), this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+    doFindTest(*finder, isc::dns::Name("b.example.org."), qtype_,
+               qtype_, rrttl_, ZoneFinder::NXRRSET,
+               expected_rdatas_, expected_sig_rdatas_);
 }
 
 // Glue-OK mode. Just go through NS delegations down (but not through
 // DNAME) and pretend it is not there.
-TYPED_TEST(DatabaseClientTest, glueOK) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, glueOK) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("ns.delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::NXRRSET, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("ns.delegation.example.org."),
                ZoneFinder::FIND_GLUE_OK);
     doFindTest(*finder, isc::dns::Name("nothere.delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::NXDOMAIN, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("nothere.delegation.example.org."),
                ZoneFinder::FIND_GLUE_OK);
-    this->expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.1");
     doFindTest(*finder, isc::dns::Name("ns.delegation.example.org."),
-               this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_DEFAULT,
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("ns.delegation.example.org."),
                ZoneFinder::FIND_GLUE_OK);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com.");
-    this->expected_rdatas_.push_back("ns.delegation.example.org.");
-    this->expected_sig_rdatas_.clear();
-    this->expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 "
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.push_back("ns.delegation.example.org.");
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 "
                                    "20000201000000 12345 example.org. "
                                    "FAKEFAKEFAKE");
     // When we request the NS, it should be SUCCESS, not DELEGATION
     // (different in GLUE_OK)
     doFindTest(*finder, isc::dns::Name("delegation.example.org."),
                isc::dns::RRType::NS(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_DEFAULT,
+               rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegation.example.org."),
                ZoneFinder::FIND_GLUE_OK);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("dname.example.com.");
-    this->expected_sig_rdatas_.clear();
-    this->expected_sig_rdatas_.push_back("DNAME 5 3 3600 20000101000000 "
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("dname.example.com.");
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back("DNAME 5 3 3600 20000101000000 "
                                    "20000201000000 12345 example.org. "
                                    "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
-               this->qtype_, isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, isc::dns::RRType::DNAME(),
+               rrttl_, ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."), ZoneFinder::FIND_GLUE_OK);
     doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
-               isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
-               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(), rrttl_,
+               ZoneFinder::DNAME, expected_rdatas_, expected_sig_rdatas_,
+               ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."), ZoneFinder::FIND_GLUE_OK);
 }
 
-TYPED_TEST(DatabaseClientTest, wildcard) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, wildcard) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // First, simple wildcard match
     // Check also that the RRSIG is added from the wildcard (not modified)
-    this->expected_rdatas_.push_back("192.0.2.5");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("192.0.2.5");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_,
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_WILDCARD);
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_WILDCARD);
     doFindTest(*finder, isc::dns::Name("b.a.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_WILDCARD);
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_WILDCARD);
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
-               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_WILDCARD);
     doFindTest(*finder, isc::dns::Name("b.a.wild.example.org"),
-               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_WILDCARD);
 
     // Direct request for this wildcard
-    this->expected_rdatas_.push_back("192.0.2.5");
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("192.0.2.5");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("*.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-    this->expected_rdatas_.clear();
-    this->expected_sig_rdatas_.clear();
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, expected_sig_rdatas_);
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("*.wild.example.org"),
-               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::NXRRSET, this->expected_rdatas_,
-               this->expected_sig_rdatas_);
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_);
     // This is nonsense, but check it doesn't match by some stupid accident
     doFindTest(*finder, isc::dns::Name("a.*.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN,
+               expected_rdatas_, expected_sig_rdatas_);
     // These should be canceled, since it is below a domain which exitsts
     doFindTest(*finder, isc::dns::Name("nothing.here.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN,
+               expected_rdatas_, expected_sig_rdatas_);
     doFindTest(*finder, isc::dns::Name("cancel.here.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-    doFindTest(*finder,
-               isc::dns::Name("below.cancel.here.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::NXRRSET,
+               expected_rdatas_, expected_sig_rdatas_);
+    doFindTest(*finder, isc::dns::Name("below.cancel.here.wild.example.org"),
+               qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN,
+               expected_rdatas_, expected_sig_rdatas_);
     // And this should be just plain empty non-terminal domain, check
     // the wildcard doesn't hurt it
     doFindTest(*finder, isc::dns::Name("here.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               qtype_, qtype_, rrttl_, ZoneFinder::NXRRSET,
+               expected_rdatas_, expected_sig_rdatas_);
     // Also make sure that the wildcard doesn't hurt the original data
     // below the wildcard
-    this->expected_rdatas_.push_back("2001:db8::5");
+    expected_rdatas_.push_back("2001:db8::5");
     doFindTest(*finder, isc::dns::Name("cancel.here.wild.example.org"),
-               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
-               this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
-    this->expected_rdatas_.clear();
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(), rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, expected_sig_rdatas_);
+    expected_rdatas_.clear();
 
     // How wildcard go together with delegation
-    this->expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.push_back("ns.example.com.");
     doFindTest(*finder, isc::dns::Name("below.delegatedwild.example.org"),
-               this->qtype_, isc::dns::RRType::NS(), this->rrttl_,
-               ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, isc::dns::RRType::NS(), rrttl_,
+               ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegatedwild.example.org"));
-    // FIXME: This doesn't look logically OK, GLUE_OK should make it transparent,
-    // so the match should either work or be canceled, but return NXDOMAIN
+    // FIXME: This doesn't look logically OK, GLUE_OK should make it
+    // transparent, so the match should either work or be canceled, but return
+    // NXDOMAIN
     doFindTest(*finder, isc::dns::Name("below.delegatedwild.example.org"),
-               this->qtype_, isc::dns::RRType::NS(), this->rrttl_,
-               ZoneFinder::DELEGATION, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, isc::dns::RRType::NS(), rrttl_,
+               ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("delegatedwild.example.org"),
                ZoneFinder::FIND_GLUE_OK);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.5");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.5");
     // These are direct matches
     const char* positive_names[] = {
         "wild.*.foo.example.org.",
@@ -2491,14 +2615,13 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
         NULL
     };
     for (const char** name = positive_names; *name != NULL; ++ name) {
-        doFindTest(*finder, isc::dns::Name(*name), this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_,
-                   this->expected_sig_rdatas_);
+        doFindTest(*finder, isc::dns::Name(*name), qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_,
+                   expected_sig_rdatas_);
     }
 
     // These are wildcard matches against empty nonterminal asterisk
-    this->expected_rdatas_.clear();
+    expected_rdatas_.clear();
     const char* negative_names[] = {
         "a.foo.example.org.",
         "wild.bar.foo.example.org.",
@@ -2510,9 +2633,8 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
     // Unless FIND_DNSSEC is specified, this is no different from other
     // NXRRSET case.
     for (const char** name = negative_names; *name != NULL; ++ name) {
-        doFindTest(*finder, isc::dns::Name(*name), this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-                   this->expected_rdatas_, this->expected_sig_rdatas_,
+        doFindTest(*finder, isc::dns::Name(*name), qtype_, qtype_, rrttl_,
+                   ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_,
                    ZoneFinder::RESULT_WILDCARD);
     }
 
@@ -2523,25 +2645,24 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
         "a.foo.bar.example.org.",
         NULL
     };
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("wild.*.foo.*.bar.example.org. NSEC");
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("wild.*.foo.*.bar.example.org. NSEC");
+    expected_sig_rdatas_.clear();
     for (const char** name = negative_dnssec_names; *name != NULL; ++ name) {
-        doFindTest(*finder, isc::dns::Name(*name), this->qtype_,
-                   RRType::NSEC(), this->rrttl_, ZoneFinder::NXRRSET,
-                   this->expected_rdatas_, this->expected_sig_rdatas_,
+        doFindTest(*finder, isc::dns::Name(*name), qtype_,
+                   RRType::NSEC(), rrttl_, ZoneFinder::NXRRSET,
+                   expected_rdatas_, expected_sig_rdatas_,
                    ZoneFinder::RESULT_WILDCARD | ZoneFinder::RESULT_NSEC_SIGNED,
                    Name("bao.example.org."), ZoneFinder::FIND_DNSSEC);
     }
 
     // CNAME on a wildcard.  Maybe not so common, but not disallowed.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
-    this->expected_sig_rdatas_.clear();
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
+    expected_sig_rdatas_.clear();
     doFindTest(*finder, isc::dns::Name("a.cnamewild.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::CNAME(),
-               this->rrttl_, ZoneFinder::CNAME,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               isc::dns::RRType::TXT(), isc::dns::RRType::CNAME(), rrttl_,
+               ZoneFinder::CNAME, expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_WILDCARD);
 
     // DNAME on a wildcard.  In our implementation we ignore DNAMEs on a
@@ -2549,120 +2670,110 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
     // rfc2672bis strongly discourages the mixture of DNAME and wildcard
     // (with SHOULD NOT).
     doFindTest(*finder, Name("a.dnamewild.example.org."),
-               this->qtype_, this->qtype_, this->rrttl_,
-               ZoneFinder::NXRRSET, this->empty_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_WILDCARD);
+               qtype_, qtype_, rrttl_, ZoneFinder::NXRRSET, empty_rdatas_,
+               empty_rdatas_, ZoneFinder::RESULT_WILDCARD);
 
     // Some strange things in the wild node
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
     doFindTest(*finder, isc::dns::Name("a.nswild.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::NS(),
-               this->rrttl_, ZoneFinder::DELEGATION,
-               this->expected_rdatas_, this->empty_rdatas_,
+               isc::dns::RRType::TXT(), isc::dns::RRType::NS(), rrttl_,
+               ZoneFinder::DELEGATION, expected_rdatas_, empty_rdatas_,
                ZoneFinder::RESULT_WILDCARD);
 }
 
-TYPED_TEST(DatabaseClientTest, noWildcard) {
+TEST_P(DatabaseClientTest, noWildcard) {
     // Tests with the NO_WILDCARD flag.
 
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // This would match *.wild.example.org, but with NO_WILDCARD should
     // result in NXDOMAIN.
-    this->expected_rdatas_.push_back("cancel.here.wild.example.org. A "
-                                     "NSEC RRSIG");
-    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("cancel.here.wild.example.org. A NSEC RRSIG");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
-               RRType::NSEC(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXDOMAIN, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               RRType::NSEC(), RRType::NSEC(), rrttl_,
+               ZoneFinder::NXDOMAIN, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
                Name("*.wild.example.org."),
                ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
 
     // Should be the same without FIND_DNSSEC (but in this case no RRsets
     // will be returned)
     doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
-               RRType::NSEC(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               RRType::NSEC(), RRType::NSEC(), rrttl_, ZoneFinder::NXDOMAIN,
+               empty_rdatas_, empty_rdatas_, ZoneFinder::RESULT_DEFAULT,
                Name::ROOT_NAME(), // name is dummy
                ZoneFinder::NO_WILDCARD);
 
     // Same for wildcard empty non terminal.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("brokenns1.example.org. A NSEC");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("brokenns1.example.org. A NSEC");
     doFindTest(*finder, isc::dns::Name("a.bar.example.org"),
-               RRType::NSEC(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXDOMAIN, this->expected_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               RRType::NSEC(), RRType::NSEC(), rrttl_,
+               ZoneFinder::NXDOMAIN, expected_rdatas_, empty_rdatas_,
+               ZoneFinder::RESULT_NSEC_SIGNED,
                Name("wild.*.foo.*.bar.example.org"),
                ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
 
     // Search for a wildcard name with NO_WILDCARD.  There should be no
     // difference.  This is, for example, necessary to provide non existence
     // of matching wildcard for isnx.nonterminal.example.org.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
     doFindTest(*finder, isc::dns::Name("*.nonterminal.example.org"),
-               RRType::NSEC(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXDOMAIN, this->expected_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
-               Name("l.example.org"),
+               RRType::NSEC(), RRType::NSEC(), rrttl_,
+               ZoneFinder::NXDOMAIN, expected_rdatas_, empty_rdatas_,
+               ZoneFinder::RESULT_NSEC_SIGNED, Name("l.example.org"),
                ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
 
     // On the other hand, if there's exact match for the wildcard name
     // it should be found regardless of NO_WILDCARD.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.5");
-    this->expected_sig_rdatas_.clear();
-    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.5");
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("*.wild.example.org"),
-               this->qtype_, this->qtype_, this->rrttl_,
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                Name("*.wild.example.org"), ZoneFinder::NO_WILDCARD);
 }
 
-TYPED_TEST(DatabaseClientTest, NXRRSET_NSEC) {
+TEST_P(DatabaseClientTest, NXRRSET_NSEC) {
     // The domain exists, but doesn't have this RRType
     // So we should get its NSEC
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
-    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_NSEC_SIGNED, Name::ROOT_NAME(),
-               ZoneFinder::FIND_DNSSEC);
+               rrttl_, ZoneFinder::NXRRSET, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, wildcardNXRRSET_NSEC) {
+TEST_P(DatabaseClientTest, wildcardNXRRSET_NSEC) {
     // The domain exists, but doesn't have this RRType
     // So we should get its NSEC
     //
     // The user will have to query us again to get the correct
     // answer (eg. prove there's not an exact match)
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->expected_rdatas_.push_back("cancel.here.wild.example.org. A NSEC "
-                                     "RRSIG");
-    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    expected_rdatas_.push_back("cancel.here.wild.example.org. A NSEC RRSIG");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     // Note that the NSEC name should NOT be synthesized.
     doFindTest(*finder, isc::dns::Name("a.wild.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
+               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_WILDCARD | ZoneFinder::RESULT_NSEC_SIGNED,
                Name("*.wild.example.org"), ZoneFinder::FIND_DNSSEC);
 }
@@ -2775,7 +2886,7 @@ dnssecFlagCheck(ZoneFinder& finder, ZoneFinder::FindResultFlags sec_flag) {
     dnssecFlagCheckForAny(finder, Name("foo.wild.bar.example.org"), sec_flag);
 }
 
-TYPED_TEST(DatabaseClientTest, dnssecResultFlags) {
+TEST_P(DatabaseClientTest, dnssecResultFlags) {
     // ZoneFinder::find() for negative cases and wildcard cases should check
     // whether the zone is signed with NSEC or NSEC3.
 
@@ -2783,124 +2894,113 @@ TYPED_TEST(DatabaseClientTest, dnssecResultFlags) {
     // (the apex node has an NSEC RR).
     {
         SCOPED_TRACE("NSEC only");
-        dnssecFlagCheck(*this->getFinder(), ZoneFinder::RESULT_NSEC_SIGNED);
+        dnssecFlagCheck(*getFinder(), ZoneFinder::RESULT_NSEC_SIGNED);
     }
 
     // Then add an NSEC3PARAM RRset at the apex (it may look weird if the
     // zone only has NSEC3PARM RRset (but no NSEC3s), but it is okay for the
     // purpose of this test).  The zone should now be considered NSEC3-signed.
     // Note that the apex NSEC still exists; NSEC3 should override NSEC.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_.reset(new RRset(this->zname_, this->qclass_,
-                                 RRType::NSEC3PARAM(), this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "1 0 12 aabbccdd"));
-    this->updater_->addRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_.reset(new RRset(zname_, qclass_, RRType::NSEC3PARAM(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "1 0 12 aabbccdd"));
+    updater_->addRRset(*rrset_);
     {
         SCOPED_TRACE("NSEC and NSEC3");
-        dnssecFlagCheck(this->updater_->getFinder(),
-                        ZoneFinder::RESULT_NSEC3_SIGNED);
+        dnssecFlagCheck(updater_->getFinder(), ZoneFinder::RESULT_NSEC3_SIGNED);
     }
 
     // Next, delete the apex NSEC.  Since NSEC3PARAM remains, the zone should
     // still be considered NSEC3-signed.
-    RRsetPtr nsec_rrset(new RRset(this->zname_, this->qclass_, RRType::NSEC(),
-                                  this->rrttl_));
-    nsec_rrset->addRdata(rdata::createRdata(RRType::NSEC(), this->qclass_,
+    RRsetPtr nsec_rrset(new RRset(zname_, qclass_, RRType::NSEC(), rrttl_));
+    nsec_rrset->addRdata(rdata::createRdata(RRType::NSEC(), qclass_,
                                             "acnamesig1.example.org. NS A "
                                             "NSEC RRSIG"));
-    this->updater_->deleteRRset(*nsec_rrset);
+    updater_->deleteRRset(*nsec_rrset);
     {
         SCOPED_TRACE("NSEC3 only");
-        dnssecFlagCheck(this->updater_->getFinder(),
-                        ZoneFinder::RESULT_NSEC3_SIGNED);
+        dnssecFlagCheck(updater_->getFinder(), ZoneFinder::RESULT_NSEC3_SIGNED);
     }
 
     // Finally, delete the NSEC3PARAM we just added above.  The zone should
     // then be considered unsigned.
-    this->updater_->deleteRRset(*this->rrset_);
+    updater_->deleteRRset(*rrset_);
     {
         SCOPED_TRACE("unsigned");
-        dnssecFlagCheck(this->updater_->getFinder(),
-                        ZoneFinder::RESULT_DEFAULT);
+        dnssecFlagCheck(updater_->getFinder(), ZoneFinder::RESULT_DEFAULT);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
+TEST_P(DatabaseClientTest, NXDOMAIN_NSEC) {
     // The domain doesn't exist, so we must get the right NSEC
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
-    this->expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
-    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
-                                         "20000201000000 12345 example.org. "
-                                         "FAKEFAKEFAKE");
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
+    expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
+    expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                   "20000201000000 12345 example.org. "
+                                   "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("www1.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_NSEC_SIGNED, Name("www.example.org."),
-               ZoneFinder::FIND_DNSSEC);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("acnamesig1.example.org. NS A NSEC RRSIG");
+               rrttl_, ZoneFinder::NXDOMAIN, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               Name("www.example.org."), ZoneFinder::FIND_DNSSEC);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("acnamesig1.example.org. NS A NSEC RRSIG");
     // This tests it works correctly in apex (there was a bug, where a check
     // for NS-alone was there and it would throw).
     doFindTest(*finder, isc::dns::Name("aa.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_NSEC_SIGNED, Name("example.org."),
-               ZoneFinder::FIND_DNSSEC);
+               rrttl_, ZoneFinder::NXDOMAIN, expected_rdatas_,
+               expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               Name("example.org."), ZoneFinder::FIND_DNSSEC);
 
     // Check that if the DB doesn't support it, the exception from there
     // is not propagated and it only does not include the NSEC
-    if (!this->is_mock_) {
+    if (!is_mock_) {
         return; // We don't make the real DB to throw
     }
     // In this case the accessor doesn't support findPreviousName(), but the
     // zone apex has NSEC, and the zone itself is considered NSEC-signed.
     doFindTest(*finder, Name("notimplnsec.example.org."),
-               RRType::TXT(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               RRType::TXT(), RRType::NSEC(), rrttl_, ZoneFinder::NXDOMAIN,
+               empty_rdatas_, empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
                Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
+TEST_P(DatabaseClientTest, emptyNonterminalNSEC) {
     // Same as NXDOMAIN_NSEC, but with empty non-terminal
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
+    expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
     doFindTest(*finder, isc::dns::Name("nonterminal.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXRRSET, this->expected_rdatas_,
-               this->expected_sig_rdatas_,
+               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(), rrttl_,
+               ZoneFinder::NXRRSET, expected_rdatas_, expected_sig_rdatas_,
                ZoneFinder::RESULT_NSEC_SIGNED, Name("l.example.org."),
                ZoneFinder::FIND_DNSSEC);
 
     // Check that if the DB doesn't support it, the exception from there
     // is not propagated and it only does not include the NSEC
-    if (!this->is_mock_) {
+    if (!is_mock_) {
         return; // We don't make the real DB to throw
     }
     // See the corresponding case of NXDOMAIN_NSEC.
     doFindTest(*finder, Name("here.wild.example.org."),
-               RRType::TXT(), RRType::NSEC(), this->rrttl_,
-               ZoneFinder::NXRRSET, this->empty_rdatas_,
-               this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               RRType::TXT(), RRType::NSEC(), rrttl_, ZoneFinder::NXRRSET,
+               empty_rdatas_, empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
                Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, anyFromFind) {
+TEST_P(DatabaseClientTest, anyFromFind) {
     // Find will reject answering an ANY query
-    EXPECT_THROW(this->getFinder()->find(isc::dns::Name("www2.example.org."),
-                                         RRType::ANY()), isc::Unexpected);
+    EXPECT_THROW(getFinder()->find(isc::dns::Name("www2.example.org."),
+                                   RRType::ANY()), isc::Unexpected);
 }
 
-TYPED_TEST(DatabaseClientTest, findRRSIGsWithoutDNSSEC) {
+TEST_P(DatabaseClientTest, findRRSIGsWithoutDNSSEC) {
     // Trying to find RRSIG records directly should work even if
     // FIND_DNSSEC flag is not specified.
 
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
     ConstZoneFinderContextPtr result =
         finder->find(isc::dns::Name("signed1.example.org."), RRType::RRSIG());
 
@@ -2926,9 +3026,9 @@ TYPED_TEST(DatabaseClientTest, findRRSIGsWithoutDNSSEC) {
 }
 
 // Test the findAll method.
-TYPED_TEST(DatabaseClientTest, getAll) {
+TEST_P(DatabaseClientTest, getAll) {
     // The domain doesn't exist, so we must get the right NSEC
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // It should act the same on the "failures"
     std::vector<ConstRRsetPtr> target;
@@ -2939,22 +3039,19 @@ TYPED_TEST(DatabaseClientTest, getAll) {
     EXPECT_EQ(ZoneFinder::NXRRSET,
               finder->findAll(isc::dns::Name("here.wild.example.org."),
                               target)->code);
-    this->expected_rdatas_.push_back("ns.delegation.example.org.");
-    this->expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.push_back("ns.delegation.example.org.");
+    expected_rdatas_.push_back("ns.example.com.");
     doFindAllTestResult(*finder, isc::dns::Name("xx.delegation.example.org."),
-                        ZoneFinder::DELEGATION, RRType::NS(),
-                        this->expected_rdatas_,
+                        ZoneFinder::DELEGATION, RRType::NS(), expected_rdatas_,
                         isc::dns::Name("delegation.example.org."));
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("www.example.org.");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
     doFindAllTestResult(*finder, isc::dns::Name("cname.example.org"),
-                        ZoneFinder::CNAME, RRType::CNAME(),
-                        this->expected_rdatas_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("dname.example.com.");
+                        ZoneFinder::CNAME, RRType::CNAME(), expected_rdatas_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("dname.example.com.");
     doFindAllTestResult(*finder, isc::dns::Name("a.dname.example.org"),
-                        ZoneFinder::DNAME, RRType::DNAME(),
-                        this->expected_rdatas_,
+                        ZoneFinder::DNAME, RRType::DNAME(), expected_rdatas_,
                         isc::dns::Name("dname.example.org."));
     // It should get the data on success
     EXPECT_EQ(ZoneFinder::SUCCESS,
@@ -2967,7 +3064,7 @@ TYPED_TEST(DatabaseClientTest, getAll) {
     size_t count(0);
     for (RdataIteratorPtr it(target[a_idx]->getRdataIterator());
          !it->isLast(); it->next()) {
-        count ++;
+        ++count;
         EXPECT_NE(previous, it->getCurrent().toText());
         EXPECT_TRUE(it->getCurrent().toText() == "192.0.2.1" ||
                     it->getCurrent().toText() == "192.0.2.2");
@@ -3001,8 +3098,8 @@ TYPED_TEST(DatabaseClientTest, getAll) {
     ConstRRsetPtr sig(target[a_idx]->getRRsig());
     ASSERT_TRUE(sig);
     EXPECT_EQ(RRType::RRSIG(), sig->getType());
-    EXPECT_EQ("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
-              sig->getRdataIterator()->getCurrent().toText());
+    EXPECT_EQ("A 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+              "FAKEFAKEFAKE", sig->getRdataIterator()->getCurrent().toText());
     EXPECT_EQ(RRType::NSEC(), target[1 - a_idx]->getType());
     it = target[1 - a_idx]->getRdataIterator();
     ASSERT_FALSE(it->isLast());
@@ -3013,171 +3110,159 @@ TYPED_TEST(DatabaseClientTest, getAll) {
     sig = target[1 - a_idx]->getRRsig();
     ASSERT_TRUE(sig);
     EXPECT_EQ(RRType::RRSIG(), sig->getType());
-    EXPECT_EQ("NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
-              sig->getRdataIterator()->getCurrent().toText());
+    EXPECT_EQ("NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+              "FAKEFAKEFAKE", sig->getRdataIterator()->getCurrent().toText());
 }
 
-TYPED_TEST(DatabaseClientTest, getOrigin) {
-    DataSourceClient::FindResult
-        zone(this->client_->findZone(Name("example.org")));
-    ASSERT_EQ(result::SUCCESS, zone.code);
+TEST_P(DatabaseClientTest, getOrigin) {
+    const DataSourceClient::FindResult result =
+        client_->findZone(Name("example.org"));
+    ASSERT_EQ(result::SUCCESS, result.code);
     boost::shared_ptr<DatabaseClient::Finder> finder(
-        dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
-    if (this->is_mock_) {
+        dynamic_pointer_cast<DatabaseClient::Finder>(result.zone_finder));
+    if (is_mock_) {
         EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
     }
-    EXPECT_EQ(this->zname_, finder->getOrigin());
+    EXPECT_EQ(zname_, finder->getOrigin());
 }
 
-TYPED_TEST(DatabaseClientTest, updaterFinder) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    ASSERT_TRUE(this->updater_);
+TEST_P(DatabaseClientTest, updaterFinder) {
+    updater_ = client_->getUpdater(zname_, false);
+    ASSERT_TRUE(updater_);
 
     // If this update isn't replacing the zone, the finder should work
     // just like the normal find() case.
-    if (this->is_mock_) {
+    if (is_mock_) {
         DatabaseClient::Finder& finder = dynamic_cast<DatabaseClient::Finder&>(
-            this->updater_->getFinder());
+            updater_->getFinder());
         EXPECT_EQ(WRITABLE_ZONE_ID, finder.zone_id());
     }
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    doFindTest(this->updater_->getFinder(), this->qname_,
-               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->empty_rdatas_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // When replacing the zone, the updater's finder shouldn't see anything
     // in the zone until something is added.
-    this->updater_.reset();
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    ASSERT_TRUE(this->updater_);
-    if (this->is_mock_) {
+    updater_.reset();
+    updater_ = client_->getUpdater(zname_, true);
+    ASSERT_TRUE(updater_);
+    if (is_mock_) {
         DatabaseClient::Finder& finder = dynamic_cast<DatabaseClient::Finder&>(
-            this->updater_->getFinder());
+            updater_->getFinder());
         EXPECT_EQ(WRITABLE_ZONE_ID, finder.zone_id());
     }
-    doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
+    doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+               ZoneFinder::NXDOMAIN, empty_rdatas_, empty_rdatas_);
 }
 
-TYPED_TEST(DatabaseClientTest, flushZone) {
+TEST_P(DatabaseClientTest, flushZone) {
     // A simple update case: flush the entire zone
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     // Before update, the name exists.
-    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(this->qname_,
-                                                this->qtype_)->code);
+    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(qname_, qtype_)->code);
 
     // start update in the replace mode.  the normal finder should still
     // be able to see the record, but the updater's finder shouldn't.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->setUpdateAccessor();
-    EXPECT_EQ(ZoneFinder::SUCCESS,
-              finder->find(this->qname_, this->qtype_)->code);
+    updater_ = client_->getUpdater(zname_, true);
+    setUpdateAccessor();
+    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(qname_, qtype_)->code);
     EXPECT_EQ(ZoneFinder::NXDOMAIN,
-              this->updater_->getFinder().find(this->qname_,
-                                               this->qtype_)->code);
+              updater_->getFinder().find(qname_, qtype_)->code);
 
     // commit the update.  now the normal finder shouldn't see it.
-    this->updater_->commit();
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->find(this->qname_,
-                                                 this->qtype_)->code);
+    updater_->commit();
+    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->find(qname_, qtype_)->code);
 
     // Check rollback wasn't accidentally performed.
-    EXPECT_FALSE(this->isRollbacked());
+    EXPECT_FALSE(isRollbacked());
 }
 
-TYPED_TEST(DatabaseClientTest, updateCancel) {
+TEST_P(DatabaseClientTest, updateCancel) {
     // similar to the previous test, but destruct the updater before commit.
 
-    ZoneFinderPtr finder = this->client_->findZone(this->zname_).zone_finder;
-    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(this->qname_,
-                                                this->qtype_)->code);
+    ZoneFinderPtr finder = client_->findZone(zname_).zone_finder;
+    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(qname_, qtype_)->code);
 
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->setUpdateAccessor();
+    updater_ = client_->getUpdater(zname_, true);
+    setUpdateAccessor();
     EXPECT_EQ(ZoneFinder::NXDOMAIN,
-              this->updater_->getFinder().find(this->qname_,
-                                               this->qtype_)->code);
+              updater_->getFinder().find(qname_, qtype_)->code);
     // DB should not have been rolled back yet.
-    EXPECT_FALSE(this->isRollbacked());
-    this->updater_.reset();            // destruct without commit
+    EXPECT_FALSE(isRollbacked());
+    updater_.reset();            // destruct without commit
 
     // reset() should have triggered rollback (although it doesn't affect
     // anything to the mock accessor implementation except for the result of
     // isRollbacked())
-    EXPECT_TRUE(this->isRollbacked(true));
-    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(this->qname_,
-                                                this->qtype_)->code);
+    EXPECT_TRUE(isRollbacked(true));
+    EXPECT_EQ(ZoneFinder::SUCCESS, finder->find(qname_, qtype_)->code);
 }
 
-TYPED_TEST(DatabaseClientTest, exceptionFromRollback) {
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
+TEST_P(DatabaseClientTest, exceptionFromRollback) {
+    updater_ = client_->getUpdater(zname_, true);
 
-    this->rrset_.reset(new RRset(Name("throw.example.org"), this->qclass_,
-                                 this->qtype_, this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.1"));
-    this->updater_->addRRset(*this->rrset_);
+    rrset_.reset(new RRset(Name("throw.example.org"), qclass_,
+                                 qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.1"));
+    updater_->addRRset(*rrset_);
     // destruct without commit.  The added name will result in an exception
     // in the MockAccessor's rollback method.  It shouldn't be propagated.
-    EXPECT_NO_THROW(this->updater_.reset());
+    EXPECT_NO_THROW(updater_.reset());
 }
 
-TYPED_TEST(DatabaseClientTest, duplicateCommit) {
+TEST_P(DatabaseClientTest, duplicateCommit) {
     // duplicate commit.  should result in exception.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->commit();
-    EXPECT_THROW(this->updater_->commit(), DataSourceError);
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->commit();
+    EXPECT_THROW(updater_->commit(), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, addRRsetToNewZone) {
+TEST_P(DatabaseClientTest, addRRsetToNewZone) {
     // Add a single RRset to a fresh empty zone
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->addRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->addRRset(*rrset_);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.2");
     {
         SCOPED_TRACE("add RRset");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 
     // Similar to the previous case, but with RRSIG
-    this->updater_.reset();
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
-    this->updater_->addRRset(*this->rrset_);
-    this->updater_->addRRset(*this->rrsigset_);
+    updater_.reset();
+    updater_ = client_->getUpdater(zname_, true);
+    updater_->addRRset(*rrset_);
+    updater_->addRRset(*rrsigset_);
 
     // confirm the expected columns were passed to the accessor (if checkable).
     const char* const rrsig_added[] = {
         "www.example.org.", "org.example.www.", "3600", "RRSIG", "A",
         "A 5 3 0 20000101000000 20000201000000 0 example.org. FAKEFAKEFAKE"
     };
-    this->checkLastAdded(rrsig_added);
+    checkLastAdded(rrsig_added);
 
-    this->expected_sig_rdatas_.clear();
-    this->expected_sig_rdatas_.push_back(
-        rrsig_added[DatabaseAccessor::ADD_RDATA]);
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back(rrsig_added[DatabaseAccessor::ADD_RDATA]);
     {
         SCOPED_TRACE("add RRset with RRSIG");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->expected_sig_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_,
+                   expected_sig_rdatas_);
     }
 
     // Add the non RRSIG RRset again, to see the attempt of adding RRSIG
     // causes any unexpected effect, in particular, whether the SIGTYPE
     // field might remain.
-    this->updater_->addRRset(*this->rrset_);
+    updater_->addRRset(*rrset_);
     const char* const rrset_added[] = {
         "www.example.org.", "org.example.www.", "3600", "A", "", "192.0.2.2"
     };
-    this->checkLastAdded(rrset_added);
+    checkLastAdded(rrset_added);
 }
 
 //
@@ -3222,31 +3307,30 @@ nsec3Check(const vector<ConstRRsetPtr>& expected_rrsets,
                 actual_rrsets.begin(), actual_rrsets.end());
 }
 
-TYPED_TEST(DatabaseClientTest, addDeleteNSEC3InZone) {
+TEST_P(DatabaseClientTest, addDeleteNSEC3InZone) {
     // Add one NSEC3 RR to the zone, delete it, and add another one.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
+    updater_ = client_->getUpdater(zname_, true);
     const ConstRRsetPtr nsec3_rrset =
         textToRRset(string(nsec3_hash) + ".example.org. 3600 IN NSEC3 " +
                     string(nsec3_rdata));
     const ConstRRsetPtr nsec3_rrset2 =
         textToRRset(string(nsec3_hash) + ".example.org. 3600 IN NSEC3 " +
                     string(nsec3_rdata2));
-    this->updater_->addRRset(*nsec3_rrset);
-    this->updater_->deleteRRset(*nsec3_rrset);
-    this->updater_->addRRset(*nsec3_rrset2);
-    this->updater_->commit();
+    updater_->addRRset(*nsec3_rrset);
+    updater_->deleteRRset(*nsec3_rrset);
+    updater_->addRRset(*nsec3_rrset2);
+    updater_->commit();
 
     // Check if we can get the expected record.
     vector<ConstRRsetPtr> expected_rrsets;
     expected_rrsets.push_back(nsec3_rrset2);
-    nsec3Check(expected_rrsets, this->zname_, nsec3_hash,
-               *this->current_accessor_);
+    nsec3Check(expected_rrsets, zname_, nsec3_hash, *current_accessor_);
 }
 
-TYPED_TEST(DatabaseClientTest, addDeleteNSEC3AndRRSIGToZone) {
+TEST_P(DatabaseClientTest, addDeleteNSEC3AndRRSIGToZone) {
     // Add one NSEC3 RR and its RRSIG to the zone, delete the RRSIG and add
     // a new one.
-    this->updater_ = this->client_->getUpdater(this->zname_, true);
+    updater_ = client_->getUpdater(zname_, true);
     const ConstRRsetPtr nsec3_rrset =
         textToRRset(string(nsec3_hash) + ".example.org. 3600 IN NSEC3 " +
                     string(nsec3_rdata));
@@ -3256,471 +3340,413 @@ TYPED_TEST(DatabaseClientTest, addDeleteNSEC3AndRRSIGToZone) {
     const ConstRRsetPtr nsec3_sig_rrset2 =
         textToRRset(string(nsec3_hash) + ".example.org. 3600 IN RRSIG " +
                     string(nsec3_sig_rdata2));
-    this->updater_->addRRset(*nsec3_rrset);
-    this->updater_->addRRset(*nsec3_sig_rrset);
-    this->updater_->deleteRRset(*nsec3_sig_rrset);
-    this->updater_->addRRset(*nsec3_sig_rrset2);
-    this->updater_->commit();
+    updater_->addRRset(*nsec3_rrset);
+    updater_->addRRset(*nsec3_sig_rrset);
+    updater_->deleteRRset(*nsec3_sig_rrset);
+    updater_->addRRset(*nsec3_sig_rrset2);
+    updater_->commit();
 
     // Check if we can get the expected record.
     vector<ConstRRsetPtr> expected_rrsets;
     expected_rrsets.push_back(nsec3_rrset);
     expected_rrsets.push_back(nsec3_sig_rrset2);
-    nsec3Check(expected_rrsets, this->zname_, nsec3_hash,
-               *this->current_accessor_);
+    nsec3Check(expected_rrsets, zname_, nsec3_hash, *current_accessor_);
 }
 
-TYPED_TEST(DatabaseClientTest, addRRsetToCurrentZone) {
+TEST_P(DatabaseClientTest, addRRsetToCurrentZone) {
     // Similar to the previous test, but not replacing the existing data.
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->addRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->addRRset(*rrset_);
 
     // We should see both old and new data.
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     {
         SCOPED_TRACE("add RRset");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
-    this->updater_->commit();
+    updater_->commit();
     {
         SCOPED_TRACE("add RRset after commit");
-        doFindTest(*finder, this->qname_, this->qtype_, this->qtype_,
-                   this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-                   this->empty_rdatas_);
+        doFindTest(*finder, qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addMultipleRRs) {
+TEST_P(DatabaseClientTest, addMultipleRRs) {
     // Similar to the previous case, but the added RRset contains multiple
     // RRs.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.3"));
-    this->updater_->addRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
-    this->expected_rdatas_.push_back("192.0.2.3");
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.3"));
+    updater_->addRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.push_back("192.0.2.3");
     {
         SCOPED_TRACE("add multiple RRs");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addRRsetOfLargerTTL) {
+TEST_P(DatabaseClientTest, addRRsetOfLargerTTL) {
     // Similar to the previous one, but the TTL of the added RRset is larger
     // than that of the existing record.  The finder should use the smaller
     // one.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_->setTTL(RRTTL(7200));
-    this->updater_->addRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_->setTTL(RRTTL(7200));
+    updater_->addRRset(*rrset_);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     {
         SCOPED_TRACE("add RRset of larger TTL");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addRRsetOfSmallerTTL) {
+TEST_P(DatabaseClientTest, addRRsetOfSmallerTTL) {
     // Similar to the previous one, but the added RRset has a smaller TTL.
     // The added TTL should be used by the finder.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_->setTTL(RRTTL(1800));
-    this->updater_->addRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_->setTTL(RRTTL(1800));
+    updater_->addRRset(*rrset_);
 
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     {
         SCOPED_TRACE("add RRset of smaller TTL");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, RRTTL(1800), ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, RRTTL(1800),
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addSameRR) {
+TEST_P(DatabaseClientTest, addSameRR) {
     // Add the same RR as that is already in the data source.
     // Currently the add interface doesn't try to suppress the duplicate,
     // neither does the finder.  We may want to revisit it in future versions.
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, this->qtype_,
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.1"));
-    this->updater_->addRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.1");
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.1"));
+    updater_->addRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.1");
     {
         SCOPED_TRACE("add same RR");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addDeviantRR) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
+TEST_P(DatabaseClientTest, addDeviantRR) {
+    updater_ = client_->getUpdater(zname_, false);
 
     // RR class mismatch.  This should be detected and rejected.
-    this->rrset_.reset(new RRset(this->qname_, RRClass::CH(), RRType::TXT(),
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "test text"));
-    EXPECT_THROW(this->updater_->addRRset(*this->rrset_), DataSourceError);
+    rrset_.reset(new RRset(qname_, RRClass::CH(), RRType::TXT(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "test text"));
+    EXPECT_THROW(updater_->addRRset(*rrset_), DataSourceError);
 
     // Out-of-zone owner name.  At a higher level this should be rejected,
     // but it doesn't happen in this interface.
-    this->rrset_.reset(new RRset(Name("example.com"), this->qclass_,
-                                 this->qtype_, this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.100"));
-    this->updater_->addRRset(*this->rrset_);
-
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.100");
+    rrset_.reset(new RRset(Name("example.com"), qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.100"));
+    updater_->addRRset(*rrset_);
+
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.100");
     {
         // Note: find() rejects out-of-zone query name with an exception
         // regardless of whether adding the RR succeeded, so this check
         // actually doesn't confirm it.
         SCOPED_TRACE("add out-of-zone RR");
-        EXPECT_THROW(this->updater_->getFinder().find(Name("example.com"),
-                                                      this->qtype_),
+        EXPECT_THROW(updater_->getFinder().find(Name("example.com"), qtype_),
                      OutOfZone);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, addEmptyRRset) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, this->qtype_,
-                                 this->rrttl_));
-    EXPECT_THROW(this->updater_->addRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, addEmptyRRset) {
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
+    EXPECT_THROW(updater_->addRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, addAfterCommit) {
-   this->updater_ = this->client_->getUpdater(this->zname_, false);
-   this->updater_->commit();
-   EXPECT_THROW(this->updater_->addRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, addAfterCommit) {
+   updater_ = client_->getUpdater(zname_, false);
+   updater_->commit();
+   EXPECT_THROW(updater_->addRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, addRRsetWithRRSIG) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_->addRRsig(*this->rrsigset_);
-    EXPECT_THROW(this->updater_->addRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, addRRsetWithRRSIG) {
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_->addRRsig(*rrsigset_);
+    EXPECT_THROW(updater_->addRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, deleteRRset) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, deleteRRset) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, this->qtype_,
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.1"));
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.1"));
 
     // Delete one RR from an RRset
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
 
     // Delete the only RR of a name
-    this->rrset_.reset(new RRset(Name("cname.example.org"), this->qclass_,
-                          RRType::CNAME(), this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "www.example.org"));
-    this->updater_->deleteRRset(*this->rrset_);
-
-    // The this->updater_ finder should immediately see the deleted results.
+    rrset_.reset(new RRset(Name("cname.example.org"), qclass_,
+                           RRType::CNAME(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "www.example.org."));
+    updater_->deleteRRset(*rrset_);
+
+    // The updater_ finder should immediately see the deleted results.
     {
         SCOPED_TRACE("delete RRset");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-                   this->empty_rdatas_, this->empty_rdatas_);
-        doFindTest(this->updater_->getFinder(), Name("cname.example.org"),
-                   this->qtype_, this->qtype_, this->rrttl_,
-                   ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-                   this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::NXRRSET, empty_rdatas_, empty_rdatas_);
+        doFindTest(updater_->getFinder(), Name("cname.example.org"),
+                   qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN, empty_rdatas_,
+                   empty_rdatas_);
     }
 
     // before committing the change, the original finder should see the
     // original record.
     {
         SCOPED_TRACE("delete RRset before commit");
-        this->expected_rdatas_.push_back("192.0.2.1");
-        doFindTest(*finder, this->qname_, this->qtype_, this->qtype_,
-                   this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-                   this->empty_rdatas_);
-
-        this->expected_rdatas_.clear();
-        this->expected_rdatas_.push_back("www.example.org.");
-        doFindTest(*finder, Name("cname.example.org"), this->qtype_,
-                   RRType::CNAME(), this->rrttl_, ZoneFinder::CNAME,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        expected_rdatas_.push_back("192.0.2.1");
+        doFindTest(*finder, qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
+
+        expected_rdatas_.clear();
+        expected_rdatas_.push_back("www.example.org.");
+        doFindTest(*finder, Name("cname.example.org"), qtype_, RRType::CNAME(),
+                   rrttl_, ZoneFinder::CNAME, expected_rdatas_, empty_rdatas_);
     }
 
     // once committed, the record should be removed from the original finder's
     // view, too.
-    this->updater_->commit();
+    updater_->commit();
     {
         SCOPED_TRACE("delete RRset after commit");
-        doFindTest(*finder, this->qname_, this->qtype_, this->qtype_,
-                   this->rrttl_, ZoneFinder::NXRRSET, this->empty_rdatas_,
-                   this->empty_rdatas_);
-        doFindTest(*finder, Name("cname.example.org"), this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
-                   this->empty_rdatas_, this->empty_rdatas_);
+        doFindTest(*finder, qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::NXRRSET, empty_rdatas_, empty_rdatas_);
+        doFindTest(*finder, Name("cname.example.org"), qtype_, qtype_, rrttl_,
+                   ZoneFinder::NXDOMAIN, empty_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, deleteRRsetToNXDOMAIN) {
+TEST_P(DatabaseClientTest, deleteRRsetToNXDOMAIN) {
     // similar to the previous case, but it removes the only record of the
     // given name.  a subsequent find() should result in NXDOMAIN.
-    this->rrset_.reset(new RRset(Name("cname.example.org"), this->qclass_,
-                           RRType::CNAME(), this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "www.example.org"));
-
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    rrset_.reset(new RRset(Name("cname.example.org"), qclass_,
+                           RRType::CNAME(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "www.example.org."));
+
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
     {
         SCOPED_TRACE("delete RRset to NXDOMAIN");
-        doFindTest(this->updater_->getFinder(), Name("cname.example.org"),
-                   this->qtype_, this->qtype_, this->rrttl_,
-                   ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-                   this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), Name("cname.example.org"),
+                   qtype_, qtype_, rrttl_, ZoneFinder::NXDOMAIN, empty_rdatas_,
+                   empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, deleteMultipleRRs) {
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, RRType::AAAA(),
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::1"));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::2"));
+TEST_P(DatabaseClientTest, deleteMultipleRRs) {
+    rrset_.reset(new RRset(qname_, qclass_, RRType::AAAA(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::1"));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::2"));
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
 
     {
         SCOPED_TRACE("delete multiple RRs");
-        doFindTest(this->updater_->getFinder(), this->qname_, RRType::AAAA(),
-                   this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-                   this->empty_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, RRType::AAAA(),
+                   qtype_, rrttl_, ZoneFinder::NXRRSET,
+                   empty_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, partialDelete) {
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, RRType::AAAA(),
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::1"));
+TEST_P(DatabaseClientTest, partialDelete) {
+    rrset_.reset(new RRset(qname_, qclass_, RRType::AAAA(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::1"));
     // This does not exist in the test data source:
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::3"));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::3"));
 
     // deleteRRset should succeed "silently", and subsequent find() should
     // find the remaining RR.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
     {
         SCOPED_TRACE("partial delete");
-        this->expected_rdatas_.push_back("2001:db8::2");
-        doFindTest(this->updater_->getFinder(), this->qname_, RRType::AAAA(),
-                   RRType::AAAA(), this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        expected_rdatas_.push_back("2001:db8::2");
+        doFindTest(updater_->getFinder(), qname_, RRType::AAAA(),
+                   RRType::AAAA(), rrttl_, ZoneFinder::SUCCESS,
+                   expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, deleteNoMatch) {
+TEST_P(DatabaseClientTest, deleteNoMatch) {
     // similar to the previous test, but there's not even a match in the
     // specified RRset.  Essentially there's no difference in the result.
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
     {
         SCOPED_TRACE("delete no match");
-        this->expected_rdatas_.push_back("192.0.2.1");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-                   this->expected_rdatas_, this->empty_rdatas_);
+        expected_rdatas_.push_back("192.0.2.1");
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, deleteWithDifferentTTL) {
+TEST_P(DatabaseClientTest, deleteWithDifferentTTL) {
     // Our delete interface simply ignores TTL (may change in a future version)
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, this->qtype_,
-                                 RRTTL(1800)));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.1"));
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->deleteRRset(*this->rrset_);
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, RRTTL(1800)));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.1"));
+    updater_ = client_->getUpdater(zname_, false);
+    updater_->deleteRRset(*rrset_);
     {
         SCOPED_TRACE("delete RRset with a different TTL");
-        doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-                   this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
-                   this->empty_rdatas_, this->empty_rdatas_);
+        doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+                   ZoneFinder::NXRRSET, empty_rdatas_, empty_rdatas_);
     }
 }
 
-TYPED_TEST(DatabaseClientTest, deleteDeviantRR) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
+TEST_P(DatabaseClientTest, deleteDeviantRR) {
+    updater_ = client_->getUpdater(zname_, false);
 
     // RR class mismatch.  This should be detected and rejected.
-    this->rrset_.reset(new RRset(this->qname_, RRClass::CH(), RRType::TXT(),
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "test text"));
-    EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_), DataSourceError);
+    rrset_.reset(new RRset(qname_, RRClass::CH(), RRType::TXT(), rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "test text"));
+    EXPECT_THROW(updater_->deleteRRset(*rrset_), DataSourceError);
 
     // Out-of-zone owner name.  At a higher level this should be rejected,
     // but it doesn't happen in this interface.
-    this->rrset_.reset(new RRset(Name("example.com"), this->qclass_,
-                                 this->qtype_, this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.100"));
-    EXPECT_NO_THROW(this->updater_->deleteRRset(*this->rrset_));
+    rrset_.reset(new RRset(Name("example.com"), qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.100"));
+    EXPECT_NO_THROW(updater_->deleteRRset(*rrset_));
 }
 
-TYPED_TEST(DatabaseClientTest, deleteAfterCommit) {
-   this->updater_ = this->client_->getUpdater(this->zname_, false);
-   this->updater_->commit();
-   EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, deleteAfterCommit) {
+   updater_ = client_->getUpdater(zname_, false);
+   updater_->commit();
+   EXPECT_THROW(updater_->deleteRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, deleteEmptyRRset) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_.reset(new RRset(this->qname_, this->qclass_, this->qtype_,
-                                 this->rrttl_));
-    EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, deleteEmptyRRset) {
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
+    EXPECT_THROW(updater_->deleteRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, deleteRRsetWithRRSIG) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_->addRRsig(*this->rrsigset_);
-    EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_), DataSourceError);
+TEST_P(DatabaseClientTest, deleteRRsetWithRRSIG) {
+    updater_ = client_->getUpdater(zname_, false);
+    rrset_->addRRsig(*rrsigset_);
+    EXPECT_THROW(updater_->deleteRRset(*rrset_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, compoundUpdate) {
+TEST_P(DatabaseClientTest, compoundUpdate) {
     // This test case performs an arbitrary chosen add/delete operations
     // in a single update transaction.  Essentially there is nothing new to
     // test here, but there may be some bugs that was overlooked and can
     // only happen in the compound update scenario, so we test it.
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    updater_ = client_->getUpdater(zname_, false);
 
     // add a new RR to an existing RRset
-    this->updater_->addRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.1");
-    this->expected_rdatas_.push_back("192.0.2.2");
-    doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->empty_rdatas_);
+    updater_->addRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
+    doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // delete an existing RR
-    this->rrset_.reset(new RRset(Name("www.example.org"), this->qclass_,
-                                 this->qtype_, this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "192.0.2.1"));
-    this->updater_->deleteRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.2");
-    doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->empty_rdatas_);
+    rrset_.reset(new RRset(Name("www.example.org"), qclass_, qtype_, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "192.0.2.1"));
+    updater_->deleteRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.2");
+    doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // re-add it
-    this->updater_->addRRset(*this->rrset_);
-    this->expected_rdatas_.push_back("192.0.2.1");
-    doFindTest(this->updater_->getFinder(), this->qname_, this->qtype_,
-               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
-               this->expected_rdatas_, this->empty_rdatas_);
+    updater_->addRRset(*rrset_);
+    expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(updater_->getFinder(), qname_, qtype_, qtype_, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // add a new RR with a new name
     const Name newname("newname.example.org");
     const RRType newtype(RRType::AAAA());
-    doFindTest(this->updater_->getFinder(), newname, newtype, newtype,
-               this->rrttl_, ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-               this->empty_rdatas_);
-    this->rrset_.reset(new RRset(newname, this->qclass_, newtype,
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::10"));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::11"));
-    this->updater_->addRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::10");
-    this->expected_rdatas_.push_back("2001:db8::11");
-    doFindTest(this->updater_->getFinder(), newname, newtype, newtype,
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->empty_rdatas_);
+    doFindTest(updater_->getFinder(), newname, newtype, newtype, rrttl_,
+               ZoneFinder::NXDOMAIN, empty_rdatas_, empty_rdatas_);
+    rrset_.reset(new RRset(newname, qclass_, newtype, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::10"));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::11"));
+    updater_->addRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::10");
+    expected_rdatas_.push_back("2001:db8::11");
+    doFindTest(updater_->getFinder(), newname, newtype, newtype, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // delete one RR from the previous set
-    this->rrset_.reset(new RRset(newname, this->qclass_, newtype,
-                                 this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
-                                              this->rrset_->getClass(),
-                                              "2001:db8::11"));
-    this->updater_->deleteRRset(*this->rrset_);
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::10");
-    doFindTest(this->updater_->getFinder(), newname, newtype, newtype,
-               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->empty_rdatas_);
+    rrset_.reset(new RRset(newname, qclass_, newtype, rrttl_));
+    rrset_->addRdata(rdata::createRdata(rrset_->getType(), rrset_->getClass(),
+                                        "2001:db8::11"));
+    updater_->deleteRRset(*rrset_);
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::10");
+    doFindTest(updater_->getFinder(), newname, newtype, newtype, rrttl_,
+               ZoneFinder::SUCCESS, expected_rdatas_, empty_rdatas_);
 
     // Commit the changes, confirm the entire changes applied.
-    this->updater_->commit();
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("192.0.2.2");
-    this->expected_rdatas_.push_back("192.0.2.1");
-    doFindTest(*finder, this->qname_, this->qtype_, this->qtype_, this->rrttl_,
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->empty_rdatas_);
-
-    this->expected_rdatas_.clear();
-    this->expected_rdatas_.push_back("2001:db8::10");
-    doFindTest(*finder, newname, newtype, newtype, this->rrttl_,
-               ZoneFinder::SUCCESS, this->expected_rdatas_,
-               this->empty_rdatas_);
+    updater_->commit();
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.2");
+    expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(*finder, qname_, qtype_, qtype_, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, empty_rdatas_);
+
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::10");
+    doFindTest(*finder, newname, newtype, newtype, rrttl_, ZoneFinder::SUCCESS,
+               expected_rdatas_, empty_rdatas_);
 }
 
-TYPED_TEST(DatabaseClientTest, invalidRdata) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+TEST_P(DatabaseClientTest, invalidRdata) {
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    EXPECT_THROW(finder->find(Name("invalidrdata.example.org."),
-                              RRType::A()),
+    EXPECT_THROW(finder->find(Name("invalidrdata.example.org."), RRType::A()),
                  DataSourceError);
     EXPECT_THROW(finder->find(Name("invalidrdata2.example.org."),
                               RRType::A(), ZoneFinder::FIND_DNSSEC),
@@ -3728,7 +3754,7 @@ TYPED_TEST(DatabaseClientTest, invalidRdata) {
 }
 
 TEST_F(MockDatabaseClientTest, missingNSEC) {
-    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    boost::shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
     /*
      * FIXME: For now, we can't really distinguish this bogus input
@@ -3741,27 +3767,24 @@ TEST_F(MockDatabaseClientTest, missingNSEC) {
                  DataSourceError);
 #endif
     doFindTest(*finder, Name("badnsec2.example.org."), RRType::A(),
-               RRType::A(), this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->expected_rdatas_, this->expected_sig_rdatas_);
+               RRType::A(), rrttl_, ZoneFinder::NXDOMAIN,
+               expected_rdatas_, expected_sig_rdatas_);
 }
 
 /*
  * Test correct use of the updater with a journal.
  */
-TYPED_TEST(DatabaseClientTest, journal) {
-    this->updater_ = this->client_->getUpdater(this->zname_, false, true);
-    this->updater_->deleteRRset(*this->soa_);
-    this->updater_->deleteRRset(*this->rrset_);
-    this->soa_.reset(new RRset(this->zname_, this->qclass_, RRType::SOA(),
-                               this->rrttl_));
-    this->soa_->addRdata(rdata::createRdata(this->soa_->getType(),
-                                            this->soa_->getClass(),
-                                            "ns1.example.org. "
-                                            "admin.example.org. "
-                                            "1235 3600 1800 2419200 7200"));
-    this->updater_->addRRset(*this->soa_);
-    this->updater_->addRRset(*this->rrset_);
-    ASSERT_NO_THROW(this->updater_->commit());
+TEST_P(DatabaseClientTest, journal) {
+    updater_ = client_->getUpdater(zname_, false, true);
+    updater_->deleteRRset(*soa_);
+    updater_->deleteRRset(*rrset_);
+    soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
+                                      "ns1.example.org. admin.example.org. "
+                                      "1235 3600 1800 2419200 7200"));
+    updater_->addRRset(*soa_);
+    updater_->addRRset(*rrset_);
+    ASSERT_NO_THROW(updater_->commit());
     std::vector<JournalEntry> expected;
     expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234,
                                     DatabaseAccessor::DIFF_DELETE,
@@ -3781,30 +3804,27 @@ TYPED_TEST(DatabaseClientTest, journal) {
                                     DatabaseAccessor::DIFF_ADD,
                                     "www.example.org.", "A", "3600",
                                     "192.0.2.2"));
-    this->checkJournal(expected);
+    checkJournal(expected);
 }
 
-TYPED_TEST(DatabaseClientTest, journalForNSEC3) {
+TEST_P(DatabaseClientTest, journalForNSEC3) {
     // Similar to the previous test, but adding/deleting NSEC3 RRs, just to
     // confirm that NSEC3 is not special for managing diffs.
     const ConstRRsetPtr nsec3_rrset =
         textToRRset(string(nsec3_hash) + ".example.org. 3600 IN NSEC3 " +
                     string(nsec3_rdata));
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false, true);
-    this->updater_->deleteRRset(*this->soa_);
-    this->updater_->deleteRRset(*nsec3_rrset);
-
-    this->soa_.reset(new RRset(this->zname_, this->qclass_, RRType::SOA(),
-                               this->rrttl_));
-    this->soa_->addRdata(rdata::createRdata(this->soa_->getType(),
-                                            this->soa_->getClass(),
-                                            "ns1.example.org. "
-                                            "admin.example.org. "
-                                            "1235 3600 1800 2419200 7200"));
-    this->updater_->addRRset(*this->soa_);
-    this->updater_->addRRset(*nsec3_rrset);
-    this->updater_->commit();
+    updater_ = client_->getUpdater(zname_, false, true);
+    updater_->deleteRRset(*soa_);
+    updater_->deleteRRset(*nsec3_rrset);
+
+    soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+    soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
+                                      "ns1.example.org. admin.example.org. "
+                                      "1235 3600 1800 2419200 7200"));
+    updater_->addRRset(*soa_);
+    updater_->addRRset(*nsec3_rrset);
+    updater_->commit();
     std::vector<JournalEntry> expected;
     expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234,
                                     DatabaseAccessor::DIFF_DELETE,
@@ -3824,21 +3844,21 @@ TYPED_TEST(DatabaseClientTest, journalForNSEC3) {
                                     DatabaseAccessor::DIFF_ADD,
                                     string(nsec3_hash) + ".example.org.",
                                     "NSEC3", "3600", nsec3_rdata));
-    this->checkJournal(expected);
+    checkJournal(expected);
 }
 
 /*
  * Push multiple delete-add sequences. Checks it is allowed and all is
  * saved.
  */
-TYPED_TEST(DatabaseClientTest, journalMultiple) {
+TEST_P(DatabaseClientTest, journalMultiple) {
     std::vector<JournalEntry> expected;
-    this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+    updater_ = client_->getUpdater(zname_, false, true);
     std::string soa_rdata = "ns1.example.org. admin.example.org. "
         "1234 3600 1800 2419200 7200";
     for (size_t i = 1; i < 100; ++ i) {
         // Remove the old SOA
-        this->updater_->deleteRRset(*this->soa_);
+        updater_->deleteRRset(*soa_);
         expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234 + i - 1,
                                         DatabaseAccessor::DIFF_DELETE,
                                         "example.org.", "SOA", "3600",
@@ -3846,21 +3866,19 @@ TYPED_TEST(DatabaseClientTest, journalMultiple) {
         // Create a new SOA
         soa_rdata = "ns1.example.org. admin.example.org. " +
             lexical_cast<std::string>(1234 + i) + " 3600 1800 2419200 7200";
-        this->soa_.reset(new RRset(this->zname_, this->qclass_, RRType::SOA(),
-                                   this->rrttl_));
-        this->soa_->addRdata(rdata::createRdata(this->soa_->getType(),
-                                                this->soa_->getClass(),
-                                                soa_rdata));
+        soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
+        soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
+                                          soa_rdata));
         // Add the new SOA
-        this->updater_->addRRset(*this->soa_);
+        updater_->addRRset(*soa_);
         expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234 + i,
                                         DatabaseAccessor::DIFF_ADD,
                                         "example.org.", "SOA", "3600",
                                         soa_rdata));
     }
-    ASSERT_NO_THROW(this->updater_->commit());
+    ASSERT_NO_THROW(updater_->commit());
     // Check the journal contains everything.
-    this->checkJournal(expected);
+    checkJournal(expected);
 }
 
 /*
@@ -3876,72 +3894,71 @@ TEST_F(MockDatabaseClientTest, journalBadSequence) {
     std::vector<JournalEntry> expected;
     {
         SCOPED_TRACE("Delete A before SOA");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
-        EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_),
-                     isc::BadValue);
+        updater_ = client_->getUpdater(zname_, false, true);
+        EXPECT_THROW(updater_->deleteRRset(*rrset_), isc::BadValue);
         // Make sure the journal is empty now
-        this->checkJournal(expected);
+        checkJournal(expected);
     }
 
     {
         SCOPED_TRACE("Add before delete");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
-        EXPECT_THROW(this->updater_->addRRset(*this->soa_), isc::BadValue);
+        updater_ = client_->getUpdater(zname_, false, true);
+        EXPECT_THROW(updater_->addRRset(*soa_), isc::BadValue);
         // Make sure the journal is empty now
-        this->checkJournal(expected);
+        checkJournal(expected);
     }
 
     {
         SCOPED_TRACE("Add A before SOA");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+        updater_ = client_->getUpdater(zname_, false, true);
         // So far OK
-        EXPECT_NO_THROW(this->updater_->deleteRRset(*this->soa_));
+        EXPECT_NO_THROW(updater_->deleteRRset(*soa_));
         // But we miss the add SOA here
-        EXPECT_THROW(this->updater_->addRRset(*this->rrset_), isc::BadValue);
+        EXPECT_THROW(updater_->addRRset(*rrset_), isc::BadValue);
         // Make sure the journal contains only the first one
         expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234,
                                         DatabaseAccessor::DIFF_DELETE,
                                         "example.org.", "SOA", "3600",
                                         "ns1.example.org. admin.example.org. "
                                         "1234 3600 1800 2419200 7200"));
-        this->checkJournal(expected);
+        checkJournal(expected);
     }
 
     {
         SCOPED_TRACE("Commit before add");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+        updater_ = client_->getUpdater(zname_, false, true);
         // So far OK
-        EXPECT_NO_THROW(this->updater_->deleteRRset(*this->soa_));
+        EXPECT_NO_THROW(updater_->deleteRRset(*soa_));
         // Commit at the wrong time
         EXPECT_THROW(updater_->commit(), isc::BadValue);
-        current_accessor_->checkJournal(expected);
+        checkJournal(expected);
     }
 
     {
         SCOPED_TRACE("Delete two SOAs");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+        updater_ = client_->getUpdater(zname_, false, true);
         // So far OK
-        EXPECT_NO_THROW(this->updater_->deleteRRset(*this->soa_));
+        EXPECT_NO_THROW(updater_->deleteRRset(*soa_));
         // Delete the SOA again
-        EXPECT_THROW(this->updater_->deleteRRset(*this->soa_), isc::BadValue);
-        this->checkJournal(expected);
+        EXPECT_THROW(updater_->deleteRRset(*soa_), isc::BadValue);
+        checkJournal(expected);
     }
 
     {
         SCOPED_TRACE("Add two SOAs");
-        this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+        updater_ = client_->getUpdater(zname_, false, true);
         // So far OK
-        EXPECT_NO_THROW(this->updater_->deleteRRset(*this->soa_));
+        EXPECT_NO_THROW(updater_->deleteRRset(*soa_));
         // Still OK
-        EXPECT_NO_THROW(this->updater_->addRRset(*this->soa_));
+        EXPECT_NO_THROW(updater_->addRRset(*soa_));
         // But this one is added again
-        EXPECT_THROW(this->updater_->addRRset(*this->soa_), isc::BadValue);
+        EXPECT_THROW(updater_->addRRset(*soa_), isc::BadValue);
         expected.push_back(JournalEntry(WRITABLE_ZONE_ID, 1234,
                                         DatabaseAccessor::DIFF_ADD,
                                         "example.org.", "SOA", "3600",
                                         "ns1.example.org. admin.example.org. "
                                         "1234 3600 1800 2419200 7200"));
-        this->checkJournal(expected);
+        checkJournal(expected);
     }
 }
 
@@ -3949,9 +3966,8 @@ TEST_F(MockDatabaseClientTest, journalBadSequence) {
  * Test it rejects to store journals when we request it together with
  * erasing the whole zone.
  */
-TYPED_TEST(DatabaseClientTest, journalOnErase) {
-    EXPECT_THROW(this->client_->getUpdater(this->zname_, true, true),
-                 isc::BadValue);
+TEST_P(DatabaseClientTest, journalOnErase) {
+    EXPECT_THROW(client_->getUpdater(zname_, true, true), isc::BadValue);
 }
 
 /*
@@ -3997,18 +4013,17 @@ makeSimpleDiff(DataSourceClient& client, const Name& zname,
     return (soa_end);
 }
 
-TYPED_TEST(DatabaseClientTest, journalReader) {
+TEST_P(DatabaseClientTest, journalReader) {
     // Check the simple case made by makeSimpleDiff.
-    ConstRRsetPtr soa_end = makeSimpleDiff(*this->client_, this->zname_,
-                                           this->qclass_, this->soa_);
+    ConstRRsetPtr soa_end = makeSimpleDiff(*client_, zname_, qclass_, soa_);
     pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
-        this->client_->getJournalReader(this->zname_, 1234, 1235);
+        client_->getJournalReader(zname_, 1234, 1235);
     EXPECT_EQ(ZoneJournalReader::SUCCESS, result.first);
     ZoneJournalReaderPtr jnl_reader = result.second;
     ASSERT_TRUE(jnl_reader);
     ConstRRsetPtr rrset = jnl_reader->getNextDiff();
     ASSERT_TRUE(rrset);
-    rrsetCheck(this->soa_, rrset);
+    rrsetCheck(soa_, rrset);
     rrset = jnl_reader->getNextDiff();
     ASSERT_TRUE(rrset);
     rrsetCheck(soa_end, rrset);
@@ -4020,38 +4035,36 @@ TYPED_TEST(DatabaseClientTest, journalReader) {
     EXPECT_THROW(jnl_reader->getNextDiff(), isc::InvalidOperation);
 }
 
-TYPED_TEST(DatabaseClientTest, readLargeJournal) {
+TEST_P(DatabaseClientTest, readLargeJournal) {
     // Similar to journalMultiple, but check that at a higher level.
 
-    this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+    updater_ = client_->getUpdater(zname_, false, true);
 
     vector<ConstRRsetPtr> expected;
     for (size_t i = 0; i < 100; ++i) {
         // Create the old SOA and remove it, and record it in the expected list
-        RRsetPtr rrset1(new RRset(this->zname_, this->qclass_, RRType::SOA(),
-                                  this->rrttl_));
+        RRsetPtr rrset1(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
         string soa_rdata = "ns1.example.org. admin.example.org. " +
             lexical_cast<std::string>(1234 + i) + " 3600 1800 2419200 7200";
-        rrset1->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+        rrset1->addRdata(rdata::createRdata(RRType::SOA(), qclass_,
                                             soa_rdata));
-        this->updater_->deleteRRset(*rrset1);
+        updater_->deleteRRset(*rrset1);
         expected.push_back(rrset1);
 
         // Create a new SOA, add it, and record it.
-        RRsetPtr rrset2(new RRset(this->zname_, this->qclass_, RRType::SOA(),
-                                  this->rrttl_));
+        RRsetPtr rrset2(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
         soa_rdata = "ns1.example.org. admin.example.org. " +
             lexical_cast<std::string>(1234 + i + 1) +
             " 3600 1800 2419200 7200";
-        rrset2->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+        rrset2->addRdata(rdata::createRdata(RRType::SOA(), qclass_,
                                             soa_rdata));
-        this->updater_->addRRset(*rrset2);
+        updater_->addRRset(*rrset2);
         expected.push_back(rrset2);
     }
-    this->updater_->commit();
+    updater_->commit();
 
-    ZoneJournalReaderPtr jnl_reader(this->client_->getJournalReader(
-                                        this->zname_, 1234, 1334).second);
+    ZoneJournalReaderPtr jnl_reader(client_->getJournalReader(
+                                        zname_, 1234, 1334).second);
     ConstRRsetPtr actual;
     int i = 0;
     while ((actual = jnl_reader->getNextDiff()) != NULL) {
@@ -4060,20 +4073,20 @@ TYPED_TEST(DatabaseClientTest, readLargeJournal) {
     EXPECT_EQ(expected.size(), i); // we should have eaten all expected data
 }
 
-TYPED_TEST(DatabaseClientTest, readJournalForNoRange) {
-    makeSimpleDiff(*this->client_, this->zname_, this->qclass_, this->soa_);
+TEST_P(DatabaseClientTest, readJournalForNoRange) {
+    makeSimpleDiff(*client_, zname_, qclass_, soa_);
 
     // The specified range does not exist in the diff storage.  The factory
     // method should result in NO_SUCH_VERSION
     pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
-        this->client_->getJournalReader(this->zname_, 1200, 1235);
+        client_->getJournalReader(zname_, 1200, 1235);
     EXPECT_EQ(ZoneJournalReader::NO_SUCH_VERSION, result.first);
     EXPECT_FALSE(result.second);
 }
 
-TYPED_TEST(DatabaseClientTest, journalReaderForNXZone) {
-    pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
-        this->client_->getJournalReader(Name("nosuchzone"), 0, 1);
+TEST_P(DatabaseClientTest, journalReaderForNXZone) {
+    const pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
+        client_->getJournalReader(Name("nosuchzone"), 0, 1);
     EXPECT_EQ(ZoneJournalReader::NO_SUCH_ZONE, result.first);
     EXPECT_FALSE(result.second);
 }
@@ -4110,23 +4123,23 @@ TEST_F(MockDatabaseClientTest, journalWithBadData) {
                    "bad-ttl");
     installBadDiff(mock_accessor, 7, DatabaseAccessor::DIFF_RDATA,
                    "bad rdata");
-    EXPECT_THROW(this->client_->getJournalReader(this->zname_, 1, 2).
+    EXPECT_THROW(client_->getJournalReader(zname_, 1, 2).
                  second->getNextDiff(), DataSourceError);
-    EXPECT_THROW(this->client_->getJournalReader(this->zname_, 3, 4).
+    EXPECT_THROW(client_->getJournalReader(zname_, 3, 4).
                  second->getNextDiff(), DataSourceError);
-    EXPECT_THROW(this->client_->getJournalReader(this->zname_, 5, 6).
+    EXPECT_THROW(client_->getJournalReader(zname_, 5, 6).
                  second->getNextDiff(), DataSourceError);
-    EXPECT_THROW(this->client_->getJournalReader(this->zname_, 7, 8).
+    EXPECT_THROW(client_->getJournalReader(zname_, 7, 8).
                  second->getNextDiff(), DataSourceError);
 }
 
 /// Let us test a little bit of NSEC3.
-TYPED_TEST(DatabaseClientTest, findNSEC3) {
+TEST_P(DatabaseClientTest, findNSEC3) {
     // Set up the faked hash calculator.
-    setNSEC3HashCreator(&this->test_nsec3_hash_creator_);
+    setNSEC3HashCreator(&test_nsec3_hash_creator_);
 
     const DataSourceClient::FindResult
-        zone(this->client_->findZone(Name("example.org")));
+        zone(client_->findZone(Name("example.org")));
     ASSERT_EQ(result::SUCCESS, zone.code);
     boost::shared_ptr<DatabaseClient::Finder> finder(
         dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
@@ -4135,122 +4148,104 @@ TYPED_TEST(DatabaseClientTest, findNSEC3) {
     EXPECT_THROW(finder->findNSEC3(Name("example.org"), false),
                  DataSourceError);
     // And enable NSEC3 in the zone.
-    this->current_accessor_->enableNSEC3();
+    (GetParam()->enable_nsec3_fn)(*current_accessor_);
 
     // The rest is in the function, it is shared with in-memory tests
     performNSEC3Test(*finder, true);
 }
 
-TYPED_TEST(DatabaseClientTest, createZone) {
+TEST_P(DatabaseClientTest, createZone) {
     const Name new_name("example.com");
-    const DataSourceClient::FindResult
-        zone(this->client_->findZone(new_name));
-    ASSERT_EQ(result::NOTFOUND, zone.code);
+    const DataSourceClient::FindResult result(client_->findZone(new_name));
+    ASSERT_EQ(result::NOTFOUND, result.code);
 
     // Adding a new zone; it should work and return true
-    ASSERT_TRUE(this->client_->createZone(new_name));
-    const DataSourceClient::FindResult
-        zone2(this->client_->findZone(new_name));
-    ASSERT_EQ(result::SUCCESS, zone2.code);
+    ASSERT_TRUE(client_->createZone(new_name));
+    const DataSourceClient::FindResult result2(client_->findZone(new_name));
+    ASSERT_EQ(result::SUCCESS, result2.code);
     // And the second call should return false since
     // it already exists
-    this->allowMoreTransaction(true);
-    ASSERT_FALSE(this->client_->createZone(new_name));
+    allowMoreTransaction(true);
+    ASSERT_FALSE(client_->createZone(new_name));
 }
 
-TYPED_TEST(DatabaseClientTest, createZoneRollbackOnLocked) {
+TEST_P(DatabaseClientTest, createZoneRollbackOnLocked) {
     const Name new_name("example.com");
-    isc::datasrc::ZoneUpdaterPtr updater =
-        this->client_->getUpdater(this->zname_, true);
-    this->allowMoreTransaction(false);
-    ASSERT_THROW(this->client_->createZone(new_name), DataSourceError);
+    isc::datasrc::ZoneUpdaterPtr updater = client_->getUpdater(zname_, true);
+    allowMoreTransaction(false);
+    ASSERT_THROW(client_->createZone(new_name), DataSourceError);
     // createZone started a transaction as well, but since it failed,
     // it should have been rolled back. Roll back the other one as
     // well, and the next attempt should succeed
     updater.reset();
-    this->allowMoreTransaction(true);
-    ASSERT_TRUE(this->client_->createZone(new_name));
+    allowMoreTransaction(true);
+    ASSERT_TRUE(client_->createZone(new_name));
 }
 
-TYPED_TEST(DatabaseClientTest, createZoneRollbackOnExists) {
+TEST_P(DatabaseClientTest, createZoneRollbackOnExists) {
     const Name new_name("example.com");
-    ASSERT_FALSE(this->client_->createZone(this->zname_));
+    ASSERT_FALSE(client_->createZone(zname_));
 
     // deleteZone started a transaction, but since the zone didn't even exist
     // the transaction was not committed but should have been rolled back.
     // The first transaction shouldn't leave any state, lock, etc, that
     // would hinder the second attempt.
-    this->allowMoreTransaction(true);
-    ASSERT_TRUE(this->client_->createZone(new_name));
+    allowMoreTransaction(true);
+    ASSERT_TRUE(client_->createZone(new_name));
 }
 
-TYPED_TEST(DatabaseClientTest, deleteZone) {
+TEST_P(DatabaseClientTest, deleteZone) {
     // Check the zone currently exists.
-    EXPECT_EQ(result::SUCCESS, this->client_->findZone(this->zname_).code);
+    EXPECT_EQ(result::SUCCESS, client_->findZone(zname_).code);
 
     // Deleting an existing zone; it should work and return true (previously
     // existed and is now deleted)
-    EXPECT_TRUE(this->client_->deleteZone(this->zname_));
+    EXPECT_TRUE(client_->deleteZone(zname_));
 
     // Now it's not found by findZone
-    EXPECT_EQ(result::NOTFOUND, this->client_->findZone(this->zname_).code);
+    EXPECT_EQ(result::NOTFOUND, client_->findZone(zname_).code);
 
     // And the second call should return false since it doesn't exist any more
-    this->allowMoreTransaction(true);
-    EXPECT_FALSE(this->client_->deleteZone(this->zname_));
+    allowMoreTransaction(true);
+    EXPECT_FALSE(client_->deleteZone(zname_));
 }
 
-TYPED_TEST(DatabaseClientTest, deleteZoneRollbackOnLocked) {
-    isc::datasrc::ZoneUpdaterPtr updater =
-        this->client_->getUpdater(this->zname_, true);
+TEST_P(DatabaseClientTest, deleteZoneRollbackOnLocked) {
+    isc::datasrc::ZoneUpdaterPtr updater = client_->getUpdater(zname_, true);
 
     // updater locks the DB so deleteZone() will fail.
-    this->allowMoreTransaction(false);
-    EXPECT_THROW(this->client_->deleteZone(this->zname_), DataSourceError);
+    allowMoreTransaction(false);
+    EXPECT_THROW(client_->deleteZone(zname_), DataSourceError);
 
     // deleteZone started a transaction as well, but since it failed,
     // it should have been rolled back. Roll back the other one as
     // well, and the next attempt should succeed
     updater.reset();
-    this->allowMoreTransaction(true);
-    EXPECT_TRUE(this->client_->deleteZone(this->zname_));
+    allowMoreTransaction(true);
+    EXPECT_TRUE(client_->deleteZone(zname_));
 }
 
-TYPED_TEST(DatabaseClientTest, deleteZoneRollbackOnNotFind) {
+TEST_P(DatabaseClientTest, deleteZoneRollbackOnNotFind) {
     // attempt of deleting non-existent zone.  result in false
     const Name new_name("example.com");
-    EXPECT_FALSE(this->client_->deleteZone(new_name));
+    EXPECT_FALSE(client_->deleteZone(new_name));
 
     // deleteZone started a transaction, but since the zone didn't even exist
     // the transaction was not committed but should have been rolled back.
     // The first transaction shouldn't leave any state, lock, etc, that
     // would hinder the second attempt.
-    this->allowMoreTransaction(true);
-    EXPECT_TRUE(this->client_->deleteZone(this->zname_));
+    allowMoreTransaction(true);
+    EXPECT_TRUE(client_->deleteZone(zname_));
 }
 
-TYPED_TEST_CASE(RRsetCollectionTest, TestAccessorTypes);
-
-// This test fixture is templated so that we can share (most of) the test
-// cases with different types of data sources.  Note that in test cases
-// we need to use 'this' to refer to member variables of the test class.
-template <typename ACCESSOR_TYPE>
-class RRsetCollectionTest : public DatabaseClientTest<ACCESSOR_TYPE> {
-public:
-    RRsetCollectionTest() :
-        DatabaseClientTest<ACCESSOR_TYPE>(),
-        updater(this->client_->getUpdater(this->zname_, false)),
-        collection(updater->getRRsetCollection())
-    {}
+INSTANTIATE_TEST_CASE_P(, RRsetCollectionTest, ::testing::Values(&mock_param));
 
-    ZoneUpdaterPtr updater;
-    isc::datasrc::RRsetCollectionBase& collection;
-};
+TEST_P(RRsetCollectionTest, find) {
+    isc::dns::RRsetCollectionBase& collection = updater->getRRsetCollection();
 
-TYPED_TEST(RRsetCollectionTest, find) {
     // Test the find() that returns ConstRRsetPtr
-    ConstRRsetPtr rrset = this->collection.find(Name("www.example.org."),
-                                                RRClass::IN(), RRType::A());
+    ConstRRsetPtr rrset = collection.find(Name("www.example.org."),
+                                          RRClass::IN(), RRType::A());
     ASSERT_TRUE(rrset);
     EXPECT_EQ(RRType::A(), rrset->getType());
     EXPECT_EQ(RRTTL(3600), rrset->getTTL());
@@ -4258,59 +4253,54 @@ TYPED_TEST(RRsetCollectionTest, find) {
     EXPECT_EQ(Name("www.example.org"), rrset->getName());
 
     // foo.example.org doesn't exist
-    rrset = this->collection.find(Name("foo.example.org"), this->qclass_,
-                                  RRType::A());
+    rrset = collection.find(Name("foo.example.org"), qclass_, RRType::A());
     EXPECT_FALSE(rrset);
 
     // www.example.org exists, but not with MX
-    rrset = this->collection.find(Name("www.example.org"), this->qclass_,
-                                  RRType::MX());
+    rrset = collection.find(Name("www.example.org"), qclass_, RRType::MX());
     EXPECT_FALSE(rrset);
 
     // www.example.org exists, with AAAA
-    rrset = this->collection.find(Name("www.example.org"), this->qclass_,
-                                  RRType::AAAA());
+    rrset = collection.find(Name("www.example.org"), qclass_, RRType::AAAA());
     EXPECT_TRUE(rrset);
 
     // www.example.org with AAAA does not exist in RRClass::CH()
-    rrset = this->collection.find(Name("www.example.org"), RRClass::CH(),
-                                  RRType::AAAA());
+    rrset = collection.find(Name("www.example.org"), RRClass::CH(),
+                            RRType::AAAA());
     EXPECT_FALSE(rrset);
 
     // Out-of-zone find()s must not throw.
-    rrset = this->collection.find(Name("www.example.com"), this->qclass_,
-                                  RRType::A());
+    rrset = collection.find(Name("www.example.com"), qclass_, RRType::A());
     EXPECT_FALSE(rrset);
 
     // "cname.example.org." with type CNAME should return the CNAME RRset
-    rrset = this->collection.find(Name("cname.example.org"), this->qclass_,
-                                  RRType::CNAME());
+    rrset = collection.find(Name("cname.example.org"), qclass_,
+                            RRType::CNAME());
     ASSERT_TRUE(rrset);
     EXPECT_EQ(RRType::CNAME(), rrset->getType());
     EXPECT_EQ(Name("cname.example.org"), rrset->getName());
 
     // "cname.example.org." with type A should return nothing
-    rrset = this->collection.find(Name("cname.example.org"), this->qclass_,
-                                  RRType::A());
+    rrset = collection.find(Name("cname.example.org"), qclass_, RRType::A());
     EXPECT_FALSE(rrset);
 
     // "dname.example.org." with type DNAME should return the DNAME RRset
-    rrset = this->collection.find(Name("dname.example.org"), this->qclass_,
-                                  RRType::DNAME());
+    rrset = collection.find(Name("dname.example.org"), qclass_,
+                            RRType::DNAME());
     ASSERT_TRUE(rrset);
     EXPECT_EQ(RRType::DNAME(), rrset->getType());
     EXPECT_EQ(Name("dname.example.org"), rrset->getName());
 
     // "below.dname.example.org." with type AAAA should return nothing
-    rrset = this->collection.find(Name("below.dname.example.org"),
-                                  this->qclass_, RRType::AAAA());
+    rrset = collection.find(Name("below.dname.example.org"),
+                            qclass_, RRType::AAAA());
     EXPECT_FALSE(rrset);
 
     // "below.dname.example.org." with type A does not return the record
     // (see top of file). See \c isc::datasrc::RRsetCollectionBase::find()
     // documentation for details.
-    rrset = this->collection.find(Name("below.dname.example.org"),
-                                  this->qclass_, RRType::A());
+    rrset = collection.find(Name("below.dname.example.org"), qclass_,
+                            RRType::A());
     EXPECT_FALSE(rrset);
 
     // With the FIND_GLUE_OK option passed to ZoneFinder's find(),
@@ -4318,8 +4308,8 @@ TYPED_TEST(RRsetCollectionTest, find) {
     // return the NS record. Without FIND_GLUE_OK, ZoneFinder's find()
     // would return DELEGATION and the find() below would return
     // nothing.
-    rrset = this->collection.find(Name("delegation.example.org"),
-                                  this->qclass_, RRType::NS());
+    rrset = collection.find(Name("delegation.example.org"), qclass_,
+                            RRType::NS());
     ASSERT_TRUE(rrset);
     EXPECT_EQ(RRType::NS(), rrset->getType());
     EXPECT_EQ(Name("delegation.example.org"), rrset->getName());
@@ -4328,26 +4318,37 @@ TYPED_TEST(RRsetCollectionTest, find) {
     // searching for some "foo.wildcard.example.org." would make
     // ZoneFinder's find() return NXDOMAIN, and the find() below should
     // return nothing.
-    rrset = this->collection.find(Name("foo.wild.example.org"),
-                                  this->qclass_, RRType::A());
+    rrset = collection.find(Name("foo.wild.example.org"), qclass_,
+                            RRType::A());
     EXPECT_FALSE(rrset);
 
     // Searching directly for "*.wild.example.org." should return the
     // record.
-    rrset = this->collection.find(Name("*.wild.example.org"),
-                                  this->qclass_, RRType::A());
+    rrset = collection.find(Name("*.wild.example.org"), qclass_,
+                            RRType::A());
     ASSERT_TRUE(rrset);
     EXPECT_EQ(RRType::A(), rrset->getType());
     EXPECT_EQ(Name("*.wild.example.org"), rrset->getName());
 }
 
-TYPED_TEST(RRsetCollectionTest, iteratorTest) {
+TEST_P(RRsetCollectionTest, iteratorTest) {
+    isc::dns::RRsetCollectionBase& collection = updater->getRRsetCollection();
+
     // Iterators are currently not implemented.
-    EXPECT_THROW(this->collection.begin(), isc::NotImplemented);
-    EXPECT_THROW(this->collection.end(), isc::NotImplemented);
+    EXPECT_THROW(collection.begin(), isc::NotImplemented);
+    EXPECT_THROW(collection.end(), isc::NotImplemented);
 }
 
-typedef RRsetCollectionTest<MockAccessor> MockRRsetCollectionTest;
+// This inherit the RRsetCollectionTest cases except for the parameterized
+// setup; it's intended to be used selected test cases that only work for mock
+// data sources.
+class MockRRsetCollectionTest : public RRsetCollectionTest {
+protected:
+    virtual void SetUp() {
+        createClient(&mock_param);
+        updater = client_->getUpdater(zname_, false);
+    }
+};
 
 TEST_F(MockRRsetCollectionTest, findError) {
     // A test using the MockAccessor for checking that FindError is
@@ -4357,79 +4358,71 @@ TEST_F(MockRRsetCollectionTest, findError) {
     // The "dsexception.example.org." name is rigged by the MockAccessor
     // to throw a DataSourceError.
     EXPECT_THROW({
-        this->collection.find(Name("dsexception.example.org"), this->qclass_,
-                              RRType::A());
-    }, RRsetCollectionError);
+            updater->getRRsetCollection().find(
+                Name("dsexception.example.org"), qclass_, RRType::A());
+        }, RRsetCollectionError);
 }
 
-TYPED_TEST_CASE(RRsetCollectionAndUpdaterTest, TestAccessorTypes);
-
-// This test fixture is templated so that we can share (most of) the test
-// cases with different types of data sources.  Note that in test cases
-// we need to use 'this' to refer to member variables of the test class.
-template <typename ACCESSOR_TYPE>
-class RRsetCollectionAndUpdaterTest : public DatabaseClientTest<ACCESSOR_TYPE> {
-public:
-    RRsetCollectionAndUpdaterTest() :
-        DatabaseClientTest<ACCESSOR_TYPE>(),
-        updater_(this->client_->getUpdater(this->zname_, false))
-    {}
-
-    ZoneUpdaterPtr updater_;
-};
-
 // Test that using addRRset() or deleteRRset() on the ZoneUpdater throws
 // after an RRsetCollection is created.
-TYPED_TEST(RRsetCollectionAndUpdaterTest, updateThrows) {
+TEST_P(RRsetCollectionTest, updateThrows) {
     // 1. Addition test
 
     // addRRset() must not throw.
-    this->updater_->addRRset(*this->rrset_);
+    updater->addRRset(*rrset_);
 
     // Now setup a new updater and call getRRsetCollection() on it.
-    this->updater_.reset();
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    (void) this->updater_->getRRsetCollection();
+    updater.reset();
+    updater = client_->getUpdater(zname_, false);
+
+    // Just call getRRsetCollection() here. The test using .find() is
+    // unnecessary for the purpose of this test case, but we have it to
+    // use the result of getRRsetCollection() and silence some compiler
+    // complaining about ignoring the return value of
+    // getRRsetCollection().
+    EXPECT_FALSE(updater->getRRsetCollection().
+                 find(Name("www.example.org"), RRClass::IN(), RRType::MX()));
 
     // addRRset() must throw isc::InvalidOperation here.
-    EXPECT_THROW(this->updater_->addRRset(*this->rrset_),
-                 isc::InvalidOperation);
+    EXPECT_THROW(updater->addRRset(*rrset_), isc::InvalidOperation);
 
     // 2. Deletion test
 
     // deleteRRset() must not throw.
-    this->updater_.reset();
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->addRRset(*this->rrset_);
-    this->updater_->deleteRRset(*this->rrset_);
+    updater.reset();
+    updater = client_->getUpdater(zname_, false);
+    updater->addRRset(*rrset_);
+    updater->deleteRRset(*rrset_);
 
     // Now setup a new updater and call getRRsetCollection() on it.
-    this->updater_.reset();
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->updater_->addRRset(*this->rrset_);
-    (void) this->updater_->getRRsetCollection();
+    updater.reset();
+    updater = client_->getUpdater(zname_, false);
+    updater->addRRset(*rrset_);
+
+    // Just call getRRsetCollection() here. The .find() is unnecessary,
+    // but we have it to use the result of getRRsetCollection().
+    updater->getRRsetCollection().find(Name("www.example.org"),
+                                       RRClass::IN(), RRType::MX());
 
     // deleteRRset() must throw isc::InvalidOperation here.
-    EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_),
-                 isc::InvalidOperation);
+    EXPECT_THROW(updater->deleteRRset(*rrset_), isc::InvalidOperation);
 }
 
 // Test that using an RRsetCollection after calling commit() on the
 // ZoneUpdater throws, as the RRsetCollection is disabled.
-TYPED_TEST(RRsetCollectionAndUpdaterTest, useAfterCommitThrows) {
-     isc::datasrc::RRsetCollectionBase& collection =
-         this->updater_->getRRsetCollection();
+TEST_P(RRsetCollectionTest, useAfterCommitThrows) {
+     isc::dns::RRsetCollectionBase& collection =
+         updater->getRRsetCollection();
 
      // find() must not throw here.
-     collection.find(Name("foo.wild.example.org"), this->qclass_, RRType::A());
+     collection.find(Name("foo.wild.example.org"), qclass_, RRType::A());
 
-     this->updater_->commit();
+     updater->commit();
 
      // find() must throw RRsetCollectionError here, as the
      // RRsetCollection is disabled.
-     EXPECT_THROW(collection.find(Name("foo.wild.example.org"),
-                                  this->qclass_, RRType::A()),
-                  RRsetCollectionError);
+     EXPECT_THROW(collection.find(Name("foo.wild.example.org"), qclass_,
+                                  RRType::A()), RRsetCollectionError);
 }
 
 }
diff --git a/src/lib/datasrc/tests/database_unittest.h b/src/lib/datasrc/tests/database_unittest.h
new file mode 100644
index 0000000..f7746b0
--- /dev/null
+++ b/src/lib/datasrc/tests/database_unittest.h
@@ -0,0 +1,278 @@
+// 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/database.h>
+#include <datasrc/tests/faked_nsec3.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+#include <dns/rrset_collection_base.h>
+#include <dns/nsec3hash.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+/// \brief Commonly used test data.
+///
+/// This is an array of 5 C-string tuples, each of the tuples has the
+/// following semantics.
+/// [0] textual form of fully qualified, dot-terminated domain name
+///     (NAME_COLUMN).
+/// [1] textual form of RR type, such as "AAAA" (TYPE_COLUMN)
+/// [2] textual numeric form of RR TTL (TTL_COLUMN)
+/// [3] textual form of RR type, intended to be used to represent the
+///     "covered type" of RRSIG RRs, but actually not used at the moment.
+///     (SIGTYPE_COLUMN)
+/// [4] textual form of RDATA of the type, e.g., "2001:db8::1" for AAAA
+///     (RDATA_COLUMN)
+///
+/// These correspond to the array fields returned by
+/// \c DatabaseAccessor::IteratorContext::getNext().  The upper-cased names
+/// surrounded by parentheses specify the corresponding field for the specific
+/// entry.
+///
+/// It ends with a special entry of an all-NULL tuple.
+///
+/// For testing a custom accessor, it's expected to "load" the data of these
+/// records on a call to \c accessor_creator member of
+/// \c DatabaseClientTestParam (see the structure description).  In tests,
+/// the loaded data should be able to be retrieved by subsequent
+/// \c getRecords() or \c getNSEC3Records() calls.  The specific realization
+/// of the load can be specific to the accessor implementation, but if it
+/// conforms to the API of the following methods of \c DatabaseAccessor,
+/// it can be done by calling \c loadTestDataGeneric():
+/// - startUpdateZone()
+/// - addRecordToZone()
+/// - commit()
+extern const char* const TEST_RECORDS[][5];
+
+/// \brief NSEC3PARAM at the zone origin and its RRSIG.
+///
+/// The semantics of the data is the same as that for TEST_RECORDS.
+///
+/// These will be "loaded" on a call to
+/// \c DatabaseClientTestParam::enable_nsec3_fn for some tests that tests
+/// NSEC3 related behavior.  If the tested accessor skips the support for
+/// NSEC3, this data ban be ignored.
+extern const char* TEST_NSEC3PARAM_RECORDS[][5];
+
+/// \brief NSEC3 RR data commonly used for NSEC3-related tests.
+///
+/// This is similar to TEST_RECORDS, but the first entry is base32-hex encoded
+/// hash value (which is expected to appear as the first label of NSEC3
+/// owner names), not an FQDN.
+///
+/// These will be "loaded" on a call to
+/// \c DatabaseClientTestParam::enable_nsec3_fn for some tests that tests
+/// NSEC3 related behavior.  If the tested accessor skips the support for
+/// NSEC3, this data ban be ignored.  The loaded data are expected to be
+/// retrievable by subsequent \c getNSEC3Records() calls on the tested
+/// accessor.
+///
+/// The specific realization of the load can be specific to the accessor
+/// implementation, but if it conforms to the API of the following methods
+/// of \c DatabaseAccessor, it can be done by calling \c enableNSEC3Generic():
+/// - startUpdateZone()
+/// - addRecordToZone()
+/// - addNSEC3RecordToZone()
+/// - commit()
+extern const char* TEST_NSEC3_RECORDS[][5];
+
+/// \brief Test parameter for DatabaseClientTest.
+///
+/// This is the type of the parameter for the parameterized DatabaseClientTest
+/// and its derived variants.  It consists of a set of function pointers,
+/// including the factory of tested accessor.  A specific accessor
+/// implementation is expected to specify an instance of this structure,
+/// filling the members with appropriate functions for that accessor
+/// implementation.
+///
+/// Note that this is intentionally defined to be of plain old type (a plain
+/// structure whose members are bare function pointers); otherwise it could
+/// cause initialization fiasco at the instantiation time.
+struct DatabaseClientTestParam {
+    /// \brief The factory of the tested accessor.
+    ///
+    /// DatabaseClientTest will call this as part of the initialization of
+    /// each test case.  This function is expected to "load" the data
+    /// specified in TEST_RECORDS so they can be used in the tests.
+    ///
+    /// The creation of the accessor will be inherently implementation
+    /// dependent, but for loading the data it may be sufficient to call
+    /// \c loadTestDataGeneric.  See TEST_RECORDS for the condition.
+    boost::shared_ptr<DatabaseAccessor> (*accessor_creator)();
+
+    /// \brief Make NSEC3 records for the test.
+    ///
+    /// Some test cases call this function when they need to test NSEC3-related
+    /// scenarios.  It's expected to "load" the data specified in
+    /// TEST_NSEC3PARAM_RECORDS and TEST_NSEC3_RECORDS.
+    ///
+    /// The passed accessor will be the one created by the preceding call
+    /// to \c accessor_creator.
+    ///
+    /// If the accessor implementation meets some condition, this member can
+    /// be the generic \c enableNSEC3Generic function.  See TEST_RECORDS
+    /// and TEST_NSEC3_RECORDS for the condition.
+    void (*enable_nsec3_fn)(DatabaseAccessor& accessor);
+};
+
+// forward declaration, needed in the definition of DatabaseClientTest.
+// this is private to the test implementation internal otherwise.
+struct JournalEntry;
+
+/// \brief Test fixture class for the DatabaseClient implementation.
+///
+/// The primary purpose of this fixture is to test the implementation of
+/// the DatabaseClient with an internal mock DatabaseAccessor accessor.
+/// But the test cases can also be used to check specific accessor
+/// implementations.  It will be convenient for implementors of new types of
+/// accessor.
+///
+/// This fixture is therefore parameterized so that a specific accessor
+/// implementation can customize accessor-specific data of the test
+/// (most notably the accessor itself, and also the way to make test data
+/// available through the accessor).
+///
+/// See database_sqlite3_unittest.cc for how to use this test with a specific
+/// accessor implementation.
+class DatabaseClientTest :
+        public ::testing::TestWithParam<const DatabaseClientTestParam*>
+{
+protected:
+    DatabaseClientTest();
+
+    // We create accessor and other objects that depend on it in SetUp, not
+    // in the constructor, so derived test classes can override the behavior.
+    virtual void SetUp() {
+        createClient(GetParam());
+    }
+
+    ~DatabaseClientTest() {
+        // Make sure we return the default creator no matter if we set it or
+        // not
+        dns::setNSEC3HashCreator(NULL);
+    }
+
+    // We initialize the client from a function, so we can call it multiple
+    // times per test.
+    void createClient(const DatabaseClientTestParam* test_param);
+
+    /// Check the zone finder is a valid one and references the zone ID and
+    /// database available here.
+    void checkZoneFinder(const DataSourceClient::FindResult& zone);
+
+    boost::shared_ptr<DatabaseClient::Finder> getFinder();
+
+    // Helper methods for update tests
+    bool isRollbacked(bool expected = false) const;
+
+    void checkLastAdded(const char* const expected[]) const;
+
+    void setUpdateAccessor();
+
+    void checkJournal(const std::vector<JournalEntry>& expected);
+
+    // Mock-only; control whether to allow subsequent transaction.
+    void allowMoreTransaction(bool is_allowed);
+
+    // Some tests only work for MockAccessor.  We remember whether our accessor
+    // is of that type.
+    bool is_mock_;
+
+    boost::shared_ptr<DatabaseAccessor> current_accessor_;
+    boost::shared_ptr<DatabaseClient> client_;
+    const std::string database_name_;
+
+    // The zone finder of the test zone commonly used in various tests.
+    boost::shared_ptr<DatabaseClient::Finder> finder_;
+
+    // Some shortcut variables for commonly used test parameters
+    const dns::Name zname_; // the zone name stored in the test data source
+    const dns::Name qname_; // commonly used name to be found
+    const dns::RRClass qclass_;      // commonly used RR class used with qname
+    const dns::RRType qtype_;        // commonly used RR type used with qname
+    const dns::RRTTL rrttl_;         // commonly used RR TTL
+    dns::RRsetPtr rrset_;            // for adding/deleting an RRset
+    dns::RRsetPtr rrsigset_;         // for adding/deleting an RRset
+    dns::RRsetPtr soa_;              // for adding/deleting an RRset
+
+    // update related objects to be tested
+    ZoneUpdaterPtr updater_;
+    boost::shared_ptr<const DatabaseAccessor> update_accessor_;
+
+    // placeholders
+    const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
+    std::vector<std::string> expected_rdatas_;
+    std::vector<std::string> expected_sig_rdatas_;
+
+    // A creator for use in several NSEC3 related tests.
+    TestNSEC3HashCreator test_nsec3_hash_creator_;
+};
+
+/// \brief Test fixture for RRsetCollectionTest with database updater.
+///
+/// Inherited from DatabaseClientTest to reuse some of the setup.
+/// This test fixture is parameterized just like DatabaseClientTest.
+class RRsetCollectionTest : public DatabaseClientTest {
+protected:
+    RRsetCollectionTest() {}
+
+    virtual void SetUp() {
+        DatabaseClientTest::SetUp();
+        updater = client_->getUpdater(zname_, false);
+    }
+
+    ZoneUpdaterPtr updater;
+};
+
+/// \brief Generic test data loader.
+///
+/// This function is intended to be used within the accessor_creator function
+/// of DatabaseClientTestParam for tested accessor that implements the
+/// following methods:
+/// - startUpdateZone()
+/// - addRecordToZone()
+/// - commit()
+void loadTestDataGeneric(DatabaseAccessor& accessor);
+
+/// \brief Generic helper to prepare NSEC3 related test data.
+///
+/// This function can be specified for the enable_nsec3_fn member
+/// of DatabaseClientTestParam if the tested accessor implements the
+/// following methods:
+/// - startUpdateZone()
+/// - addRecordToZone()
+/// - addNSEC3RecordToZone()
+/// - commit()
+void enableNSEC3Generic(DatabaseAccessor& accessor);
+
+} // namespace test
+} // namespace datasrc
+} // namespace isc
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/factory_unittest.cc b/src/lib/datasrc/tests/factory_unittest.cc
index 2031d50..cc03ce3 100644
--- a/src/lib/datasrc/tests/factory_unittest.cc
+++ b/src/lib/datasrc/tests/factory_unittest.cc
@@ -29,6 +29,7 @@ using namespace isc::data;
 
 std::string SQLITE_DBFILE_EXAMPLE_ORG = TEST_DATA_DIR "/example.org.sqlite3";
 const std::string STATIC_DS_FILE = TEST_DATA_DIR "/static.zone";
+const std::string STATIC_BAD_DS_FILE = TEST_DATA_DIR "/static-bad.zone";
 const std::string ROOT_ZONE_FILE = TEST_DATA_DIR "/root.zone";
 
 namespace {
@@ -160,78 +161,6 @@ TEST(FactoryTest, sqlite3ClientBadConfig) {
         isc::dns::Name("example.org."), false));
 }
 
-TEST(FactoryTest, memoryClient) {
-    // We start out by building the configuration data bit by bit,
-    // testing each form of 'bad config', until we have a good one.
-    // Then we do some very basic operation on the client (detailed
-    // tests are left to the implementation-specific backends)
-    ElementPtr config;
-    ASSERT_THROW(DataSourceClientContainer client("memory", config),
-                 DataSourceError);
-
-    config = Element::create("asdf");
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config = Element::createMap();
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("type", ElementPtr());
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("type", Element::create(1));
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("type", Element::create("FOO"));
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("type", Element::create("memory"));
-    // no config at all should result in a default empty memory client
-    ASSERT_NO_THROW(DataSourceClientContainer("memory", config));
-
-    config->set("class", ElementPtr());
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("class", Element::create(1));
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("class", Element::create("FOO"));
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("class", Element::create("IN"));
-    ASSERT_NO_THROW(DataSourceClientContainer("memory", config));
-
-    config->set("zones", ElementPtr());
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("zones", Element::create(1));
-    ASSERT_THROW(DataSourceClientContainer("memory", config),
-                 DataSourceError);
-
-    config->set("zones", Element::createList());
-    DataSourceClientContainer dsc("memory", config);
-
-    // Once it is able to load some zones, we should add a few tests
-    // here to see that it does.
-    DataSourceClient::FindResult result(
-        dsc.getInstance().findZone(isc::dns::Name("no.such.zone.")));
-    ASSERT_EQ(result::NOTFOUND, result.code);
-
-    ASSERT_THROW(dsc.getInstance().getIterator(isc::dns::Name("example.org.")),
-                 DataSourceError);
-
-    ASSERT_THROW(dsc.getInstance().getUpdater(isc::dns::Name("no.such.zone."),
-                                              false), isc::NotImplemented);
-}
-
 TEST(FactoryTest, badType) {
     ASSERT_THROW(DataSourceClientContainer("foo", ElementPtr()),
                                            DataSourceError);
@@ -259,13 +188,9 @@ TEST(FactoryTest, staticDS) {
 }
 
 // Check that file not containing BIND./CH is rejected
-//
-// FIXME: This test is disabled because the InMemoryZoneFinder::load does
-// not check if the data loaded correspond with the origin. The static
-// factory is not the place to fix that.
-TEST(FactoryTest, DISABLED_staticDSBadFile) {
+TEST(FactoryTest, staticDSBadFile) {
     // The only configuration is the file to load.
-    const ConstElementPtr config(new StringElement(STATIC_DS_FILE));
+    const ConstElementPtr config(new StringElement(STATIC_BAD_DS_FILE));
     // See it does not want the file
     EXPECT_THROW(DataSourceClientContainer("static", config), DataSourceError);
 }
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
index 26a7b8d..13dd5fb 100644
--- a/src/lib/datasrc/tests/faked_nsec3.h
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -15,7 +15,7 @@
 #ifndef FAKED_NSEC3_H
 #define FAKED_NSEC3_H
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 #include <dns/nsec3hash.h>
 
diff --git a/src/lib/datasrc/tests/master_loader_callbacks_test.cc b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
index dc44461..fb4487a 100644
--- a/src/lib/datasrc/tests/master_loader_callbacks_test.cc
+++ b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
@@ -65,7 +65,7 @@ public:
     virtual ZoneFinder& getFinder() {
         isc_throw(isc::NotImplemented, "Not to be called in this test");
     }
-    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+    virtual isc::dns::RRsetCollectionBase& getRRsetCollection() {
         isc_throw(isc::NotImplemented, "Not to be called in this test");
     }
     virtual void deleteRRset(const isc::dns::AbstractRRset&) {
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
index a5d73b4..f77d212 100644
--- a/src/lib/datasrc/tests/memory/Makefile.am
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -32,6 +32,7 @@ run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
 run_unittests_SOURCES += memory_segment_test.h
 run_unittests_SOURCES += segment_object_holder_unittest.cc
 run_unittests_SOURCES += memory_client_unittest.cc
+run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += zone_data_loader_unittest.cc
 run_unittests_SOURCES += zone_data_updater_unittest.cc
 run_unittests_SOURCES += zone_table_segment_test.h
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 0a03645..74e7917 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -59,6 +59,7 @@ namespace {
 const char* rrset_data[] = {
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "68 3600 300 3600000 3600",
+    "example.org. 3600 IN NS ns1.example.org.",
     "a.example.org. 3600 IN A 192.168.0.1\n" // RRset containing 2 RRs
     "a.example.org. 3600 IN A 192.168.0.2",
     "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
@@ -225,7 +226,7 @@ TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
 
     EXPECT_THROW(client_->load(Name("."),
                                TEST_DATA_DIR "/empty.zone"),
-                 EmptyZone);
+                 ZoneValidationError);
 
     EXPECT_EQ(0, client_->getZoneCount());
 
@@ -255,6 +256,11 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // RRType::NS() RRset
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // RRType::MX() RRset
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -377,6 +383,10 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(RRType::SOA(), set->type);
 
     set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
+    set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
@@ -402,6 +412,10 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(RRType::SOA(), set->type);
 
     set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
+    set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
@@ -636,9 +650,14 @@ TEST_F(MemoryClientTest, getIterator) {
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
     // First we have the SOA
-    ConstRRsetPtr rrset_soa(iterator->getNextRRset());
-    EXPECT_TRUE(rrset_soa);
-    EXPECT_EQ(RRType::SOA(), rrset_soa->getType());
+    ConstRRsetPtr rrset(iterator->getNextRRset());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // Then the NS
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
     // There's nothing else in this iterator
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
@@ -659,6 +678,11 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // Then, the NS
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // Only one RRType::A() RRset
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -667,7 +691,6 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     // There's nothing else in this zone
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
 
-
     // separate_rrs = true
     ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
 
@@ -676,6 +699,11 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // Then, the NS
+    rrset = iterator2->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // First RRType::A() RRset
     rrset = iterator2->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -751,6 +779,11 @@ TEST_F(MemoryClientTest, findZoneData) {
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(RRType::SOA(), set->type);
 
+    /* Check NS */
+    set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
     set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
diff --git a/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
index a45c2bd..b36b294 100644
--- a/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
@@ -632,9 +632,9 @@ addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs) {
     checkEncode(RRClass::IN(), RRType::A(), rdata_list_, 0, rrsigs);
 
     ConstRdataPtr mx_rdata1 = createRdata(RRType::MX(), RRClass::IN(),
-                                          "5 mx1.example.com");
+                                          "5 mx1.example.com.");
     ConstRdataPtr mx_rdata2 = createRdata(RRType::MX(), RRClass::IN(),
-                                          "10 mx2.example.com");
+                                          "10 mx2.example.com.");
     rdata_list_.clear();
     rdata_list_.push_back(mx_rdata1);
     rdata_list_.push_back(mx_rdata2);
@@ -767,13 +767,13 @@ TEST_F(RdataSerializationTest, badAddRdata) {
 
     // Likewise.  Inconsistent name compression policy.
     const ConstRdataPtr ns_rdata =
-        createRdata(RRType::NS(), RRClass::IN(), "ns.example");
+        createRdata(RRType::NS(), RRClass::IN(), "ns.example.");
     encoder_.start(RRClass::IN(), RRType::DNAME());
     EXPECT_THROW(encoder_.addRdata(*ns_rdata), isc::BadValue);
 
     // Same as the previous one, opposite inconsistency.
     const ConstRdataPtr dname_rdata =
-        createRdata(RRType::DNAME(), RRClass::IN(), "dname.example");
+        createRdata(RRType::DNAME(), RRClass::IN(), "dname.example.");
     encoder_.start(RRClass::IN(), RRType::NS());
     EXPECT_THROW(encoder_.addRdata(*dname_rdata), isc::BadValue);
 
diff --git a/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
new file mode 100644
index 0000000..04e285b
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2013  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/memory/rrset_collection.h>
+
+#include "memory_segment_test.h"
+
+#include <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/segment_object_holder.h>
+#include <dns/rrttl.h>
+#include <dns/rdataclass.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace std;
+using namespace isc::datasrc;
+using namespace isc::datasrc::memory;
+using namespace isc::datasrc::memory::detail;
+
+namespace {
+
+// Note: This class uses loadZoneData() to construct a ZoneData object,
+// which internally uses an RRsetCollection for validation. We assume
+// that loadZoneData() works at this point and test the RRsetCollection
+// around the ZoneData returned.
+class RRsetCollectionTest : public ::testing::Test {
+public:
+    RRsetCollectionTest() :
+        rrclass("IN"),
+        origin("example.org"),
+        zone_file(TEST_DATA_DIR "/rrset-collection.zone"),
+        zone_data_holder(mem_sgmt,
+                         loadZoneData(mem_sgmt, rrclass, origin, zone_file),
+                         rrclass),
+        collection(*zone_data_holder.get(), rrclass)
+    {}
+
+    const RRClass rrclass;
+    const Name origin;
+    std::string zone_file;
+    test::MemorySegmentTest mem_sgmt;
+    SegmentObjectHolder<ZoneData, RRClass> zone_data_holder;
+    RRsetCollection collection;
+};
+
+TEST_F(RRsetCollectionTest, find) {
+    const RRsetCollection& ccln = collection;
+    ConstRRsetPtr rrset = ccln.find(Name("www.example.org"), rrclass,
+                                    RRType::A());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+    EXPECT_EQ(RRTTL(3600), rrset->getTTL());
+    EXPECT_EQ(RRClass("IN"), rrset->getClass());
+    EXPECT_EQ(Name("www.example.org"), rrset->getName());
+
+    // foo.example.org doesn't exist
+    rrset = ccln.find(Name("foo.example.org"), rrclass, RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, but not with MX
+    rrset = ccln.find(Name("www.example.org"), rrclass, RRType::MX());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, with AAAA
+    rrset = ccln.find(Name("www.example.org"), rrclass, RRType::AAAA());
+    EXPECT_TRUE(rrset);
+
+    // www.example.org with AAAA does not exist in RRClass::CH()
+    rrset = ccln.find(Name("www.example.org"), RRClass::CH(),
+                            RRType::AAAA());
+    EXPECT_FALSE(rrset);
+}
+
+} // namespace
diff --git a/src/lib/datasrc/tests/memory/testdata/Makefile.am b/src/lib/datasrc/tests/memory/testdata/Makefile.am
index ef5f08b..b076837 100644
--- a/src/lib/datasrc/tests/memory/testdata/Makefile.am
+++ b/src/lib/datasrc/tests/memory/testdata/Makefile.am
@@ -29,6 +29,7 @@ EXTRA_DIST += example.org-rrsigs.zone
 EXTRA_DIST += example.org-wildcard-dname.zone
 EXTRA_DIST += example.org-wildcard-ns.zone
 EXTRA_DIST += example.org-wildcard-nsec3.zone
+EXTRA_DIST += rrset-collection.zone
 
 EXTRA_DIST += 2503-test.zone
 EXTRA_DIST += 2504-test.zone
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
index 6e5c1b8..799b54e 100644
--- a/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
@@ -1,4 +1,5 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 76 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 77 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN A	 	192.168.0.2
 ns1.example.org.		      3600 IN AAAA 	::1
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone b/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
index f11b9b8..899a412 100644
--- a/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
@@ -1,2 +1,3 @@
 ;; empty example.org zone
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 71 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
index f473ae6..b94d806 100644
--- a/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
@@ -1,4 +1,5 @@
 ;; Multiple RDATA for testing separate RRs iterator
-example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 80 3600 300 3600000 3600
+example.org.			 3600 IN NS	ns1.example.org.
 a.example.org.		   	 3600 IN A	192.168.0.1
 a.example.org.		   	 3600 IN A	192.168.0.2
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone b/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
index ef5f887..59dda88 100644
--- a/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
@@ -1,5 +1,6 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 69 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone b/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
index 1c780b1..3ea070f 100644
--- a/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
@@ -1,7 +1,8 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 74 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 75 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
 ns1.example.org.		      3600 IN RRSIG	A 7 2 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
diff --git a/src/lib/datasrc/tests/memory/testdata/rrset-collection.zone b/src/lib/datasrc/tests/memory/testdata/rrset-collection.zone
new file mode 100644
index 0000000..332848f
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/rrset-collection.zone
@@ -0,0 +1,4 @@
+example.org.	     3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 72 3600 300 3600000 3600
+example.org.	     3600 IN NS		ns1.example.org.
+www.example.org.     3600 IN A		192.0.2.6
+www.example.org.     3600 IN AAAA	2001:db8::6
diff --git a/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
index 02ad2bd..921ca68 100644
--- a/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
+++ b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
@@ -194,8 +194,14 @@ checkBasicFields(const AbstractRRset& actual_rrset, const RdataSet* rdataset,
 // a temporary non-copyable object.
 boost::shared_ptr<TreeNodeRRset>
 createRRset(const RRClass& rrclass, const ZoneNode* node,
-            const RdataSet* rdataset, bool dnssec_ok)
+            const RdataSet* rdataset, bool dnssec_ok,
+            const void* ttl_data = NULL)
 {
+    if (ttl_data) {
+        return (boost::shared_ptr<TreeNodeRRset>(
+                    new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok,
+                                      ttl_data)));
+    }
     return (boost::shared_ptr<TreeNodeRRset>(
                 new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok)));
 }
@@ -243,6 +249,13 @@ TEST_F(TreeNodeRRsetTest, create) {
                                   true),
                      wildcard_rdataset_, match_name_, rrclass_, RRType::A(),
                      3600, 2, 1);
+
+    // Constructed with explicit TTL
+    const uint32_t ttl = 0;     // use 0 to avoid byte-order conversion
+    checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true,
+                                  &ttl),
+                     a_rdataset_, www_name_, rrclass_, RRType::A(), 0, 2,
+                     1);
 }
 
 // The following two templated functions are helper to encapsulate the
@@ -337,6 +350,25 @@ TEST_F(TreeNodeRRsetTest, toWire) {
     }
 
     {
+        SCOPED_TRACE("with RRSIG, DNSSEC OK, explicit TTL");
+        const uint32_t ttl = 0;
+        const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true,
+                                  &ttl);
+        // We need separate variable for the following two: SunStudio cannot
+        // automatically promote RRsetPtr to ConstRRsetPtr in the templated
+        // function.
+        ConstRRsetPtr expected_rrset =
+            textToRRset("www.example.com. 0 IN A 192.0.2.1\n"
+                        "www.example.com. 0 IN A 192.0.2.2");
+        ConstRRsetPtr expected_rrsig_rrset =
+            textToRRset("www.example.com. 0 IN RRSIG "
+                        "A 5 2 3600 20120814220826 "
+                        "20120715220826 1234 example.com. FAKE");
+        checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_,
+                          expected_rrset, expected_rrsig_rrset, true);
+    }
+
+    {
         SCOPED_TRACE("with RRSIG, DNSSEC not OK");
         const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, false);
         checkToWireResult(expected_renderer, actual_renderer, rrset,
@@ -396,7 +428,7 @@ TEST_F(TreeNodeRRsetTest, toWire) {
         const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   true);
         checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,true);
+                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_, true);
     }
 
     {
@@ -407,7 +439,7 @@ TEST_F(TreeNodeRRsetTest, toWire) {
         const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   false);
         checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,false);
+                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_, false);
     }
 }
 
@@ -522,6 +554,14 @@ TEST_F(TreeNodeRRsetTest, toText) {
     // Constructed with RRSIG, and it should be visible.
     checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true),
                 a_rrset_, a_rrsig_rrset_);
+    // Same as the previous, but with explicit TTL.
+    const uint32_t ttl = 0;
+    checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true, &ttl),
+                textToRRset("www.example.com. 0 IN A 192.0.2.1\n"
+                            "www.example.com. 0 IN A 192.0.2.2"),
+                textToRRset("www.example.com. 0 IN RRSIG A 5 2 3600 "
+                            "20120814220826 20120715220826 1234 example.com. "
+                            "FAKE"));
     // Constructed with RRSIG, and it should be invisible.
     checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, false),
                 a_rrset_, ConstRRsetPtr());
@@ -556,6 +596,11 @@ TEST_F(TreeNodeRRsetTest, isSameKind) {
     EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
                                               a_rdataset_, true)));
 
+    // Similar to the previous, but with explicit (different TTL) => still same
+    const uint32_t ttl = 0;
+    EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
+                                              a_rdataset_, true, &ttl)));
+
     // Same name (node), different type (rdataset) => not same kind
     EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
                                                aaaa_rdataset_, true)));
diff --git a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
index c005bf1..abc6f13 100644
--- a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
@@ -12,13 +12,15 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <dns/name.h>
-#include <dns/rrclass.h>
-
+#include <datasrc/memory/zone_data_loader.h>
 #include <datasrc/memory/rdataset.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/zone_data_updater.h>
-#include <datasrc/memory/zone_data_loader.h>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
 
 #include "memory_segment_test.h"
 
@@ -62,4 +64,13 @@ TEST_F(ZoneDataLoaderTest, loadRRSIGFollowsNothing) {
     // Teardown checks for memory segment leaks
 }
 
+TEST_F(ZoneDataLoaderTest, zoneMinTTL) {
+    // This should hold outside of the loader class, but we do double check.
+    zone_data_ = loadZoneData(mem_sgmt_, zclass_, Name("example.org"),
+                              TEST_DATA_DIR
+                              "/example.org-nsec3-signed.zone");
+    isc::util::InputBuffer b(zone_data_->getMinTTLData(), sizeof(uint32_t));
+    EXPECT_EQ(RRTTL(1200), RRTTL(b));
+}
+
 }
diff --git a/src/lib/datasrc/tests/memory/zone_data_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
index 1605fa2..ffbd0f6 100644
--- a/src/lib/datasrc/tests/memory/zone_data_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
@@ -12,19 +12,22 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/memory/rdataset.h>
+
 #include "memory_segment_test.h"
 
 #include <dns/rdataclass.h>
 
 #include <exceptions/exceptions.h>
 
+#include <util/buffer.h>
+
 #include <dns/name.h>
 #include <dns/labelsequence.h>
 #include <dns/rrclass.h>
-
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/zone_data.h>
+#include <dns/rrttl.h>
 
 #include <testutils/dnsmessage_test.h>
 
@@ -258,4 +261,21 @@ TEST_F(ZoneDataTest, isSigned) {
     zone_data_->setSigned(false);
     EXPECT_FALSE(zone_data_->isSigned());
 }
+
+// A simple wrapper to reconstruct an RRTTL object from wire-format TTL
+// data (32 bits)
+RRTTL
+createRRTTL(const void* ttl_data) {
+    isc::util::InputBuffer b(ttl_data, sizeof(uint32_t));
+    return (RRTTL(b));
+}
+
+TEST_F(ZoneDataTest, minTTL) {
+    // By default it's tentatively set to "max TTL"
+    EXPECT_EQ(RRTTL::MAX_TTL(), createRRTTL(zone_data_->getMinTTLData()));
+
+    // Explicitly set, then retrieve it.
+    zone_data_->setMinTTL(1200);
+    EXPECT_EQ(RRTTL(1200), createRRTTL(zone_data_->getMinTTLData()));
+}
 }
diff --git a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
index 63c69c8..93ca0c9 100644
--- a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
@@ -12,6 +12,10 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/rdataset.h>
+#include <datasrc/memory/zone_data.h>
+
 #include <testutils/dnsmessage_test.h>
 
 #include <exceptions/exceptions.h>
@@ -19,10 +23,7 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrset.h>
-
-#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/zone_data_updater.h>
+#include <dns/rrttl.h>
 
 #include "memory_segment_test.h"
 
@@ -86,6 +87,16 @@ getNode(isc::util::MemorySegment& mem_sgmt, const Name& name,
     return (node);
 }
 
+TEST_F(ZoneDataUpdaterTest, zoneMinTTL) {
+    // If we add SOA, zone's min TTL will be updated.
+    updater_->add(textToRRset(
+                      "example.org. 3600 IN SOA . . 0 0 0 0 1200",
+                      zclass_, zname_),
+                  ConstRRsetPtr());
+    isc::util::InputBuffer b(zone_data_->getMinTTLData(), sizeof(uint32_t));
+    EXPECT_EQ(RRTTL(1200), RRTTL(b));
+}
+
 TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
     // RRSIG that doesn't have covered RRset can be added.  The resulting
     // rdataset won't have "normal" RDATA but sig RDATA.
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index 42667da..b1ebaf4 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -53,19 +53,6 @@ namespace {
 using result::SUCCESS;
 using result::EXIST;
 
-/// \brief expensive rrset converter
-///
-/// converts any specialized rrset (which may not have implemented some
-/// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
-/// checks.
-///
-/// Done very inefficiently through text representation, speed should not
-/// be a concern here.
-ConstRRsetPtr
-convertRRset(ConstRRsetPtr src) {
-    return (textToRRset(src->toText()));
-}
-
 /// \brief Test fixture for the InMemoryZoneFinder class
 class InMemoryZoneFinderTest : public ::testing::Test {
     // A straightforward pair of textual RR(set) and a RRsetPtr variable
@@ -105,7 +92,6 @@ protected:
                           ZoneFinder::FindResultFlags expected_flags =
                           ZoneFinder::RESULT_DEFAULT);
 
-public:
     InMemoryZoneFinderTest() :
         class_(RRClass::IN()),
         origin_("example.org"),
@@ -119,13 +105,14 @@ public:
         // Note that this contains an out-of-zone RR, and due to the
         // validation check of masterLoad() used below, we cannot add SOA.
         const RRsetData zone_data[] = {
+            {"example.org. 300 IN SOA . . 0 0 0 0 100", &rr_soa_},
             {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
             {"example.org. 300 IN A 192.0.2.1", &rr_a_},
             {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
             // This one will place rr_ns_a_ at a zone cut, making it a glue:
-            {"ns.example.org. 300 IN NS 192.0.2.2", &rr_ns_ns_},
+            {"ns.example.org. 300 IN NS 192.0.2.2.", &rr_ns_ns_},
             {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
-            {"cname.example.org. 300 IN CNAME canonical.example.org",
+            {"cname.example.org. 300 IN CNAME canonical.example.org.",
              &rr_cname_},
             {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
             {"dname.example.org. 300 IN DNAME target.example.org.",
@@ -185,7 +172,18 @@ public:
         };
 
         for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
-            *zone_data[i].rrset = textToRRset(zone_data[i].text);
+            if (zone_data[i].rrset == &rr_soa_) {
+                // This is zone's SOA.  We need to specify the origin for
+                // textToRRset; otherwise it would throw.
+                *zone_data[i].rrset = textToRRset(zone_data[i].text, class_,
+                                                  origin_);
+            } else {
+                // For other data, we should rather omit the origin (the root
+                // name will be used by default); there's some out-of-zone
+                // name, which would trigger an exception if we specified
+                // origin_.
+                *zone_data[i].rrset = textToRRset(zone_data[i].text);
+            }
         }
 
     }
@@ -200,6 +198,24 @@ public:
         updater_.add(rrset, rrset->getRRsig());
     }
 
+    /// \brief expensive rrset converter
+    ///
+    /// converts any specialized rrset (which may not have implemented some
+    /// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
+    /// checks.
+    ///
+    /// Done very inefficiently through text representation, speed should not
+    /// be a concern here.
+    ConstRRsetPtr
+    convertRRset(ConstRRsetPtr src) {
+        // If the type is SOA, textToRRset performs a stricter check, so we
+        // should specify the origin.  For now we don't use out-of-zone
+        // owner names (e.g. for pathological cases) with this method, so it
+        // works for all test data.  If future changes break this assumption
+        // we should adjust it.
+        return (textToRRset(src->toText(), class_, origin_));
+    }
+
     // Some data to test with
     const RRClass class_;
     const Name origin_;
@@ -218,6 +234,8 @@ public:
     RRsetPtr
         // Out of zone RRset
         rr_out_,
+        // SOA of example.org
+        rr_soa_,
         // NS of example.org
         rr_ns_,
         // A of ns.example.org
@@ -293,75 +311,110 @@ public:
         if (zone_finder == NULL) {
             zone_finder = &zone_finder_;
         }
-        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
-            RRsetPtr(); // note we use the same type as of retval of getRRsig()
         // The whole block is inside, because we need to check the result and
         // we can't assign to FindResult
         EXPECT_NO_THROW({
                 ZoneFinderContextPtr find_result(zone_finder->find(
                                                      name, rrtype, options));
-                // Check it returns correct answers
-                EXPECT_EQ(result, find_result->code);
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-                          find_result->isWildcard());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                          != 0, find_result->isNSECSigned());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                          != 0, find_result->isNSEC3Signed());
-                if (check_answer) {
-                    if (!answer) {
-                        ASSERT_FALSE(find_result->rrset);
-                    } else {
-                        ASSERT_TRUE(find_result->rrset);
-                        ConstRRsetPtr result_rrset(
-                            convertRRset(find_result->rrset));
-                        rrsetCheck(answer, result_rrset);
-                        if (answer_sig &&
-                            (options & ZoneFinder::FIND_DNSSEC) != 0) {
-                            ASSERT_TRUE(result_rrset->getRRsig());
-                            rrsetCheck(answer_sig, result_rrset->getRRsig());
-                        } else {
-                            EXPECT_FALSE(result_rrset->getRRsig());
-                        }
-                    }
-                } else if (check_wild_answer) {
-                    ASSERT_NE(ConstRRsetPtr(), answer) <<
-                        "Wrong test, don't check for wild names if you expect "
-                        "empty answer";
-                    ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
-                        "No answer found";
-                    // Build the expected answer using the given name and
-                    // other parameter of the base wildcard RRset.
-                    RRsetPtr wildanswer(new RRset(name, answer->getClass(),
-                                                  answer->getType(),
-                                                  answer->getTTL()));
-                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
-                    for (; !expectedIt->isLast(); expectedIt->next()) {
-                        wildanswer->addRdata(expectedIt->getCurrent());
-                    }
-
-                    ConstRRsetPtr result_rrset(
-                        convertRRset(find_result->rrset));
-                    rrsetCheck(wildanswer, result_rrset);
-
-                    // Same for the RRSIG, if any.
-                    if (answer_sig) {
-                        ASSERT_TRUE(result_rrset->getRRsig());
-
-                        RRsetPtr wildsig(new RRset(name,
-                                                   answer_sig->getClass(),
-                                                   RRType::RRSIG(),
-                                                   answer_sig->getTTL()));
-                        RdataIteratorPtr expectedIt(
-                            answer_sig->getRdataIterator());
-                        for (; !expectedIt->isLast(); expectedIt->next()) {
-                            wildsig->addRdata(expectedIt->getCurrent());
-                        }
-                        rrsetCheck(wildsig, result_rrset->getRRsig());
-                    }
-                }
+                findTestCommon(name, result, find_result, check_answer,
+                               answer, expected_flags, options,
+                               check_wild_answer);
             });
     }
+
+    void findAtOriginTest(const RRType& rrtype,
+                          ZoneFinder::Result result,
+                          bool check_answer = true,
+                          const ConstRRsetPtr& answer = ConstRRsetPtr(),
+                          ZoneFinder::FindResultFlags expected_flags =
+                          ZoneFinder::RESULT_DEFAULT,
+                          memory::InMemoryZoneFinder* zone_finder = NULL,
+                          ZoneFinder::FindOptions options =
+                          ZoneFinder::FIND_DEFAULT,
+                          bool use_minttl = false)
+    {
+        SCOPED_TRACE("findAtOriginTest for " + rrtype.toText());
+
+        if (zone_finder == NULL) {
+            zone_finder = &zone_finder_;
+        }
+        ZoneFinderContextPtr find_result(zone_finder->findAtOrigin(
+                                             rrtype, use_minttl, options));
+        findTestCommon(origin_, result, find_result, check_answer, answer,
+                       expected_flags, options, false);
+    }
+
+private:
+    void findTestCommon(const Name& name, ZoneFinder::Result result,
+                        ZoneFinderContextPtr find_result,
+                        bool check_answer,
+                        const ConstRRsetPtr& answer,
+                        ZoneFinder::FindResultFlags expected_flags,
+                        ZoneFinder::FindOptions options,
+                        bool check_wild_answer)
+    {
+        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
+            RRsetPtr(); // note we use the same type as of retval of getRRsig()
+
+        // Check it returns correct answers
+        EXPECT_EQ(result, find_result->code);
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+                  find_result->isWildcard());
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
+                  find_result->isNSECSigned());
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
+                  find_result->isNSEC3Signed());
+        if (check_answer) {
+            if (!answer) {
+                ASSERT_FALSE(find_result->rrset);
+            } else {
+                ASSERT_TRUE(find_result->rrset);
+                ConstRRsetPtr result_rrset(convertRRset(find_result->rrset));
+                rrsetCheck(answer, result_rrset);
+                if (answer_sig && (options & ZoneFinder::FIND_DNSSEC) != 0) {
+                    ASSERT_TRUE(result_rrset->getRRsig());
+                    rrsetCheck(answer_sig, result_rrset->getRRsig());
+                } else {
+                    EXPECT_FALSE(result_rrset->getRRsig());
+                }
+            }
+        } else if (check_wild_answer) {
+            ASSERT_NE(ConstRRsetPtr(), answer) <<
+                "Wrong test, don't check for wild names if you expect "
+                "empty answer";
+            ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
+                "No answer found";
+            // Build the expected answer using the given name and
+            // other parameter of the base wildcard RRset.
+            RRsetPtr wildanswer(new RRset(name, answer->getClass(),
+                                          answer->getType(),
+                                          answer->getTTL()));
+            RdataIteratorPtr expectedIt(answer->getRdataIterator());
+            for (; !expectedIt->isLast(); expectedIt->next()) {
+                wildanswer->addRdata(expectedIt->getCurrent());
+            }
+
+            ConstRRsetPtr result_rrset(convertRRset(find_result->rrset));
+            rrsetCheck(wildanswer, result_rrset);
+
+            // Same for the RRSIG, if any.
+            if (answer_sig) {
+                ASSERT_TRUE(result_rrset->getRRsig());
+
+                RRsetPtr wildsig(new RRset(name, answer_sig->getClass(),
+                                           RRType::RRSIG(),
+                                           answer_sig->getTTL()));
+                RdataIteratorPtr expectedIt(
+                    answer_sig->getRdataIterator());
+                for (; !expectedIt->isLast(); expectedIt->next()) {
+                    wildsig->addRdata(expectedIt->getCurrent());
+                }
+                rrsetCheck(wildsig, result_rrset->getRRsig());
+            }
+        }
+    }
+
+protected:
     /**
      * \brief Calls the findAll on the finder and checks the result.
      */
@@ -389,14 +442,23 @@ public:
         }
         EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
                   find_result->isWildcard());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                  != 0, find_result->isNSECSigned());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                  != 0, find_result->isNSEC3Signed());
-        // Convert all rrsets to 'full' ones before checking
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
+                  find_result->isNSECSigned());
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
+                  find_result->isNSEC3Signed());
+        // Convert all rrsets to 'full' ones before checking.  Also, confirm
+        // each RRset of the vector is of the "same kind" as one would be
+        // found by the find() method.
         std::vector<ConstRRsetPtr> converted_rrsets;
         BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
             converted_rrsets.push_back(convertRRset(cur_rrset));
+
+            // As we know findAll() succeeded, this find() should also
+            // succeed, and the two sets should be "identical".
+            const ZoneFinderContextPtr result =
+                finder->find(name, cur_rrset->getType());
+            ASSERT_TRUE(result->rrset);
+            EXPECT_TRUE(result->rrset->isSameKind(*cur_rrset));
         }
         rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
                     converted_rrsets.begin(), converted_rrsets.end());
@@ -583,7 +645,6 @@ TEST_F(InMemoryZoneFinderTest, glue) {
     findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
              true, rr_child_ns_);
 
-
     // If we do it in the "glue OK" mode, we should find the exact match.
     findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
              rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
@@ -619,6 +680,101 @@ TEST_F(InMemoryZoneFinderTest, glue) {
              NULL, ZoneFinder::FIND_GLUE_OK);
 }
 
+TEST_F(InMemoryZoneFinderTest, findAtOrigin) {
+    // Add origin NS.
+    rr_ns_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                "NS 5 3 3600 20120814220826 20120715220826 "
+                                "1234 example.org. FAKE"));
+    addToZoneData(rr_ns_);
+
+    // Specified type of RR exists, no DNSSEC
+    findAtOriginTest(RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
+
+    // Specified type of RR exists, with DNSSEC
+    findAtOriginTest(RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_,
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, no DNSSEC
+    findAtOriginTest(RRType::TXT(), ZoneFinder::NXRRSET);
+
+    // Specified type of RR doesn't exist, with DNSSEC.  First, make the
+    // zone "NSEC-signed", then check.
+    rr_nsec_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                   "NSEC 5 3 3600 20120814220826 "
+                                   "20120715220826 1234 example.org. FAKE"));
+    addToZoneData(rr_nsec_);
+    findAtOriginTest(RRType::TXT(), ZoneFinder::NXRRSET, true, rr_nsec_,
+                     ZoneFinder::RESULT_NSEC_SIGNED, NULL,
+                     ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, with DNSSEC, enabling NSEC3.  First,
+    // make the zone "NSEC3-signed" (by just installing NSEC3PARAM; we don't
+    // need to add NSEC3s for the purpose of this test), then check.
+    addToZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
+                            "1 0 12 aabbccdd"));
+    findAtOriginTest(RRType::TXT(), ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
+                     ZoneFinder::RESULT_NSEC3_SIGNED, NULL,
+                     ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_F(InMemoryZoneFinderTest, findAtOriginWithMinTTL) {
+    // Install zone's SOA.  This also sets internal zone data min TTL field.
+    addToZoneData(rr_soa_);
+
+    // Specify the use of min TTL, then the resulting TTL should be derived
+    // from the SOA MINTTL (which is smaller).
+    findAtOriginTest(RRType::SOA(), ZoneFinder::SUCCESS, true,
+                     textToRRset("example.org. 100 IN SOA . . 0 0 0 0 100",
+                                 class_, origin_),
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DEFAULT, true);
+
+    // Add signed NS for the following test.
+    RRsetPtr ns_rrset(textToRRset("example.org. 300 IN NS ns.example.org."));
+    ns_rrset->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                   "NS 5 3 3600 20120814220826 20120715220826 "
+                                   "1234 example.org. FAKE"));
+    addToZoneData(ns_rrset);
+
+    // If DNSSEC is requested, TTL of the RRSIG should also be the min.
+    ns_rrset->setTTL(RRTTL(100));      // reset TTL to the expected one
+    findAtOriginTest(RRType::NS(), ZoneFinder::SUCCESS, true, ns_rrset,
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DEFAULT, true);
+
+    // If we don't request the use of min TTL, the original TTL will be used.
+    findAtOriginTest(RRType::SOA(), ZoneFinder::SUCCESS, true, rr_soa_,
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DEFAULT, false);
+
+    // If the found RRset has a smaller TTL than SOA, the original TTL should
+    // win.
+    rr_a_->setTTL(RRTTL(10));
+    addToZoneData(rr_a_);
+    findAtOriginTest(RRType::A(), ZoneFinder::SUCCESS, true, rr_a_,
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DEFAULT, true);
+
+    // If no RRset is returned, use_minttl doesn't matter (it shouldn't cause
+    // disruption)
+    findAtOriginTest(RRType::TXT(), ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
+                     ZoneFinder::RESULT_DEFAULT, NULL,
+                     ZoneFinder::FIND_DEFAULT, true);
+
+    // If it results in NXRRSET with NSEC, and if we specify the use of min
+    // TTL, the NSEC and RRSIG should have the min TTL (again, though, this
+    // use case is not really the intended one)
+    rr_nsec_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                   "NSEC 5 3 3600 20120814220826 "
+                                   "20120715220826 1234 example.org. FAKE"));
+    addToZoneData(rr_nsec_);
+    rr_nsec_->setTTL(RRTTL(100)); // reset it to the expected one
+    findAtOriginTest(RRType::TXT(), ZoneFinder::NXRRSET, true, rr_nsec_,
+                     ZoneFinder::RESULT_NSEC_SIGNED, NULL,
+                     ZoneFinder::FIND_DNSSEC, true);
+}
+
 /**
  * \brief Test searching.
  *
@@ -986,21 +1142,42 @@ InMemoryZoneFinderTest::wildcardCheck(
     }
 }
 
+// We have combinations of these cases (6 in total)
+// expected_flags: NSEC, NSEC3, RESULT_DEFAULT
+// options: NO_WILDCARD, FIND_DEFAULT
+
+// 1. Normal case: expected = DEFAULT, options = DEFAULT
 TEST_F(InMemoryZoneFinderTest, wildcard) {
-    // Normal case
     wildcardCheck();
 }
 
+// 2. options: expected = DEFAULT, options = NO_WILDCARD
+TEST_F(InMemoryZoneFinderTest, wildcardDisabled) {
+    // Similar to the previous once, but check the behavior for a non signed
+    // zone just in case.
+    wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
+}
+
+// 3. options: expected = NSEC_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardWithNSEC) {
+    wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DEFAULT);
+}
+
+// 4. options: expected = NSEC_SIGNED, options = NO_WILDCARD
 TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
     // Wildcard is disabled.  In practice, this is used as part of query
     // processing for an NSEC-signed zone, so we test that case specifically.
     wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
 }
 
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
-    // Similar to the previous once, but check the behavior for a non signed
-    // zone just in case.
-    wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
+// 5. options: expected = NSEC3_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardWithNSEC3) {
+    wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DEFAULT);
+}
+
+// 6. options: expected = NSEC3_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC3) {
+    wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::NO_WILDCARD);
 }
 
 /*
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
deleted file mode 100644
index 85be310..0000000
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ /dev/null
@@ -1,2246 +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 "faked_nsec3.h"
-
-#include <exceptions/exceptions.h>
-
-#include <dns/masterload.h>
-#include <dns/name.h>
-#include <dns/nsec3hash.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrttl.h>
-#include <dns/masterload.h>
-
-#include <datasrc/client.h>
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
-
-#include "test_client.h"
-
-#include <testutils/dnsmessage_test.h>
-
-#include <gtest/gtest.h>
-
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <sstream>
-#include <vector>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-using namespace isc::testutils;
-using boost::shared_ptr;
-using namespace isc::datasrc::test;
-
-namespace {
-// Commonly used result codes (Who should write the prefix all the time)
-using result::SUCCESS;
-using result::EXIST;
-
-class InMemoryClientTest : public ::testing::Test {
-protected:
-    InMemoryClientTest() : rrclass(RRClass::IN())
-    {}
-    RRClass rrclass;
-    InMemoryClient memory_client;
-};
-
-TEST_F(InMemoryClientTest, add_find_Zone) {
-    // test add zone
-    // Bogus zone (NULL)
-    EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
-                 isc::InvalidParameter);
-
-    // add zones with different names one by one
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("a")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("b")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("c")))));
-    // add zones with the same name suffix
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("x.d.e.f")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("o.w.y.d.e.f")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("p.w.y.d.e.f")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("q.w.y.d.e.f")))));
-    // add super zone and its subzone
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("g.h")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                               Name("i.g.h")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("z.d.e.f")))));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("j.z.d.e.f")))));
-
-    // different zone class isn't allowed.
-    EXPECT_EQ(result::EXIST, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("q.w.y.d.e.f")))));
-
-    // names are compared in a case insensitive manner.
-    EXPECT_EQ(result::EXIST, memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("Q.W.Y.d.E.f")))));
-
-    // test find zone
-    EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
-    EXPECT_EQ(Name("a"),
-              memory_client.findZone(Name("a")).zone_finder->getOrigin());
-
-    EXPECT_EQ(result::SUCCESS,
-              memory_client.findZone(Name("j.z.d.e.f")).code);
-    EXPECT_EQ(Name("j.z.d.e.f"),
-              memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
-                  getOrigin());
-
-    // NOTFOUND
-    EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
-    EXPECT_EQ(ConstZoneFinderPtr(),
-              memory_client.findZone(Name("d.e.f")).zone_finder);
-
-    EXPECT_EQ(result::NOTFOUND,
-              memory_client.findZone(Name("w.y.d.e.f")).code);
-    EXPECT_EQ(ConstZoneFinderPtr(),
-              memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
-
-    // there's no exact match.  the result should be the longest match,
-    // and the code should be PARTIALMATCH.
-    EXPECT_EQ(result::PARTIALMATCH,
-              memory_client.findZone(Name("j.g.h")).code);
-    EXPECT_EQ(Name("g.h"),
-              memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
-
-    EXPECT_EQ(result::PARTIALMATCH,
-              memory_client.findZone(Name("z.i.g.h")).code);
-    EXPECT_EQ(Name("i.g.h"),
-              memory_client.findZone(Name("z.i.g.h")).zone_finder->
-                  getOrigin());
-}
-
-TEST_F(InMemoryClientTest, iterator) {
-    // Just some preparations of data
-    boost::shared_ptr<InMemoryZoneFinder>
-        zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
-    RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
-                                  RRTTL(300)));
-    aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
-    RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
-                                  RRTTL(300)));
-    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
-    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
-    RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
-                                  RRTTL(300)));
-    subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
-    // First, the zone is not there, so it should throw
-    EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
-    // This zone is not there either, even when there's a zone containing this
-    EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
-    // Now, an empty zone
-    ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-    // It throws Unexpected when we are past the end
-    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
-    EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
-    EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
-    EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
-
-    // Check it with full zone.
-    vector<ConstRRsetPtr> expected_rrsets;
-    expected_rrsets.push_back(aRRsetA);
-    expected_rrsets.push_back(aRRsetAAAA);
-    expected_rrsets.push_back(subRRsetA);
-
-    iterator = memory_client.getIterator(Name("a"));
-    vector<ConstRRsetPtr> actual_rrsets;
-    ConstRRsetPtr actual;
-    while ((actual = iterator->getNextRRset()) != NULL) {
-        actual_rrsets.push_back(actual);
-    }
-
-    rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
-                actual_rrsets.begin(), actual_rrsets.end());
-
-}
-
-TEST_F(InMemoryClientTest, iterator_separate_rrs) {
-    // Exactly the same tests as for iterator, but now with separate_rrs = true
-    // For the one that returns actual data, the AAAA should now be split up
-    boost::shared_ptr<InMemoryZoneFinder>
-        zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
-    RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
-                                  RRTTL(300)));
-    aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
-    RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
-                                  RRTTL(300)));
-    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
-    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
-    RRsetPtr aRRsetAAAA_r1(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
-                                  RRTTL(300)));
-    aRRsetAAAA_r1->addRdata(rdata::in::AAAA("2001:db8::1"));
-    RRsetPtr aRRsetAAAA_r2(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
-                                  RRTTL(300)));
-    aRRsetAAAA_r2->addRdata(rdata::in::AAAA("2001:db8::2"));
-
-    RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
-                                  RRTTL(300)));
-    subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
-    EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
-
-    // First, the zone is not there, so it should throw
-    EXPECT_THROW(memory_client.getIterator(Name("b"), true), DataSourceError);
-    // This zone is not there either, even when there's a zone containing this
-    EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
-    // Now, an empty zone
-    ZoneIteratorPtr iterator(memory_client.getIterator(Name("a"), true));
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-    // It throws Unexpected when we are past the end
-    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
-
-    ASSERT_EQ(result::SUCCESS, zone->add(aRRsetA));
-    ASSERT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
-    ASSERT_EQ(result::SUCCESS, zone->add(subRRsetA));
-    // Check it with full zone, one by one.
-    // It should be in ascending order in case of InMemory data source
-    // (isn't guaranteed in general)
-    iterator = memory_client.getIterator(Name("a"), true);
-    EXPECT_EQ(aRRsetA->toText(), iterator->getNextRRset()->toText());
-    EXPECT_EQ(aRRsetAAAA_r1->toText(), iterator->getNextRRset()->toText());
-    EXPECT_EQ(aRRsetAAAA_r2->toText(), iterator->getNextRRset()->toText());
-    EXPECT_EQ(subRRsetA->toText(), iterator->getNextRRset()->toText());
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-}
-
-TEST_F(InMemoryClientTest, getZoneCount) {
-    EXPECT_EQ(0, memory_client.getZoneCount());
-    memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
-                                                       Name("example.com"))));
-    EXPECT_EQ(1, memory_client.getZoneCount());
-
-    // duplicate add.  counter shouldn't change
-    memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
-                                                       Name("example.com"))));
-    EXPECT_EQ(1, memory_client.getZoneCount());
-
-    // add one more
-    memory_client.addZone(
-                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
-                                                       Name("example.org"))));
-    EXPECT_EQ(2, memory_client.getZoneCount());
-}
-
-TEST_F(InMemoryClientTest, startUpdateZone) {
-    EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
-                 isc::NotImplemented);
-}
-
-// Commonly used RRSIG data
-const char* const rrsig_a_txt =
-    "example.org. 300 IN RRSIG A 5 3 3600 20000101000000 20000201000000 12345 "
-    "example.org. FAKEFAKEFAKE\n";
-const char* const rrsig_ns_txt =
-    "example.org. 300 IN RRSIG NS 5 3 3600 20000101000000 20000201000000 "
-    "54321 example.org. FAKEFAKEFAKEFAKE\n";
-// This RRset has two RRSIGs
-const char* const rrsig_aaaa_txt =
-    "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
-    "12345 example.org. FAKEFAKEFAKE\n"
-    "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
-    "54321 example.org. FAKEFAKEFAKEFAKE\n";
-
-// A helper callback of masterLoad() used in InMemoryZoneFinderTest.
-void
-setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
-    *(*it) = rrset;
-    ++it;
-}
-
-/// \brief Test fixture for the InMemoryZoneFinder class
-class InMemoryZoneFinderTest : public ::testing::Test {
-    // A straightforward pair of textual RR(set) and a RRsetPtr variable
-    // to store the RRset.  Used to build test data below.
-    struct RRsetData {
-        const char* const text; // textual representation of an RRset
-        RRsetPtr* rrset;
-    };
-protected:
-    // The following sub tests are shared by multiple test cases, changing
-    // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
-    // expected_flags is set to either RESULT_NSEC_SIGNED or
-    // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
-    // find() is expected to set the corresponding flags.
-    // find_options should be set to FIND_DNSSEC for NSEC-signed case when
-    // NSEC is expected to be returned.
-    void findCheck(ZoneFinder::FindResultFlags expected_flags =
-                   ZoneFinder::RESULT_DEFAULT,
-                   ZoneFinder::FindOptions find_options =
-                   ZoneFinder::FIND_DEFAULT);
-    void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
-                        ZoneFinder::RESULT_DEFAULT);
-    void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                       ZoneFinder::RESULT_DEFAULT,
-                       ZoneFinder::FindOptions find_options =
-                       ZoneFinder::FIND_DEFAULT);
-    void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                               ZoneFinder::RESULT_DEFAULT,
-                               ZoneFinder::FindOptions find_options =
-                               ZoneFinder::FIND_DEFAULT);
-    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                          ZoneFinder::RESULT_DEFAULT);
-    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                            ZoneFinder::RESULT_DEFAULT);
-    void findNSECENTCheck(const Name& ent_name,
-                          ConstRRsetPtr expected_nsec,
-                          ZoneFinder::FindResultFlags expected_flags =
-                          ZoneFinder::RESULT_DEFAULT);
-
-public:
-    InMemoryZoneFinderTest() :
-        class_(RRClass::IN()),
-        origin_("example.org"),
-        zone_finder_(class_, origin_)
-    {
-        // Build test RRsets.  Below, we construct an RRset for
-        // each textual RR(s) of zone_data, and assign it to the corresponding
-        // rr_xxx.
-        // Note that this contains an out-of-zone RR, and due to the
-        // validation check of masterLoad() used below, we cannot add SOA.
-        const RRsetData zone_data[] = {
-            {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
-            {"example.org. 300 IN A 192.0.2.1", &rr_a_},
-            {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
-            {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
-            {"cname.example.org. 300 IN CNAME canonical.example.org",
-             &rr_cname_},
-            {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
-            {"dname.example.org. 300 IN DNAME target.example.org.",
-             &rr_dname_},
-            {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
-            {"dname.example.org. 300 IN NS ns.dname.example.org.",
-             &rr_dname_ns_},
-            {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
-            {"child.example.org. 300 IN NS ns.child.example.org.",
-             &rr_child_ns_},
-            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
-             &rr_child_ds_},
-            {"ns.child.example.org. 300 IN A 192.0.2.153",
-             &rr_child_glue_},
-            {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
-             &rr_grandchild_ns_},
-            {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
-             &rr_grandchild_glue_},
-            {"dname.child.example.org. 300 IN DNAME example.com.",
-             &rr_child_dname_},
-            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
-            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
-            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
-             &rr_cnamewild_},
-            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
-            {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
-            {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
-             &rr_nested_emptywild_},
-            {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
-            {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
-             &rr_dnamewild_},
-            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
-            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
-            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
-             &rr_not_wild_another_},
-            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
-             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
-             &rr_nsec3_},
-            {"example.org. 300 IN NSEC wild.*.foo.example.org. "
-             "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
-            // Together with the apex NSEC, these next NSECs make a complete
-            // chain in the case of the zone for the emptyNonterminal tests
-            // (We may want to clean up this generator code and/or masterLoad
-            // so that we can prepare conflicting datasets better)
-            {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
-             "A RRSIG NSEC", &rr_ent_nsec2_},
-            {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
-             &rr_ent_nsec3_},
-            {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
-             &rr_ent_nsec4_},
-            // And these are NSECs used in different tests
-            {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
-             &rr_ns_nsec_},
-            {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
-             &rr_wild_nsec_},
-            {NULL, NULL}
-        };
-
-        stringstream zone_data_stream;
-        vector<RRsetPtr*> rrsets;
-        for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
-            zone_data_stream << zone_data[i].text << "\n";
-            rrsets.push_back(zone_data[i].rrset);
-        }
-
-        masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
-                   boost::bind(setRRset, _1, rrsets.begin()));
-    }
-
-    ~InMemoryZoneFinderTest() {
-        // Make sure we reset the hash creator to the default
-        setNSEC3HashCreator(NULL);
-    }
-
-    // Some data to test with
-    const RRClass class_;
-    const Name origin_;
-    // The zone finder to torture by tests
-    InMemoryZoneFinder zone_finder_;
-
-    // Placeholder for storing RRsets to be checked with rrsetsCheck()
-    vector<ConstRRsetPtr> actual_rrsets_;
-
-    /*
-     * Some RRsets to put inside the zone.
-     */
-    RRsetPtr
-        // Out of zone RRset
-        rr_out_,
-        // NS of example.org
-        rr_ns_,
-        // A of ns.example.org
-        rr_ns_a_,
-        // AAAA of ns.example.org
-        rr_ns_aaaa_,
-        // A of example.org
-        rr_a_;
-    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
-    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
-    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
-    RRsetPtr rr_dname_a_; // for mixed DNAME + A case
-    RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
-    RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
-    RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
-    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
-    RRsetPtr rr_child_glue_; // glue RR of the child domain
-    RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
-    RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
-    RRsetPtr rr_child_dname_; // A DNAME under NS
-    RRsetPtr rr_wild_;        // Wildcard record
-    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
-    RRsetPtr rr_emptywild_;
-    RRsetPtr rr_nested_emptywild_;
-    RRsetPtr rr_nswild_, rr_dnamewild_;
-    RRsetPtr rr_child_wild_;
-    RRsetPtr rr_under_wild_;
-    RRsetPtr rr_not_wild_;
-    RRsetPtr rr_not_wild_another_;
-    RRsetPtr rr_nsec3_;
-    RRsetPtr rr_nsec_;
-    RRsetPtr rr_ent_nsec2_;
-    RRsetPtr rr_ent_nsec3_;
-    RRsetPtr rr_ent_nsec4_;
-    RRsetPtr rr_ns_nsec_;
-    RRsetPtr rr_wild_nsec_;
-
-    // A faked NSEC3 hash calculator for convenience.
-    // Tests that need to use the faked hashed values should call
-    // setNSEC3HashCreator() with a pointer to this variable at the beginning
-    // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
-    TestNSEC3HashCreator nsec3_hash_creator_;
-
-    /**
-     * \brief Test one find query to the zone finder.
-     *
-     * Asks a query to the zone finder and checks it does not throw and returns
-     * expected results. It returns nothing, it just signals failures
-     * to GTEST.
-     *
-     * \param name The name to ask for.
-     * \param rrtype The RRType to ask of.
-     * \param result The expected code of the result.
-     * \param check_answer Should a check against equality of the answer be
-     *     done?
-     * \param answer The expected rrset, if any should be returned.
-     * \param expected_flags The expected result flags returned via find().
-     *     These can be tested using isWildcard() etc.
-     * \param zone_finder Check different InMemoryZoneFinder object than
-     *     zone_finder_ (if NULL, uses zone_finder_)
-     * \param check_wild_answer Checks that the answer has the same RRs, type
-     *     class and TTL as the eqxpected answer and that the name corresponds
-     *     to the one searched. It is meant for checking answers for wildcard
-     *     queries.
-     */
-    void findTest(const Name& name, const RRType& rrtype,
-                  ZoneFinder::Result result,
-                  bool check_answer = true,
-                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
-                  ZoneFinder::FindResultFlags expected_flags =
-                  ZoneFinder::RESULT_DEFAULT,
-                  InMemoryZoneFinder* zone_finder = NULL,
-                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
-                  bool check_wild_answer = false)
-    {
-        SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
-
-        if (zone_finder == NULL) {
-            zone_finder = &zone_finder_;
-        }
-        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
-            RRsetPtr(); // note we use the same type as of retval of getRRsig()
-        // The whole block is inside, because we need to check the result and
-        // we can't assign to FindResult
-        EXPECT_NO_THROW({
-                ZoneFinderContextPtr find_result(zone_finder->find(
-                                                     name, rrtype, options));
-                // Check it returns correct answers
-                EXPECT_EQ(result, find_result->code);
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-                          find_result->isWildcard());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                          != 0, find_result->isNSECSigned());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                          != 0, find_result->isNSEC3Signed());
-                if (check_answer) {
-                    if (!answer) {
-                        ASSERT_FALSE(find_result->rrset);
-                    } else {
-                        ASSERT_TRUE(find_result->rrset);
-                        rrsetCheck(answer, find_result->rrset);
-                        if (answer_sig) {
-                            ASSERT_TRUE(find_result->rrset->getRRsig());
-                            rrsetCheck(answer_sig,
-                                       find_result->rrset->getRRsig());
-                        }
-                    }
-                } else if (check_wild_answer) {
-                    ASSERT_NE(ConstRRsetPtr(), answer) <<
-                        "Wrong test, don't check for wild names if you expect "
-                        "empty answer";
-                    ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
-                        "No answer found";
-                    // Build the expected answer using the given name and
-                    // other parameter of the base wildcard RRset.
-                    RRsetPtr wildanswer(new RRset(name, answer->getClass(),
-                                                  answer->getType(),
-                                                  answer->getTTL()));
-                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
-                    for (; !expectedIt->isLast(); expectedIt->next()) {
-                        wildanswer->addRdata(expectedIt->getCurrent());
-                    }
-                    rrsetCheck(wildanswer, find_result->rrset);
-
-                    // Same for the RRSIG, if any.
-                    if (answer_sig) {
-                        ASSERT_TRUE(find_result->rrset->getRRsig());
-
-                        RRsetPtr wildsig(new RRset(name,
-                                                   answer_sig->getClass(),
-                                                   RRType::RRSIG(),
-                                                   answer_sig->getTTL()));
-                        RdataIteratorPtr expectedIt(
-                            answer_sig->getRdataIterator());
-                        for (; !expectedIt->isLast(); expectedIt->next()) {
-                            wildsig->addRdata(expectedIt->getCurrent());
-                        }
-                        rrsetCheck(wildsig, find_result->rrset->getRRsig());
-                    }
-                }
-            });
-    }
-    /**
-     * \brief Calls the findAll on the finder and checks the result.
-     */
-    void findAllTest(const Name& name, ZoneFinder::Result result,
-                     const vector<ConstRRsetPtr>& expected_rrsets,
-                     ZoneFinder::FindResultFlags expected_flags =
-                     ZoneFinder::RESULT_DEFAULT,
-                     InMemoryZoneFinder* finder = NULL,
-                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
-                     ZoneFinder::FindOptions options =
-                     ZoneFinder::FIND_DEFAULT)
-    {
-        if (finder == NULL) {
-            finder = &zone_finder_;
-        }
-        std::vector<ConstRRsetPtr> target;
-        ZoneFinderContextPtr find_result(finder->findAll(name, target,
-                                                         options));
-        EXPECT_EQ(result, find_result->code);
-        if (!rrset_result) {
-            EXPECT_FALSE(find_result->rrset);
-        } else {
-            ASSERT_TRUE(find_result->rrset);
-            rrsetCheck(rrset_result, find_result->rrset);
-        }
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-                  find_result->isWildcard());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                  != 0, find_result->isNSECSigned());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                  != 0, find_result->isNSEC3Signed());
-        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
-                    target.begin(), target.end());
-    }
-};
-
-/**
- * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
- *
- * Takes the created zone finder and checks its properties they are the same
- * as passed parameters.
- */
-TEST_F(InMemoryZoneFinderTest, constructor) {
-    ASSERT_EQ(class_, zone_finder_.getClass());
-    ASSERT_EQ(origin_, zone_finder_.getOrigin());
-}
-/**
- * \brief Test adding.
- *
- * We test that it throws at the correct moments and the correct exceptions.
- * And we test the return value.
- */
-TEST_F(InMemoryZoneFinderTest, add) {
-    // This one does not belong to this zone
-    EXPECT_THROW(zone_finder_.add(rr_out_), OutOfZone);
-    // Test null pointer
-    EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
-                 InMemoryZoneFinder::NullRRset);
-
-    // Now put all the data we have there. It should throw nothing
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
-
-    // Try putting there something twice, it should be rejected
-    EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
-    EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
-}
-
-TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
-    rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
-    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
-    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
-    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
-    // CNAME and RRSIG can coexist
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
-                              "3600 20000101000000 20000201000000 12345 "
-                              "example.org. FAKEFAKEFAKE")));
-
-    // Same for NSEC
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname.example.org. 300 IN NSEC "
-                              "dname.example.org. CNAME RRSIG NSEC")));
-
-    // Same as above, but adding NSEC first.
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname2.example.org. 300 IN NSEC "
-                              "dname.example.org. CNAME RRSIG NSEC")));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname2.example.org. 300 IN CNAME c.example.")));
-
-    // If there's another type of RRset with NSEC, it should still fail.
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname3.example.org. 300 IN A 192.0.2.1")));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(
-                  textToRRset("cname3.example.org. 300 IN NSEC "
-                              "dname.example.org. CNAME RRSIG NSEC")));
-    EXPECT_THROW(zone_finder_.add(textToRRset("cname3.example.org. 300 "
-                                              "IN CNAME c.example.")),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, findCNAME) {
-    // install CNAME RR
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
-
-    // Find A RR of the same.  Should match the CNAME
-    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
-             rr_cname_);
-
-    // Find the CNAME itself.  Should result in normal SUCCESS
-    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
-             rr_cname_);
-}
-
-TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
-    // There's nothing special when we find a CNAME under a zone cut
-    // (with FIND_GLUE_OK).  The behavior is different from BIND 9,
-    // so we test this case explicitly.
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
-    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
-        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
-    findTest(Name("cname.child.example.org"), RRType::AAAA(),
-             ZoneFinder::CNAME, true, rr_cname_under_cut_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-// Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
-// Having a CNAME there is disallowed too, but it is tested by
-// addOtherThenCNAME and addCNAMEThenOther.
-TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
-    rr_dname_->addRdata(generic::DNAME("target2.example.org."));
-    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
-}
-
-/*
- * These two tests ensure that we can't have DNAME and NS at the same
- * node with the exception of the apex of zone (forbidden by RFC 2672)
- */
-TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
-    EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
-    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
-}
-
-// It is allowed to have NS and DNAME at apex
-TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-
-    // The NS should be possible to be found, below should be DNAME, not
-    // delegation
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-    findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
-             rr_dname_apex_);
-}
-
-TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
-}
-
-// TODO: Test (and implement) adding data under DNAME. That is forbidden by
-// 2672 as well.
-
-// Search under a DNAME record. It should return the DNAME
-TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
-    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
-             true, rr_dname_);
-}
-
-// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
-// influences only the data below (see RFC 2672, section 3)
-TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
-
-    const Name dname_name(rr_dname_->getName());
-    findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
-    findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
-             rr_dname_);
-    findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
-}
-
-// Try searching something that is both under NS and DNAME, without and with
-// GLUE_OK mode (it should stop at the NS and DNAME respectively).
-TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
-    zone_finder_.add(rr_child_ns_);
-    zone_finder_.add(rr_child_dname_);
-
-    Name lowName("below.dname.child.example.org.");
-
-    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
-    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-// Test adding child zones and zone cut handling
-TEST_F(InMemoryZoneFinderTest, delegationNS) {
-    // add in-zone data
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-
-    // install a zone cut
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
-
-    // below the zone cut
-    findTest(Name("www.child.example.org"), RRType::A(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-
-    // at the zone cut
-    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-
-    // finding NS for the apex (origin) node.  This must not be confused
-    // with delegation due to the existence of an NS RR.
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-
-    // unusual case of "nested delegation": the highest cut should be used.
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
-    findTest(Name("www.grand.child.example.org"), RRType::A(),
-             // note: !rr_grandchild_ns_
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-}
-
-TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
-    // Similar setup to the previous one, but with DS RR at the delegation
-    // point.
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));
-
-    // Normal types of query should result in delegation, but DS query
-    // should be considered in-zone (but only exactly at the delegation point).
-    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
-             true, rr_child_ds_);
-    findTest(Name("grand.child.example.org"), RRType::DS(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-
-    // There's nothing special for DS query at the zone apex.  It would
-    // normally result in NXRRSET.
-    findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
-             true, ConstRRsetPtr());
-}
-
-TEST_F(InMemoryZoneFinderTest, findAny) {
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
-
-    vector<ConstRRsetPtr> expected_sets;
-
-    // origin
-    expected_sets.push_back(rr_a_);
-    expected_sets.push_back(rr_ns_);
-    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
-
-    // out zone name
-    EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
-                             vector<ConstRRsetPtr>()),
-                 OutOfZone);
-
-    expected_sets.clear();
-    expected_sets.push_back(rr_child_glue_);
-    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
-
-    // add zone cut
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
-
-    // zone cut
-    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
-                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
-                NULL, rr_child_ns_);
-
-    // glue for this zone cut
-    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
-                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
-                NULL, rr_child_ns_);
-}
-
-TEST_F(InMemoryZoneFinderTest, glue) {
-    // install zone data:
-    // a zone cut
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
-    // glue for this cut
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
-    // a nested zone cut (unusual)
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
-    // glue under the deeper zone cut
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
-
-    // by default glue is hidden due to the zone cut
-    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-
-
-    // If we do it in the "glue OK" mode, we should find the exact match.
-    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
-             rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // glue OK + NXRRSET case
-    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
-             true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // glue OK + NXDOMAIN case
-    findTest(Name("www.child.example.org"), RRType::A(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-
-    // nested cut case.  The glue should be found.
-    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
-             ZoneFinder::SUCCESS,
-             true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // A non-existent name in nested cut.  This should result in delegation
-    // at the highest zone cut.
-    findTest(Name("www.grand.child.example.org"), RRType::TXT(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-/**
- * \brief Test searching.
- *
- * Check it finds or does not find correctly and does not throw exceptions.
- * \todo This doesn't do any kind of CNAME and so on. If it isn't
- *     directly there, it just tells it doesn't exist.
- */
-void
-InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
-                                  ZoneFinder::FindOptions find_options)
-{
-    // Fill some data inside
-    // Now put all the data we have there. It should throw nothing
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
-    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    }
-
-    // These two should be successful
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-    findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
-             rr_ns_a_);
-
-    // These domains don't exist. (and one is out of the zone).  In an
-    // NSEC-signed zone with DNSSEC records requested, it should return the
-    // covering NSEC for the query name (the actual NSEC in the test data may
-    // not really "cover" it, but for the purpose of this test it's okay).
-    ConstRRsetPtr expected_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-        expected_nsec = rr_nsec_;
-    }
-
-    // There's no other name between this one and the origin, so when NSEC
-    // is to be returned it should be the origin NSEC.
-    findTest(Name("nothere.example.org"), RRType::A(),
-             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-             NULL, find_options);
-
-    // The previous name in the zone is "ns.example.org", but it doesn't
-    // have an NSEC.  It should be skipped and the origin NSEC will be
-    // returned as the "closest NSEC".
-    findTest(Name("nxdomain.example.org"), RRType::A(),
-             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-             NULL, find_options);
-    EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
-                 OutOfZone);
-
-    // These domain exist but don't have the provided RRType.  For the latter
-    // one we now add its NSEC (which was delayed so that it wouldn't break
-    // other cases above).
-    findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags, NULL, find_options);
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_nsec_));
-        if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-            expected_nsec = rr_ns_nsec_;
-        }
-    }
-    findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags, NULL, find_options);
-}
-
-TEST_F(InMemoryZoneFinderTest, find) {
-    findCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
-    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
-    // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
-    // anything (the NSEC3_SIGNED flag is always set, and no records are
-    // returned for negative cases regardless).
-    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
-    // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
-    findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Generalized test for Empty Nonterminal (ENT) cases with NSEC
-void
-InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
-    ConstRRsetPtr expected_nsec,
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
-
-    // Sanity check: Should result in NXRRSET
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-    // Sanity check: No NSEC added yet
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags,
-             NULL, ZoneFinder::FIND_DNSSEC);
-
-    // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
-    // there are no sigs)
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ent_nsec2_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ent_nsec3_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ent_nsec4_));
-
-    // Should result in NXRRSET, and RESULT_NSEC_SIGNED
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(),
-             expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
-
-    // And check for the NSEC if DNSSEC_OK
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
-             NULL, ZoneFinder::FIND_DNSSEC);
-}
-
-TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
-    // Non-wildcard case
-    findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
-}
-
-TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminalWildcard) {
-    // Wildcard case, above actual wildcard
-    findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
-}
-
-TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminalAtWildcard) {
-    // Wildcard case, at actual wildcard
-    findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
-                     ZoneFinder::RESULT_WILDCARD);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
-    // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
-    findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
-}
-
-void
-InMemoryZoneFinderTest::emptyNodeCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    /*
-     * The backend RBTree for this test should look like as follows:
-     *          example.org
-     *               |
-     *              baz (empty; easy case)
-     *            /  |  \
-     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
-     *              bbb
-     *             /
-     *           aaa
-     */
-
-    // Construct the test zone
-    const char* const names[] = {
-        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
-        "bbb.baz.example.org.", NULL};
-    for (int i = 0; names[i] != NULL; ++i) {
-        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
-                                          " 300 IN A 192.0.2.1");
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    }
-
-    // empty node matching, easy case: the node for 'baz' exists with
-    // no data.
-    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-
-    // empty node matching, a trickier case: the node for 'foo' is part of
-    // "x.foo", which should be considered an empty node.
-    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-
-    // "org" is contained in "example.org", but it shouldn't be treated as
-    // NXRRSET because it's out of zone.
-    // Note: basically we don't expect such a query to be performed (the common
-    // operation is to identify the best matching zone first then perform
-    // search it), but we shouldn't be confused even in the unexpected case.
-    EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNode) {
-    emptyNodeCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
-    emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
-    emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, load) {
-    // Put some data inside the zone
-    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
-    // Loading with different origin should fail
-    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
-                 MasterLoadError);
-    // See the original data is still there, survived the exception
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-    // Create correct zone
-    InMemoryZoneFinder rootzone(class_, Name("."));
-    // Try putting something inside
-    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
-    // Load the zone. It should overwrite/remove the above RRset
-    EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
-
-    // Now see there are some rrsets (we don't look inside, though)
-    findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
-    findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
-    findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
-             false, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
-    // But this should no longer be here
-    findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
-
-    // Try loading zone that is wrong in a different way
-    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
-                 MasterLoadError);
-}
-
-TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
-    // The initial test set doesn't have SOA at the apex.
-    findTest(origin_, RRType::SOA(), ZoneFinder::NXRRSET, false,
-             ConstRRsetPtr());
-
-    // The content of the new version of zone to be first installed to
-    // the SQLite3 data source, then to in-memory via SQLite3.  The data are
-    // chosen to cover major check points of the implementation:
-    // - the previously non-existent record is added (SOA)
-    // - An RRSIG is given from the iterator before the RRset it covers
-    //   (RRSIG for SOA, because they are sorted by name then rrtype as text)
-    // - An RRset containing multiple RRs (ns1/A)
-    // - RRSIGs for different owner names
-    stringstream ss;
-    const char* const soa_txt = "example.org. 300 IN SOA . . 0 0 0 0 0\n";
-    const char* const soa_sig_txt = "example.org. 300 IN RRSIG SOA 5 3 300 "
-        "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
-    const char* const a_txt =
-        "ns1.example.org. 300 IN A 192.0.2.1\n"
-        "ns1.example.org. 300 IN A 192.0.2.2\n";
-    const char* const a_sig_txt = "ns1.example.org. 300 IN RRSIG A 5 3 300 "
-        "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
-    ss << soa_txt << soa_sig_txt << a_txt << a_sig_txt;
-    shared_ptr<DataSourceClient> db_client = unittest::createSQLite3Client(
-        class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied", ss);
-    zone_finder_.load(*db_client->getIterator(origin_));
-
-    // The new content should be visible, including the previously-nonexistent
-    // SOA.
-    RRsetPtr expected_answer = textToRRset(soa_txt, RRClass::IN(), origin_);
-    expected_answer->addRRsig(textToRRset(soa_sig_txt));
-    findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, true,
-             expected_answer, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_DNSSEC);
-
-    expected_answer = textToRRset(a_txt);
-    expected_answer->addRRsig(textToRRset(a_sig_txt));
-    findTest(Name("ns1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
-             expected_answer, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_DNSSEC);
-
-    // File name should be (re)set to empty.
-    EXPECT_TRUE(zone_finder_.getFileName().empty());
-
-    // Loading the zone with an iterator separating RRs of the same RRset
-    // will fail because the resulting sequence doesn't meet assumptions of
-    // the (current) in-memory implementation.
-    EXPECT_THROW(zone_finder_.load(*db_client->getIterator(origin_, true)),
-                 MasterLoadError);
-
-    // Load the zone from a file that contains more realistic data (borrowed
-    // from a different test).  There's nothing special in this case for the
-    // purpose of this test, so it should just succeed.
-    db_client = unittest::createSQLite3Client(
-        class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
-        TEST_DATA_DIR "/contexttest-almost-obsolete.zone");
-    zone_finder_.load(*db_client->getIterator(origin_));
-
-    // just checking a couple of RRs in the new version of zone.
-    findTest(Name("mx1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
-             textToRRset("mx1.example.org. 3600 IN A 192.0.2.10"));
-    findTest(Name("ns1.example.org"), RRType::AAAA(), ZoneFinder::SUCCESS,
-             true, textToRRset("ns1.example.org. 3600 IN AAAA 2001:db8::1"));
-}
-
-/*
- * Test that puts a (simple) wildcard into the zone and checks we can
- * correctly find the data.
- */
-void
-InMemoryZoneFinderTest::wildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags,
-    ZoneFinder::FindOptions find_options)
-{
-    /*
-     *            example.org.
-     *                 |
-     *             [cname]wild (not *.wild, should have wild mark)
-     *                 |
-     *                 *
-     */
-
-    // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
-    // add RRSIGs to the records.
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
-        (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        // Convenience shortcut.  The RDATA is not really validatable, but
-        // it doesn't matter for our tests.
-        const char* const rrsig_common = "5 3 3600 "
-            "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
-
-        find_options = find_options | ZoneFinder::FIND_DNSSEC;
-        rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
-                                       string(rrsig_common)));
-        rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
-                                            "RRSIG CNAME " +
-                                            string(rrsig_common)));
-    }
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
-    // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
-    // (the content of the NSEC3 shouldn't matter)
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    }
-
-    // Search at the parent. The parent will not have the A, but it will
-    // be in the wildcard (so check the wildcard isn't matched at the parent)
-    {
-        SCOPED_TRACE("Search at parent");
-        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-            findTest(Name("wild.example.org"), RRType::A(),
-                     ZoneFinder::NXRRSET, true, rr_nsec_, expected_flags,
-                     NULL, find_options);
-        } else {
-            findTest(Name("wild.example.org"), RRType::A(),
-                     ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
-                     expected_flags, NULL, find_options);
-        }
-    }
-
-    // For the test setup of "NSEC-signed" zone, we might expect it will
-    // be returned with a negative result, either because wildcard match is
-    // disabled by the search option or because wildcard match is canceled
-    // per protocol.
-    ConstRRsetPtr expected_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-        expected_nsec = rr_nsec_;
-    }
-    // Explicitly converting the following to const pointers; some compilers
-    // would complain about mixed use of const and non const in ?: below.
-    const ConstRRsetPtr rr_wild = rr_wild_;
-    const ConstRRsetPtr rr_cnamewild = rr_cnamewild_;
-
-    // Search the original name of wildcard
-    {
-        SCOPED_TRACE("Search directly at *");
-        findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
-                 true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
-                 find_options);
-    }
-
-    // Below some of the test cases will normally result in a wildcard match;
-    // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
-    // and, when available and requested, the covering NSEC will be returned.
-    // The following are shortcut parameters to unify these cases.
-    const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
-    const ZoneFinder::FindResultFlags wild_expected_flags =
-        wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
-        expected_flags;
-
-    // Search "created" name.
-    {
-        SCOPED_TRACE("Search at created child");
-        findTest(Name("a.wild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_wild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    // Search name that has CNAME.
-    {
-        SCOPED_TRACE("Matching CNAME");
-        findTest(Name("a.cnamewild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_cnamewild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    // Search another created name, this time little bit lower
-    {
-        SCOPED_TRACE("Search at created grand-child");
-        findTest(Name("a.b.wild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_wild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
-    {
-        SCOPED_TRACE("Search under non-wildcard");
-        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-    }
-
-    // Wildcard match, but no data.  We add the additional NSEC at the wildcard
-    // at this point so that it wouldn't break other tests above.  Note also
-    // that in the NO_WILDCARD case the resulting NSEC is the same.  Ideally
-    // we could use a more tricky setup so we can distinguish these cases,
-    // but for this purpose it's not bad; what we'd like to test here is that
-    // wildcard substitution doesn't happen for either case, and the
-    // NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
-    ConstRRsetPtr expected_wild_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_nsec_));
-        expected_wild_nsec = rr_wild_nsec_;
-    }
-    {
-        SCOPED_TRACE("Search at wildcard, no data");
-        findTest(Name("a.wild.example.org"), RRType::AAAA(),
-                 wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
-                 wild_ok ? expected_wild_nsec : expected_wild_nsec,
-                 wild_expected_flags, NULL, find_options);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcard) {
-    // Normal case
-    wildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardNSEC3) {
-    // Similar to the previous one, but the zone signed with NSEC3
-    wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardNSEC) {
-    // Similar to the previous one, but the zone is signed with NSEC
-    wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
-    // Wildcard is disabled.  In practice, this is used as part of query
-    // processing for an NSEC-signed zone, so we test that case specifically.
-    wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
-    // Similar to the previous once, but check the behavior for a non signed
-    // zone just in case.
-    wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
-}
-
-/*
- * Test that we don't match a wildcard if we get under delegation.
- * By 4.3.3 of RFC1034:
- * "Wildcard RRs do not apply:
- *   - When the query is in another zone.  That is, delegation cancels
- *     the wildcard defaults."
- */
-TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
-
-    {
-        SCOPED_TRACE("Looking under delegation point");
-        findTest(Name("a.child.example.org"), RRType::A(),
-                 ZoneFinder::DELEGATION, true, rr_child_ns_);
-    }
-
-    {
-        SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
-        findTest(Name("a.child.example.org"), RRType::A(),
-                 ZoneFinder::DELEGATION, true, rr_child_ns_,
-                 ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-    }
-}
-
-// Tests combination of wildcard and ANY.
-void
-InMemoryZoneFinderTest::anyWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    }
-
-    vector<ConstRRsetPtr> expected_sets;
-
-    // First try directly the name (normal match)
-    {
-        SCOPED_TRACE("Asking directly for *");
-        expected_sets.push_back(rr_wild_);
-        findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
-                    expected_sets);
-    }
-
-    // Then a wildcard match
-    {
-        SCOPED_TRACE("Asking in the wild way");
-        expected_sets.clear();
-        RRsetPtr expected(new RRset(Name("a.wild.example.org"),
-                                    rr_wild_->getClass(), rr_wild_->getType(),
-                                    rr_wild_->getTTL()));
-        expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
-        expected_sets.push_back(expected);
-        findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
-                    expected_sets,
-                    ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcard) {
-    anyWildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
-    anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
-    anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Test there's nothing in the wildcard in the middle if we load
-// wild.*.foo.example.org.
-void
-InMemoryZoneFinderTest::emptyWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    /*
-     *            example.org.
-     *                foo
-     *                 *
-     *               wild
-     */
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-    }
-
-    {
-        SCOPED_TRACE("Asking for the original record under wildcard");
-        findTest(Name("wild.*.foo.example.org"), RRType::A(),
-                 ZoneFinder::SUCCESS, true, rr_emptywild_);
-    }
-
-    {
-        SCOPED_TRACE("Asking for A record");
-        findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(),
-                 ZoneFinder::RESULT_WILDCARD | expected_flags);
-        findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(), expected_flags);
-        findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(), expected_flags);
-    }
-
-    {
-        SCOPED_TRACE("Asking for ANY record");
-        findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
-                    vector<ConstRRsetPtr>(), expected_flags);
-
-        findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
-                    vector<ConstRRsetPtr>(),
-                    ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-
-    {
-        SCOPED_TRACE("Asking on the non-terminal");
-        findTest(Name("wild.bar.foo.example.org"), RRType::A(),
-                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
-                 ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
-    emptyWildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
-    emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
-    emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Same as emptyWildcard, but with multiple * in the path.
-TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
-
-    {
-        SCOPED_TRACE("Asking for the original record under wildcards");
-        findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
-            ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
-    }
-
-    {
-        SCOPED_TRACE("Matching wildcard against empty nonterminal");
-
-        const char* names[] = {
-            "baz.foo.*.bar.example.org",
-            "baz.foo.baz.bar.example.org",
-            "*.foo.baz.bar.example.org",
-            NULL
-        };
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
-                     ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
-        }
-    }
-
-    // Domains to test
-    const char* names[] = {
-        "*.foo.*.bar.example.org",
-        "foo.*.bar.example.org",
-        "*.bar.example.org",
-        "bar.example.org",
-        NULL
-    };
-
-    {
-        SCOPED_TRACE("Asking directly for A on parent nodes");
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
-        }
-    }
-
-    {
-        SCOPED_TRACE("Asking for ANY on parent nodes");
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-
-            findAllTest(Name(*name), ZoneFinder::NXRRSET,
-                        vector<ConstRRsetPtr>());
-        }
-    }
-}
-
-// We run this part twice from the below test, in two slightly different
-// situations
-void
-InMemoryZoneFinderTest::doCancelWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags,
-    ZoneFinder::FindOptions find_options)
-{
-    // These should be canceled
-    {
-        SCOPED_TRACE("Canceled under foo.wild.example.org");
-
-        // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
-        // should be returned.  The expected NSEC is actually just the only
-        // NSEC in the test data, but in this context it doesn't matter;
-        // it's sufficient just to check any NSEC is returned (or not).
-        ConstRRsetPtr expected_nsec; // by default it's NULL
-        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-            (find_options & ZoneFinder::FIND_DNSSEC)) {
-            expected_nsec = rr_nsec_;
-        }
-
-        findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-        findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-    }
-
-    // This is existing, non-wildcard domain, shouldn't wildcard at all
-    {
-        SCOPED_TRACE("Existing domain under foo.wild.example.org");
-        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::SUCCESS, true, rr_not_wild_);
-    }
-
-    // These should be caught by the wildcard
-    {
-        SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
-
-        const char* names[] = {
-            "aaa.bbb.wild.example.org",
-            "aaa.zzz.wild.example.org",
-            "zzz.wild.example.org",
-            NULL
-        };
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-
-            findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
-                     rr_wild_,
-                     ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
-                     ZoneFinder::FIND_DEFAULT, true);
-        }
-    }
-
-    // This shouldn't be wildcarded, it's an existing domain
-    {
-        SCOPED_TRACE("The foo.wild.example.org itself");
-        findTest(Name("foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
-    }
-}
-
-/*
- * This tests that if there's a name between the wildcard domain and the
- * searched one, it will not trigger wildcard, for example, if we have
- * *.wild.example.org and bar.foo.wild.example.org, then we know
- * foo.wild.example.org exists and is not wildcard. Therefore, search for
- * aaa.foo.wild.example.org should return NXDOMAIN.
- *
- * Tests few cases "around" the canceled wildcard match, to see something that
- * shouldn't be canceled isn't.
- */
-TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck();
-    }
-
-    // Try putting another one under foo.wild....
-    // The result should be the same but it will be done in another way in the
-    // code, because the foo.wild.example.org will exist in the tree.
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck();
-    }
-}
-
-// Same tests as cancelWildcard for NSEC3-signed zone
-TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-    }
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-    }
-}
-
-// Same tests as cancelWildcard for NSEC-signed zone.  Check both cases with
-// or without FIND_DNSSEC option.  NSEC should be returned only when the option
-// is given.
-TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
-                              ZoneFinder::FIND_DNSSEC);
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-    }
-    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
-                              ZoneFinder::FIND_DNSSEC);
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
-    // We reject loading the zone if it contains a wildcard name for
-    // NS or DNAME.
-    EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
-    EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, swap) {
-    // build one zone finder with some data
-    InMemoryZoneFinder finder1(class_, origin_);
-    EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
-    EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
-
-    // build another zone finder of a different RR class with some other data
-    const Name other_origin("version.bind");
-    ASSERT_NE(origin_, other_origin); // make sure these two are different
-    InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
-    EXPECT_EQ(result::SUCCESS,
-              finder2.add(textToRRset("version.bind. 0 CH TXT \"test\"",
-                                      RRClass::CH())));
-
-    finder1.swap(finder2);
-    EXPECT_EQ(other_origin, finder1.getOrigin());
-    EXPECT_EQ(origin_, finder2.getOrigin());
-    EXPECT_EQ(RRClass::CH(), finder1.getClass());
-    EXPECT_EQ(RRClass::IN(), finder2.getClass());
-    // make sure the zone data is swapped, too
-    EXPECT_THROW(finder1.find(origin_, RRType::NS()), OutOfZone);
-    findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
-    EXPECT_THROW(finder2.find(other_origin, RRType::TXT()), OutOfZone);
-}
-
-TEST_F(InMemoryZoneFinderTest, getFileName) {
-    // for an empty zone the file name should also be empty.
-    EXPECT_TRUE(zone_finder_.getFileName().empty());
-
-    // if loading a zone fails the file name shouldn't be set.
-    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
-                 MasterLoadError);
-    EXPECT_TRUE(zone_finder_.getFileName().empty());
-
-    // after a successful load, the specified file name should be set
-    InMemoryZoneFinder rootzone(class_, Name("."));
-    EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
-    EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
-    // overriding load, which will fail
-    EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
-                 MasterLoadError);
-    // the file name should be intact.
-    EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
-
-    // After swap, file names should also be swapped.
-    zone_finder_.swap(rootzone);
-    EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
-    EXPECT_TRUE(rootzone.getFileName().empty());
-}
-
-TEST_F(InMemoryZoneFinderTest, addRRsig) {
-    // A simple valid case: adding an RRset to be signed followed by an RRSIG
-    // that covers the first RRset
-    zone_finder_.add(rr_a_);
-    zone_finder_.add(textToRRset(rrsig_a_txt));
-    ZoneFinderContextPtr result = zone_finder_.find(origin_, RRType::A(),
-                                                    ZoneFinder::FIND_DNSSEC);
-    EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
-    ASSERT_TRUE(result->rrset);
-    ASSERT_TRUE(result->rrset->getRRsig());
-    actual_rrsets_.push_back(result->rrset->getRRsig());
-    rrsetsCheck(rrsig_a_txt, actual_rrsets_.begin(), actual_rrsets_.end());
-
-    // Confirm a separate RRISG for a different type can be added
-    actual_rrsets_.clear();
-    zone_finder_.add(rr_ns_);
-    zone_finder_.add(textToRRset(rrsig_ns_txt));
-    result = zone_finder_.find(origin_, RRType::NS(), ZoneFinder::FIND_DNSSEC);
-    EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
-    ASSERT_TRUE(result->rrset);
-    ASSERT_TRUE(result->rrset->getRRsig());
-    actual_rrsets_.push_back(result->rrset->getRRsig());
-    rrsetsCheck(rrsig_ns_txt, actual_rrsets_.begin(), actual_rrsets_.end());
-
-    // Check a case with multiple RRSIGs
-    actual_rrsets_.clear();
-    zone_finder_.add(rr_ns_aaaa_);
-    zone_finder_.add(textToRRset(rrsig_aaaa_txt));
-    result = zone_finder_.find(Name("ns.example.org"), RRType::AAAA(),
-                               ZoneFinder::FIND_DNSSEC);
-    EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
-    ASSERT_TRUE(result->rrset);
-    ASSERT_TRUE(result->rrset->getRRsig());
-    actual_rrsets_.push_back(result->rrset->getRRsig());
-    rrsetsCheck(rrsig_aaaa_txt, actual_rrsets_.begin(), actual_rrsets_.end());
-}
-
-TEST_F(InMemoryZoneFinderTest, addRRsigWithoutCovered) {
-    // The current implementation rejects attempts of adding RRSIG without
-    // covered RRsets already in the zone.
-
-    // Name doesn't exist
-    EXPECT_THROW(zone_finder_.add(
-                     textToRRset("notexist.example.org. 300 IN RRSIG A 5 3 "
-                                 "3600 20000101000000 20000201000000 12345 "
-                                 "example.org. FAKEFAKEFAKE\n")),
-                 InMemoryZoneFinder::AddError);
-
-    // Name exists, but is empty.
-    zone_finder_.add(rr_emptywild_);
-    EXPECT_THROW(zone_finder_.add(
-                     textToRRset("foo.example.org. 300 IN RRSIG A 5 3 "
-                                 "3600 20000101000000 20000201000000 12345 "
-                                 "example.org. FAKEFAKEFAKE\n")),
-                 InMemoryZoneFinder::AddError);
-
-    // Add RRSIG RRset without covered RR
-    zone_finder_.add(rr_a_);
-    EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_ns_txt)),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
-    // Tests with other types of bogus input
-
-    // Empty RRSIG RRset.
-    EXPECT_THROW(zone_finder_.add(RRsetPtr(new RRset(origin_, class_,
-                                                     RRType::RRSIG(),
-                                                     RRTTL(300)))),
-                                  InMemoryZoneFinder::AddError);
-
-    // RRSIG with mixed covered types
-    zone_finder_.add(rr_a_);    // make sure the covered name exists
-    // textToRRset() doesn't work as intended for this pathological case,
-    // so we need to construct the RRset by hand.
-    RRsetPtr rrset(new RRset(origin_, class_, RRType::RRSIG(), RRTTL(300)));
-    rrset->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
-                                   "12345 example.org. FAKEFAKEFAKE"));
-    rrset->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
-                                   "54321 example.org. FAKEFAKEFAKEFAKE"));
-    EXPECT_THROW(zone_finder_.add(rrset), InMemoryZoneFinder::AddError);
-
-    // An attempt of overriding an existing RRSIG.  The current implementation
-    // prohibits that.
-    zone_finder_.add(textToRRset(rrsig_a_txt));
-    EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addNSEC3) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    const string nsec3_text = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    // This name shouldn't be found in the normal domain tree.
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
-    EXPECT_EQ(ZoneFinder::NXDOMAIN,
-              zone_finder_.find(Name(string(apex_hash) + ".example.org"),
-                                RRType::NSEC3())->code);
-    // Dedicated NSEC3 find should be able to find it.
-    findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
-                   zone_finder_.findNSEC3(Name("example.org"), false));
-
-    // This implementation rejects duplicate/update add of the same hash name
-    EXPECT_EQ(result::EXIST,
-              zone_finder_.add(textToRRset(
-                                   string(apex_hash) + ".example.org." +
-                                   string(nsec3_common) + " AAAA")));
-    // The original NSEC3 should be intact
-    findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
-                   zone_finder_.findNSEC3(Name("example.org"), false));
-
-    // NSEC3-like name but of ordinary RR type should go to normal tree.
-    const string nonsec3_text = string(apex_hash) + ".example.org. " +
-        "300 IN A 192.0.2.1";
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
-    EXPECT_EQ(ZoneFinder::SUCCESS,
-              zone_finder_.find(Name(string(apex_hash) + ".example.org"),
-                                RRType::A())->code);
-}
-
-TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Similar to the previous case, but NSEC3 owner name is lower-cased.
-    const string nsec3_text = string(apex_hash_lower) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
-    findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
-                   zone_finder_.findNSEC3(Name("example.org"), false));
-}
-
-TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Check that the internal storage ensures comparison based on the NSEC3
-    // semantics, regardless of the add order or the letter-case of hash.
-
-    // Adding "0P..", "2v..", then "2T..".
-    const string smallest = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    const string middle = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    const string largest = string(xyw_hash) + ".example.org." +
-        string(nsec3_common);
-    zone_finder_.add(textToRRset(smallest));
-    zone_finder_.add(textToRRset(largest));
-    zone_finder_.add(textToRRset(middle));
-
-    // Then look for NSEC3 that covers a name whose hash is "2S.."
-    // The covering NSEC3 should be "0P.."
-    findNSEC3Check(false, 4, smallest, "",
-                   zone_finder_.findNSEC3(Name("www.example.org"), false));
-
-    // Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
-    // The covering NSEC3 should be "2v.." in both cases
-    findNSEC3Check(false, 4, largest, "",
-                   zone_finder_.findNSEC3(Name("xxx.example.org"), false));
-    findNSEC3Check(false, 4, largest, "",
-                   zone_finder_.findNSEC3(Name("yyy.example.org"), false));
-}
-
-TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
-    // Our implementation refuses to load NSEC3 at a wildcard name
-    EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
-                                              string(nsec3_common))),
-                 InMemoryZoneFinder::AddError);
-
-    // Likewise, if the owner name of NSEC3 has too many labels, it's refused.
-    EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
-                                              ".example.org." +
-                                              string(nsec3_common))),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
-    // In this current implementation multiple NSEC3 RDATA isn't supported.
-    RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
-                             RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
-    nsec3->addRdata(
-        generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
-    nsec3->addRdata(
-        generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
-    EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Adding NSEC3 and its RRSIG
-    const string nsec3_text = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
-    const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
-        string(nsec3_rrsig_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
-
-    // Then look for it.  The NSEC3 should have the RRSIG that was just added.
-    findNSEC3Check(true, origin_.getLabelCount(),
-                   nsec3_text + "\n" + nsec3_rrsig_text, "",
-                   zone_finder_.findNSEC3(Name("example.org"), false));
-
-    // Duplicate add of RRSIG for the same NSEC3 is prohibited.
-    EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
-                 InMemoryZoneFinder::AddError);
-
-    // Same check using the lower-cased name.  This also confirms matching
-    // is case-insensitive.
-    EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
-                                              ".example.org."
-                                              + string(nsec3_rrsig_common))),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
-    // adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
-    // a space for NSEC3 namespace isn't yet allocated)
-    EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
-                                              ".example.org." +
-                                              string(nsec3_rrsig_common))),
-                 InMemoryZoneFinder::AddError);
-
-    // Add an NSEC3
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(
-                  textToRRset(string(apex_hash) + ".example.org." +
-                              string(nsec3_common))));
-
-    // Then add an NSEC3 for a non existent NSEC3.  It should fail in the
-    // current implementation.
-    EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
-                                              ".example.org." +
-                                              string(nsec3_rrsig_common))),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
-    // First, add an NSEC3PARAM RR
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                           "1 0 12 aabbccdd")));
-    // Adding an NSEC3 that has matching parameters is okay.
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(
-                  textToRRset(string(apex_hash) + ".example.org." +
-                              string(nsec3_common))));
-    // NSEC3 with inconsistent parameter will be rejected
-    EXPECT_THROW(zone_finder_.add(
-                     textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
-                                 "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
-    // Add an NSEC3 without adding NSEC3PARAM
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(
-                  textToRRset(string(apex_hash) + ".example.org." +
-                              string(nsec3_common))));
-    // Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
-    EXPECT_THROW(zone_finder_.add(
-                     textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
-                                 "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
-                 InMemoryZoneFinder::AddError);
-
-    // Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
-    EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                              "1 0 1 aabbccdd")),
-                 InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
-    // In this current implementation multiple NSEC3PARAM isn't supported.
-    RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
-                                  RRType::NSEC3PARAM(), RRTTL(300)));
-    nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
-    nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
-    EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
-}
-
-TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
-    // This is a normal NSEC3PARAM at the zone origin
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                           "1 0 12 aabbccdd")));
-    // Add another (with different param) at a non origin node.  This is
-    // awkward, but the implementation accepts it as an ordinary RR.
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
-                                           "1 1 1 aabbccdd")));
-}
-
-TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
-    // Check if it can load validly NSEC3-signed zone.  At this moment
-    // it's sufficient to see it doesn't crash
-    zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
-
-    // Reload the zone with a version that doesn't have NSEC3PARAM.
-    // This is an abnormal case, but the implementation accepts it.
-    zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
-}
-
-// This test checks that the NSEC3 names don't really exist in the real
-// namespace.
-TEST_F(InMemoryZoneFinderTest, queryToNSEC3Name) {
-    // Add the NSEC3 and NSEC3PARAM there.
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                           "1 0 12 aabbccdd")));
-    const Name nsec3domain(string(apex_hash) + ".example.org.");
-    // Adding an NSEC3 that has matching parameters is okay.
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(
-                  textToRRset(string(apex_hash) + ".example.org." +
-                              string(nsec3_common))));
-    // Now, the domain should not exist
-    findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXDOMAIN, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
-             ZoneFinder::FIND_DNSSEC);
-    // If we add an A record, the domain should exist
-    ConstRRsetPtr rrset(textToRRset(string(apex_hash) +
-                                    ".example.org. 300 IN A 192.0.2.1"));
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
-    // Searching for a different RRType will tell us this RRset doesn't exist
-    findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
-             ZoneFinder::FIND_DNSSEC);
-    // Searching for the A record would find it
-    findTest(nsec3domain, RRType::A(), ZoneFinder::SUCCESS, true,
-             rrset, ZoneFinder::RESULT_DEFAULT, &zone_finder_,
-             ZoneFinder::FIND_DNSSEC);
-}
-
-// Continuation of the previous test (queryToNSEC3Name), we check we don't break
-// the empty nonterminal case by existence of NSEC3 record with that name.
-TEST_F(InMemoryZoneFinderTest, queryToNSEC3NameNonterminal) {
-    // Add the NSEC3 and NSEC3PARAM there.
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                           "1 0 12 aabbccdd")));
-    const Name nsec3domain(string(apex_hash) + ".example.org.");
-    // Adding an NSEC3 that has matching parameters is okay.
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(
-                  textToRRset(string(apex_hash) + ".example.org." +
-                              string(nsec3_common))));
-    // Something below the name
-    ConstRRsetPtr rrset(textToRRset("below." + string(apex_hash) +
-                                    ".example.org. 300 IN A 192.0.2.1"));
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
-    // Now, the node is empty non-terminal.
-    findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
-             ZoneFinder::FIND_DNSSEC);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Add a few NSEC3 records:
-    // apex (example.org.): hash=0P..
-    // ns1.example.org:     hash=2T..
-    // w.example.org:       hash=01..
-    // zzz.example.org:     hash=R5..
-    const string apex_nsec3_text = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(apex_nsec3_text)));
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
-    const string w_nsec3_text = string(w_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(w_nsec3_text)));
-    const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text)));
-
-    performNSEC3Test(zone_finder_);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
-    // findNSEC3() should be rejected.
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-
-    // Only having NSEC3PARAM isn't enough
-    EXPECT_EQ(result::SUCCESS,
-              zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
-                                           "1 0 12 aabbccdd")));
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-
-    // Unless NSEC3 for apex is added the result in the recursive mode
-    // is guaranteed.
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-}
-
-TEST_F(InMemoryZoneFinderTest, loadAndFindNSEC3) {
-    // Using more realistic example, borrowed from RFC5155, with compliant
-    // hash calculator.  We only confirm the data source can load it
-    // successfully and find correct NSEC3 RRs for some selected cases
-    // (detailed tests have been done above).
-
-    InMemoryZoneFinder finder(class_, Name("example"));
-    finder.load(TEST_DATA_COMMONDIR "/rfc5155-example.zone.signed");
-
-    // See RFC5155 B.1
-    ZoneFinder::FindNSEC3Result result1 =
-        finder.findNSEC3(Name("c.x.w.example"), true);
-    ASSERT_TRUE(result1.closest_proof);
-    // We compare closest_labels as int so the error report will be more
-    // readable in case it fails.
-    EXPECT_EQ(4, static_cast<int>(result1.closest_labels));
-    EXPECT_EQ(Name("b4um86eghhds6nea196smvmlo4ors995.example"),
-              result1.closest_proof->getName());
-    ASSERT_TRUE(result1.next_proof);
-    EXPECT_EQ(Name("0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example"),
-              result1.next_proof->getName());
-
-    // See RFC5155 B.2.
-    ZoneFinder::FindNSEC3Result result2 =
-        finder.findNSEC3(Name("ns1.example"), true);
-    ASSERT_TRUE(result2.closest_proof);
-    EXPECT_EQ(3, static_cast<int>(result2.closest_labels));
-    EXPECT_EQ(Name("2t7b4g4vsa5smi47k61mv5bv1a22bojr.example"),
-              result2.closest_proof->getName());
-    ASSERT_FALSE(result2.next_proof);
-
-    // See RFC5155 B.5.
-    ZoneFinder::FindNSEC3Result result3 =
-        finder.findNSEC3(Name("a.z.w.example"), true);
-    ASSERT_TRUE(result3.closest_proof);
-    EXPECT_EQ(3, static_cast<int>(result3.closest_labels));
-    EXPECT_EQ(Name("k8udemvp1j2f7eg6jebps17vp3n8i58h.example"),
-              result3.closest_proof->getName());
-    ASSERT_TRUE(result3.next_proof);
-    EXPECT_EQ(Name("q04jkcevqvmu85r014c7dkba38o0ji5r.example"),
-              result3.next_proof->getName());
-}
-}
diff --git a/src/lib/datasrc/tests/rbnode_rrset_unittest.cc b/src/lib/datasrc/tests/rbnode_rrset_unittest.cc
deleted file mode 100644
index 57e8dbd..0000000
--- a/src/lib/datasrc/tests/rbnode_rrset_unittest.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright (C) 2012  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/rdataclass.h>
-#include <datasrc/rbnode_rrset.h>
-#include <testutils/dnsmessage_test.h>
-
-#include <dns/tests/unittest_util.h>
-
-#include <gtest/gtest.h>
-
-#include <sstream>
-#include <stdexcept>
-
-using isc::UnitTestUtil;
-
-using namespace isc;
-using namespace isc::datasrc;
-using namespace isc::datasrc::internal;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::testutils;
-using namespace isc::util;
-using namespace std;
-
-// These tests are very similar to those for RRset - indeed, this file was
-// created from those tests.  However, the significant difference in behaviour
-// between RRset and RBNodeRRset - that the "set" methods in the latter mostly
-// result in exceptions being thrown - preclude use of full type
-// parameterisation of the tests.
-
-namespace {
-const char* const RRSIG_TXT =
-    "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
-    "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
-    "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
-    "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-    "f49t+sXKPzbipN9g+s1ZPiIyofc=";
-
-class RBNodeRRsetTest : public ::testing::Test {
-protected:
-    RBNodeRRsetTest() :
-        test_name("test.example.com"),
-        test_domain("example.com"),
-        test_nsname("ns.example.com"),
-        rrset_a(ConstRRsetPtr(new RRset(
-                test_name, RRClass::IN(), RRType::A(), RRTTL(3600)))),
-        rrset_a_empty(ConstRRsetPtr(new RRset(
-                      test_name, RRClass::IN(), RRType::A(), RRTTL(3600)))),
-        rrset_ns(ConstRRsetPtr(new RRset(
-                 test_domain, RRClass::IN(), RRType::NS(), RRTTL(86400)))),
-        rrset_ch_txt(ConstRRsetPtr(new RRset(
-                     test_domain, RRClass::CH(), RRType::TXT(), RRTTL(0)))),
-        rrset_siga(new RRset(test_name, RRClass::IN(), RRType::RRSIG(),
-                   RRTTL(3600)))
-
-    {
-        // Add a couple of Rdata elements to the A RRset.  The easiest way to
-        // do this is to override the "const" restrictions.  As this is a test,
-        // we don't feel too bad about doing so.
-        AbstractRRset* a_rrset =
-            const_cast<AbstractRRset*>(rrset_a.getUnderlyingRRset().get());
-        a_rrset->addRdata(in::A("192.0.2.1"));
-        a_rrset->addRdata(in::A("192.0.2.2"));
-
-        // Create the RRSIG corresponding to the rrset_a record.  The RDATA
-        // won't match the A record it covers, although it is internally
-        // self-consistent.
-        AbstractRRset* sig_rrset =
-            const_cast<AbstractRRset*>(rrset_siga.get());
-        sig_rrset->addRdata(generic::RRSIG(RRSIG_TXT));
-    }
-
-    const Name test_name;
-    const Name test_domain;
-    const Name test_nsname;
-
-    RBNodeRRset rrset_a;
-    RBNodeRRset rrset_a_empty;
-    const RBNodeRRset rrset_ns;
-    const RBNodeRRset rrset_ch_txt;
-
-    ConstRRsetPtr rrset_siga;
-};
-
-TEST_F(RBNodeRRsetTest, getRdataCount) {
-    EXPECT_EQ(0, rrset_a_empty.getRdataCount());
-    EXPECT_EQ(2, rrset_a.getRdataCount());
-}
-
-TEST_F(RBNodeRRsetTest, getName) {
-    EXPECT_EQ(test_name, rrset_a.getName());
-    EXPECT_EQ(test_domain, rrset_ns.getName());
-}
-
-TEST_F(RBNodeRRsetTest, getClass) {
-    EXPECT_EQ(RRClass("IN"), rrset_a.getClass());
-    EXPECT_EQ(RRClass("CH"), rrset_ch_txt.getClass());
-}
-
-TEST_F(RBNodeRRsetTest, getType) {
-    EXPECT_EQ(RRType("A"), rrset_a.getType());
-    EXPECT_EQ(RRType("NS"), rrset_ns.getType());
-    EXPECT_EQ(RRType("TXT"), rrset_ch_txt.getType());
-}
-
-TEST_F(RBNodeRRsetTest, getTTL) {
-    EXPECT_EQ(RRTTL(3600), rrset_a.getTTL());
-    EXPECT_EQ(RRTTL(86400), rrset_ns.getTTL());
-    EXPECT_EQ(RRTTL(0), rrset_ch_txt.getTTL());
-}
-
-TEST_F(RBNodeRRsetTest, setName) {
-    EXPECT_THROW(rrset_a.setName(test_nsname), NotImplemented);
-}
-
-TEST_F(RBNodeRRsetTest, setTTL) {
-    EXPECT_THROW(rrset_a.setTTL(RRTTL(86400)), NotImplemented);
-}
-
-TEST_F(RBNodeRRsetTest, toText) {
-    EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
-              "test.example.com. 3600 IN A 192.0.2.2\n",
-              rrset_a.toText());
-
-    // toText() cannot be performed for an empty RRset.
-    EXPECT_THROW(rrset_a_empty.toText(), EmptyRRset);
-}
-
-TEST_F(RBNodeRRsetTest, isSameKind) {
-    RBNodeRRset rrset_p(ConstRRsetPtr(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(3600))));
-    RBNodeRRset rrset_q(ConstRRsetPtr(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(3600))));
-    RRset rrset_w(test_name, RRClass::IN(), RRType::A(), RRTTL(3600));
-    RRset rrset_x(test_nsname, RRClass::IN(), RRType::A(), RRTTL(3600));
-    RRset rrset_y(test_name, RRClass::IN(), RRType::NS(), RRTTL(3600));
-    RRset rrset_z(test_name, RRClass::CH(), RRType::A(), RRTTL(3600));
-
-    EXPECT_TRUE(rrset_p.isSameKind(rrset_p));
-    EXPECT_FALSE(rrset_p.isSameKind(rrset_q));
-
-    EXPECT_TRUE(rrset_p.isSameKind(rrset_w));
-    EXPECT_FALSE(rrset_p.isSameKind(rrset_x));
-    EXPECT_FALSE(rrset_p.isSameKind(rrset_y));
-    EXPECT_FALSE(rrset_p.isSameKind(rrset_z));
-}
-
-// Note: although the next two tests are essentially the same and used common
-// test code, they use different test data: the MessageRenderer produces
-// compressed wire data whereas the OutputBuffer does not.
-
-template <typename T>
-void
-performToWireTest(T& dataHolder, const RBNodeRRset& rrset,
-                  const RBNodeRRset& rrset_empty, const char* testdata)
-{
-    rrset.toWire(dataHolder);
-
-    std::vector<unsigned char> wiredata;
-    UnitTestUtil::readWireData(testdata, wiredata);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, dataHolder.getData(),
-                        dataHolder.getLength(), &wiredata[0], wiredata.size());
-
-    // toWire() cannot be performed for an empty RRset.
-    dataHolder.clear();
-    EXPECT_THROW(rrset_empty.toWire(dataHolder), EmptyRRset);
-}
-
-TEST_F(RBNodeRRsetTest, toWireRenderer) {
-    MessageRenderer renderer;
-    performToWireTest(renderer, rrset_a, rrset_a_empty, "rrset_toWire2");
-}
-
-TEST_F(RBNodeRRsetTest, toWireBuffer) {
-    OutputBuffer buffer(0);
-    performToWireTest(buffer, rrset_a, rrset_a_empty, "rrset_toWire1");
-}
-
-TEST_F(RBNodeRRsetTest, addRdata) {
-    EXPECT_THROW(rrset_a.addRdata(in::A("192.0.2.3")), NotImplemented);
-
-    // Check the same goes for trying to add the wrong type of data
-    EXPECT_THROW(rrset_a.addRdata(generic::NS(test_nsname)), NotImplemented);
-}
-
-TEST_F(RBNodeRRsetTest, addRdataPtr) {
-    EXPECT_THROW(rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
-                                                    rrset_a_empty.getClass(),
-                                                    "192.0.2.1")),
-                 NotImplemented);
-}
-
-TEST_F(RBNodeRRsetTest, getRDataIterator) {
-    RdataIteratorPtr it = rrset_a.getRdataIterator();
-    for (int i = 0; i < 2; ++i) {
-        ASSERT_FALSE(it->isLast());
-        ASSERT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
-
-        it->next();
-        ASSERT_FALSE(it->isLast());
-        ASSERT_EQ(0, it->getCurrent().compare(in::A("192.0.2.2")));
-
-        it->next();
-        ASSERT_TRUE(it->isLast());
-
-        // Should be able repeat the iteration by calling first().
-        it->first();
-    }
-}
-
-// test operator<<.  We simply confirm it appends the result of toText().
-TEST_F(RBNodeRRsetTest, LeftShiftOperator) {
-    ostringstream oss;
-    oss << rrset_a;
-    EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
-              "test.example.com. 3600 IN A 192.0.2.2\n", oss.str());
-}
-
-// addRRSIG tests.
-TEST_F(RBNodeRRsetTest, addRRsigConstRdataPointer) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    ConstRdataPtr data = createRdata(rrset_siga->getType(),
-                                     rrset_siga->getClass(), RRSIG_TXT);
-    rrset_a.addRRsig(data);
-    rrsetCheck(rrset_siga, rrset_a.getRRsig());
-}
-
-TEST_F(RBNodeRRsetTest, addRRsigRdataPointer) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    RdataPtr data = createRdata(rrset_siga->getType(), rrset_siga->getClass(),
-                                RRSIG_TXT);
-    rrset_a.addRRsig(data);
-    rrsetCheck(rrset_siga, rrset_a.getRRsig());
-}
-
-TEST_F(RBNodeRRsetTest, addRRsigAbstractRRset) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    rrset_a.addRRsig(*(rrset_siga.get()));
-    rrsetCheck(rrset_siga, rrset_a.getRRsig());
-}
-
-TEST_F(RBNodeRRsetTest, addRRsigConstantRRsetPointer) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    rrset_a.addRRsig(rrset_siga);
-    rrsetCheck(rrset_siga, rrset_a.getRRsig());
-}
-
-TEST_F(RBNodeRRsetTest, addRRsigRRsetPointer) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    RRsetPtr rrsig(new RRset(test_name, RRClass::IN(), RRType::RRSIG(),
-                   RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG(RRSIG_TXT));
-    rrset_a.addRRsig(rrsig);
-    rrsetCheck(rrset_siga, rrset_a.getRRsig());
-}
-
-TEST_F(RBNodeRRsetTest, removeRRsig) {
-    EXPECT_FALSE(rrset_a.getRRsig());
-    rrset_a.addRRsig(*(rrset_siga.get()));
-    EXPECT_TRUE(rrset_a.getRRsig());
-    rrset_a.removeRRsig();
-    EXPECT_FALSE(rrset_a.getRRsig());
-}
-
-}   // Anonymous namespace
diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc
deleted file mode 100644
index 2370631..0000000
--- a/src/lib/datasrc/tests/rbtree_unittest.cc
+++ /dev/null
@@ -1,1074 +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 <gtest/gtest.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <datasrc/rbtree.h>
-
-#include <dns/tests/unittest_util.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-using isc::UnitTestUtil;
-using namespace isc::datasrc;
-
-// XXX: some compilers cannot find class static constants used in
-// EXPECT_xxx macros, for which we need an explicit empty definition.
-const size_t Name::MAX_LABELS;
-
-/* The initial structure of rbtree
- *
- *             .
- *             |
- *             b
- *           /   \
- *          a    d.e.f
- *              /  |   \
- *             c   |    g.h
- *                 |     |
- *                w.y    i
- *              /  |  \   \
- *             x   |   z   k
- *                 |   |
- *                 p   j
- *               /   \
- *              o     q
- */
-
-namespace {
-class TreeHolder {
-public:
-    TreeHolder(util::MemorySegment& mem_sgmt, RBTree<int>* tree) :
-        mem_sgmt_(mem_sgmt), tree_(tree)
-    {}
-    ~TreeHolder() {
-        RBTree<int>::destroy(mem_sgmt_, tree_);
-    }
-    RBTree<int>* get() { return (tree_); }
-private:
-    util::MemorySegment& mem_sgmt_;
-    RBTree<int>* tree_;
-};
-
-class RBTreeTest : public::testing::Test {
-protected:
-    RBTreeTest() :
-        rbtree_holder_(mem_sgmt_, RBTree<int>::create(mem_sgmt_)),
-        rbtree_expose_empty_node_holder_(mem_sgmt_,
-                                         RBTree<int>::create(mem_sgmt_, true)),
-        rbtree(*rbtree_holder_.get()),
-        rbtree_expose_empty_node(*rbtree_expose_empty_node_holder_.get()),
-        crbtnode(NULL)
-    {
-        const char* const domain_names[] = {
-            "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
-            "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
-        int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
-        for (int i = 0; i < name_count; ++i) {
-            rbtree.insert(mem_sgmt_, Name(domain_names[i]), &rbtnode);
-            rbtnode->setData(RBNode<int>::NodeDataPtr(new int(i + 1)));
-
-            rbtree_expose_empty_node.insert(mem_sgmt_, Name(domain_names[i]),
-                                            &rbtnode);
-            rbtnode->setData(RBNode<int>::NodeDataPtr(new int(i + 1)));
-
-        }
-    }
-
-    util::MemorySegmentLocal mem_sgmt_;
-    TreeHolder rbtree_holder_;
-    TreeHolder rbtree_expose_empty_node_holder_;
-    RBTree<int>& rbtree;
-    RBTree<int>& rbtree_expose_empty_node;
-    RBNode<int>* rbtnode;
-    const RBNode<int>* crbtnode;
-    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
-};
-
-TEST_F(RBTreeTest, nodeCount) {
-    EXPECT_EQ(15, rbtree.getNodeCount());
-
-    // Delete all nodes, then the count should be set to 0.  This also tests
-    // the behavior of deleteAllNodes().
-    rbtree.deleteAllNodes(mem_sgmt_);
-    EXPECT_EQ(0, rbtree.getNodeCount());
-}
-
-TEST_F(RBTreeTest, setGetData) {
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(11)));
-    EXPECT_EQ(11, *(rbtnode->getData()));
-}
-
-TEST_F(RBTreeTest, insertNames) {
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_,
-                                                        Name("d.e.f"),
-                                                        &rbtnode));
-    EXPECT_EQ(Name("d.e.f"), rbtnode->getName());
-    EXPECT_EQ(15, rbtree.getNodeCount());
-
-    // insert not exist node
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("0"),
-                                                  &rbtnode));
-    EXPECT_EQ(Name("0"), rbtnode->getName());
-    EXPECT_EQ(16, rbtree.getNodeCount());
-
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
-                                                  Name("example.com"),
-                                                  &rbtnode));
-    EXPECT_EQ(17, rbtree.getNodeCount());
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(12)));
-
-    // return ALREADYEXISTS, since node "example.com" already has
-    // been explicitly inserted
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_,
-                                                        Name("example.com"),
-                                                        &rbtnode));
-    EXPECT_EQ(17, rbtree.getNodeCount());
-
-    // split the node "d.e.f"
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("k.e.f"),
-                                                  &rbtnode));
-    EXPECT_EQ(Name("k"), rbtnode->getName());
-    EXPECT_EQ(19, rbtree.getNodeCount());
-
-    // split the node "g.h"
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_, Name("h"),
-                                                        &rbtnode));
-    EXPECT_EQ(Name("h"), rbtnode->getName());
-    EXPECT_EQ(20, rbtree.getNodeCount());
-
-    // add child domain
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
-                                                  Name("m.p.w.y.d.e.f"),
-                                                  &rbtnode));
-    EXPECT_EQ(Name("m"), rbtnode->getName());
-    EXPECT_EQ(21, rbtree.getNodeCount());
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
-                                                  Name("n.p.w.y.d.e.f"),
-                                                  &rbtnode));
-    EXPECT_EQ(Name("n"), rbtnode->getName());
-    EXPECT_EQ(22, rbtree.getNodeCount());
-
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("l.a"),
-                                                  &rbtnode));
-    EXPECT_EQ(Name("l"), rbtnode->getName());
-    EXPECT_EQ(23, rbtree.getNodeCount());
-
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("r.d.e.f"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("s.d.e.f"),
-                                                  &rbtnode));
-    EXPECT_EQ(25, rbtree.getNodeCount());
-
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
-                                                  Name("h.w.y.d.e.f"),
-                                                  &rbtnode));
-
-    // add more nodes one by one to cover leftRotate and rightRotate
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_, Name("f"),
-                                                        &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("m"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("nm"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("om"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("k"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("l"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("fe"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("ge"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("i"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("ae"),
-                                                  &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("n"),
-                                                  &rbtnode));
-}
-
-TEST_F(RBTreeTest, subTreeRoot) {
-    // This is a testcase for a particular issue that went unchecked in
-    // #2089's implementation, but was fixed in #2092. The issue was
-    // that when a node was fissioned, FLAG_SUBTREE_ROOT was not being
-    // copied correctly.
-
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("d.e.f"),
-                                              &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
-                                              &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
-                                              &rbtnode));
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
-                                              &rbtnode));
-    EXPECT_EQ(RBTree<int>::SUCCESS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("k.e.f"),
-                                              &rbtnode));
-
-    // "g.h" is not a subtree root
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("g.h"), &rbtnode));
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-
-    // fission the node "g.h"
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("h"),
-                                              &rbtnode));
-
-    // the node "h" (h.down_ -> "g") should not be a subtree root. "g"
-    // should be a subtree root.
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-
-    // "g.h" should be a subtree root now.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("g.h"), &rbtnode));
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-}
-
-TEST_F(RBTreeTest, additionalNodeFission) {
-    // These are additional nodeFission tests added by #2054's rewrite
-    // of RBTree::nodeFission(). These test specific corner cases that
-    // are not covered by other tests.
-
-    // Insert "t.0" (which becomes the left child of its parent)
-    EXPECT_EQ(RBTree<int>::SUCCESS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("t.0"),
-                                              &rbtnode));
-
-    // "t.0" is not a subtree root
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("t.0"), &rbtnode));
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-
-    // fission the node "t.0"
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS,
-              rbtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
-                                              &rbtnode));
-
-    // the node "0" ("0".down_ -> "t") should not be a subtree root. "t"
-    // should be a subtree root.
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-
-    // "t.0" should be a subtree root now.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("t.0"), &rbtnode));
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_SUBTREE_ROOT));
-}
-
-TEST_F(RBTreeTest, findName) {
-    // find const rbtnode
-    // exact match
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("a"), &crbtnode));
-    EXPECT_EQ(Name("a"), crbtnode->getName());
-
-    // not found
-    EXPECT_EQ(RBTree<int>::NOTFOUND, rbtree.find(Name("d.e.f"), &crbtnode));
-    EXPECT_EQ(RBTree<int>::NOTFOUND, rbtree.find(Name("y.d.e.f"), &crbtnode));
-    EXPECT_EQ(RBTree<int>::NOTFOUND, rbtree.find(Name("x"), &crbtnode));
-    EXPECT_EQ(RBTree<int>::NOTFOUND, rbtree.find(Name("m.n"), &crbtnode));
-
-    // if we expose empty node, we can get the empty node created during insert
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("d.e.f"), &crbtnode));
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name("w.y.d.e.f"), &crbtnode));
-
-    // partial match
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH, rbtree.find(Name("m.b"), &crbtnode));
-    EXPECT_EQ(Name("b"), crbtnode->getName());
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              rbtree_expose_empty_node.find(Name("m.d.e.f"), &crbtnode));
-
-    // find rbtnode
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("q.w.y.d.e.f"),
-                                                   &rbtnode));
-    EXPECT_EQ(Name("q"), rbtnode->getName());
-}
-
-TEST_F(RBTreeTest, findError) {
-    // For the version that takes a node chain, the chain must be empty.
-    RBTreeNodeChain<int> chain;
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("a"), &crbtnode,
-                                                   chain));
-    // trying to reuse the same chain.  it should result in an exception.
-    EXPECT_THROW(rbtree.find(Name("a"), &crbtnode, chain),
-                 BadValue);
-}
-
-TEST_F(RBTreeTest, flags) {
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
-                                                  Name("flags.example"),
-                                                  &rbtnode));
-
-    // by default, flags are all off
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // set operation, by default it enables the flag
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // try disable the flag explicitly
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, false);
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // try enable the flag explicitly
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, true);
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // setting an unknown flag will trigger an exception
-    EXPECT_THROW(rbtnode->setFlag(static_cast<RBNode<int>::Flags>(2), true),
-                 isc::InvalidParameter);
-}
-
-bool
-testCallback(const RBNode<int>&, bool* callback_checker) {
-    *callback_checker = true;
-    return (false);
-}
-
-template <typename T>
-void
-performCallbackTest(RBTree<int>& rbtree,
-                    util::MemorySegmentLocal& mem_sgmt,
-                    const T& name_called,
-                    const T& name_not_called)
-{
-    RBNode<int>* rbtnode;
-    const RBNode<int>* crbtnode;
-
-    // by default callback isn't enabled
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt,
-                                                  Name("callback.example"),
-                                                  &rbtnode));
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // enable/re-disable callback
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, false);
-    EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // enable again for subsequent tests
-    rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
-    // add more levels below and above the callback node for partial match.
-    RBNode<int>* subrbtnode;
-    EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt,
-                                                  Name("sub.callback.example"),
-                                                  &subrbtnode));
-    subrbtnode->setData(RBNode<int>::NodeDataPtr(new int(2)));
-    RBNode<int>* parentrbtnode;
-    EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt,
-                                                        Name("example"),
-                                                        &parentrbtnode));
-    // the child/parent nodes shouldn't "inherit" the callback flag.
-    // "rbtnode" may be invalid due to the insertion, so we need to re-find
-    // it.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("callback.example"),
-                                                   &rbtnode));
-    EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-    EXPECT_FALSE(subrbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-    EXPECT_FALSE(parentrbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
-
-    // check if the callback is called from find()
-    RBTreeNodeChain<int> node_path1;
-    bool callback_called = false;
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree.find(name_called, &crbtnode, node_path1,
-                          testCallback, &callback_called));
-    EXPECT_TRUE(callback_called);
-
-    // enable callback at the parent node, but it doesn't have data so
-    // the callback shouldn't be called.
-    RBTreeNodeChain<int> node_path2;
-    parentrbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
-    callback_called = false;
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree.find(name_not_called, &crbtnode, node_path2,
-                          testCallback, &callback_called));
-    EXPECT_FALSE(callback_called);
-}
-
-TEST_F(RBTreeTest, callbackName) {
-    const Name n1("sub.callback.example");
-    const Name n2("callback.example");
-
-    performCallbackTest(rbtree, mem_sgmt_, n1, n2);
-}
-
-TEST_F(RBTreeTest, callbackLabelSequence) {
-    const Name n1("sub.callback.example");
-    const Name n2("callback.example");
-    const LabelSequence ls1(n1);
-    const LabelSequence ls2(n2);
-
-    performCallbackTest(rbtree, mem_sgmt_, ls1, ls2);
-}
-
-TEST_F(RBTreeTest, chainLevel) {
-    RBTreeNodeChain<int> chain;
-
-    // by default there should be no level in the chain.
-    EXPECT_EQ(0, chain.getLevelCount());
-
-    // insert one node to the tree and find it.  there should be exactly
-    // one level in the chain.
-    TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_, true));
-    RBTree<int>& tree(*tree_holder.get());
-    Name node_name(Name::ROOT_NAME());
-    EXPECT_EQ(RBTree<int>::SUCCESS, tree.insert(mem_sgmt_, node_name,
-                                                &rbtnode));
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(node_name, &crbtnode, chain));
-    EXPECT_EQ(1, chain.getLevelCount());
-
-    // Check the name of the found node (should have '.' as both non-absolute
-    // and absolute name
-    EXPECT_EQ(".", crbtnode->getLabels().toText());
-    EXPECT_EQ(".", crbtnode->getAbsoluteLabels(buf).toText());
-
-    /*
-     * Now creating a possibly deepest tree with MAX_LABELS levels.
-     * it should look like:
-     *           (.)
-     *            |
-     *            a
-     *            |
-     *            a
-     *            : (MAX_LABELS - 1) "a"'s
-     *
-     * then confirm that find() for the deepest name succeeds without any
-     * disruption, and the resulting chain has the expected level.
-     * Note that the root name (".") solely belongs to a single level,
-     * so the levels begin with 2.
-     */
-    for (unsigned int i = 2; i <= Name::MAX_LABELS; ++i) {
-        node_name = Name("a.").concatenate(node_name);
-        EXPECT_EQ(RBTree<int>::SUCCESS, tree.insert(mem_sgmt_, node_name,
-                                                    &rbtnode));
-        RBTreeNodeChain<int> found_chain;
-        EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                  tree.find(node_name, &crbtnode, found_chain));
-        EXPECT_EQ(i, found_chain.getLevelCount());
-
-        // The non-absolute name should only have the first label
-        EXPECT_EQ("a", crbtnode->getLabels().toText());
-        // But the absolute name should have all labels
-        EXPECT_EQ(node_name.toText(),
-                  crbtnode->getAbsoluteLabels(buf).toText());
-    }
-
-    // Confirm the last inserted name has the possible maximum length with
-    // maximum label count.  This confirms the rbtree and chain level cannot
-    // be larger.
-    EXPECT_EQ(Name::MAX_LABELS, node_name.getLabelCount());
-    EXPECT_THROW(node_name.concatenate(Name("a.")), TooLongName);
-}
-
-TEST_F(RBTreeTest, getAbsoluteNameError) {
-    // an empty chain isn't allowed.
-    RBTreeNodeChain<int> chain;
-    EXPECT_THROW(chain.getAbsoluteName(), BadValue);
-}
-
-/*
- * The domain order should be:
- * ., a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f,
- * q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
- *             . (no data, can't be found)
- *             |
- *             b
- *           /   \
- *          a    d.e.f
- *              /  |   \
- *             c   |    g.h
- *                 |     |
- *                w.y    i
- *              /  |  \   \
- *             x   |   z   k
- *                 |   |
- *                 p   j
- *               /   \
- *              o     q
- */
-const char* const names[] = {
-    "a", "b", "c", "d.e.f", "x.d.e.f", "w.y.d.e.f", "o.w.y.d.e.f",
-    "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f", "j.z.d.e.f",
-    "g.h", "i.g.h", "k.g.h"};
-const size_t name_count(sizeof(names) / sizeof(*names));
-
-const char* const upper_node_names[] = {
-    ".", ".", ".", ".", "d.e.f", "d.e.f", "w.y.d.e.f",
-    "w.y.d.e.f", "w.y.d.e.f", "d.e.f", "z.d.e.f",
-    ".", "g.h", "g.h"};
-
-TEST_F(RBTreeTest, getUpperNode) {
-    RBTreeNodeChain<int> node_path;
-    const RBNode<int>* node = NULL;
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree_expose_empty_node.find(Name(names[0]),
-                                            &node,
-                                            node_path));
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-
-        const RBNode<int>* upper_node = node->getUpperNode();
-        if (upper_node_names[i] != NULL) {
-            const RBNode<int>* upper_node2 = NULL;
-            EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                      rbtree_expose_empty_node.find(Name(upper_node_names[i]),
-                                                    &upper_node2));
-            EXPECT_NE(static_cast<void*>(NULL), upper_node2);
-            EXPECT_EQ(upper_node, upper_node2);
-        } else {
-            EXPECT_EQ(static_cast<void*>(NULL), upper_node);
-        }
-
-        node = rbtree_expose_empty_node.nextNode(node_path);
-    }
-
-    // We should have reached the end of the tree.
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-TEST_F(RBTreeTest, nextNode) {
-    RBTreeNodeChain<int> node_path;
-    const RBNode<int>* node = NULL;
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              rbtree.find(Name(names[0]), &node, node_path));
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(Name(names[i]), node_path.getAbsoluteName());
-        node = rbtree.nextNode(node_path);
-    }
-
-    // We should have reached the end of the tree.
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-// Just walk using previousNode until the beginning of the tree and check it is
-// OK
-//
-// rbtree - the tree to walk
-// node - result of previous call to find(), starting position of the walk
-// node_path - the path from the previous call to find(), will be modified
-// chain_length - the number of names that should be in the chain to be walked
-//   (0 means it should be empty, 3 means 'a', 'b' and 'c' should be there -
-//   this is always from the beginning of the names[] list).
-// skip_first - if this is false, the node should already contain the node with
-//   the first name of the chain. If it is true, the node should be NULL
-//   (true is for finds that return no match, false for the ones that return
-//   match)
-void
-previousWalk(RBTree<int>& rbtree, const RBNode<int>* node,
-             RBTreeNodeChain<int>& node_path, size_t chain_length,
-             bool skip_first)
-{
-    if (skip_first) {
-        // If the first is not found, this is supposed to be NULL and we skip
-        // it in our checks.
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        node = rbtree.previousNode(node_path);
-    }
-    for (size_t i(chain_length); i > 0; --i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(Name(names[i - 1]), node_path.getAbsoluteName());
-        // Find the node at the path and check the value is the same
-        // (that it really returns the correct corresponding node)
-        //
-        // The "empty" nodes can not be found
-        if (node->getData()) {
-            const RBNode<int>* node2(NULL);
-            RBTreeNodeChain<int> node_path2;
-            EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                      rbtree.find(Name(names[i - 1]), &node2, node_path2));
-            EXPECT_EQ(node, node2);
-        }
-        node = rbtree.previousNode(node_path);
-    }
-
-    // We should have reached the start of the tree.
-    ASSERT_NE(static_cast<void*>(NULL), node);
-    EXPECT_EQ(".", node->getLabels().toText());
-
-    // With one more call it results in NULL
-    node = rbtree.previousNode(node_path);
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-
-    // Calling previousNode() yet again should still return NULL without
-    // fail.
-    node = rbtree.previousNode(node_path);
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-// Check the previousNode
-TEST_F(RBTreeTest, previousNode) {
-    // First, iterate the whole tree from the end to the beginning.
-    RBTreeNodeChain<int> node_path;
-    EXPECT_THROW(rbtree.previousNode(node_path), isc::BadValue) <<
-        "Throw before a search was done on the path";
-    const RBNode<int>* node(NULL);
-    {
-        SCOPED_TRACE("Iterate through");
-        EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                  rbtree.find(Name(names[name_count - 1]), &node, node_path));
-        previousWalk(rbtree, node, node_path, name_count, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Iterate from the middle");
-        // Now, start somewhere in the middle, but within the real node.
-        EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                  rbtree.find(Name(names[4]), &node, node_path));
-        previousWalk(rbtree, node, node_path, 5, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start at the first");
-        // If we start at the lowest (which is "a"), we get to the beginning
-        // right away.
-        EXPECT_EQ(RBTree<int>::EXACTMATCH,
-                  rbtree.find(Name(names[0]), &node, node_path));
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        node = rbtree.previousNode(node_path);
-        ASSERT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(".", node->getLabels().toText());
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start before the first");
-        // If we start before the lowest (. < 0. < a.), we should not get a
-        // node.  Its previous node should be the root.
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find<void*>(Name("0"), &node, node_path, NULL, NULL));
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        node = rbtree.previousNode(node_path);
-        ASSERT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(".", node->getLabels().toText());
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start after the last");
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find(Name("z"), &node, node_path));
-        previousWalk(rbtree, node, node_path, name_count, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start below a leaf");
-        // We exit a leaf by going down. We should start by the one
-        // we exited - 'c' (actually, we should get it by the find, as partial
-        // match).
-        EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-                  rbtree.find(Name("b.c"), &node, node_path));
-        previousWalk(rbtree, node, node_path, 3, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the right of a leaf");
-        // When searching for this, we exit the 'x' node to the right side,
-        // so we should go x afterwards.
-
-        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
-        // and not PARTIALMATCH.
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find(Name("xy.d.e.f"), &node, node_path));
-        previousWalk(rbtree, node, node_path, 5, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the left of a leaf");
-        // This is similar to the previous, but we exit the 'z' leaf to the
-        // left side, so should not visit z at all then.
-
-        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
-        // and not PARTIALMATCH.
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find(Name("yz.d.e.f"), &node, node_path));
-        previousWalk(rbtree, node, node_path, 9, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the right of a parent");
-        // When searching for this, we exit the 'g.h' node to the right
-        // side, so we should go to g.h's children afterwards.
-
-        // 'g.h' is an empty node, so we get a NOTFOUND and not
-        // PARTIALMATCH.
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find(Name("x.h"), &node, node_path));
-        // 'g.h' is the COMMONANCESTOR.
-        EXPECT_EQ(node_path.getLastComparedNode()->getName(), Name("g.h"));
-        EXPECT_EQ(NameComparisonResult::COMMONANCESTOR,
-                  node_path.getLastComparisonResult().getRelation());
-        // find() exits to the right of 'g.h'
-        EXPECT_GT(node_path.getLastComparisonResult().getOrder(), 0);
-        // We then descend into 'i.g.h' and walk all the nodes in the
-        // tree.
-        previousWalk(rbtree, node, node_path, name_count, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start inside a wrong node");
-        // The d.e.f is a single node, but we want only part of it. We
-        // should start iterating before it.
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  rbtree.find(Name("e.f"), &node, node_path));
-        previousWalk(rbtree, node, node_path, 3, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Lookup in empty tree");
-        // Just check it doesn't crash, etc.
-        TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
-        RBTree<int>& empty_tree(*tree_holder.get());
-        EXPECT_EQ(RBTree<int>::NOTFOUND,
-                  empty_tree.find(Name("x"), &node, node_path));
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        EXPECT_EQ(static_cast<void*>(NULL),
-                  empty_tree.previousNode(node_path));
-        node = NULL;
-        node_path.clear();
-    }
-}
-
-TEST_F(RBTreeTest, nextNodeError) {
-    // Empty chain for nextNode() is invalid.
-    RBTreeNodeChain<int> chain;
-    EXPECT_THROW(rbtree.nextNode(chain), BadValue);
-}
-
-// A helper function for getLastComparedNode() below.
-void
-comparisonChecks(const RBTreeNodeChain<int>& chain,
-                 int expected_order, int expected_common_labels,
-                 NameComparisonResult::NameRelation expected_reln)
-{
-    if (expected_order > 0) {
-        EXPECT_LT(0, chain.getLastComparisonResult().getOrder());
-    } else if (expected_order < 0) {
-        EXPECT_GT(0, chain.getLastComparisonResult().getOrder());
-    } else {
-        EXPECT_EQ(0, chain.getLastComparisonResult().getOrder());
-    }
-    EXPECT_EQ(expected_common_labels,
-              chain.getLastComparisonResult().getCommonLabels());
-    EXPECT_EQ(expected_reln,
-              chain.getLastComparisonResult().getRelation());
-}
-
-TEST_F(RBTreeTest, getLastComparedNode) {
-    RBTree<int>& tree = rbtree_expose_empty_node; // use the "empty OK" mode
-    RBTreeNodeChain<int> chain;
-
-    // initially there should be no 'last compared'.
-    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
-
-    // A search for an empty tree should result in no 'last compared', too.
-    TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
-    RBTree<int>& empty_tree(*tree_holder.get());
-    EXPECT_EQ(RBTree<int>::NOTFOUND,
-              empty_tree.find(Name("a"), &crbtnode, chain));
-    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
-    chain.clear();
-
-    const RBNode<int>* expected_node = NULL;
-
-    // Exact match case.  The returned node should be last compared.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(Name("x.d.e.f"), &expected_node, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // 1 = # labels of "x" (note: excluding ".")
-    comparisonChecks(chain, 0, 1, NameComparisonResult::EQUAL);
-    chain.clear();
-
-    // Partial match, search stopped at the matching node, which should be
-    // the last compared node.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(Name("k.g.h"), &expected_node));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("x.k.g.h"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // k.g.h < x.k.g.h, 1 = # labels of "k"
-    comparisonChecks(chain, 1, 1, NameComparisonResult::SUBDOMAIN);
-    chain.clear();
-
-    // Partial match, search stopped in the subtree below the matching node
-    // after following a left branch.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(Name("x.d.e.f"), &expected_node));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("a.d.e.f"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // a < x, no common labels
-    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Partial match, search stopped in the subtree below the matching node
-    // after following a right branch.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(Name("z.d.e.f"), &expected_node));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("zz.d.e.f"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // zz > z, no common label
-    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Partial match, search stopped at a node for a super domain of the
-    // search name in the subtree below the matching node.
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              tree.find(Name("w.y.d.e.f"), &expected_node));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("y.d.e.f"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // y < w.y, 1 = # labels of "y"
-    comparisonChecks(chain, -1, 1, NameComparisonResult::SUPERDOMAIN);
-    chain.clear();
-
-    // Partial match, search stopped at a node that share a common ancestor
-    // with the search name in the subtree below the matching node.
-    // (the expected node is the same as the previous case)
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("z.y.d.e.f"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // z.y > w.y, 1 = # labels of "y"
-    comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
-    chain.clear();
-
-    // Search stops in the highest level (under ".") after following a left
-    // branch. (find() still returns PARTIALMATCH due to the top level ".")
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, tree.find(Name("c"), &expected_node));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("bb"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // bb < c, no common label
-    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Search stops in the highest level (under ".") after following a right
-    // branch. (the expected node is the same as the previous case)
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              tree.find(Name("d"), &crbtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // d > c, no common label
-    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
-    chain.clear();
-}
-
-TEST_F(RBTreeTest, dumpTree) {
-    std::ostringstream str;
-    std::ostringstream str2;
-    rbtree.dumpTree(str);
-    str2 << "tree has 15 node(s)\n"
-            ". (black) [invisible] [subtreeroot]\n"
-            "     begin down from .\n"
-            "     b (black) [subtreeroot]\n"
-            "          a (black)\n"
-            "               NULL\n"
-            "               NULL\n"
-            "          d.e.f (black) [invisible]\n"
-            "               begin down from d.e.f\n"
-            "               w.y (black) [invisible] [subtreeroot]\n"
-            "                    begin down from w.y\n"
-            "                    p (black) [subtreeroot]\n"
-            "                         o (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                         q (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                    end down from w.y\n"
-            "                    x (red)\n"
-            "                         NULL\n"
-            "                         NULL\n"
-            "                    z (red)\n"
-            "                         begin down from z\n"
-            "                         j (black) [subtreeroot]\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                         end down from z\n"
-            "                         NULL\n"
-            "                         NULL\n"
-            "               end down from d.e.f\n"
-            "               c (red)\n"
-            "                    NULL\n"
-            "                    NULL\n"
-            "               g.h (red)\n"
-            "                    begin down from g.h\n"
-            "                    i (black) [subtreeroot]\n"
-            "                         NULL\n"
-            "                         k (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                    end down from g.h\n"
-            "                    NULL\n"
-            "                    NULL\n"
-            "     end down from .\n"
-            "     NULL\n"
-            "     NULL\n";
-    EXPECT_EQ(str2.str(), str.str());
-}
-
-TEST_F(RBTreeTest, swap) {
-    // Store info about the first tree
-    std::ostringstream str1;
-    rbtree.dumpTree(str1);
-    size_t count1(rbtree.getNodeCount());
-
-    // Create second one and store state
-    TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
-    RBTree<int>& tree2(*tree_holder.get());
-    RBNode<int>* node;
-    tree2.insert(mem_sgmt_, Name("second"), &node);
-    std::ostringstream str2;
-    tree2.dumpTree(str2);
-
-    // Swap them
-    ASSERT_NO_THROW(tree2.swap(rbtree));
-
-    // Check their sizes
-    ASSERT_EQ(1, rbtree.getNodeCount());
-    ASSERT_EQ(count1, tree2.getNodeCount());
-
-    // And content
-    std::ostringstream out;
-    rbtree.dumpTree(out);
-    ASSERT_EQ(str2.str(), out.str());
-    out.str("");
-    tree2.dumpTree(out);
-    ASSERT_EQ(str1.str(), out.str());
-}
-
-// Matching in the "root zone" may be special (e.g. there's no parent,
-// any domain names should be considered a subdomain of it), so it makes
-// sense to test cases with the root zone explicitly.
-TEST_F(RBTreeTest, root) {
-    TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
-    RBTree<int>& root(*tree_holder.get());
-    root.insert(mem_sgmt_, Name::ROOT_NAME(), &rbtnode);
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
-
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              root.find(Name::ROOT_NAME(), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              root.find(Name("example.com"), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-
-    // Insert a new name that better matches the query name.  find() should
-    // find the better one.
-    root.insert(mem_sgmt_, Name("com"), &rbtnode);
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(2)));
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              root.find(Name("example.com"), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-
-    // Perform the same tests for the tree that allows matching against empty
-    // nodes.
-    TreeHolder tree_holder_emptyok(mem_sgmt_,
-                                   RBTree<int>::create(mem_sgmt_, true));
-    RBTree<int>& root_emptyok(*tree_holder_emptyok.get());
-    root_emptyok.insert(mem_sgmt_, Name::ROOT_NAME(), &rbtnode);
-    EXPECT_EQ(RBTree<int>::EXACTMATCH,
-              root_emptyok.find(Name::ROOT_NAME(), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              root_emptyok.find(Name("example.com"), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-
-    root.insert(mem_sgmt_, Name("com"), &rbtnode);
-    EXPECT_EQ(RBTree<int>::PARTIALMATCH,
-              root.find(Name("example.com"), &crbtnode));
-    EXPECT_EQ(rbtnode, crbtnode);
-}
-
-TEST_F(RBTreeTest, getAbsoluteLabels) {
-    // The full absolute names of the nodes in the tree
-    // with the addition of the explicit root node
-    const char* const domain_names[] = {
-        "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
-        "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
-    // The names of the nodes themselves, as they end up in the tree
-    const char* const first_labels[] = {
-        "c", "b", "a", "x", "z", "g.h", "i", "o",
-        "j", "p", "q", "k"};
-
-    const int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name(domain_names[i]),
-                  &crbtnode));
-
-        // First make sure the names themselves are not absolute
-        const LabelSequence ls(crbtnode->getLabels());
-        EXPECT_EQ(first_labels[i], ls.toText());
-        EXPECT_FALSE(ls.isAbsolute());
-
-        // Now check the absolute names
-        const LabelSequence abs_ls(crbtnode->getAbsoluteLabels(buf));
-        EXPECT_EQ(Name(domain_names[i]).toText(), abs_ls.toText());
-        EXPECT_TRUE(abs_ls.isAbsolute());
-    }
-
-    // Explicitly add and find a root node, to see that getAbsoluteLabels
-    // also works when getLabels() already returns an absolute LabelSequence
-    rbtree.insert(mem_sgmt_, Name("."), &rbtnode);
-    rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
-
-    EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("."), &crbtnode));
-
-    EXPECT_TRUE(crbtnode->getLabels().isAbsolute());
-    EXPECT_EQ(".", crbtnode->getLabels().toText());
-    EXPECT_TRUE(crbtnode->getAbsoluteLabels(buf).isAbsolute());
-    EXPECT_EQ(".", crbtnode->getAbsoluteLabels(buf).toText());
-}
-
-}
diff --git a/src/lib/datasrc/tests/testdata/static-bad.zone b/src/lib/datasrc/tests/testdata/static-bad.zone
new file mode 100644
index 0000000..500ccca
--- /dev/null
+++ b/src/lib/datasrc/tests/testdata/static-bad.zone
@@ -0,0 +1,3 @@
+NOTBIND.           3600    CH  SOA NOTBIND. NOTBIND. 4 3600 300 36000 3600
+NOTBIND.           3600    CH  NS  NOTBIND.
+VERSION.NOTBIND.   3600    CH  TXT "10"
diff --git a/src/lib/datasrc/tests/testdata/static.zone b/src/lib/datasrc/tests/testdata/static.zone
index 5e9e8a6..51525db 100644
--- a/src/lib/datasrc/tests/testdata/static.zone
+++ b/src/lib/datasrc/tests/testdata/static.zone
@@ -1,2 +1,3 @@
-BIND.           3600    CH  SOA BIND. BIND. 1 3600 300 36000 3600
+BIND.           3600    CH  SOA BIND. BIND. 3 3600 300 36000 3600
+BIND.           3600    CH  NS  BIND.
 VERSION.BIND.   3600    CH  TXT "10"
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 85b167e..a5c8a8f 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -18,7 +18,7 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/database.h>
diff --git a/src/lib/datasrc/tests/zone_loader_unittest.cc b/src/lib/datasrc/tests/zone_loader_unittest.cc
index 28153e4..4b42185 100644
--- a/src/lib/datasrc/tests/zone_loader_unittest.cc
+++ b/src/lib/datasrc/tests/zone_loader_unittest.cc
@@ -14,6 +14,7 @@
 
 #include <datasrc/zone_loader.h>
 #include <datasrc/data_source.h>
+#include <datasrc/rrset_collection_base.h>
 
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/memory_client.h>
@@ -21,6 +22,7 @@
 #include <dns/rrclass.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
+#include <dns/rdataclass.h>
 #include <util/memory_segment_local.h>
 #include <exceptions/exceptions.h>
 
@@ -32,15 +34,11 @@
 #include <string>
 #include <vector>
 
-using isc::dns::RRClass;
-using isc::dns::Name;
-using isc::dns::RRType;
-using isc::dns::ConstRRsetPtr;
-using isc::dns::RRsetPtr;
+using namespace isc::dns;
+using namespace isc::datasrc;
+using boost::shared_ptr;
 using std::string;
 using std::vector;
-using boost::shared_ptr;
-using namespace isc::datasrc;
 
 namespace {
 
@@ -51,8 +49,97 @@ public:
         missing_zone_(false),
         rrclass_(RRClass::IN())
     {}
-    virtual FindResult findZone(const Name&) const {
-        isc_throw(isc::NotImplemented, "Method not used in tests");
+    class Finder : public ZoneFinder {
+    public:
+        Finder(const Name& origin) :
+            origin_(origin)
+        {}
+        Name getOrigin() const {
+            return (origin_);
+        }
+        RRClass getClass() const {
+            return (RRClass::IN());
+        }
+        // The rest is not to be called, so they throw.
+        shared_ptr<Context> find(const Name&, const RRType&,
+                                 const FindOptions)
+        {
+            isc_throw(isc::NotImplemented, "Not implemented");
+        }
+        shared_ptr<Context> findAll(const Name&,
+                                    vector<ConstRRsetPtr>&,
+                                    const FindOptions)
+        {
+            isc_throw(isc::NotImplemented, "Not implemented");
+        }
+        FindNSEC3Result findNSEC3(const Name&, bool) {
+            isc_throw(isc::NotImplemented, "Not implemented");
+        }
+    private:
+        Name origin_;
+    };
+    class Iterator : public ZoneIterator {
+    public:
+        Iterator(const Name& origin) :
+            origin_(origin),
+            soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
+                           RRTTL(3600)))
+        {
+            // The RData here is bogus, but it is not used to anything. There
+            // just needs to be some.
+            soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
+                                               Name::ROOT_NAME(),
+                                               0, 0, 0, 0, 0));
+            rrsets_.push_back(soa_);
+
+            // There is no NS record on purpose here.
+
+            // Dummy A rrset. This is used for checking zone data after
+            // reload.
+            RRsetPtr rrset(new RRset(Name("tstzonedata").concatenate(origin_),
+                                     RRClass::IN(), RRType::A(),
+                                     RRTTL(3600)));
+            rrset->addRdata(rdata::in::A("192.0.2.1"));
+            rrsets_.push_back(rrset);
+
+            rrsets_.push_back(ConstRRsetPtr());
+
+            it_ = rrsets_.begin();
+        }
+        virtual isc::dns::ConstRRsetPtr getNextRRset() {
+            ConstRRsetPtr result = *it_;
+            ++it_;
+            return (result);
+        }
+        virtual isc::dns::ConstRRsetPtr getSOA() const {
+            return (soa_);
+        }
+    private:
+        const Name origin_;
+        const RRsetPtr soa_;
+        std::vector<ConstRRsetPtr> rrsets_;
+        std::vector<ConstRRsetPtr>::const_iterator it_;
+    };
+    virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
+                                        bool) const
+    {
+        if (name != Name("example.org")) {
+            isc_throw(DataSourceError, "No such zone");
+        }
+        return (ZoneIteratorPtr(new Iterator(Name("example.org"))));
+    }
+    virtual FindResult findZone(const Name& name) const {
+        const Name origin("example.org");
+        const ZoneFinderPtr finder(new Finder(origin));
+        NameComparisonResult compar(origin.compare(name));
+        switch (compar.getRelation()) {
+            case NameComparisonResult::EQUAL:
+                return (FindResult(result::SUCCESS, finder));
+            case NameComparisonResult::SUPERDOMAIN:
+                return (FindResult(result::PARTIALMATCH, finder));
+            default:
+                return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+        }
     };
     virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
         getJournalReader(const Name&, uint32_t, uint32_t) const
@@ -77,24 +164,16 @@ public:
     RRClass rrclass_;
 };
 
-// Test implementation of RRsetCollectionBase.
+// Test implementation of RRsetCollectionBase. This is currently just a
+// wrapper around \c isc::datasrc::RRsetCollectionBase;
+// \c isc::datasrc::RRsetCollectionBase may become an abstract class in
+// the future.
 class TestRRsetCollection : public isc::datasrc::RRsetCollectionBase {
 public:
     TestRRsetCollection(ZoneUpdater& updater,
                         const isc::dns::RRClass& rrclass) :
         isc::datasrc::RRsetCollectionBase(updater, rrclass)
     {}
-
-    virtual ~TestRRsetCollection() {}
-
-protected:
-    virtual RRsetCollectionBase::IterPtr getBeginning() {
-        isc_throw(isc::NotImplemented, "This method is not implemented.");
-    }
-
-    virtual RRsetCollectionBase::IterPtr getEnd() {
-        isc_throw(isc::NotImplemented, "This method is not implemented.");
-    }
 };
 
 // The updater isn't really correct according to the API. For example,
@@ -111,7 +190,7 @@ public:
     virtual ZoneFinder& getFinder() {
         return (finder_);
     }
-    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+    virtual isc::dns::RRsetCollectionBase& getRRsetCollection() {
         if (!rrset_collection_) {
             rrset_collection_.reset(new TestRRsetCollection(*this,
                                                             client_->rrclass_));
@@ -214,13 +293,6 @@ protected:
         source_client_(ztable_segment_, rrclass_)
     {}
     void prepareSource(const Name& zone, const char* filename) {
-        // TODO:
-        // Currently, source_client_ is of InMemoryClient and its load()
-        // uses a different code than the ZoneLoader (so we can cross-check
-        // the implementations). Currently, the load() doesn't perform any
-        // post-load checks. It will change in #2499, at which point the
-        // loading may start failing depending on details of the test data. We
-        // should prepare the data by some different method then.
         source_client_.load(zone, string(TEST_DATA_DIR) + "/" + filename);
     }
 private:
@@ -507,17 +579,6 @@ TEST_F(ZoneLoaderTest, loadCheck) {
     EXPECT_FALSE(destination_client_.commit_called_);
 }
 
-// The same test, but for copying from other data source
-TEST_F(ZoneLoaderTest, copyCheck) {
-    prepareSource(Name("example.org"), "novalidate.zone");
-    ZoneLoader loader(destination_client_, Name("example.org"),
-                      source_client_);
-
-    EXPECT_THROW(loader.loadIncremental(10), ZoneContentError);
-    // The messages go to the log. We don't have an easy way to examine them.
-    EXPECT_FALSE(destination_client_.commit_called_);
-}
-
 // Check a warning doesn't disrupt the loading of the zone
 TEST_F(ZoneLoaderTest, loadCheckWarn) {
     ZoneLoader loader(destination_client_, Name("example.org"),
@@ -541,4 +602,18 @@ TEST_F(ZoneLoaderTest, copyCheckWarn) {
 
 }
 
+// Test there's validation of the data in the zone loader when copying
+// from another data source.
+TEST_F(ZoneLoaderTest, copyCheck) {
+    // In this test, my_source_client provides a zone that does not
+    // validate (no NS).
+    MockClient my_source_client;
+    ZoneLoader loader(destination_client_, Name("example.org"),
+                      my_source_client);
+
+    EXPECT_THROW(loader.loadIncremental(10), ZoneContentError);
+    // The messages go to the log. We don't have an easy way to examine them.
+    EXPECT_FALSE(destination_client_.commit_called_);
+}
+
 }
diff --git a/src/lib/datasrc/tests/zonetable_unittest.cc b/src/lib/datasrc/tests/zonetable_unittest.cc
deleted file mode 100644
index 5a29a44..0000000
--- a/src/lib/datasrc/tests/zonetable_unittest.cc
+++ /dev/null
@@ -1,128 +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 <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-
-#include <datasrc/zonetable.h>
-// We use InMemoryZone to put something into the table
-#include <datasrc/memory_datasrc.h>
-
-#include <gtest/gtest.h>
-
-using namespace isc::dns;
-using namespace isc::datasrc;
-
-namespace {
-TEST(ZoneTest, init) {
-    InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
-    EXPECT_EQ(Name("example.com"), zone.getOrigin());
-    EXPECT_EQ(RRClass::IN(), zone.getClass());
-
-    InMemoryZoneFinder ch_zone(RRClass::CH(), Name("example"));
-    EXPECT_EQ(Name("example"), ch_zone.getOrigin());
-    EXPECT_EQ(RRClass::CH(), ch_zone.getClass());
-}
-
-TEST(ZoneTest, find) {
-    InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
-    EXPECT_EQ(ZoneFinder::NXDOMAIN,
-              zone.find(Name("www.example.com"), RRType::A())->code);
-}
-
-class ZoneTableTest : public ::testing::Test {
-protected:
-    ZoneTableTest() : zone1(new InMemoryZoneFinder(RRClass::IN(),
-                                                   Name("example.com"))),
-                      zone2(new InMemoryZoneFinder(RRClass::IN(),
-                                                   Name("example.net"))),
-                      zone3(new InMemoryZoneFinder(RRClass::IN(),
-                                                   Name("example"))),
-                      zone_table(ZoneTable::create(mem_sgmt_))
-    {}
-
-    ~ZoneTableTest() {
-        ZoneTable::destroy(mem_sgmt_, zone_table);
-    }
-    ZoneFinderPtr zone1, zone2, zone3;
-    isc::util::MemorySegmentLocal mem_sgmt_;
-    ZoneTable* zone_table;
-};
-
-TEST_F(ZoneTableTest, addZone) {
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
-    EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zone1));
-    // names are compared in a case insensitive manner.
-    EXPECT_EQ(result::EXIST, zone_table->addZone(
-                  mem_sgmt_,
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
-                                                       Name("EXAMPLE.COM")))));
-
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
-
-    // Zone table is indexed only by name.  Duplicate origin name with
-    // different zone class isn't allowed.
-    EXPECT_EQ(result::EXIST, zone_table->addZone(
-                  mem_sgmt_,
-                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
-                                                       Name("example.com")))));
-
-    /// Bogus zone (NULL)
-    EXPECT_THROW(zone_table->addZone(mem_sgmt_, ZoneFinderPtr()),
-                 isc::InvalidParameter);
-}
-
-TEST_F(ZoneTableTest, DISABLED_removeZone) {
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
-
-    EXPECT_EQ(result::SUCCESS, zone_table->removeZone(Name("example.net")));
-    EXPECT_EQ(result::NOTFOUND, zone_table->removeZone(Name("example.net")));
-}
-
-TEST_F(ZoneTableTest, findZone) {
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
-
-    EXPECT_EQ(result::SUCCESS, zone_table->findZone(Name("example.com")).code);
-    EXPECT_EQ(Name("example.com"),
-              zone_table->findZone(Name("example.com")).zone->getOrigin());
-
-    EXPECT_EQ(result::NOTFOUND,
-              zone_table->findZone(Name("example.org")).code);
-    EXPECT_EQ(ConstZoneFinderPtr(),
-              zone_table->findZone(Name("example.org")).zone);
-
-    // there's no exact match.  the result should be the longest match,
-    // and the code should be PARTIALMATCH.
-    EXPECT_EQ(result::PARTIALMATCH,
-              zone_table->findZone(Name("www.example.com")).code);
-    EXPECT_EQ(Name("example.com"),
-              zone_table->findZone(Name("www.example.com")).zone->getOrigin());
-
-    // make sure the partial match is indeed the longest match by adding
-    // a zone with a shorter origin and query again.
-    ZoneFinderPtr zone_com(new InMemoryZoneFinder(RRClass::IN(), Name("com")));
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone_com));
-    EXPECT_EQ(Name("example.com"),
-              zone_table->findZone(Name("www.example.com")).zone->getOrigin());
-}
-}
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 01d6a83..ca73bb5 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -18,731 +18,18 @@
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
+#include <dns/rrset_collection_base.h>
 
 #include <datasrc/exceptions.h>
 #include <datasrc/result.h>
-#include <datasrc/rrset_collection_base.h>
 
 #include <utility>
-#include <vector>
 
 namespace isc {
 namespace datasrc {
 
-/// \brief Out of zone exception
-///
-/// This is thrown when a method is called for a name or RRset which
-/// is not in or below the zone.
-class OutOfZone : public ZoneException {
-public:
-    OutOfZone(const char* file, size_t line, const char* what) :
-        ZoneException(file, line, what) {}
-};
-
-/// \brief The base class to search a zone for RRsets
-///
-/// The \c ZoneFinder class is an abstract base class for representing
-/// an object that performs DNS lookups in a specific zone accessible via
-/// a data source.  In general, different types of data sources (in-memory,
-/// database-based, etc) define their own derived classes of \c ZoneFinder,
-/// implementing ways to retrieve the required data through the common
-/// interfaces declared in the base class.  Each concrete \c ZoneFinder
-/// object is therefore (conceptually) associated with a specific zone
-/// of one specific data source instance.
-///
-/// The origin name and the RR class of the associated zone are available
-/// via the \c getOrigin() and \c getClass() methods, respectively.
-///
-/// The most important method of this class is \c find(), which performs
-/// the lookup for a given domain and type.  See the description of the
-/// method for details.
-///
-/// \note It's not clear whether we should request that a zone finder form a
-/// "transaction", that is, whether to ensure the finder is not susceptible
-/// to changes made by someone else than the creator of the finder.  If we
-/// don't request that, for example, two different lookup results for the
-/// same name and type can be different if other threads or programs make
-/// updates to the zone between the lookups.  We should revisit this point
-/// as we gain more experiences.
-class ZoneFinder {
-public:
-    /// Result codes of the \c find() method.
-    ///
-    /// Note: the codes are tentative.  We may need more, or we may find
-    /// some of them unnecessary as we implement more details.
-    ///
-    /// See the description of \c find() for further details of how
-    /// these results should be interpreted.
-    enum Result {
-        SUCCESS,                ///< An exact match is found.
-        DELEGATION,             ///< The search encounters a zone cut.
-        NXDOMAIN, ///< There is no domain name that matches the search name
-        NXRRSET,  ///< There is a matching name but no RRset of the search type
-        CNAME,    ///< The search encounters and returns a CNAME RR
-        DNAME    ///< The search encounters and returns a DNAME RR
-    };
-
-    /// Special attribute flags on the result of the \c find() method
-    ///
-    /// The flag values defined here are intended to signal to the caller
-    /// that it may need special handling on the result.  This is particularly
-    /// of concern when DNSSEC is requested.  For example, for negative
-    /// responses the caller would want to know whether the zone is signed
-    /// with NSEC or NSEC3 so that it can subsequently provide necessary
-    /// proof of the result.
-    ///
-    /// The caller is generally expected to get access to the information
-    /// via read-only getter methods of \c FindContext so that it won't rely
-    /// on specific details of the representation of the flags.  So these
-    /// definitions are basically only meaningful for data source
-    /// implementations.
-    enum FindResultFlags {
-        RESULT_DEFAULT = 0,       ///< The default flags
-        RESULT_WILDCARD = 1,      ///< find() resulted in a wildcard match
-        RESULT_NSEC_SIGNED = 2,   ///< The zone is signed with NSEC RRs
-        RESULT_NSEC3_SIGNED = 4   ///< The zone is signed with NSEC3 RRs
-    };
-
-    /// Find options.
-    ///
-    /// The option values are used as a parameter for \c find().
-    /// These are values of a bitmask type.  Bitwise operations can be
-    /// performed on these values to express compound options.
-    enum FindOptions {
-        FIND_DEFAULT = 0,       ///< The default options
-        FIND_GLUE_OK = 1,       ///< Allow search under a zone cut
-        FIND_DNSSEC = 2,        ///< Require DNSSEC data in the answer
-                                ///< (RRSIG, NSEC, etc.). The implementation
-                                ///< is allowed to include it even if it is
-                                ///< not set.
-        NO_WILDCARD = 4         ///< Do not try wildcard matching.
-    };
-
-protected:
-    /// \brief A convenient tuple representing a set of find() results.
-    ///
-    /// This helper structure is specifically expected to be used as an input
-    /// for the construct of the \c Context class object used by derived
-    /// ZoneFinder implementations.  This is therefore defined as protected.
-    struct ResultContext {
-        ResultContext(Result code_param,
-                      isc::dns::ConstRRsetPtr rrset_param,
-                      FindResultFlags flags_param = RESULT_DEFAULT) :
-            code(code_param), rrset(rrset_param), flags(flags_param)
-        {}
-        const Result code;
-        const isc::dns::ConstRRsetPtr rrset;
-        const FindResultFlags flags;
-    };
-
-public:
-    /// \brief A helper function to strip RRSIGs when FIND_DNSSEC is not
-    /// requested.
-    static isc::dns::ConstRRsetPtr
-    stripRRsigs(isc::dns::ConstRRsetPtr rp, const FindOptions options);
-
-    /// \brief Context of the result of a find() call.
-    ///
-    /// This class encapsulates results and (possibly) associated context
-    /// of a call to the \c find() method.   The public member variables of
-    /// this class represent the result of the call.  They are a
-    /// straightforward tuple of the result code and a pointer (and
-    /// optionally special flags) to the found RRset.
-    ///
-    /// These member variables will be initialized on construction and never
-    /// change, so for convenience we allow the applications to refer to some
-    /// of the members directly.  For some others we provide read-only accessor
-    /// methods to hide specific representation.
-    ///
-    /// Another role of this class is to provide the interface to some common
-    /// processing logic that may be necessary using the result of \c find().
-    /// Specifically, it's expected to be used in the context of DNS query
-    /// handling, where the caller would need to look into the data source
-    /// again based on the \c find() result.  For example, it would need to
-    /// get A and/or AAAA records for some of the answer or authority RRs.
-    ///
-    /// This class defines (a set of) method(s) that can be commonly used
-    /// for such purposes for any type of data source (as long as it conforms
-    /// to the public \c find() interface).  In some cases, a specific data
-    /// source implementation may want to (and can) optimize the processing
-    /// exploiting its internal data structure and the knowledge of the context
-    /// of the precedent \c find() call.  Such a data source implementation
-    /// can define a derived class of the base Context and override the
-    /// specific virtual method.
-    ///
-    /// This base class defines these common protected methods along with
-    /// some helper pure virtual methods that would be necessary for the
-    /// common methods.  If a derived class wants to use the common version
-    /// of the protected method, it needs to provide expected result through
-    /// their implementation of the pure virtual methods.
-    ///
-    /// This class object is generally expected to be associated with the
-    /// ZoneFinder that originally performed the \c find() call, and expects
-    /// the finder is valid throughout the lifetime of this object.  It's
-    /// caller's responsibility to ensure that assumption.
-    class Context {
-    public:
-        /// \brief The constructor.
-        ///
-        /// \param options The find options specified for the find() call.
-        /// \param result The result of the find() call.
-        Context(FindOptions options, const ResultContext& result) :
-            code(result.code), rrset(result.rrset),
-            flags_(result.flags), options_(options)
-        {}
-
-        /// \brief The destructor.
-        virtual ~Context() {}
-
-        const Result code;
-        const isc::dns::ConstRRsetPtr rrset;
-
-        /// Return true iff find() results in a wildcard match.
-        bool isWildcard() const { return ((flags_ & RESULT_WILDCARD) != 0); }
-
-        /// Return true when the underlying zone is signed with NSEC.
-        ///
-        /// The \c find() implementation allows this to return false if
-        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
-        /// is signed or which of NSEC/NSEC3 is used.
-        ///
-        /// When this is returned, the implementation of find() must ensure
-        /// that \c rrset be a valid NSEC RRset as described in \c find()
-        /// documentation.
-        bool isNSECSigned() const {
-            return ((flags_ & RESULT_NSEC_SIGNED) != 0);
-        }
-
-        /// Return true when the underlying zone is signed with NSEC3.
-        ///
-        /// The \c find() implementation allows this to return false if
-        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
-        /// is signed or which of NSEC/NSEC3 is used.
-        bool isNSEC3Signed() const {
-            return ((flags_ & RESULT_NSEC3_SIGNED) != 0);
-        }
-
-        /// \brief Find and return additional RRsets corresponding to the
-        ///        result of \c find().
-        ///
-        /// If this context is based on a normal find() call that resulted
-        /// in SUCCESS or DELEGATION, it examines the returned RRset (in many
-        /// cases NS, sometimes MX or others), searches the data source for
-        /// specified type of additional RRs for each RDATA of the RRset
-        /// (e.g., A or AAAA for the name server addresses), and stores the
-        /// result in the given vector.  The vector may not be empty; this
-        /// method appends any found RRsets to it, without touching existing
-        /// elements.
-        ///
-        /// If this context is based on a findAll() call that resulted in
-        /// SUCCESS, it performs the same process for each RRset returned in
-        /// the \c findAll() call.
-        ///
-        /// The caller specifies desired RR types of the additional RRsets
-        /// in \c requested_types.  Normally it consists of A and/or AAAA
-        /// types, but other types can be specified.
-        ///
-        /// This method is meaningful only when the precedent find()/findAll()
-        /// call resulted in SUCCESS or DELEGATION.  Otherwise this method
-        /// does nothing.
-        ///
-        /// \note The additional RRsets returned via method are limited to
-        /// ones contained in the zone which the corresponding find/findAll
-        /// call searched (possibly including glues under a zone cut where
-        /// they are applicable).  If the caller needs to get out-of-zone
-        /// additional RRsets, it needs to explicitly finds them by
-        /// identifying the corresponding zone and calls \c find() for it.
-        ///
-        /// \param requested_types A vector of RR types for desired additional
-        ///  RRsets.
-        /// \param result A vector to which any found additional RRsets are
-        /// to be inserted.
-        void getAdditional(
-            const std::vector<isc::dns::RRType>& requested_types,
-            std::vector<isc::dns::ConstRRsetPtr>& result)
-        {
-            // Perform common checks, and delegate the process to the default
-            // or specialized implementation.
-            if (code != SUCCESS && code != DELEGATION) {
-                return;
-            }
-
-            getAdditionalImpl(requested_types, result);
-        }
-
-    protected:
-        /// \brief Return the \c ZoneFinder that created this \c Context.
-        ///
-        /// A derived class implementation can return NULL if it defines
-        /// other protected methods that require a non NULL result from
-        /// this method.  Otherwise it must return a valid, non NULL pointer
-        /// to the \c ZoneFinder object.
-        ///
-        /// When returning non NULL, the ownership of the pointed object
-        /// was not transferred to the caller; it cannot be assumed to be
-        /// valid after the originating \c Context object is destroyed.
-        /// Also, the caller must not try to delete the returned object.
-        virtual ZoneFinder* getFinder() = 0;
-
-        /// \brief Return a vector of RRsets corresponding to findAll() result.
-        ///
-        /// This method returns a set of RRsets that correspond to the
-        /// returned RRsets to a prior \c findAll() call.
-        ///
-        /// A derived class implementation can return NULL if it defines
-        /// other protected methods that require a non NULL result from
-        /// this method.  Otherwise it must return a valid, non NULL pointer
-        /// to a vector that correspond to the expected set of RRsets.
-        ///
-        /// When returning non NULL, the ownership of the pointed object
-        /// was not transferred to the caller; it cannot be assumed to be
-        /// valid after the originating \c Context object is destroyed.
-        /// Also, the caller must not try to delete the returned object.
-        virtual const std::vector<isc::dns::ConstRRsetPtr>*
-        getAllRRsets() const = 0;
-
-        /// \brief Actual implementation of getAdditional().
-        ///
-        /// This base class defines a default implementation that can be
-        /// used for any type of data sources.  A data source implementation
-        /// can override it.
-        ///
-        /// The default version of this implementation requires both
-        /// \c getFinder() and \c getAllRRsets() return valid results.
-        virtual void getAdditionalImpl(
-            const std::vector<isc::dns::RRType>& requested_types,
-            std::vector<isc::dns::ConstRRsetPtr>& result);
-
-    private:
-        const FindResultFlags flags_;
-    protected:
-        const FindOptions options_;
-    };
-
-    /// \brief Generic ZoneFinder context that works for all implementations.
-    ///
-    /// This is a concrete derived class of \c ZoneFinder::Context that
-    /// only use the generic (default) versions of the protected methods
-    /// and therefore work for any data source implementation.
-    ///
-    /// A data source implementation can use this class to create a
-    /// \c Context object as a return value of \c find() or \c findAll()
-    /// method if it doesn't have to optimize specific protected methods.
-    class GenericContext : public Context {
-    public:
-        /// \brief The constructor for the normal find call.
-        ///
-        /// This constructor is expected to be called from the \c find()
-        /// method when it constructs the return value.
-        ///
-        /// \param finder The ZoneFinder on which find() is called.
-        /// \param options See the \c Context class.
-        /// \param result See the \c Context class.
-        GenericContext(ZoneFinder& finder, FindOptions options,
-                       const ResultContext& result) :
-            Context(options, result), finder_(finder)
-        {}
-
-        /// \brief The constructor for the normal findAll call.
-        ///
-        /// This constructor is expected to be called from the \c findAll()
-        /// method when it constructs the return value.
-        ///
-        /// It copies the vector that is to be returned to the caller of
-        /// \c findAll() for possible subsequent use.  Note that it cannot
-        /// simply hold a reference to the vector because the caller may
-        /// alter it after the \c findAll() call.
-        ///
-        /// \param finder The ZoneFinder on which findAll() is called.
-        /// \param options See the \c Context class.
-        /// \param result See the \c Context class.
-        /// \param all_set Reference to the vector given by the caller of
-        ///       \c findAll(), storing the RRsets to be returned.
-        GenericContext(ZoneFinder& finder, FindOptions options,
-                       const ResultContext& result,
-                       const std::vector<isc::dns::ConstRRsetPtr>& all_set) :
-            Context(options, result), finder_(finder), all_set_(all_set)
-        {}
-
-    protected:
-        virtual ZoneFinder* getFinder() { return (&finder_); }
-        virtual const std::vector<isc::dns::ConstRRsetPtr>*
-        getAllRRsets() const {
-            return (&all_set_);
-        }
-
-    private:
-        ZoneFinder& finder_;
-        std::vector<isc::dns::ConstRRsetPtr> all_set_;
-    };
-
-    ///
-    /// \name Constructors and Destructor.
-    ///
-    //@{
-protected:
-    /// 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).
-    ZoneFinder() {}
-public:
-    /// The destructor.
-    virtual ~ZoneFinder() {}
-    //@}
-
-    ///
-    /// \name Getter Methods
-    ///
-    /// These methods should never throw an exception.
-    //@{
-    /// Return the origin name of the zone.
-    virtual isc::dns::Name getOrigin() const = 0;
-
-    /// Return the RR class of the zone.
-    virtual isc::dns::RRClass getClass() const = 0;
-    //@}
-
-    ///
-    /// \name Search Methods
-    ///
-    //@{
-    /// Search the zone for a given pair of domain name and RR type.
-    ///
-    /// Each derived version of this method searches the underlying backend
-    /// for the data that best matches the given name and type.
-    /// This method is expected to be "intelligent", and identifies the
-    /// best possible answer for the search key.  Specifically,
-    ///
-    /// - If the search name belongs under a zone cut, it returns the code
-    ///   of \c DELEGATION and the NS RRset at the zone cut.
-    /// - If there is no matching name, it returns the code of \c NXDOMAIN.
-    /// - If there is a matching name but no RRset of the search type, it
-    ///   returns the code of \c NXRRSET.  This case includes the search name
-    ///   matches an empty node of the zone.
-    /// - If there is a CNAME RR of the searched name but there is no
-    ///   RR of the searched type of the name (so this type is different from
-    ///   CNAME), it returns the code of \c CNAME and that CNAME RR.
-    ///   Note that if the searched RR type is CNAME, it is considered
-    ///   a successful match, and the code of \c SUCCESS will be returned.
-    /// - If the search name matches a delegation point of DNAME, it returns
-    ///   the code of \c DNAME and that DNAME RR.
-    ///
-    /// No RRset will be returned in the \c NXDOMAIN and \c NXRRSET cases
-    /// (\c rrset member of \c FindContext will be NULL), unless DNSSEC data
-    /// are required.  See below for the cases with DNSSEC.
-    ///
-    /// The returned \c FindContext object can also provide supplemental
-    /// information about the search result via its methods returning a
-    /// boolean value.  Such information may be useful for the caller if
-    /// the caller wants to collect additional DNSSEC proofs based on the
-    /// search result.
-    ///
-    /// The \c options parameter specifies customized behavior of the search.
-    /// Their semantics is as follows (they are or bit-field):
-    ///
-    /// - \c FIND_GLUE_OK Allow search under a zone cut.  By default the search
-    ///   will stop once it encounters a zone cut.  If this option is specified
-    ///   it remembers information about the highest zone cut and continues
-    ///   the search until it finds an exact match for the given name or it
-    ///   detects there is no exact match.  If an exact match is found,
-    ///   RRsets for that name are searched just like the normal case;
-    ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
-    ///   with the information of the highest zone cut will be returned.
-    ///   Note: the term "glue" in the DNS protocol standard may sometimes
-    ///   cause confusion: some people use this term strictly for an address
-    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
-    ///   some others seem to give it broader flexibility.  Nevertheless,
-    ///   in this API the "GLUE OK" simply means the search by find() can
-    ///   continue beyond a zone cut; the derived class implementation does
-    ///   not have to, and should not, check whether the type is an address
-    ///   record or whether the query name is pointed by some NS RR.
-    ///   It's up to the caller with which definition of "glue" the search
-    ///   result with this option should be used.
-    /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
-    ///   returned with the answer. It is allowed for the data source to
-    ///   include them even when not requested.
-    /// - \c NO_WILDCARD Do not try wildcard matching.  This option is of no
-    ///   use for normal lookups; it's intended to be used to get a DNSSEC
-    ///   proof of the non existence of any matching wildcard or non existence
-    ///   of an exact match when a wildcard match is found.
-    ///
-    /// In general, \c name is expected to be included in the zone, that is,
-    /// it should be equal to or a subdomain of the zone origin.  Otherwise
-    /// this method will return \c NXDOMAIN with an empty RRset.  But such a
-    /// case should rather be considered a caller's bug.
-    ///
-    /// \note For this reason it's probably better to throw an exception
-    /// than returning \c NXDOMAIN.  This point should be revisited in a near
-    /// future version.  In any case applications shouldn't call this method
-    /// for an out-of-zone name.
-    ///
-    /// <b>DNSSEC considerations:</b>
-    /// The result when DNSSEC data are required can be very complicated,
-    /// especially if it involves negative result or wildcard match.
-    /// Specifically, if an application calls this method for DNS query
-    /// processing with DNSSEC data, and if the search result code is
-    /// either \c NXDOMAIN or \c NXRRRSET, and/or \c isWildcard() returns
-    /// true, then the application will need to find additional NSEC or
-    /// NSEC3 records for supplemental proofs.  This method helps the
-    /// application for such post search processing.
-    ///
-    /// First, it tells the application whether the zone is signed with
-    /// NSEC or NSEC3 via the \c isNSEC(3)Signed() method.  Any sanely signed
-    /// zone should be signed with either (and only one) of these two types
-    /// of RRs; however, the application should expect that the zone could
-    /// be broken and these methods could both return false.  But this method
-    /// should ensure that not both of these methods return true.
-    ///
-    /// In case it's signed with NSEC3, there is no further information
-    /// returned from this method.
-    ///
-    /// In case it's signed with NSEC, this method will possibly return
-    /// a related NSEC RRset in the \c rrset member of \c FindContext.
-    /// What kind of NSEC is returned depends on the result code
-    /// (\c NXDOMAIN or \c NXRRSET) and on whether it's a wildcard match:
-    ///
-    /// - In case of NXDOMAIN, the returned NSEC covers the queried domain
-    ///   that proves that the query name does not exist in the zone.  Note
-    ///   that this does not necessarily prove it doesn't even match a
-    ///   wildcard (even if the result of NXDOMAIN can only happen when
-    ///   there's no matching wildcard either).  It is caller's
-    ///   responsibility to provide a proof that there is no matching
-    ///   wildcard if that proof is necessary.
-    /// - In case of NXRRSET, we need to consider the following cases
-    ///   referring to Section 3.1.3 of RFC4035:
-    ///
-    /// -# (Normal) no data: there is a matching non-wildcard name with a
-    ///    different RR type.  This is the "No Data" case of the RFC.
-    /// -# (Normal) empty non terminal: there is no matching (exact or
-    ///    wildcard) name, but there is a subdomain with an RR of the query
-    ///    name.  This is one case of "Name Error" of the RFC.
-    /// -# Wildcard empty non terminal: similar to 2a, but the empty name
-    ///    is a wildcard, and matches the query name by wildcard expansion.
-    ///    This is a special case of "Name Error" of the RFC.
-    /// -# Wildcard no data: there is no exact match name, but there is a
-    ///    wildcard name that matches the query name with a different type
-    ///    of RR.  This is the "Wildcard No Data" case of the RFC.
-    ///
-    /// In case 1, \c find() returns NSEC of the matching name.
-    ///
-    /// In case 2, \c find() will return NSEC for the interval where the
-    /// empty nonterminal lives. The end of the interval is the subdomain
-    /// causing existence of the empty nonterminal (if there's
-    /// sub.x.example.com, and no record in x.example.com, then
-    /// x.example.com exists implicitly - is the empty nonterminal and
-    /// sub.x.example.com is the subdomain causing it).  Note that this NSEC
-    /// proves not only the existence of empty non terminal name but also
-    /// the non existence of possibly matching wildcard name, because
-    /// there can be no better wildcard match than the exact matching empty
-    /// name.
-    ///
-    /// In case 3, \c find() will return NSEC for the interval where the
-    /// wildcard empty nonterminal lives.   Cases 2 and 3 are especially
-    /// complicated and confusing.  See the examples below.
-    ///
-    /// In case 4, \c find() will return NSEC of the matching wildcard name.
-    ///
-    /// Examples: if zone "example.com" has the following record:
-    /// \code
-    /// a.example.com. NSEC a.b.example.com.
-    /// \endcode
-    /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
-    /// will result in NXRRSET, and this NSEC will be returned.
-    /// Likewise, if zone "example.org" has the following record,
-    /// \code
-    /// a.example.org. NSEC x.*.b.example.org.
-    /// \endcode
-    /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
-    /// result in NXRRSET and this NSEC; \c isWildcard() on the returned
-    /// \c FindContext object will return true.
-    ///
-    /// \exception std::bad_alloc Memory allocation such as for constructing
-    ///  the resulting RRset fails
-    /// \throw OutOfZone The Name \c name is outside of the origin of the
-    /// zone of this ZoneFinder.
-    /// \exception DataSourceError Derived class specific exception, e.g.
-    /// when encountering a bad zone configuration or database connection
-    /// failure.  Although these are considered rare, exceptional events,
-    /// it can happen under relatively usual conditions (unlike memory
-    /// allocation failure).  So, in general, the application is expected
-    /// to catch this exception, either specifically or as a result of
-    /// catching a base exception class, and handle it gracefully.
-    ///
-    /// \param name The domain name to be searched for.
-    /// \param type The RR type to be searched for.
-    /// \param options The search options.
-    /// \return A \c FindContext object enclosing the search result
-    ///         (see above).
-    virtual boost::shared_ptr<Context> find(const isc::dns::Name& name,
-                                            const isc::dns::RRType& type,
-                                            const FindOptions options
-                                            = FIND_DEFAULT) = 0;
-
-    ///
-    /// \brief Finds all RRsets in the given name.
-    ///
-    /// This function works almost exactly in the same way as the find one. The
-    /// only difference is, when the lookup is successful (eg. the code is
-    /// SUCCESS), all the RRsets residing in the named node are
-    /// copied into the \c target parameter and the rrset member of the result
-    /// is NULL. All the other (unsuccessful) cases are handled the same,
-    /// including returning delegations, NSEC/NSEC3 availability and NSEC
-    /// proofs, wildcard information etc. The options parameter works the
-    /// same way and it should conform to the same exception restrictions.
-    ///
-    /// \param name \see find, parameter name
-    /// \param target the successfull result is returned through this
-    /// \param options \see find, parameter options
-    /// \return \see find and it's result
-    virtual boost::shared_ptr<Context> findAll(
-        const isc::dns::Name& name,
-        std::vector<isc::dns::ConstRRsetPtr> &target,
-        const FindOptions options = FIND_DEFAULT) = 0;
-
-    /// A helper structure to represent the search result of \c findNSEC3().
-    ///
-    /// The idea is similar to that of \c FindContext, but \c findNSEC3() has
-    /// special interface and semantics, we use a different structure to
-    /// represent the result.
-    struct FindNSEC3Result {
-        FindNSEC3Result(bool param_matched, uint8_t param_closest_labels,
-                        isc::dns::ConstRRsetPtr param_closest_proof,
-                        isc::dns::ConstRRsetPtr param_next_proof) :
-            matched(param_matched), closest_labels(param_closest_labels),
-            closest_proof(param_closest_proof),
-            next_proof(param_next_proof)
-        {}
-
-        /// true iff closest_proof is a matching NSEC3
-        const bool matched;
-
-        /// The number of labels of the identified closest encloser.
-        const uint8_t closest_labels;
-
-        /// Either the NSEC3 for the closest provable encloser of the given
-        /// name or NSEC3 that covers the name
-        const isc::dns::ConstRRsetPtr closest_proof;
-
-        /// When non NULL, NSEC3 for the next closer name.
-        const isc::dns::ConstRRsetPtr next_proof;
-    };
-
-    /// Search the zone for the NSEC3 RR(s) that prove existence or non
-    /// existence of a give name.
-    ///
-    /// It searches the NSEC3 namespace of the zone (how that namespace is
-    /// implemented can vary in specific data source implementation) for NSEC3
-    /// RRs that match or cover the NSEC3 hash value for the given name.
-    ///
-    /// If \c recursive is false, it will first look for the NSEC3 that has
-    /// a matching hash.  If it doesn't exist, it identifies the covering NSEC3
-    /// for the hash.  In either case the search stops at that point and the
-    /// found NSEC3 RR(set) will be returned in the closest_proof member of
-    /// \c FindNSEC3Result.  \c matched is true or false depending on
-    /// the found NSEC3 is a matched one or covering one.  \c next_proof
-    /// is always NULL.  closest_labels must be equal to the number of
-    /// labels of \c name (and therefore meaningless).
-    ///
-    /// If \c recursive is true, it will continue the search toward the zone
-    /// apex (origin name) until it finds a provable encloser, that is,
-    /// an ancestor of \c name that has a matching NSEC3.  This is the closest
-    /// provable encloser of \c name as defined in RFC5155.  In this case,
-    /// if the found encloser is not equal to \c name, the search should
-    /// have seen a covering NSEC3 for the immediate child of the found
-    /// encloser.  That child name is the next closer name as defined in
-    /// RFC5155.  In this case, this method returns the NSEC3 for the
-    /// closest encloser in \c closest_proof, and the NSEC3 for the next
-    /// closer name in \c next_proof of \c FindNSEC3Result.  This set of
-    /// NSEC3 RRs provide the closest encloser proof as defined in RFC5155.
-    /// closest_labels will be set to the number of labels of the identified
-    /// closest encloser.  This will be useful when the caller needs to
-    /// construct the closest encloser name from the original \c name.
-    /// If, on the other hand, the found closest name is equal to \c name,
-    /// this method simply returns it in \c closest_proof.  \c next_proof
-    /// is set to NULL.  In all cases \c matched is set to true.
-    /// closest_labels will be set to the number of labels of \c name.
-    ///
-    /// When looking for NSEC3, this method retrieves NSEC3 parameters from
-    /// the corresponding zone to calculate hash values.  Actual implementation
-    /// of how to do this will differ in different data sources.  If the
-    /// NSEC3 parameters are not available \c DataSourceError exception
-    /// will be thrown.
-    ///
-    /// \note This implicitly means this method assumes the zone does not
-    /// have more than one set of parameters.  This assumption should be
-    /// reasonable in actual deployment and will help simplify the interface
-    /// and implementation.  But if there's a real need for supporting
-    /// multiple sets of parameters in a single zone, we will have to
-    /// extend this method so that, e.g., the caller can specify the parameter
-    /// set.
-    ///
-    /// In general, this method expects the zone is properly signed with NSEC3
-    /// RRs.  Specifically, it assumes at least the apex node has a matching
-    /// NSEC3 RR (so the search in the recursive mode must always succeed);
-    /// it also assumes that it can retrieve NSEC parameters (iterations,
-    /// algorithm, and salt) from the zone as noted above.  If these
-    /// assumptions aren't met, \c DataSourceError exception will be thrown.
-    ///
-    /// \exception OutOfZone name is not a subdomain of the zone origin
-    /// \exception DataSourceError Low-level or internal datasource errors
-    /// happened, or the zone isn't properly signed with NSEC3
-    /// (NSEC3 parameters cannot be found, no NSEC3s are available, etc).
-    /// \exception std::bad_alloc The underlying implementation involves
-    /// memory allocation and it fails
-    ///
-    /// \param name The name for which NSEC3 RRs are to be found.  It must
-    /// be a subdomain of the zone.
-    /// \param recursive Whether or not search should continue until it finds
-    /// a provable encloser (see above).
-    ///
-    /// \return The search result and whether or not the closest_proof is
-    /// a matching NSEC3, in the form of \c FindNSEC3Result object.
-    virtual FindNSEC3Result
-    findNSEC3(const isc::dns::Name& name, bool recursive) = 0;
-    //@}
-};
-
-/// \brief Operator to combine FindOptions
-///
-/// We would need to manually static-cast the options if we put or
-/// between them, which is undesired with bit-flag options. Therefore
-/// we hide the cast here, which is the simplest solution and it still
-/// provides reasonable level of type safety.
-inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
-                                          ZoneFinder::FindOptions b)
-{
-    return (static_cast<ZoneFinder::FindOptions>(static_cast<unsigned>(a) |
-                                                 static_cast<unsigned>(b)));
-}
-
-/// \brief Operator to combine FindResultFlags
-///
-/// Similar to the same operator for \c FindOptions.  Refer to the description
-/// of that function.
-inline ZoneFinder::FindResultFlags operator |(
-    ZoneFinder::FindResultFlags a,
-    ZoneFinder::FindResultFlags b)
-{
-    return (static_cast<ZoneFinder::FindResultFlags>(
-                static_cast<unsigned>(a) | static_cast<unsigned>(b)));
-}
-
-/// \brief A pointer-like type pointing to a \c ZoneFinder object.
-typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
-
-/// \brief A pointer-like type pointing to an immutable \c ZoneFinder object.
-typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
-
-/// \brief A pointer-like type pointing to a \c ZoneFinder::Context object.
-typedef boost::shared_ptr<ZoneFinder::Context> ZoneFinderContextPtr;
-
-/// \brief A pointer-like type pointing to an immutable
-/// \c ZoneFinder::Context object.
-typedef boost::shared_ptr<ZoneFinder::Context> ConstZoneFinderContextPtr;
-
 /// \brief A forward declaration
-class RRsetCollectionBase;
+class ZoneFinder;
 
 /// The base class to make updates to a single zone.
 ///
@@ -809,7 +96,7 @@ public:
     /// Return an RRsetCollection for the updater.
     ///
     /// This method returns an \c RRsetCollection for the updater,
-    /// implementing the \c isc::datasrc::RRsetCollectionBase
+    /// implementing the \c isc::dns::RRsetCollectionBase
     /// interface. Typically, the returned \c RRsetCollection is a
     /// singleton for its \c ZoneUpdater. The returned RRsetCollection
     /// object must not be used after its corresponding \c ZoneUpdater
@@ -819,15 +106,51 @@ public:
     /// \c ZoneUpdater implementation.
     ///
     /// The behavior of the RRsetCollection is similar to the behavior
-    /// of the \c Zonefinder returned by \c getFinder().
+    /// of the \c Zonefinder returned by \c getFinder().  In fact, it's
+    /// redundant in a sense because one can implement the
+    /// \c dns::RRsetCollectionBase interface using an updater and
+    /// \c getFinder() interface (unless it's expected to support zone
+    /// iteration, and the initial implementation of the \c RRsetCollection
+    /// returned by this method doesn't support it).  We still provide it
+    /// as an updater's method so it will be easier for an updater
+    /// implementation to customize the \c RRsetCollection implementation,
+    /// and also for making it easy to impose restrictions described below.
+    ///
+    /// Specific data sources may have special restrictions.  That's
+    /// especially the case for database-based data sources.  Such
+    /// restrictions may also result in limiting the usage of the
+    /// \c RRsetCollection as described in the following paragraphs.  A
+    /// specific updater implementation may provide more flexible
+    /// behavior, but applications using this interface must assume
+    /// the most restricted case unless it knows it uses a particular
+    /// specialized updater implementation that loosens specific restrictions.
+    ///
+    /// To summarize the restrictions:
+    /// - An application must not add or delete RRsets after
+    ///   \c getRRsetCollection() is called.
+    /// - An application must not use the returned collection from
+    ///   \c getRRsetCollection() once \c commit() is called on the updater
+    ///   that generates the collection.
+    ///
     /// Implementations of \c ZoneUpdater may not allow adding or
-    /// deleting RRsets after \c getRRsetCollection() is called.
-    /// Implementations of \c ZoneUpdater may disable a previously
-    /// returned \c RRsetCollection after \c commit() is called. If an
-    /// \c RRsetCollection is disabled, using methods such as \c find()
-    /// and using its iterator would cause an exception to be
-    /// thrown. See \c isc::datasrc::RRsetCollectionBase for details.
-    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() = 0;
+    /// deleting RRsets after \c getRRsetCollection() is called. This is
+    /// because if an iterator of the collection is being used at that time
+    /// the modification to the zone may break an internal assumption of the
+    /// iterator and may result in unexpected behavior.  Also, the iterator
+    /// may conceptually hold a "reader lock" of the zone (in an implementation
+    /// dependent manner), which would prevent the addition or deletion,
+    /// surprising the caller (who would normally expect it to succeed).
+    ///
+    /// Implementations of \c ZoneUpdater may disable a previously returned
+    /// \c RRsetCollection after \c commit() is called.  This is because
+    /// the returned \c RRsetCollection may internally rely on the conceptual
+    /// transaction of the updater that generates the collection (which would
+    /// be literally the case for database-based data sources), and once
+    /// the transaction is committed anything that relies on it won't be valid.
+    /// If an \c RRsetCollection is disabled, using methods such as \c find()
+    /// and using its iterator would cause an exception to be thrown. See
+    /// \c isc::datasrc::RRsetCollectionBase for details.
+    virtual isc::dns::RRsetCollectionBase& getRRsetCollection() = 0;
 
     /// Add an RRset to a zone via the updater
     ///
@@ -877,8 +200,9 @@ public:
     /// \c DataSourceError exception.
     ///
     /// Implementations of \c ZoneUpdater may not allow adding or
-    /// deleting RRsets after \c getRRsetCollection() is called. In this
-    /// case, implementations throw an \c InvalidOperation exception.
+    /// deleting RRsets after \c getRRsetCollection() is called (see
+    /// the description of \c getRRsetCollection()).  In this case,
+    /// implementations throw an \c InvalidOperation exception.
     ///
     /// If journaling was requested when getting this updater, it will reject
     /// to add the RRset if the squence doesn't look like and IXFR (see
@@ -952,8 +276,9 @@ public:
     /// \c DataSourceError exception.
     ///
     /// Implementations of \c ZoneUpdater may not allow adding or
-    /// deleting RRsets after \c getRRsetCollection() is called. In this
-    /// case, implementations throw an \c InvalidOperation exception.
+    /// deleting RRsets after \c getRRsetCollection() is called (see
+    /// the description of \c getRRsetCollection()).  In this case,
+    /// implementations throw an \c InvalidOperation exception.
     ///
     /// If journaling was requested when getting this updater, it will reject
     /// to add the RRset if the squence doesn't look like and IXFR (see
diff --git a/src/lib/datasrc/zone_finder.cc b/src/lib/datasrc/zone_finder.cc
index 562b43f..b4240c0 100644
--- a/src/lib/datasrc/zone_finder.cc
+++ b/src/lib/datasrc/zone_finder.cc
@@ -12,13 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/zone_finder.h>
+#include <datasrc/data_source.h>
+
 #include <dns/rdata.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 
-#include <datasrc/zone.h>
-
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
@@ -26,6 +27,96 @@ using namespace isc::dns::rdata;
 namespace isc {
 namespace datasrc {
 
+namespace {
+// Identify zone's SOA and return its MINTTL in the form of RRTTL.
+RRTTL
+getMinTTL(ZoneFinder& finder, ConstRRsetPtr rrset) {
+    ConstRRsetPtr soa_rrset;
+    if (rrset->getType() == RRType::SOA()) {
+        // Shortcut: if we are looking at SOA itself (which should be the
+        // case in the expected scenario), we can simply use its RDATA.
+        soa_rrset = rrset;
+    } else {
+        soa_rrset =
+            finder.findAtOrigin(RRType::SOA(), false,
+                                ZoneFinder::FIND_DEFAULT)->rrset;
+    }
+
+    // In a valid zone there is one and only one SOA RR at the origin.
+    // Otherwise either zone data or the data source implementation is broken.
+    if (!soa_rrset || soa_rrset->getRdataCount() != 1) {
+        isc_throw(DataSourceError, "Zone " << rrset->getName().toText(true)
+                  << "/" << rrset->getClass().toText() << " is broken: "
+                  << (!soa_rrset ? "no SOA" : "empty SOA"));
+    }
+
+    return (RRTTL(dynamic_cast<const generic::SOA&>(
+                      soa_rrset->getRdataIterator()->getCurrent()).
+                  getMinimum()));
+}
+
+// Make a fresh copy of given RRset, just replacing RRTTL with the given one.
+RRsetPtr
+copyRRset(const AbstractRRset& rrset, const RRTTL& ttl) {
+    RRsetPtr rrset_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                  rrset.getType(), ttl));
+    for (RdataIteratorPtr rit = rrset.getRdataIterator();
+         !rit->isLast();
+         rit->next()) {
+        rrset_copy->addRdata(rit->getCurrent());
+    }
+
+    ConstRRsetPtr rrsig = rrset.getRRsig();
+    if (rrsig) {
+        RRsetPtr rrsig_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                      RRType::RRSIG(), ttl));
+        for (RdataIteratorPtr rit = rrsig->getRdataIterator();
+             !rit->isLast();
+             rit->next()) {
+            rrsig_copy->addRdata(rit->getCurrent());
+        }
+        rrset_copy->addRRsig(rrsig_copy);
+    }
+
+    return (rrset_copy);
+}
+}
+
+ZoneFinderContextPtr
+ZoneFinder::findAtOrigin(const dns::RRType& type, bool use_minttl,
+                         FindOptions options)
+{
+    ZoneFinderContextPtr context = find(getOrigin(), type, options);
+
+    // If we are requested to use the min TTL and the RRset's RR TTL is larger
+    // than that, we need to make a copy of the RRset, replacing the TTL,
+    // and return a newly created context copying other parameters.
+    if (use_minttl && context->rrset) {
+        const AbstractRRset& rrset = *context->rrset;
+        const RRTTL min_ttl = getMinTTL(*this, context->rrset);
+        if (min_ttl < rrset.getTTL()) {
+            FindResultFlags flags_copy = RESULT_DEFAULT;
+            if (context->isWildcard()) {
+                flags_copy = flags_copy | RESULT_WILDCARD;
+            }
+            if (context->isNSECSigned()) {
+                flags_copy = flags_copy | RESULT_NSEC_SIGNED;
+            } else if (context->isNSEC3Signed()) {
+                flags_copy = flags_copy | RESULT_NSEC3_SIGNED;
+            }
+
+            return (ZoneFinderContextPtr(
+                        new GenericContext(*this, options,
+                                           ResultContext(context->code,
+                                                         copyRRset(rrset,
+                                                                   min_ttl),
+                                                         flags_copy))));
+        }
+    }
+
+    return (context);
+}
+
 isc::dns::ConstRRsetPtr
 ZoneFinder::stripRRsigs(isc::dns::ConstRRsetPtr rp,
                         const FindOptions options) {
diff --git a/src/lib/datasrc/zone_finder.h b/src/lib/datasrc/zone_finder.h
new file mode 100644
index 0000000..83851f6
--- /dev/null
+++ b/src/lib/datasrc/zone_finder.h
@@ -0,0 +1,808 @@
+// 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 DATASRC_ZONE_FINDER_H
+#define DATASRC_ZONE_FINDER_H 1
+
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+
+#include <datasrc/exceptions.h>
+#include <datasrc/result.h>
+
+#include <utility>
+#include <vector>
+
+namespace isc {
+namespace datasrc {
+
+/// \brief Out of zone exception
+///
+/// This is thrown when a method is called for a name or RRset which
+/// is not in or below the zone.
+class OutOfZone : public ZoneException {
+public:
+    OutOfZone(const char* file, size_t line, const char* what) :
+        ZoneException(file, line, what) {}
+};
+
+/// \brief The base class to search a zone for RRsets
+///
+/// The \c ZoneFinder class is an abstract base class for representing
+/// an object that performs DNS lookups in a specific zone accessible via
+/// a data source.  In general, different types of data sources (in-memory,
+/// database-based, etc) define their own derived classes of \c ZoneFinder,
+/// implementing ways to retrieve the required data through the common
+/// interfaces declared in the base class.  Each concrete \c ZoneFinder
+/// object is therefore (conceptually) associated with a specific zone
+/// of one specific data source instance.
+///
+/// The origin name and the RR class of the associated zone are available
+/// via the \c getOrigin() and \c getClass() methods, respectively.
+///
+/// The most important method of this class is \c find(), which performs
+/// the lookup for a given domain and type.  See the description of the
+/// method for details.
+///
+/// \note It's not clear whether we should request that a zone finder form a
+/// "transaction", that is, whether to ensure the finder is not susceptible
+/// to changes made by someone else than the creator of the finder.  If we
+/// don't request that, for example, two different lookup results for the
+/// same name and type can be different if other threads or programs make
+/// updates to the zone between the lookups.  We should revisit this point
+/// as we gain more experiences.
+class ZoneFinder {
+public:
+    /// Result codes of the \c find() method.
+    ///
+    /// Note: the codes are tentative.  We may need more, or we may find
+    /// some of them unnecessary as we implement more details.
+    ///
+    /// See the description of \c find() for further details of how
+    /// these results should be interpreted.
+    enum Result {
+        SUCCESS,                ///< An exact match is found.
+        DELEGATION,             ///< The search encounters a zone cut.
+        NXDOMAIN, ///< There is no domain name that matches the search name
+        NXRRSET,  ///< There is a matching name but no RRset of the search type
+        CNAME,    ///< The search encounters and returns a CNAME RR
+        DNAME    ///< The search encounters and returns a DNAME RR
+    };
+
+    /// Special attribute flags on the result of the \c find() method
+    ///
+    /// The flag values defined here are intended to signal to the caller
+    /// that it may need special handling on the result.  This is particularly
+    /// of concern when DNSSEC is requested.  For example, for negative
+    /// responses the caller would want to know whether the zone is signed
+    /// with NSEC or NSEC3 so that it can subsequently provide necessary
+    /// proof of the result.
+    ///
+    /// The caller is generally expected to get access to the information
+    /// via read-only getter methods of \c FindContext so that it won't rely
+    /// on specific details of the representation of the flags.  So these
+    /// definitions are basically only meaningful for data source
+    /// implementations.
+    enum FindResultFlags {
+        RESULT_DEFAULT = 0,       ///< The default flags
+        RESULT_WILDCARD = 1,      ///< find() resulted in a wildcard match
+        RESULT_NSEC_SIGNED = 2,   ///< The zone is signed with NSEC RRs
+        RESULT_NSEC3_SIGNED = 4   ///< The zone is signed with NSEC3 RRs
+    };
+
+    /// Find options.
+    ///
+    /// The option values are used as a parameter for \c find().
+    /// These are values of a bitmask type.  Bitwise operations can be
+    /// performed on these values to express compound options.
+    enum FindOptions {
+        FIND_DEFAULT = 0,       ///< The default options
+        FIND_GLUE_OK = 1,       ///< Allow search under a zone cut
+        FIND_DNSSEC = 2,        ///< Require DNSSEC data in the answer
+                                ///< (RRSIG, NSEC, etc.). The implementation
+                                ///< is allowed to include it even if it is
+                                ///< not set.
+        NO_WILDCARD = 4         ///< Do not try wildcard matching.
+    };
+
+protected:
+    /// \brief A convenient tuple representing a set of find() results.
+    ///
+    /// This helper structure is specifically expected to be used as an input
+    /// for the construct of the \c Context class object used by derived
+    /// ZoneFinder implementations.  This is therefore defined as protected.
+    struct ResultContext {
+        ResultContext(Result code_param,
+                      isc::dns::ConstRRsetPtr rrset_param,
+                      FindResultFlags flags_param = RESULT_DEFAULT) :
+            code(code_param), rrset(rrset_param), flags(flags_param)
+        {}
+        const Result code;
+        const isc::dns::ConstRRsetPtr rrset;
+        const FindResultFlags flags;
+    };
+
+public:
+    /// \brief A helper function to strip RRSIGs when FIND_DNSSEC is not
+    /// requested.
+    static isc::dns::ConstRRsetPtr
+    stripRRsigs(isc::dns::ConstRRsetPtr rp, const FindOptions options);
+
+    /// \brief Context of the result of a find() call.
+    ///
+    /// This class encapsulates results and (possibly) associated context
+    /// of a call to the \c find() method.   The public member variables of
+    /// this class represent the result of the call.  They are a
+    /// straightforward tuple of the result code and a pointer (and
+    /// optionally special flags) to the found RRset.
+    ///
+    /// These member variables will be initialized on construction and never
+    /// change, so for convenience we allow the applications to refer to some
+    /// of the members directly.  For some others we provide read-only accessor
+    /// methods to hide specific representation.
+    ///
+    /// Another role of this class is to provide the interface to some common
+    /// processing logic that may be necessary using the result of \c find().
+    /// Specifically, it's expected to be used in the context of DNS query
+    /// handling, where the caller would need to look into the data source
+    /// again based on the \c find() result.  For example, it would need to
+    /// get A and/or AAAA records for some of the answer or authority RRs.
+    ///
+    /// This class defines (a set of) method(s) that can be commonly used
+    /// for such purposes for any type of data source (as long as it conforms
+    /// to the public \c find() interface).  In some cases, a specific data
+    /// source implementation may want to (and can) optimize the processing
+    /// exploiting its internal data structure and the knowledge of the context
+    /// of the precedent \c find() call.  Such a data source implementation
+    /// can define a derived class of the base Context and override the
+    /// specific virtual method.
+    ///
+    /// This base class defines these common protected methods along with
+    /// some helper pure virtual methods that would be necessary for the
+    /// common methods.  If a derived class wants to use the common version
+    /// of the protected method, it needs to provide expected result through
+    /// their implementation of the pure virtual methods.
+    ///
+    /// This class object is generally expected to be associated with the
+    /// ZoneFinder that originally performed the \c find() call, and expects
+    /// the finder is valid throughout the lifetime of this object.  It's
+    /// caller's responsibility to ensure that assumption.
+    class Context {
+    public:
+        /// \brief The constructor.
+        ///
+        /// \param options The find options specified for the find() call.
+        /// \param result The result of the find() call.
+        Context(FindOptions options, const ResultContext& result) :
+            code(result.code), rrset(result.rrset),
+            flags_(result.flags), options_(options)
+        {}
+
+        /// \brief The destructor.
+        virtual ~Context() {}
+
+        const Result code;
+        const isc::dns::ConstRRsetPtr rrset;
+
+        /// Return true iff find() results in a wildcard match.
+        bool isWildcard() const { return ((flags_ & RESULT_WILDCARD) != 0); }
+
+        /// Return true when the underlying zone is signed with NSEC.
+        ///
+        /// The \c find() implementation allows this to return false if
+        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+        /// is signed or which of NSEC/NSEC3 is used.
+        ///
+        /// When this is returned, the implementation of find() must ensure
+        /// that \c rrset be a valid NSEC RRset as described in \c find()
+        /// documentation.
+        bool isNSECSigned() const {
+            return ((flags_ & RESULT_NSEC_SIGNED) != 0);
+        }
+
+        /// Return true when the underlying zone is signed with NSEC3.
+        ///
+        /// The \c find() implementation allows this to return false if
+        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+        /// is signed or which of NSEC/NSEC3 is used.
+        bool isNSEC3Signed() const {
+            return ((flags_ & RESULT_NSEC3_SIGNED) != 0);
+        }
+
+        /// \brief Find and return additional RRsets corresponding to the
+        ///        result of \c find().
+        ///
+        /// If this context is based on a normal find() call that resulted
+        /// in SUCCESS or DELEGATION, it examines the returned RRset (in many
+        /// cases NS, sometimes MX or others), searches the data source for
+        /// specified type of additional RRs for each RDATA of the RRset
+        /// (e.g., A or AAAA for the name server addresses), and stores the
+        /// result in the given vector.  The vector may not be empty; this
+        /// method appends any found RRsets to it, without touching existing
+        /// elements.
+        ///
+        /// If this context is based on a findAll() call that resulted in
+        /// SUCCESS, it performs the same process for each RRset returned in
+        /// the \c findAll() call.
+        ///
+        /// The caller specifies desired RR types of the additional RRsets
+        /// in \c requested_types.  Normally it consists of A and/or AAAA
+        /// types, but other types can be specified.
+        ///
+        /// This method is meaningful only when the precedent find()/findAll()
+        /// call resulted in SUCCESS or DELEGATION.  Otherwise this method
+        /// does nothing.
+        ///
+        /// \note The additional RRsets returned via method are limited to
+        /// ones contained in the zone which the corresponding find/findAll
+        /// call searched (possibly including glues under a zone cut where
+        /// they are applicable).  If the caller needs to get out-of-zone
+        /// additional RRsets, it needs to explicitly finds them by
+        /// identifying the corresponding zone and calls \c find() for it.
+        ///
+        /// \param requested_types A vector of RR types for desired additional
+        ///  RRsets.
+        /// \param result A vector to which any found additional RRsets are
+        /// to be inserted.
+        void getAdditional(
+            const std::vector<isc::dns::RRType>& requested_types,
+            std::vector<isc::dns::ConstRRsetPtr>& result)
+        {
+            // Perform common checks, and delegate the process to the default
+            // or specialized implementation.
+            if (code != SUCCESS && code != DELEGATION) {
+                return;
+            }
+
+            getAdditionalImpl(requested_types, result);
+        }
+
+    protected:
+        /// \brief Return the \c ZoneFinder that created this \c Context.
+        ///
+        /// A derived class implementation can return NULL if it defines
+        /// other protected methods that require a non NULL result from
+        /// this method.  Otherwise it must return a valid, non NULL pointer
+        /// to the \c ZoneFinder object.
+        ///
+        /// When returning non NULL, the ownership of the pointed object
+        /// was not transferred to the caller; it cannot be assumed to be
+        /// valid after the originating \c Context object is destroyed.
+        /// Also, the caller must not try to delete the returned object.
+        virtual ZoneFinder* getFinder() = 0;
+
+        /// \brief Return a vector of RRsets corresponding to findAll() result.
+        ///
+        /// This method returns a set of RRsets that correspond to the
+        /// returned RRsets to a prior \c findAll() call.
+        ///
+        /// A derived class implementation can return NULL if it defines
+        /// other protected methods that require a non NULL result from
+        /// this method.  Otherwise it must return a valid, non NULL pointer
+        /// to a vector that correspond to the expected set of RRsets.
+        ///
+        /// When returning non NULL, the ownership of the pointed object
+        /// was not transferred to the caller; it cannot be assumed to be
+        /// valid after the originating \c Context object is destroyed.
+        /// Also, the caller must not try to delete the returned object.
+        virtual const std::vector<isc::dns::ConstRRsetPtr>*
+        getAllRRsets() const = 0;
+
+        /// \brief Actual implementation of getAdditional().
+        ///
+        /// This base class defines a default implementation that can be
+        /// used for any type of data sources.  A data source implementation
+        /// can override it.
+        ///
+        /// The default version of this implementation requires both
+        /// \c getFinder() and \c getAllRRsets() return valid results.
+        virtual void getAdditionalImpl(
+            const std::vector<isc::dns::RRType>& requested_types,
+            std::vector<isc::dns::ConstRRsetPtr>& result);
+
+    private:
+        const FindResultFlags flags_;
+    protected:
+        const FindOptions options_;
+    };
+
+    /// \brief Generic ZoneFinder context that works for all implementations.
+    ///
+    /// This is a concrete derived class of \c ZoneFinder::Context that
+    /// only use the generic (default) versions of the protected methods
+    /// and therefore work for any data source implementation.
+    ///
+    /// A data source implementation can use this class to create a
+    /// \c Context object as a return value of \c find() or \c findAll()
+    /// method if it doesn't have to optimize specific protected methods.
+    class GenericContext : public Context {
+    public:
+        /// \brief The constructor for the normal find call.
+        ///
+        /// This constructor is expected to be called from the \c find()
+        /// method when it constructs the return value.
+        ///
+        /// \param finder The ZoneFinder on which find() is called.
+        /// \param options See the \c Context class.
+        /// \param result See the \c Context class.
+        GenericContext(ZoneFinder& finder, FindOptions options,
+                       const ResultContext& result) :
+            Context(options, result), finder_(finder)
+        {}
+
+        /// \brief The constructor for the normal findAll call.
+        ///
+        /// This constructor is expected to be called from the \c findAll()
+        /// method when it constructs the return value.
+        ///
+        /// It copies the vector that is to be returned to the caller of
+        /// \c findAll() for possible subsequent use.  Note that it cannot
+        /// simply hold a reference to the vector because the caller may
+        /// alter it after the \c findAll() call.
+        ///
+        /// \param finder The ZoneFinder on which findAll() is called.
+        /// \param options See the \c Context class.
+        /// \param result See the \c Context class.
+        /// \param all_set Reference to the vector given by the caller of
+        ///       \c findAll(), storing the RRsets to be returned.
+        GenericContext(ZoneFinder& finder, FindOptions options,
+                       const ResultContext& result,
+                       const std::vector<isc::dns::ConstRRsetPtr>& all_set) :
+            Context(options, result), finder_(finder), all_set_(all_set)
+        {}
+
+    protected:
+        virtual ZoneFinder* getFinder() { return (&finder_); }
+        virtual const std::vector<isc::dns::ConstRRsetPtr>*
+        getAllRRsets() const {
+            return (&all_set_);
+        }
+
+    private:
+        ZoneFinder& finder_;
+        std::vector<isc::dns::ConstRRsetPtr> all_set_;
+    };
+
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    //@{
+protected:
+    /// 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).
+    ZoneFinder() {}
+public:
+    /// The destructor.
+    virtual ~ZoneFinder() {}
+    //@}
+
+    ///
+    /// \name Getter Methods
+    ///
+    /// These methods should never throw an exception.
+    //@{
+    /// Return the origin name of the zone.
+    virtual isc::dns::Name getOrigin() const = 0;
+
+    /// Return the RR class of the zone.
+    virtual isc::dns::RRClass getClass() const = 0;
+    //@}
+
+    ///
+    /// \name Search Methods
+    ///
+    //@{
+    /// \brief Search the zone for a given pair of domain name and RR type.
+    ///
+    /// Each derived version of this method searches the underlying backend
+    /// for the data that best matches the given name and type.
+    /// This method is expected to be "intelligent", and identifies the
+    /// best possible answer for the search key.  Specifically,
+    ///
+    /// - If the search name belongs under a zone cut, it returns the code
+    ///   of \c DELEGATION and the NS RRset at the zone cut.
+    /// - If there is no matching name, it returns the code of \c NXDOMAIN.
+    /// - If there is a matching name but no RRset of the search type, it
+    ///   returns the code of \c NXRRSET.  This case includes the search name
+    ///   matches an empty node of the zone.
+    /// - If there is a CNAME RR of the searched name but there is no
+    ///   RR of the searched type of the name (so this type is different from
+    ///   CNAME), it returns the code of \c CNAME and that CNAME RR.
+    ///   Note that if the searched RR type is CNAME, it is considered
+    ///   a successful match, and the code of \c SUCCESS will be returned.
+    /// - If the search name matches a delegation point of DNAME, it returns
+    ///   the code of \c DNAME and that DNAME RR.
+    ///
+    /// No RRset will be returned in the \c NXDOMAIN and \c NXRRSET cases
+    /// (\c rrset member of \c FindContext will be NULL), unless DNSSEC data
+    /// are required.  See below for the cases with DNSSEC.
+    ///
+    /// The returned \c FindContext object can also provide supplemental
+    /// information about the search result via its methods returning a
+    /// boolean value.  Such information may be useful for the caller if
+    /// the caller wants to collect additional DNSSEC proofs based on the
+    /// search result.
+    ///
+    /// The \c options parameter specifies customized behavior of the search.
+    /// Their semantics is as follows (they are or bit-field):
+    ///
+    /// - \c FIND_GLUE_OK Allow search under a zone cut.  By default the search
+    ///   will stop once it encounters a zone cut.  If this option is specified
+    ///   it remembers information about the highest zone cut and continues
+    ///   the search until it finds an exact match for the given name or it
+    ///   detects there is no exact match.  If an exact match is found,
+    ///   RRsets for that name are searched just like the normal case;
+    ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
+    ///   with the information of the highest zone cut will be returned.
+    ///   Note: the term "glue" in the DNS protocol standard may sometimes
+    ///   cause confusion: some people use this term strictly for an address
+    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
+    ///   some others seem to give it broader flexibility.  Nevertheless,
+    ///   in this API the "GLUE OK" simply means the search by find() can
+    ///   continue beyond a zone cut; the derived class implementation does
+    ///   not have to, and should not, check whether the type is an address
+    ///   record or whether the query name is pointed by some NS RR.
+    ///   It's up to the caller with which definition of "glue" the search
+    ///   result with this option should be used.
+    /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
+    ///   returned with the answer. It is allowed for the data source to
+    ///   include them even when not requested.
+    /// - \c NO_WILDCARD Do not try wildcard matching.  This option is of no
+    ///   use for normal lookups; it's intended to be used to get a DNSSEC
+    ///   proof of the non existence of any matching wildcard or non existence
+    ///   of an exact match when a wildcard match is found.
+    ///
+    /// In general, \c name is expected to be included in the zone, that is,
+    /// it should be equal to or a subdomain of the zone origin.  Otherwise
+    /// this method will return \c NXDOMAIN with an empty RRset.  But such a
+    /// case should rather be considered a caller's bug.
+    ///
+    /// \note For this reason it's probably better to throw an exception
+    /// than returning \c NXDOMAIN.  This point should be revisited in a near
+    /// future version.  In any case applications shouldn't call this method
+    /// for an out-of-zone name.
+    ///
+    /// <b>DNSSEC considerations:</b>
+    /// The result when DNSSEC data are required can be very complicated,
+    /// especially if it involves negative result or wildcard match.
+    /// Specifically, if an application calls this method for DNS query
+    /// processing with DNSSEC data, and if the search result code is
+    /// either \c NXDOMAIN or \c NXRRRSET, and/or \c isWildcard() returns
+    /// true, then the application will need to find additional NSEC or
+    /// NSEC3 records for supplemental proofs.  This method helps the
+    /// application for such post search processing.
+    ///
+    /// First, it tells the application whether the zone is signed with
+    /// NSEC or NSEC3 via the \c isNSEC(3)Signed() method.  Any sanely signed
+    /// zone should be signed with either (and only one) of these two types
+    /// of RRs; however, the application should expect that the zone could
+    /// be broken and these methods could both return false.  But this method
+    /// should ensure that not both of these methods return true.
+    ///
+    /// In case it's signed with NSEC3, there is no further information
+    /// returned from this method.
+    ///
+    /// In case it's signed with NSEC, this method will possibly return
+    /// a related NSEC RRset in the \c rrset member of \c FindContext.
+    /// What kind of NSEC is returned depends on the result code
+    /// (\c NXDOMAIN or \c NXRRSET) and on whether it's a wildcard match:
+    ///
+    /// - In case of NXDOMAIN, the returned NSEC covers the queried domain
+    ///   that proves that the query name does not exist in the zone.  Note
+    ///   that this does not necessarily prove it doesn't even match a
+    ///   wildcard (even if the result of NXDOMAIN can only happen when
+    ///   there's no matching wildcard either).  It is caller's
+    ///   responsibility to provide a proof that there is no matching
+    ///   wildcard if that proof is necessary.
+    /// - In case of NXRRSET, we need to consider the following cases
+    ///   referring to Section 3.1.3 of RFC4035:
+    ///
+    /// -# (Normal) no data: there is a matching non-wildcard name with a
+    ///    different RR type.  This is the "No Data" case of the RFC.
+    /// -# (Normal) empty non terminal: there is no matching (exact or
+    ///    wildcard) name, but there is a subdomain with an RR of the query
+    ///    name.  This is one case of "Name Error" of the RFC.
+    /// -# Wildcard empty non terminal: similar to 2a, but the empty name
+    ///    is a wildcard, and matches the query name by wildcard expansion.
+    ///    This is a special case of "Name Error" of the RFC.
+    /// -# Wildcard no data: there is no exact match name, but there is a
+    ///    wildcard name that matches the query name with a different type
+    ///    of RR.  This is the "Wildcard No Data" case of the RFC.
+    ///
+    /// In case 1, \c find() returns NSEC of the matching name.
+    ///
+    /// In case 2, \c find() will return NSEC for the interval where the
+    /// empty nonterminal lives. The end of the interval is the subdomain
+    /// causing existence of the empty nonterminal (if there's
+    /// sub.x.example.com, and no record in x.example.com, then
+    /// x.example.com exists implicitly - is the empty nonterminal and
+    /// sub.x.example.com is the subdomain causing it).  Note that this NSEC
+    /// proves not only the existence of empty non terminal name but also
+    /// the non existence of possibly matching wildcard name, because
+    /// there can be no better wildcard match than the exact matching empty
+    /// name.
+    ///
+    /// In case 3, \c find() will return NSEC for the interval where the
+    /// wildcard empty nonterminal lives.   Cases 2 and 3 are especially
+    /// complicated and confusing.  See the examples below.
+    ///
+    /// In case 4, \c find() will return NSEC of the matching wildcard name.
+    ///
+    /// Examples: if zone "example.com" has the following record:
+    /// \code
+    /// a.example.com. NSEC a.b.example.com.
+    /// \endcode
+    /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
+    /// will result in NXRRSET, and this NSEC will be returned.
+    /// Likewise, if zone "example.org" has the following record,
+    /// \code
+    /// a.example.org. NSEC x.*.b.example.org.
+    /// \endcode
+    /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
+    /// result in NXRRSET and this NSEC; \c isWildcard() on the returned
+    /// \c FindContext object will return true.
+    ///
+    /// \exception std::bad_alloc Memory allocation such as for constructing
+    ///  the resulting RRset fails
+    /// \throw OutOfZone The Name \c name is outside of the origin of the
+    /// zone of this ZoneFinder.
+    /// \exception DataSourceError Derived class specific exception, e.g.
+    /// when encountering a bad zone configuration or database connection
+    /// failure.  Although these are considered rare, exceptional events,
+    /// it can happen under relatively usual conditions (unlike memory
+    /// allocation failure).  So, in general, the application is expected
+    /// to catch this exception, either specifically or as a result of
+    /// catching a base exception class, and handle it gracefully.
+    ///
+    /// \param name The domain name to be searched for.
+    /// \param type The RR type to be searched for.
+    /// \param options The search options.
+    /// \return A \c FindContext object enclosing the search result
+    ///         (see above).
+    virtual boost::shared_ptr<Context> find(const isc::dns::Name& name,
+                                            const isc::dns::RRType& type,
+                                            const FindOptions options
+                                            = FIND_DEFAULT) = 0;
+
+    /// \brief Search for an RRset of given RR type at the zone origin.
+    ///
+    /// In terms of API this method is equivalent to a call to \c find() where
+    /// the \c name parameter is the zone origin (return value of
+    /// \c getOrigin()) and is redundant.  This method is provided as an
+    /// optimization point for some kind of finder implementations that can
+    /// exploit the fact that the query name is the zone origin and for
+    /// applications that want to possibly benefit from such implementations.
+    ///
+    /// If \c use_minttl is set to \c true and the returned context would
+    /// contain a non NULL RRset, its RR TTL is (possibly) adjusted so that
+    /// it's set to the minimum of its own TTL and the minimum TTL field value
+    /// of the zone's SOA record.  If the RRset contains an RRSIG, its TTL
+    /// is also adjusted in the same way.
+    ///
+    /// The origin of a zone is special in some points: for any valid zone
+    /// there should always be an SOA and at least one NS RR there, which
+    /// also means the origin name is never empty.  Also, the SOA record can
+    /// be used in a DNS response for negative answers, in which case the
+    /// RR TTL must be set to minimum of its own RRTTL and the value of the
+    /// minimum TTL field.  Although these operations can be performed
+    /// through other public interfaces, they can be sometimes suboptimal
+    /// in performance or could be more efficient in a specialized
+    /// implementation.  For example, a specific implementation of
+    /// \c getOrigin() could involve a dynamic creation of a \c Name object,
+    /// which is less efficient; on the other hand, the underlying finder
+    /// implementation may have an efficient way to access RRs of the origin
+    /// in implementation specific way; and, while reconstructing an RRset
+    /// with replacing the TTL is relatively expensive, this can be done
+    /// much faster if the need for it is known beforehand.
+    ///
+    /// If the underlying finder implementation wants to optimize these cases,
+    /// it can do so by specializing the method.  It has the default
+    /// implementation for any other implementations, which should work for
+    /// any finder implementation as long as it conforms to other public
+    /// interfaces.
+    ///
+    /// So, an implementation of a finder does not have to care about this
+    /// method unless it sees the need for optimizing the behavior.
+    /// Also, applications normally do not have to use this interface;
+    /// using the generic \c find() method (with some post call processing)
+    /// can do everything this method can provide.  The default implementation
+    /// may even be slower than such straightforward usage due to the
+    /// internal overhead.  This method should be used if and only if the
+    /// application needs to achieve the possible best performance with an
+    /// optimized finder implementation.
+    ///
+    /// \param type The RR type to be searched for.
+    /// \param use_minttl Whether to adjust the TTL (see the description).
+    /// \param options The search options.  Same for \c find().
+    ///
+    /// \return A \c FindContext object enclosing the search result.
+    ///         See \c find().
+    virtual boost::shared_ptr<Context> findAtOrigin(
+        const isc::dns::RRType& type, bool use_minttl,
+        FindOptions options);
+
+public:
+    ///
+    /// \brief Finds all RRsets in the given name.
+    ///
+    /// This function works almost exactly in the same way as the find one. The
+    /// only difference is, when the lookup is successful (eg. the code is
+    /// SUCCESS), all the RRsets residing in the named node are
+    /// copied into the \c target parameter and the rrset member of the result
+    /// is NULL. All the other (unsuccessful) cases are handled the same,
+    /// including returning delegations, NSEC/NSEC3 availability and NSEC
+    /// proofs, wildcard information etc. The options parameter works the
+    /// same way and it should conform to the same exception restrictions.
+    ///
+    /// \param name \see find, parameter name
+    /// \param target the successfull result is returned through this
+    /// \param options \see find, parameter options
+    /// \return \see find and it's result
+    virtual boost::shared_ptr<Context> findAll(
+        const isc::dns::Name& name,
+        std::vector<isc::dns::ConstRRsetPtr> &target,
+        const FindOptions options = FIND_DEFAULT) = 0;
+
+    /// A helper structure to represent the search result of \c findNSEC3().
+    ///
+    /// The idea is similar to that of \c FindContext, but \c findNSEC3() has
+    /// special interface and semantics, we use a different structure to
+    /// represent the result.
+    struct FindNSEC3Result {
+        FindNSEC3Result(bool param_matched, uint8_t param_closest_labels,
+                        isc::dns::ConstRRsetPtr param_closest_proof,
+                        isc::dns::ConstRRsetPtr param_next_proof) :
+            matched(param_matched), closest_labels(param_closest_labels),
+            closest_proof(param_closest_proof),
+            next_proof(param_next_proof)
+        {}
+
+        /// true iff closest_proof is a matching NSEC3
+        const bool matched;
+
+        /// The number of labels of the identified closest encloser.
+        const uint8_t closest_labels;
+
+        /// Either the NSEC3 for the closest provable encloser of the given
+        /// name or NSEC3 that covers the name
+        const isc::dns::ConstRRsetPtr closest_proof;
+
+        /// When non NULL, NSEC3 for the next closer name.
+        const isc::dns::ConstRRsetPtr next_proof;
+    };
+
+    /// Search the zone for the NSEC3 RR(s) that prove existence or non
+    /// existence of a give name.
+    ///
+    /// It searches the NSEC3 namespace of the zone (how that namespace is
+    /// implemented can vary in specific data source implementation) for NSEC3
+    /// RRs that match or cover the NSEC3 hash value for the given name.
+    ///
+    /// If \c recursive is false, it will first look for the NSEC3 that has
+    /// a matching hash.  If it doesn't exist, it identifies the covering NSEC3
+    /// for the hash.  In either case the search stops at that point and the
+    /// found NSEC3 RR(set) will be returned in the closest_proof member of
+    /// \c FindNSEC3Result.  \c matched is true or false depending on
+    /// the found NSEC3 is a matched one or covering one.  \c next_proof
+    /// is always NULL.  closest_labels must be equal to the number of
+    /// labels of \c name (and therefore meaningless).
+    ///
+    /// If \c recursive is true, it will continue the search toward the zone
+    /// apex (origin name) until it finds a provable encloser, that is,
+    /// an ancestor of \c name that has a matching NSEC3.  This is the closest
+    /// provable encloser of \c name as defined in RFC5155.  In this case,
+    /// if the found encloser is not equal to \c name, the search should
+    /// have seen a covering NSEC3 for the immediate child of the found
+    /// encloser.  That child name is the next closer name as defined in
+    /// RFC5155.  In this case, this method returns the NSEC3 for the
+    /// closest encloser in \c closest_proof, and the NSEC3 for the next
+    /// closer name in \c next_proof of \c FindNSEC3Result.  This set of
+    /// NSEC3 RRs provide the closest encloser proof as defined in RFC5155.
+    /// closest_labels will be set to the number of labels of the identified
+    /// closest encloser.  This will be useful when the caller needs to
+    /// construct the closest encloser name from the original \c name.
+    /// If, on the other hand, the found closest name is equal to \c name,
+    /// this method simply returns it in \c closest_proof.  \c next_proof
+    /// is set to NULL.  In all cases \c matched is set to true.
+    /// closest_labels will be set to the number of labels of \c name.
+    ///
+    /// When looking for NSEC3, this method retrieves NSEC3 parameters from
+    /// the corresponding zone to calculate hash values.  Actual implementation
+    /// of how to do this will differ in different data sources.  If the
+    /// NSEC3 parameters are not available \c DataSourceError exception
+    /// will be thrown.
+    ///
+    /// \note This implicitly means this method assumes the zone does not
+    /// have more than one set of parameters.  This assumption should be
+    /// reasonable in actual deployment and will help simplify the interface
+    /// and implementation.  But if there's a real need for supporting
+    /// multiple sets of parameters in a single zone, we will have to
+    /// extend this method so that, e.g., the caller can specify the parameter
+    /// set.
+    ///
+    /// In general, this method expects the zone is properly signed with NSEC3
+    /// RRs.  Specifically, it assumes at least the apex node has a matching
+    /// NSEC3 RR (so the search in the recursive mode must always succeed);
+    /// it also assumes that it can retrieve NSEC parameters (iterations,
+    /// algorithm, and salt) from the zone as noted above.  If these
+    /// assumptions aren't met, \c DataSourceError exception will be thrown.
+    ///
+    /// \exception OutOfZone name is not a subdomain of the zone origin
+    /// \exception DataSourceError Low-level or internal datasource errors
+    /// happened, or the zone isn't properly signed with NSEC3
+    /// (NSEC3 parameters cannot be found, no NSEC3s are available, etc).
+    /// \exception std::bad_alloc The underlying implementation involves
+    /// memory allocation and it fails
+    ///
+    /// \param name The name for which NSEC3 RRs are to be found.  It must
+    /// be a subdomain of the zone.
+    /// \param recursive Whether or not search should continue until it finds
+    /// a provable encloser (see above).
+    ///
+    /// \return The search result and whether or not the closest_proof is
+    /// a matching NSEC3, in the form of \c FindNSEC3Result object.
+    virtual FindNSEC3Result
+    findNSEC3(const isc::dns::Name& name, bool recursive) = 0;
+    //@}
+};
+
+/// \brief Operator to combine FindOptions
+///
+/// We would need to manually static-cast the options if we put or
+/// between them, which is undesired with bit-flag options. Therefore
+/// we hide the cast here, which is the simplest solution and it still
+/// provides reasonable level of type safety.
+inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
+                                          ZoneFinder::FindOptions b)
+{
+    return (static_cast<ZoneFinder::FindOptions>(static_cast<unsigned>(a) |
+                                                 static_cast<unsigned>(b)));
+}
+
+/// \brief Operator to combine FindResultFlags
+///
+/// Similar to the same operator for \c FindOptions.  Refer to the description
+/// of that function.
+inline ZoneFinder::FindResultFlags operator |(
+    ZoneFinder::FindResultFlags a,
+    ZoneFinder::FindResultFlags b)
+{
+    return (static_cast<ZoneFinder::FindResultFlags>(
+                static_cast<unsigned>(a) | static_cast<unsigned>(b)));
+}
+
+/// \brief A pointer-like type pointing to a \c ZoneFinder object.
+typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
+
+/// \brief A pointer-like type pointing to an immutable \c ZoneFinder object.
+typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
+
+/// \brief A pointer-like type pointing to a \c ZoneFinder::Context object.
+typedef boost::shared_ptr<ZoneFinder::Context> ZoneFinderContextPtr;
+
+/// \brief A pointer-like type pointing to an immutable
+/// \c ZoneFinder::Context object.
+typedef boost::shared_ptr<ZoneFinder::Context> ConstZoneFinderContextPtr;
+
+} // end of datasrc
+} // end of isc
+
+#endif  // DATASRC_ZONE_FINDER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/zone_finder_context.cc b/src/lib/datasrc/zone_finder_context.cc
index 482eb65..8d7edf0 100644
--- a/src/lib/datasrc/zone_finder_context.cc
+++ b/src/lib/datasrc/zone_finder_context.cc
@@ -19,7 +19,7 @@
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 #include <boost/foreach.hpp>
 
diff --git a/src/lib/datasrc/zone_iterator.h b/src/lib/datasrc/zone_iterator.h
new file mode 100644
index 0000000..e1c6929
--- /dev/null
+++ b/src/lib/datasrc/zone_iterator.h
@@ -0,0 +1,105 @@
+// 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_ZONE_ITERATOR_H
+#define DATASRC_ZONE_ITERATOR_H 1
+
+#include <dns/rrset.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <datasrc/zone.h>
+
+namespace isc {
+namespace datasrc {
+
+/**
+ * \brief Read-only iterator to a zone.
+ *
+ * You can get an instance of (descendand of) ZoneIterator from
+ * DataSourceClient::getIterator() method. The actual concrete implementation
+ * will be different depending on the actual data source used. This is the
+ * abstract interface.
+ *
+ * There's no way to start iterating from the beginning again or return.
+ */
+class ZoneIterator : public boost::noncopyable {
+public:
+    /**
+     * \brief Destructor
+     *
+     * Virtual destructor. It is empty, but ensures the right destructor from
+     * descendant is called.
+     */
+    virtual ~ ZoneIterator() { }
+
+    /**
+     * \brief Get next RRset from the zone.
+     *
+     * This returns the next RRset in the zone as a shared pointer. The
+     * shared pointer is used to allow both accessing in-memory data and
+     * automatic memory management.
+     *
+     * Any special order is not guaranteed.
+     *
+     * While this can potentially throw anything (including standard allocation
+     * errors), it should be rare.
+     *
+     * \return Pointer to the next RRset or NULL pointer when the iteration
+     *     gets to the end of the zone.
+     */
+    virtual isc::dns::ConstRRsetPtr getNextRRset() = 0;
+
+    /**
+     * \brief Return the SOA record of the zone in the iterator context.
+     *
+     * This method returns the zone's SOA record (if any, and a valid zone
+     * should have it) in the form of an RRset object.  This SOA is identical
+     * to that (again, if any) contained in the sequence of RRsets returned
+     * by the iterator.  In that sense this method is redundant, but is
+     * provided as a convenient utility for the application of the
+     * iterator; the application may need to know the SOA serial or the
+     * SOA RR itself for the purpose of protocol handling or skipping the
+     * expensive iteration processing.
+     *
+     * If the zone doesn't have an SOA (which is broken, but some data source
+     * may allow that situation), this method returns NULL.  Also, in the
+     * normal and valid case, the SOA should have exactly one RDATA, but
+     * this API does not guarantee it as some data source may accept such an
+     * abnormal condition.  It's up to the caller whether to check the number
+     * of RDATA and how to react to the unexpected case.
+     *
+     * Each concrete derived method must ensure that the SOA returned by this
+     * method is identical to the zone's SOA returned via the iteration.
+     * For example, even if another thread or process updates the SOA while
+     * the iterator is working, the result of this method must not be
+     * affected by the update.  For database based data sources, this can
+     * be done by making the entire iterator operation as a single database
+     * transaction, but the actual implementation can differ.
+     *
+     * \exception None
+     *
+     * \return A shared pointer to an SOA RRset that would be returned
+     * from the iteration.  It will be NULL if the zone doesn't have an SOA.
+     */
+    virtual isc::dns::ConstRRsetPtr getSOA() const = 0;
+};
+
+}
+}
+#endif  // DATASRC_ZONE_ITERATOR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/zone_loader.cc b/src/lib/datasrc/zone_loader.cc
index 9e9dd4a..d0f4a64 100644
--- a/src/lib/datasrc/zone_loader.cc
+++ b/src/lib/datasrc/zone_loader.cc
@@ -17,15 +17,15 @@
 
 #include <datasrc/client.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
 #include <datasrc/logger.h>
-#include <datasrc/rrset_collection_base.h>
 
 #include <dns/rrset.h>
 #include <dns/zone_checker.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
+#include <dns/rrset_collection_base.h>
 
 #include <boost/bind.hpp>
 
@@ -33,6 +33,7 @@
 
 using isc::dns::Name;
 using isc::dns::ConstRRsetPtr;
+using isc::dns::RRsetCollectionBase;
 using isc::dns::MasterLoader;
 using isc::dns::MasterLexer;
 
diff --git a/src/lib/datasrc/zonetable.cc b/src/lib/datasrc/zonetable.cc
deleted file mode 100644
index 1193181..0000000
--- a/src/lib/datasrc/zonetable.cc
+++ /dev/null
@@ -1,160 +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 <util/memory_segment.h>
-
-#include <dns/name.h>
-
-#include <datasrc/zonetable.h>
-#include <datasrc/rbtree.h>
-
-#include <cassert>
-
-using namespace std;
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-
-/// \short Private data and implementation of ZoneTable
-struct ZoneTable::ZoneTableImpl {
-    // Type aliases to make it shorter
-    typedef RBTree<ZoneFinder> ZoneTree;
-    typedef RBNode<ZoneFinder> ZoneNode;
-
-    // The actual storage
-    ZoneTree* zones_;
-
-    // Constructor
-    ZoneTableImpl(util::MemorySegment& mem_sgmt) :
-        zones_(ZoneTree::create(mem_sgmt))
-    {}
-
-    /*
-     * The implementation methods are here and just wrap-called in the
-     * ZoneTable. We have variables locally (without impl_->), have
-     * type aliases, etc. And they will get inlined anyway.
-     */
-
-    // Implementation of ZoneTable::addZone
-    result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
-        // Sanity check
-        if (!zone) {
-            isc_throw(InvalidParameter,
-                      "Null pointer is passed to ZoneTable::addZone()");
-        }
-
-        // Get the node where we put the zone
-        ZoneNode* node(NULL);
-        switch (zones_->insert(mem_sgmt, zone->getOrigin(), &node)) {
-            // This is OK
-            case ZoneTree::SUCCESS:
-            case ZoneTree::ALREADYEXISTS:
-                break;
-            // Can Not Happen
-            default:
-                assert(0);
-        }
-        // Can Not Happen
-        assert(node);
-
-        // Is it empty? We either just created it or it might be nonterminal
-        if (node->isEmpty()) {
-            node->setData(zone);
-            return (result::SUCCESS);
-        } else { // There's something there already
-            return (result::EXIST);
-        }
-    }
-
-    // Implementation of ZoneTable::findZone
-    ZoneTable::FindResult findZone(const Name& name) const {
-        ZoneNode *node(NULL);
-        result::Result my_result;
-
-        // Translate the return codes
-        switch (zones_->find(name, &node)) {
-            case ZoneTree::EXACTMATCH:
-                my_result = result::SUCCESS;
-                break;
-            case ZoneTree::PARTIALMATCH:
-                my_result = result::PARTIALMATCH;
-                break;
-            // We have no data there, so translate the pointer to NULL as well
-            case ZoneTree::NOTFOUND:
-                return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
-            // Can Not Happen
-            default:
-                assert(0);
-                // Because of warning
-                return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
-        }
-
-        // Can Not Happen (remember, NOTFOUND is handled)
-        assert(node);
-
-        return (FindResult(my_result, node->getData()));
-    }
-};
-
-ZoneTable::ZoneTable(util::MemorySegment& mem_sgmt) :
-    impl_(new ZoneTableImpl(mem_sgmt))
-{}
-
-ZoneTable::~ZoneTable() {
-    delete impl_;
-}
-
-ZoneTable*
-ZoneTable::create(util::MemorySegment& mem_sgmt) {
-    // The ZoneTable constructor can throw, so we need to prevent memory leak.
-    // This is ugly, but for now this seems to be the only place we need
-    // this, and since we'll substantially revise this code soon, so we don't
-    // work around it by this hack at the moment.
-    void* p = mem_sgmt.allocate(sizeof(ZoneTable));
-    try {
-        return (new(p) ZoneTable(mem_sgmt));
-    } catch (...) {
-        mem_sgmt.deallocate(p, sizeof(ZoneTable));
-        throw;
-    }
-}
-
-void
-ZoneTable::destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable) {
-    ZoneTableImpl::ZoneTree::destroy(mem_sgmt, ztable->impl_->zones_);
-    ztable->~ZoneTable();
-    mem_sgmt.deallocate(ztable, sizeof(ZoneTable));
-}
-
-result::Result
-ZoneTable::addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
-    return (impl_->addZone(mem_sgmt, zone));
-}
-
-result::Result
-ZoneTable::removeZone(const Name&) {
-    // TODO Implement
-    assert(0);
-    // This should not ever be returned, the assert should kill us by now
-    return (result::SUCCESS);
-}
-
-ZoneTable::FindResult
-ZoneTable::findZone(const Name& name) const {
-    return (impl_->findZone(name));
-}
-
-} // end of namespace datasrc
-} // end of namespace isc
diff --git a/src/lib/datasrc/zonetable.h b/src/lib/datasrc/zonetable.h
deleted file mode 100644
index 911391c..0000000
--- a/src/lib/datasrc/zonetable.h
+++ /dev/null
@@ -1,160 +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 ZONETABLE_H
-#define ZONETABLE_H 1
-
-#include <util/memory_segment.h>
-
-#include <dns/rrset.h>
-
-#include <datasrc/zone.h>
-
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dns {
-class Name;
-class RRClass;
-}
-
-namespace datasrc {
-
-/// \brief A set of authoritative zones.
-///
-/// \c ZoneTable class is primarily intended to be used as a backend for the
-/// \c MemoryDataSrc class, but is exposed as a separate class in case some
-/// application wants to use it directly (e.g. for a customized data source
-/// implementation).
-///
-/// For more descriptions about its struct and interfaces, please refer to the
-/// corresponding struct and interfaces of \c MemoryDataSrc.
-class ZoneTable {
-public:
-    struct FindResult {
-        FindResult(result::Result param_code, const ZoneFinderPtr param_zone) :
-            code(param_code), zone(param_zone)
-        {}
-        const result::Result code;
-        const ZoneFinderPtr zone;
-    };
-    ///
-    /// \name Constructors and Destructor.
-    ///
-    /// \b Note:
-    /// The copy constructor and the assignment operator are intentionally
-    /// defined as private, making this class non copyable.
-    //@{
-private:
-    ZoneTable(const ZoneTable& source);
-    ZoneTable& operator=(const ZoneTable& source);
-
-    /// Constructor.
-    ///
-    /// An object of this class is always expected to be created by the
-    /// allocator (\c create()), so the constructor is hidden as private.
-    ///
-    /// This constructor internally involves resource allocation, and if
-    /// it fails, a corresponding standard exception will be thrown.
-    /// It never throws an exception otherwise.
-    ZoneTable(util::MemorySegment& mem_sgmt);
-
-    /// The destructor.
-    ///
-    /// An object of this class is always expected to be destroyed explicitly
-    /// by \c destroy(), so the constructor is hidden as private.
-    ~ZoneTable();
-    //@}
-
-public:
-    /// \brief Allocate and construct \c ZoneTable
-    ///
-    /// This static method allocates memory for a new \c ZoneTable object
-    /// from the given memory segment, constructs the object, and returns
-    /// a pointer to it.
-    ///
-    /// \throw std::bad_alloc Memory allocation fails.
-    ///
-    /// \param mem_sgmt A \c MemorySegment from which memory for the new
-    /// \c ZoneTable is allocated.
-    static ZoneTable* create(util::MemorySegment& mem_sgmt);
-
-    /// \brief Destruct and deallocate \c ZoneTable
-    ///
-    /// \throw none
-    ///
-    /// \param mem_sgmt The \c MemorySegment that allocated memory for
-    /// \c ztable.
-    /// \param ztable A non NULL pointer to a valid \c ZoneTable object
-    /// that was originally created by the \c create() method (the behavior
-    /// is undefined if this condition isn't met).
-    static void destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable);
-
-    /// Add a \c Zone to the \c ZoneTable.
-    ///
-    /// \c Zone must not be associated with a NULL pointer; otherwise
-    /// an exception of class \c InvalidParameter will be thrown.
-    /// If internal resource allocation fails, a corresponding standard
-    /// exception will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// \param zone A \c Zone object to be added.
-    /// \return \c result::SUCCESS If the zone is successfully
-    /// added to the zone table.
-    /// \return \c result::EXIST The zone table already contains
-    /// zone of the same origin.
-    result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone);
-
-    /// Remove a \c Zone of the given origin name from the \c ZoneTable.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param origin The origin name of the zone to be removed.
-    /// \return \c result::SUCCESS If the zone is successfully
-    /// removed from the zone table.
-    /// \return \c result::NOTFOUND The zone table does not
-    /// store the zone that matches \c origin.
-    result::Result removeZone(const isc::dns::Name& origin);
-
-    /// Find a \c Zone that best matches the given name in the \c ZoneTable.
-    ///
-    /// It searches the internal storage for a \c Zone that gives the
-    /// longest match against \c name, and returns the result in the
-    /// form of a \c FindResult object as follows:
-    /// - \c code: The result code of the operation.
-    ///   - \c result::SUCCESS: A zone that gives an exact match
-    ///    is found
-    ///   - \c result::PARTIALMATCH: A zone whose origin is a
-    ///    super domain of \c name is found (but there is no exact match)
-    ///   - \c result::NOTFOUND: For all other cases.
-    /// - \c zone: A "Boost" shared pointer to the found \c Zone object if one
-    ///  is found; otherwise \c NULL.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param name A domain name for which the search is performed.
-    /// \return A \c FindResult object enclosing the search result (see above).
-    FindResult findZone(const isc::dns::Name& name) const;
-
-private:
-    struct ZoneTableImpl;
-    ZoneTableImpl* impl_;
-};
-}
-}
-#endif  // ZONETABLE_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 822c4e3..f169fe6 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -32,6 +32,7 @@ libb10_dhcp___la_SOURCES += option.cc option.h
 libb10_dhcp___la_SOURCES += option_custom.cc option_custom.h
 libb10_dhcp___la_SOURCES += option_data_types.cc option_data_types.h
 libb10_dhcp___la_SOURCES += option_definition.cc option_definition.h
+libb10_dhcp___la_SOURCES += option_space.cc option_space.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
 libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
 libb10_dhcp___la_SOURCES += std_option_defs.h
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index a3921cc..78f511d 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -267,20 +267,12 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
     return (offset);
 }
 
-void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
-                           const isc::dhcp::Option::OptionCollection& options) {
-    for (Option::OptionCollection::const_iterator it = options.begin();
-         it != options.end(); ++it) {
-        it->second->pack(buf);
-    }
-}
-
 void
 LibDHCP::packOptions(isc::util::OutputBuffer& buf,
                      const Option::OptionCollection& options) {
     for (Option::OptionCollection::const_iterator it = options.begin();
          it != options.end(); ++it) {
-        it->second->pack4(buf);
+        it->second->pack(buf);
     }
 }
 
@@ -329,10 +321,35 @@ LibDHCP::initStdOptionDefs4() {
 
     // Now let's add all option definitions.
     for (int i = 0; i < OPTION_DEF_PARAMS_SIZE4; ++i) {
-        OptionDefinitionPtr definition(new OptionDefinition(OPTION_DEF_PARAMS4[i].name,
-                                                            OPTION_DEF_PARAMS4[i].code,
-                                                            OPTION_DEF_PARAMS4[i].type,
-                                                            OPTION_DEF_PARAMS4[i].array));
+        std::string encapsulates(OPTION_DEF_PARAMS4[i].encapsulates);
+        if (!encapsulates.empty() && OPTION_DEF_PARAMS4[i].array) {
+            isc_throw(isc::BadValue, "invalid standard option definition: "
+                      << "option with code '" << OPTION_DEF_PARAMS4[i].code
+                      << "' may not encapsulate option space '"
+                      << encapsulates << "' because the definition"
+                      << " indicates that this option comprises an array"
+                      << " of values");
+        }
+
+        // Depending whether the option encapsulates an option space or not
+        // we pick different constructor to create an instance of the option
+        // definition.
+        OptionDefinitionPtr definition;
+        if (encapsulates.empty()) {
+            // Option does not encapsulate any option space.
+            definition.reset(new OptionDefinition(OPTION_DEF_PARAMS4[i].name,
+                                                  OPTION_DEF_PARAMS4[i].code,
+                                                  OPTION_DEF_PARAMS4[i].type,
+                                                  OPTION_DEF_PARAMS4[i].array));
+
+        } else {
+            // Option does encapsulate an option space.
+            definition.reset(new OptionDefinition(OPTION_DEF_PARAMS4[i].name,
+                                                  OPTION_DEF_PARAMS4[i].code,
+                                                  OPTION_DEF_PARAMS4[i].type,
+                                                  OPTION_DEF_PARAMS4[i].encapsulates));
+
+        }
 
         for (int rec = 0; rec < OPTION_DEF_PARAMS4[i].records_size; ++rec) {
             definition->addRecordField(OPTION_DEF_PARAMS4[i].records[rec]);
@@ -358,10 +375,34 @@ LibDHCP::initStdOptionDefs6() {
     v6option_defs_.clear();
 
     for (int i = 0; i < OPTION_DEF_PARAMS_SIZE6; ++i) {
-        OptionDefinitionPtr definition(new OptionDefinition(OPTION_DEF_PARAMS6[i].name,
-                                                            OPTION_DEF_PARAMS6[i].code,
-                                                            OPTION_DEF_PARAMS6[i].type,
-                                                            OPTION_DEF_PARAMS6[i].array));
+        std::string encapsulates(OPTION_DEF_PARAMS6[i].encapsulates);
+        if (!encapsulates.empty() && OPTION_DEF_PARAMS6[i].array) {
+            isc_throw(isc::BadValue, "invalid standard option definition: "
+                      << "option with code '" << OPTION_DEF_PARAMS6[i].code
+                      << "' may not encapsulate option space '"
+                      << encapsulates << "' because the definition"
+                      << " indicates that this option comprises an array"
+                      << " of values");
+        }
+
+        // Depending whether an option encapsulates an option space or not
+        // we pick different constructor to create an instance of the option
+        // definition.
+        OptionDefinitionPtr definition;
+        if (encapsulates.empty()) {
+            // Option does not encapsulate any option space.
+            definition.reset(new OptionDefinition(OPTION_DEF_PARAMS6[i].name,
+                                                  OPTION_DEF_PARAMS6[i].code,
+                                                  OPTION_DEF_PARAMS6[i].type,
+                                                  OPTION_DEF_PARAMS6[i].array));
+        } else {
+            // Option does encapsulate an option space.
+            definition.reset(new OptionDefinition(OPTION_DEF_PARAMS6[i].name,
+                                                  OPTION_DEF_PARAMS6[i].code,
+                                                  OPTION_DEF_PARAMS6[i].type,
+                                                  OPTION_DEF_PARAMS6[i].encapsulates));
+
+        }
 
         for (int rec = 0; rec < OPTION_DEF_PARAMS6[i].records_size; ++rec) {
             definition->addRecordField(OPTION_DEF_PARAMS6[i].records[rec]);
diff --git a/src/lib/dhcp/libdhcp++.dox b/src/lib/dhcp/libdhcp++.dox
index 013b6f2..194175a 100644
--- a/src/lib/dhcp/libdhcp++.dox
+++ b/src/lib/dhcp/libdhcp++.dox
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 /**
 @page libdhcp libdhcp++
 
@@ -76,4 +90,4 @@ Another useful methods are dedicated to transmission
 Note that receive4() and receive6() methods may return NULL, e.g.
 when timeout is reached or if dhcp daemon receives a signal.
 
-*/
\ No newline at end of file
+*/
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index bc47405..c6594b9 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -88,16 +88,6 @@ public:
                                               uint16_t type,
                                               const OptionBuffer& buf);
 
-    /// Builds collection of options.
-    ///
-    /// Builds raw (on-wire) data for provided collection of options.
-    ///
-    /// @param buf output buffer (assembled options will be stored here)
-    /// @param options collection of options to store to
-    static void packOptions6(isc::util::OutputBuffer& buf,
-                             const isc::dhcp::Option::OptionCollection& options);
-
-
     /// @brief Stores options in a buffer.
     ///
     /// Stores all options defined in options containers in a on-wire
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index dbdac0c..e06b163 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -84,51 +84,14 @@ Option::check() {
 }
 
 void Option::pack(isc::util::OutputBuffer& buf) {
-    switch (universe_) {
-    case V6:
-        return (pack6(buf));
-
-    case V4:
-        return (pack4(buf));
-
-    default:
-        isc_throw(BadValue, "Failed to pack " << type_ << " option as the "
-                  << "universe type is unknown.");
+    // Write a header.
+    packHeader(buf);
+    // Write data.
+    if (!data_.empty()) {
+        buf.writeData(&data_[0], data_.size());
     }
-}
-
-void
-Option::pack4(isc::util::OutputBuffer& buf) {
-    if (universe_ == V4) {
-        // Write a header.
-        packHeader(buf);
-        // Write data.
-        if (!data_.empty()) {
-            buf.writeData(&data_[0], data_.size());
-        }
-        // Write sub-options.
-        packOptions(buf);
-    } else {
-        isc_throw(BadValue, "Invalid universe type " << universe_);
-    }
-
-    return;
-}
-
-void Option::pack6(isc::util::OutputBuffer& buf) {
-    if (universe_ == V6) {
-        // Write a header.
-        packHeader(buf);
-        // Write data.
-        if (!data_.empty()) {
-            buf.writeData(&data_[0], data_.size());
-        }
-        // Write sub-options.
-        packOptions(buf);
-    } else {
-        isc_throw(BadValue, "Invalid universe type " << universe_);
-    }
-    return;
+    // Write sub-options.
+    packOptions(buf);
 }
 
 void
@@ -153,16 +116,7 @@ Option::packHeader(isc::util::OutputBuffer& buf) {
 
 void
 Option::packOptions(isc::util::OutputBuffer& buf) {
-    switch (universe_) {
-    case V4:
-        LibDHCP::packOptions(buf, options_);
-        return;
-    case V6:
-        LibDHCP::packOptions6(buf, options_);
-        return;
-    default:
-        isc_throw(isc::BadValue, "Invalid universe type " << universe_);
-    }
+    LibDHCP::packOptions(buf, options_);
 }
 
 void Option::unpack(OptionBufferConstIter begin,
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index e4105cc..553e825 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -158,28 +158,13 @@ public:
     ///
     /// Writes option in wire-format to buffer, returns pointer to first unused
     /// byte after stored option (that is useful for writing options one after
-    /// another). Used in DHCPv6 options.
-    ///
-    /// @todo Migrate DHCPv6 code to pack(OutputBuffer& buf) version
+    /// another).
     ///
     /// @param buf pointer to a buffer
     ///
     /// @throw BadValue Universe of the option is neither V4 nor V6.
     virtual void pack(isc::util::OutputBuffer& buf);
 
-    /// @brief Writes option in a wire-format to a buffer.
-    ///
-    /// Method will throw if option storing fails for some reason.
-    ///
-    /// @todo Once old (DHCPv6) implementation is rewritten,
-    /// unify pack4() and pack6() and rename them to just pack().
-    ///
-    /// @param buf output buffer (option will be stored there)
-    ///
-    /// @throw OutOfRange Option type is greater than 255.
-    /// @throw BadValue Universe is not V4.
-    virtual void pack4(isc::util::OutputBuffer& buf);
-
     /// @brief Parses received buffer.
     ///
     /// @param begin iterator to first byte of option data
@@ -317,13 +302,6 @@ public:
     virtual bool equal(const OptionPtr& other) const;
 
 protected:
-    /// Builds raw (over-wire) buffer of this option, including all
-    /// defined suboptions. Version for building DHCPv4 options.
-    ///
-    /// @param buf output buffer (built options will be stored here)
-    ///
-    /// @throw BadValue Universe is not V6.
-    virtual void pack6(isc::util::OutputBuffer& buf);
 
     /// @brief Store option's header in a buffer.
     ///
diff --git a/src/lib/dhcp/option4_addrlst.cc b/src/lib/dhcp/option4_addrlst.cc
index 86da9f6..436d07d 100644
--- a/src/lib/dhcp/option4_addrlst.cc
+++ b/src/lib/dhcp/option4_addrlst.cc
@@ -64,7 +64,7 @@ Option4AddrLst::Option4AddrLst(uint8_t type, const IOAddress& addr)
 }
 
 void
-Option4AddrLst::pack4(isc::util::OutputBuffer& buf) {
+Option4AddrLst::pack(isc::util::OutputBuffer& buf) {
 
     if (addrs_.size() * V4ADDRESS_LEN > 255) {
         isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_ << " is too big."
diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h
index 927f75b..21bbbe1 100644
--- a/src/lib/dhcp/option4_addrlst.h
+++ b/src/lib/dhcp/option4_addrlst.h
@@ -29,6 +29,11 @@
 namespace isc {
 namespace dhcp {
 
+/// Forward declaration to Option4AddrLst class.
+class Option4AddrLst;
+
+/// A pointer to the Option4AddrLst object.
+typedef boost::shared_ptr<Option4AddrLst> Option4AddrLstPtr;
 
 /// @brief DHCPv4 Option class for handling list of IPv4 addresses.
 ///
@@ -87,11 +92,8 @@ public:
     ///
     /// Method will throw if option storing fails for some reason.
     ///
-    /// TODO Once old (DHCPv6) implementation is rewritten,
-    /// unify pack4() and pack6() and rename them to just pack().
-    ///
     /// @param buf output buffer (option will be stored there)
-    virtual void pack4(isc::util::OutputBuffer& buf);
+    virtual void pack(isc::util::OutputBuffer& buf);
 
     /// Returns string representation of the option.
     ///
diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc
index 068e360..3d2a1a9 100644
--- a/src/lib/dhcp/option_custom.cc
+++ b/src/lib/dhcp/option_custom.cc
@@ -387,14 +387,10 @@ OptionCustom::dataFieldToText(const OptionDataType data_type,
 }
 
 void
-OptionCustom::pack4(isc::util::OutputBuffer& buf) {
-    if (len() > 255) {
-        isc_throw(OutOfRange, "DHCPv4 Option " << type_
-                  << " value is too high. At most 255 is supported.");
-    }
+OptionCustom::pack(isc::util::OutputBuffer& buf) {
 
-    buf.writeUint8(type_);
-    buf.writeUint8(len() - getHeaderLen());
+    // Pack DHCP header (V4 or V6).
+    packHeader(buf);
 
     // Write data from buffers.
     for (std::vector<OptionBuffer>::const_iterator it = buffers_.begin();
@@ -411,21 +407,6 @@ OptionCustom::pack4(isc::util::OutputBuffer& buf) {
     packOptions(buf);
 }
 
-void
-OptionCustom::pack6(isc::util::OutputBuffer& buf) {
-    buf.writeUint16(type_);
-    buf.writeUint16(len() - getHeaderLen());
-
-    // Write data from buffers.
-    for (std::vector<OptionBuffer>::const_iterator it = buffers_.begin();
-         it != buffers_.end(); ++it) {
-        if (!it->empty()) {
-            buf.writeData(&(*it)[0], it->size());
-        }
-    }
-
-    packOptions(buf);
-}
 
 asiolink::IOAddress
 OptionCustom::readAddress(const uint32_t index) const {
diff --git a/src/lib/dhcp/option_custom.h b/src/lib/dhcp/option_custom.h
index 0ee4688..c25347b 100644
--- a/src/lib/dhcp/option_custom.h
+++ b/src/lib/dhcp/option_custom.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -249,6 +249,11 @@ public:
     void writeString(const std::string& text,
                      const uint32_t index = 0);
 
+    /// @brief Writes DHCP option in a wire format to a buffer.
+    ///
+    /// @param buf output buffer (option will be stored there).
+    virtual void pack(isc::util::OutputBuffer& buf);
+
     /// @brief Parses received buffer.
     ///
     /// @param begin iterator to first byte of option data
@@ -278,18 +283,6 @@ public:
     void setData(const OptionBufferConstIter first,
                  const OptionBufferConstIter last);
 
-protected:
-
-    /// @brief Writes DHCPv4 option in a wire format to a buffer.
-    ///
-    /// @param buf output buffer (option will be stored there).
-    virtual void pack4(isc::util::OutputBuffer& buf);
-
-    /// @brief Writes DHCPv6 option in a wire format to a buffer.
-    ///
-    /// @param buf output buffer (built options will be stored here)
-    virtual void pack6(isc::util::OutputBuffer& buf);
-
 private:
 
     /// @brief Verify that the option comprises an array of values.
@@ -352,6 +345,9 @@ private:
     std::vector<OptionBuffer> buffers_;
 };
 
+/// A pointer to the OptionCustom object.
+typedef boost::shared_ptr<OptionCustom> OptionCustomPtr;
+
 } // namespace isc::dhcp
 } // namespace isc
 
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index d2b5aae..59ff022 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -21,6 +21,7 @@
 #include <dhcp/option_definition.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
+#include <dhcp/option_space.h>
 #include <util/encode/hex.h>
 #include <util/strutil.h>
 #include <boost/algorithm/string/classification.hpp>
@@ -40,7 +41,8 @@ OptionDefinition::OptionDefinition(const std::string& name,
     : name_(name),
       code_(code),
       type_(OPT_UNKNOWN_TYPE),
-      array_type_(array_type) {
+      array_type_(array_type),
+      encapsulated_space_("") {
     // Data type is held as enum value by this class.
     // Use the provided option type string to get the
     // corresponding enum value.
@@ -54,7 +56,33 @@ OptionDefinition::OptionDefinition(const std::string& name,
     : name_(name),
       code_(code),
       type_(type),
-      array_type_(array_type) {
+      array_type_(array_type),
+      encapsulated_space_("") {
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                   const uint16_t code,
+                                   const std::string& type,
+                                   const char* encapsulated_space)
+    : name_(name),
+      code_(code),
+      // Data type is held as enum value by this class.
+      // Use the provided option type string to get the
+      // corresponding enum value.
+      type_(OptionDataTypeUtil::getDataType(type)),
+      array_type_(false),
+      encapsulated_space_(encapsulated_space) {
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                   const uint16_t code,
+                                   const OptionDataType type,
+                                   const char* encapsulated_space)
+    : name_(name),
+      code_(code),
+      type_(type),
+      array_type_(false),
+      encapsulated_space_(encapsulated_space) {
 }
 
 void
@@ -188,8 +216,8 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
         const RecordFieldsCollection& records = getRecordFields();
         if (records.size() > values.size()) {
             isc_throw(InvalidOptionValue, "number of data fields for the option"
-                      << " type " << type_ << " is greater than number of values"
-                      << " provided.");
+                      << " type '" <<  getCode() << "' is greater than number"
+                      << " of values provided.");
         }
         for (size_t i = 0; i < records.size(); ++i) {
             writeToBuffer(util::str::trim(values[i]),
@@ -228,6 +256,11 @@ OptionDefinition::validate() const {
         all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
         err_str << "invalid option name '" << name_ << "'";
 
+    } else if (!encapsulated_space_.empty() &&
+               !OptionSpace::validateName(encapsulated_space_)) {
+        err_str << "invalid encapsulated option space name: '"
+                << encapsulated_space_ << "'";
+
     } else if (type_ >= OPT_UNKNOWN_TYPE) {
         // Option definition must be of a known type.
         err_str << "option type value " << type_ << " is out of range.";
@@ -411,14 +444,8 @@ OptionDefinition::writeToBuffer(const std::string& value,
         OptionDataTypeUtil::writeString(value, buf);
         return;
     case OPT_FQDN_TYPE:
-        {
-            // FQDN implementation is not terribly complicated but will require
-            // creation of some additional logic (maybe object) that will parse
-            // the fqdn into labels.
-            isc_throw(isc::NotImplemented, "write of FQDN record into option buffer"
-                      " is not supported yet");
-            return;
-        }
+        OptionDataTypeUtil::writeFqdn(value, buf);
+        return;
     default:
         // We hit this point because invalid option data type has been specified
         // This may be the case because 'empty' or 'record' data type has been
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index efcaba0..df5def7 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -146,10 +146,10 @@ public:
     /// @param type option data type as string.
     /// @param array_type array indicator, if true it indicates that the
     /// option fields are the array.
-    OptionDefinition(const std::string& name,
-                     const uint16_t code,
-                     const std::string& type,
-                     const bool array_type = false);
+    explicit OptionDefinition(const std::string& name,
+                              const uint16_t code,
+                              const std::string& type,
+                              const bool array_type = false);
 
     /// @brief Constructor.
     ///
@@ -158,10 +158,49 @@ public:
     /// @param type option data type.
     /// @param array_type array indicator, if true it indicates that the
     /// option fields are the array.
-    OptionDefinition(const std::string& name,
-                     const uint16_t code,
-                     const OptionDataType type,
-                     const bool array_type = false);
+    explicit OptionDefinition(const std::string& name,
+                              const uint16_t code,
+                              const OptionDataType type,
+                              const bool array_type = false);
+
+    /// @brief Constructor.
+    ///
+    /// This constructor sets the name of the option space that is
+    /// encapsulated by this option. The encapsulated option space
+    /// indentifies sub-options that are carried within this option.
+    /// This constructor does not allow to set array indicator
+    /// because options comprising an array of data fields must
+    /// not be used with sub-options.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @param type option data type given as string.
+    /// @param encapsulated_space name of the option space being
+    /// encapsulated by this option.
+    explicit OptionDefinition(const std::string& name,
+                              const uint16_t code,
+                              const std::string& type,
+                              const char* encapsulated_space);
+
+    /// @brief Constructor.
+    ///
+    /// This constructor sets the name of the option space that is
+    /// encapsulated by this option. The encapsulated option space
+    /// indentifies sub-options that are carried within this option.
+    /// This constructor does not allow to set array indicator
+    /// because options comprising an array of data fields must
+    /// not be used with sub-options.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @param type option data type.
+    /// @param encapsulated_space name of the option space being
+    /// encapsulated by this option.
+    explicit OptionDefinition(const std::string& name,
+                              const uint16_t code,
+                              const OptionDataType type,
+                              const char* encapsulated_space);
+
 
     /// @brief Adds data field to the record.
     ///
@@ -192,10 +231,17 @@ public:
     /// @return option code.
     uint16_t getCode() const { return (code_); }
 
+    /// @brief Return name of the encapsulated option space.
+    ///
+    /// @return name of the encapsulated option space.
+    std::string getEncapsulatedSpace() const {
+        return (encapsulated_space_);
+    }
+
     /// @brief Return option name.
     ///
     /// @return option name.
-    const std::string& getName() const { return (name_); }
+    std::string getName() const { return (name_); }
 
     /// @brief Return list of record fields.
     ///
@@ -456,6 +502,8 @@ private:
     OptionDataType type_;
     /// Indicates wheter option is a single value or array.
     bool array_type_;
+    /// Name of the space being encapsulated by this option.
+    std::string encapsulated_space_;
     /// Collection of data fields within the record.
     RecordFieldsCollection record_fields_;
 };
diff --git a/src/lib/dhcp/option_int_array.h b/src/lib/dhcp/option_int_array.h
index 5004152..1babee5 100644
--- a/src/lib/dhcp/option_int_array.h
+++ b/src/lib/dhcp/option_int_array.h
@@ -25,6 +25,23 @@
 namespace isc {
 namespace dhcp {
 
+/// Forward declaration of OptionIntArray.
+template<typename T>
+class OptionIntArray;
+
+/// @defgroup option_int_array_defs Typedefs for OptionIntArray class.
+///
+/// @brief Classes that represent options comprising array of integers.
+///
+/// @{
+typedef OptionIntArray<uint8_t> OptionUint8Array;
+typedef boost::shared_ptr<OptionUint8Array> OptionUint8ArrayPtr;
+typedef OptionIntArray<uint16_t> OptionUint16Array;
+typedef boost::shared_ptr<OptionUint16Array> OptionUint16ArrayPtr;
+typedef OptionIntArray<uint32_t> OptionUint32Array;
+typedef boost::shared_ptr<OptionUint32Array> OptionUint32ArrayPtr;
+/// @}
+
 /// This template class represents DHCP (v4 or v6) option with an
 /// array of integer values. The type of the elements in the array
 /// can be any of the following:
@@ -107,6 +124,13 @@ public:
         unpack(begin, end);
     }
 
+    /// @brief Adds a new value to the array.
+    ///
+    /// @param value a value being added.
+    void addValue(const T value) {
+        values_.push_back(value);
+    }
+
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// byte after stored option.
     ///
diff --git a/src/lib/dhcp/option_space.cc b/src/lib/dhcp/option_space.cc
new file mode 100644
index 0000000..f9f5bee
--- /dev/null
+++ b/src/lib/dhcp/option_space.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2012, 2013 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 <dhcp/option_space.h>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+namespace isc {
+namespace dhcp {
+
+OptionSpace::OptionSpace(const std::string& name, const bool vendor_space)
+    : name_(name), vendor_space_(vendor_space) {
+    //  Check that provided option space name is valid.
+    if (!validateName(name_)) {
+        isc_throw(InvalidOptionSpace, "Invalid option space name "
+                  << name_);
+    }
+}
+
+bool
+OptionSpace::validateName(const std::string& name) {
+
+    using namespace boost::algorithm;
+
+    // Allowed characters are: lower or upper case letters, digits,
+    // underscores and hyphens. Empty option spaces are not allowed.
+    if (all(name, boost::is_from_range('a', 'z') ||
+            boost::is_from_range('A', 'Z') ||
+            boost::is_digit() ||
+            boost::is_any_of(std::string("-_"))) &&
+        !name.empty() &&
+        // Hyphens and underscores are not allowed at the beginning
+        // and at the end of the option space name.
+        !all(find_head(name, 1), boost::is_any_of(std::string("-_"))) &&
+        !all(find_tail(name, 1), boost::is_any_of(std::string("-_")))) {
+        return (true);
+
+    }
+    return (false);
+}
+
+OptionSpace6::OptionSpace6(const std::string& name)
+    : OptionSpace(name),
+      enterprise_number_(0) {
+}
+
+OptionSpace6::OptionSpace6(const std::string& name,
+                           const uint32_t enterprise_number)
+    : OptionSpace(name, true),
+      enterprise_number_(enterprise_number) {
+}
+
+void
+OptionSpace6::setVendorSpace(const uint32_t enterprise_number) {
+    enterprise_number_ = enterprise_number;
+    OptionSpace::setVendorSpace();
+}
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
diff --git a/src/lib/dhcp/option_space.h b/src/lib/dhcp/option_space.h
new file mode 100644
index 0000000..9eebd76
--- /dev/null
+++ b/src/lib/dhcp/option_space.h
@@ -0,0 +1,189 @@
+// Copyright (C) 2012, 2013 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_SPACE_H
+#define OPTION_SPACE_H
+
+#include <exceptions/exceptions.h>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception to be thrown when invalid option space
+/// is specified.
+class InvalidOptionSpace : public Exception {
+public:
+    InvalidOptionSpace(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// OptionSpace forward declaration.
+class OptionSpace;
+/// A pointer to OptionSpace object.
+typedef boost::shared_ptr<OptionSpace> OptionSpacePtr;
+/// A collection of option spaces.
+typedef std::map<std::string, OptionSpacePtr> OptionSpaceCollection;
+
+/// @brief DHCP option space.
+///
+/// This class represents single option space. The option spaces are used
+/// to group DHCP options having unique option codes. The special type
+/// of the option space is so called "vendor specific option space".
+/// It groups sub-options being sent within Vendor Encapsulated Options.
+/// For DHCPv4 it is the option with code 43. The option spaces are
+/// assigned to option instances represented by isc::dhcp::Option and
+/// other classes derived from it. Each particular option may belong to
+/// multiple option spaces.
+/// This class may be used to represent any DHCPv4 option space. If the
+/// option space is to group DHCPv4 Vendor Encapsulated Options then
+/// "vendor space" flag must be set using \ref OptionSpace::setVendorSpace
+/// or the argument passed to the constructor. In theory, this class can
+/// be also used to represent non-vendor specific DHCPv6 option space
+/// but this is discouraged. For DHCPv6 option spaces the OptionSpace6
+/// class should be used instead.
+///
+/// @note this class is intended to be used to represent DHCPv4 option
+/// spaces only. However, it hasn't been called OptionSpace4 (that would
+/// suggest that it is specific to DHCPv4) because it can be also
+/// used to represent some DHCPv6 option spaces and is a base class
+/// for \ref OptionSpace6. Thus, if one declared the container as follows:
+/// @code
+/// std::vector<OptionSpace4> container;
+/// @endcode
+/// it would suggest that the container holds DHCPv4 option spaces while
+/// it could hold both DHCPv4 and DHCPv6 option spaces as the OptionSpace6
+/// object could be upcast to OptionSpace4. This confusion does not appear
+/// when OptionSpace is used as a name for the base class.
+class OptionSpace {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param name option space name.
+    /// @param vendor_space boolean value that indicates that the object
+    /// describes the vendor specific option space.
+    ///
+    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
+    /// contains invalid characters or is empty. This constructor uses
+    /// \ref validateName function to check that the specified name is
+    /// correct.
+    OptionSpace(const std::string& name, const bool vendor_space = false);
+
+    /// @brief Return option space name.
+    ///
+    /// @return option space name.
+    const std::string& getName() const { return (name_); }
+
+    /// @brief Mark option space as non-vendor space.
+    void clearVendorSpace() {
+        vendor_space_ = false;
+    }
+
+    /// @brief Check if option space is vendor specific.
+    ///
+    /// @return boolean value that indicates if the object describes
+    /// the vendor specific option space.
+    bool isVendorSpace() const { return (vendor_space_); }
+
+    /// @brief Mark option space as vendor specific.
+    void setVendorSpace() {
+        vendor_space_ = true;
+    }
+
+    /// @brief Checks that the provided option space name is valid.
+    ///
+    /// It is expected that option space name consists of upper or
+    /// lower case letters or digits. Also, it may contain underscores
+    /// or dashes. Other characters are prohibited. The empty option
+    /// space names are invalid.
+    ///
+    /// @param name option space name to be validated.
+    ///
+    /// @return true if the option space is valid, else it returns false.
+    static bool validateName(const std::string& name);
+
+private:
+    std::string name_;  ///< Holds option space name.
+
+    bool vendor_space_; ///< Is this the vendor space?
+
+};
+
+/// @brief DHCPv6 option space with enterprise number assigned.
+///
+/// This class extends the base class with the support for enterprise numbers.
+/// The enterprise numbers are assigned by IANA to various organizations
+/// and they are carried as uint32_t integers in DHCPv6 Vendor Specific
+/// Information Options (VSIO). For more information refer to RFC3315.
+/// All option spaces that group VSIO options must have enterprise number
+/// set. It can be set using a constructor or \ref setVendorSpace function.
+/// The extra functionality of this class (enterprise numbers) allows to
+/// represent DHCPv6 vendor-specific option spaces but this class is also
+/// intended to be used for all other DHCPv6 option spaces. That way all
+/// DHCPv6 option spaces can be stored in the container holding OptionSpace6
+/// objects. Also, it is easy to mark vendor-specific option space as non-vendor
+/// specific option space (and the other way around) without a need to cast
+/// between OptionSpace and OptionSpace6 types.
+class OptionSpace6 : public OptionSpace {
+public:
+
+    /// @brief Constructor for non-vendor-specific options.
+    ///
+    /// This constructor marks option space as non-vendor specific.
+    ///
+    /// @param name option space name.
+    ///
+    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
+    /// contains invalid characters or is empty. This constructor uses
+    /// \ref OptionSpace::validateName function to check that the specified
+    /// name is correct.
+    OptionSpace6(const std::string& name);
+
+    /// @brief Constructor for vendor-specific options.
+    ///
+    /// This constructor marks option space as vendor specific and sets
+    /// enterprise number to a given value.
+    ///
+    /// @param name option space name.
+    /// @param enterprise_number enterprise number.
+    ///
+    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
+    /// contains invalid characters or is empty. This constructor uses
+    /// \ref OptionSpace::validateName function to check that the specified
+    /// name is correct.
+    OptionSpace6(const std::string& name, const uint32_t enterprise_number);
+
+    /// @brief Return enterprise number for the option space.
+    ///
+    /// @return enterprise number.
+    uint32_t getEnterpriseNumber() const { return (enterprise_number_); }
+
+    /// @brief Mark option space as vendor specific.
+    ///
+    /// @param enterprise_number enterprise number.
+    void setVendorSpace(const uint32_t enterprise_number);
+
+private:
+    
+    uint32_t enterprise_number_; ///< IANA assigned enterprise number.
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // OPTION_SPACE_H
diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc
index d3b22de..0592807 100644
--- a/src/lib/dhcp/pkt4.cc
+++ b/src/lib/dhcp/pkt4.cc
@@ -219,7 +219,7 @@ void Pkt4::check() {
     uint8_t msg_type = getType();
     if (msg_type > DHCPLEASEACTIVE) {
         isc_throw(BadValue, "Invalid DHCP message type received: "
-                  << msg_type);
+                  << static_cast<int>(msg_type));
     }
 }
 
@@ -230,10 +230,10 @@ uint8_t Pkt4::getType() const {
     }
 
     // Check if Message Type is specified as OptionInt<uint8_t>
-    boost::shared_ptr<OptionInt<uint8_t> > typeOpt =
+    boost::shared_ptr<OptionInt<uint8_t> > type_opt =
         boost::dynamic_pointer_cast<OptionInt<uint8_t> >(generic);
-    if (typeOpt) {
-        return (typeOpt->getValue());
+    if (type_opt) {
+        return (type_opt->getValue());
     }
 
     // Try to use it as generic option
@@ -253,7 +253,6 @@ void Pkt4::setType(uint8_t dhcp_type) {
     }
 }
 
-
 void Pkt4::repack() {
     bufferOut_.writeData(&data_[0], data_.size());
 }
@@ -263,7 +262,7 @@ Pkt4::toText() {
     stringstream tmp;
     tmp << "localAddr=" << local_addr_.toText() << ":" << local_port_
         << " remoteAddr=" << remote_addr_.toText()
-        << ":" << remote_port_ << ", msgtype=" << getType()
+        << ":" << remote_port_ << ", msgtype=" << static_cast<int>(getType())
         << ", transid=0x" << hex << transid_ << dec << endl;
 
     for (isc::dhcp::Option::OptionCollection::iterator opt=options_.begin();
diff --git a/src/lib/dhcp/pkt6.cc b/src/lib/dhcp/pkt6.cc
index 2c97b07..c3a98bf 100644
--- a/src/lib/dhcp/pkt6.cc
+++ b/src/lib/dhcp/pkt6.cc
@@ -90,7 +90,7 @@ Pkt6::packUDP() {
         bufferOut_.writeUint8( (transid_) & 0xff );
 
         // the rest are options
-        LibDHCP::packOptions6(bufferOut_, options_);
+        LibDHCP::packOptions(bufferOut_, options_);
     }
     catch (const Exception& e) {
         /// @todo: throw exception here once we turn this function to void.
@@ -155,8 +155,8 @@ Pkt6::toText() {
     tmp << "localAddr=[" << local_addr_.toText() << "]:" << local_port_
         << " remoteAddr=[" << remote_addr_.toText()
         << "]:" << remote_port_ << endl;
-    tmp << "msgtype=" << msg_type_ << ", transid=0x" << hex << transid_
-        << dec << endl;
+    tmp << "msgtype=" << static_cast<int>(msg_type_) << ", transid=0x" <<
+        hex << transid_ << dec << endl;
     for (isc::dhcp::Option::OptionCollection::iterator opt=options_.begin();
          opt != options_.end();
          ++opt) {
diff --git a/src/lib/dhcp/std_option_defs.h b/src/lib/dhcp/std_option_defs.h
index 144df8b..839a5d9 100644
--- a/src/lib/dhcp/std_option_defs.h
+++ b/src/lib/dhcp/std_option_defs.h
@@ -50,6 +50,8 @@ struct OptionDefParams {
     bool array;                    // is array
     const OptionDataType* records; // record fields
     size_t records_size;           // number of fields in a record
+    const char* encapsulates;      // option space encapsulated by
+                                   // the particular option.
 };
 
 // fqdn option record fields.
@@ -64,128 +66,128 @@ RECORD_DECL(FQDN_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_STRING_TYPE);
 
 /// @brief Definitions of standard DHCPv4 options.
 const OptionDefParams OPTION_DEF_PARAMS4[] = {
-    { "subnet-mask", DHO_SUBNET_MASK, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
-    { "time-offset", DHO_TIME_OFFSET, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
-    { "routers", DHO_ROUTERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
-    { "time-servers", DHO_TIME_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "subnet-mask", DHO_SUBNET_MASK, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
+    { "time-offset", DHO_TIME_OFFSET, OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
+    { "routers", DHO_ROUTERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "time-servers", DHO_TIME_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "name-servers", DHO_NAME_SERVERS, OPT_IPV4_ADDRESS_TYPE,
-      false, NO_RECORD_DEF },
+      false, NO_RECORD_DEF, "" },
     { "domain-name-servers", DHO_DOMAIN_NAME_SERVERS,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
-    { "log-servers", DHO_LOG_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "log-servers", DHO_LOG_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "cookie-servers", DHO_COOKIE_SERVERS, OPT_IPV4_ADDRESS_TYPE,
-      true, NO_RECORD_DEF },
-    { "lpr-servers", DHO_LPR_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
-    { "impress-servers", DHO_IMPRESS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      true, NO_RECORD_DEF, "" },
+    { "lpr-servers", DHO_LPR_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "impress-servers", DHO_IMPRESS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "resource-location-servers", DHO_RESOURCE_LOCATION_SERVERS,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
-    { "host-name", DHO_HOST_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
-    { "boot-size", DHO_BOOT_SIZE, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
-    { "merit-dump", DHO_MERIT_DUMP, OPT_STRING_TYPE, false, NO_RECORD_DEF },
-    { "domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE, false, NO_RECORD_DEF },
-    { "swap-server", DHO_SWAP_SERVER, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
-    { "root-path", DHO_ROOT_PATH, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "host-name", DHO_HOST_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "boot-size", DHO_BOOT_SIZE, OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
+    { "merit-dump", DHO_MERIT_DUMP, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE, false, NO_RECORD_DEF, "" },
+    { "swap-server", DHO_SWAP_SERVER, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
+    { "root-path", DHO_ROOT_PATH, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
     { "extensions-path", DHO_EXTENSIONS_PATH, OPT_STRING_TYPE,
-      false, NO_RECORD_DEF },
-    { "ip-forwarding", DHO_IP_FORWARDING, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+      false, NO_RECORD_DEF, "" },
+    { "ip-forwarding", DHO_IP_FORWARDING, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
     { "non-local-source-routing", DHO_NON_LOCAL_SOURCE_ROUTING,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
-    { "policy-filter", DHO_POLICY_FILTER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
+    { "policy-filter", DHO_POLICY_FILTER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "max-dgram-reassembly", DHO_MAX_DGRAM_REASSEMBLY,
-      OPT_UINT16_TYPE, false, NO_RECORD_DEF },
-    { "default-ip-ttl", DHO_DEFAULT_IP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
+    { "default-ip-ttl", DHO_DEFAULT_IP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
     { "path-mtu-aging-timeout", DHO_PATH_MTU_AGING_TIMEOUT,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "path-mtu-plateau-table", DHO_PATH_MTU_PLATEAU_TABLE,
-      OPT_UINT16_TYPE, true, NO_RECORD_DEF },
-    { "interface-mtu", DHO_INTERFACE_MTU, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
+    { "interface-mtu", DHO_INTERFACE_MTU, OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
     { "all-subnets-local", DHO_ALL_SUBNETS_LOCAL,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
     { "broadcast-address", DHO_BROADCAST_ADDRESS,
-      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     { "perform-mask-discovery", DHO_PERFORM_MASK_DISCOVERY,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
-    { "mask-supplier", DHO_MASK_SUPPLIER, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
+    { "mask-supplier", DHO_MASK_SUPPLIER, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
     { "router-discovery", DHO_ROUTER_DISCOVERY,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
     { "router-solicitation-address", DHO_ROUTER_SOLICITATION_ADDRESS,
-      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     { "static-routes", DHO_STATIC_ROUTES,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "trailer-encapsulation", DHO_TRAILER_ENCAPSULATION,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
     { "arp-cache-timeout", DHO_ARP_CACHE_TIMEOUT,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "ieee802-3-encapsulation", DHO_IEEE802_3_ENCAPSULATION,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
-    { "default-tcp-ttl", DHO_DEFAULT_TCP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
+    { "default-tcp-ttl", DHO_DEFAULT_TCP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
     { "tcp-keepalive-internal", DHO_TCP_KEEPALIVE_INTERVAL,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "tcp-keepalive-garbage", DHO_TCP_KEEPALIVE_GARBAGE,
-      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
-    { "nis-domain", DHO_NIS_DOMAIN, OPT_STRING_TYPE, false, NO_RECORD_DEF },
-    { "nis-servers", DHO_NIS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
-    { "ntp-servers", DHO_NTP_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF, "" },
+    { "nis-domain", DHO_NIS_DOMAIN, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "nis-servers", DHO_NIS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "ntp-servers", DHO_NTP_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "vendor-encapsulated-options", DHO_VENDOR_ENCAPSULATED_OPTIONS,
-      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+      OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "vendor-encapsulated-options-space" },
     { "netbios-name-servers", DHO_NETBIOS_NAME_SERVERS,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "netbios-dd-server", DHO_NETBIOS_DD_SERVER,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "netbios-node-type", DHO_NETBIOS_NODE_TYPE,
-      OPT_UINT8_TYPE, false, NO_RECORD_DEF },
-    { "netbios-scope", DHO_NETBIOS_SCOPE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
-    { "font-servers", DHO_FONT_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
+    { "netbios-scope", DHO_NETBIOS_SCOPE, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "font-servers", DHO_FONT_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "x-display-manager", DHO_X_DISPLAY_MANAGER,
-      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "dhcp-requested-address", DHO_DHCP_REQUESTED_ADDRESS,
-      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
-    { "dhcp-lease-time", DHO_DHCP_LEASE_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
+    { "dhcp-lease-time", DHO_DHCP_LEASE_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-option-overload", DHO_DHCP_OPTION_OVERLOAD,
-      OPT_UINT8_TYPE, false, NO_RECORD_DEF },
-    { "dhcp-message-type", DHO_DHCP_MESSAGE_TYPE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
+    { "dhcp-message-type", DHO_DHCP_MESSAGE_TYPE, OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-server-identifier", DHO_DHCP_SERVER_IDENTIFIER,
-      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-parameter-request-list", DHO_DHCP_PARAMETER_REQUEST_LIST,
-      OPT_UINT8_TYPE, true, NO_RECORD_DEF },
-    { "dhcp-message", DHO_DHCP_MESSAGE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT8_TYPE, true, NO_RECORD_DEF, "" },
+    { "dhcp-message", DHO_DHCP_MESSAGE, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-max-message-size", DHO_DHCP_MAX_MESSAGE_SIZE,
-      OPT_UINT16_TYPE, false, NO_RECORD_DEF },
-    { "dhcp-renewal-time", DHO_DHCP_RENEWAL_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
+    { "dhcp-renewal-time", DHO_DHCP_RENEWAL_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-rebinding-time", DHO_DHCP_REBINDING_TIME,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "vendor-class-identifier", DHO_VENDOR_CLASS_IDENTIFIER,
-      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     { "dhcp-client-identifier", DHO_DHCP_CLIENT_IDENTIFIER,
-      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "nwip-domain-name", DHO_NWIP_DOMAIN_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
-    { "nwip-suboptions", DHO_NWIP_SUBOPTIONS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "user-class", DHO_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "fqdn", DHO_FQDN, OPT_RECORD_TYPE, false, RECORD_DEF(FQDN_RECORDS) },
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "nwip-domain-name", DHO_NWIP_DOMAIN_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "nwip-suboptions", DHO_NWIP_SUBOPTIONS, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "user-class", DHO_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "fqdn", DHO_FQDN, OPT_RECORD_TYPE, false, RECORD_DEF(FQDN_RECORDS), "" },
     { "dhcp-agent-options", DHO_DHCP_AGENT_OPTIONS,
-      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+      OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "dhcp-agent-options-space" },
     // Unfortunatelly the AUTHENTICATE option contains a 64-bit
     // data field called 'replay-detection' that can't be added
     // as a record field to a custom option. Also, there is no
     // dedicated option class to handle it so we simply return
     // binary option type for now.
     // @todo implement a class to handle AUTH option.
-    { "authenticate", DHO_AUTHENTICATE, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "authenticate", DHO_AUTHENTICATE, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     { "client-last-transaction-time", DHO_CLIENT_LAST_TRANSACTION_TIME,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
-    { "associated-ip", DHO_ASSOCIATED_IP, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
+    { "associated-ip", DHO_ASSOCIATED_IP, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "subnet-selection", DHO_SUBNET_SELECTION,
-      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     // The following options need a special encoding of data
     // being carried by them. Therefore, there is no way they can
     // be handled by OptionCustom. We may need to implement
     // dedicated classes to handle them. Until that happens
     // let's treat them as 'binary' options.
-    { "domain-search", DHO_DOMAIN_SEARCH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "domain-search", DHO_DOMAIN_SEARCH, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     { "vivco-suboptions", DHO_VIVCO_SUBOPTIONS,
-      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     { "vivso-suboptions", DHO_VIVSO_SUBOPTIONS, OPT_BINARY_TYPE,
-      false, NO_RECORD_DEF }
+      false, NO_RECORD_DEF, "" }
 
         // @todo add definitions for all remaning options.
 };
@@ -222,8 +224,6 @@ RECORD_DECL(REMOTE_ID_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 RECORD_DECL(STATUS_CODE_RECORDS, OPT_UINT16_TYPE, OPT_STRING_TYPE);
 // vendor-class
 RECORD_DECL(VENDOR_CLASS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
-// vendor-opts
-RECORD_DECL(VENDOR_OPTS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 
 /// Standard DHCPv6 option definitions.
 ///
@@ -236,84 +236,84 @@ RECORD_DECL(VENDOR_OPTS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 /// warning about lack of initializers for some struct members
 /// causing build to fail.
 const OptionDefParams OPTION_DEF_PARAMS6[] = {
-    { "clientid", D6O_CLIENTID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "serverid", D6O_SERVERID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(IA_NA_RECORDS) },
-    { "ia-ta", D6O_IA_TA, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
-    { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(IAADDR_RECORDS) },
-    { "oro", D6O_ORO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
-    { "preference", D6O_PREFERENCE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
-    { "elapsed-time", D6O_ELAPSED_TIME, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
-    { "relay-msg", D6O_RELAY_MSG, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "clientid", D6O_CLIENTID, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "serverid", D6O_SERVERID, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(IA_NA_RECORDS), "" },
+    { "ia-ta", D6O_IA_TA, OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
+    { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(IAADDR_RECORDS), "" },
+    { "oro", D6O_ORO, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
+    { "preference", D6O_PREFERENCE, OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
+    { "elapsed-time", D6O_ELAPSED_TIME, OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
+    { "relay-msg", D6O_RELAY_MSG, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     // Unfortunatelly the AUTH option contains a 64-bit data field
     // called 'replay-detection' that can't be added as a record
     // field to a custom option. Also, there is no dedicated
     // option class to handle it so we simply return binary
     // option type for now.
     // @todo implement a class to handle AUTH option.
-    { "auth", D6O_AUTH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "unicast", D6O_UNICAST, OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "auth", D6O_AUTH, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "unicast", D6O_UNICAST, OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     { "status-code", D6O_STATUS_CODE, OPT_RECORD_TYPE, false,
-      RECORD_DEF(STATUS_CODE_RECORDS) },
-    { "rapid-commit", D6O_RAPID_COMMIT, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
-    { "user-class", D6O_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+      RECORD_DEF(STATUS_CODE_RECORDS), "" },
+    { "rapid-commit", D6O_RAPID_COMMIT, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "" },
+    { "user-class", D6O_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
     { "vendor-class", D6O_VENDOR_CLASS, OPT_RECORD_TYPE, false,
-      RECORD_DEF(VENDOR_CLASS_RECORDS) },
-    { "vendor-opts", D6O_VENDOR_OPTS, OPT_RECORD_TYPE, false,
-      RECORD_DEF(VENDOR_OPTS_RECORDS) },
-    { "interface-id", D6O_INTERFACE_ID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "reconf-msg", D6O_RECONF_MSG, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+      RECORD_DEF(VENDOR_CLASS_RECORDS), "" },
+    { "vendor-opts", D6O_VENDOR_OPTS, OPT_UINT32_TYPE, false,
+      NO_RECORD_DEF, "vendor-opts-space" },
+    { "interface-id", D6O_INTERFACE_ID, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "reconf-msg", D6O_RECONF_MSG, OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
     { "reconf-accept", D6O_RECONF_ACCEPT, OPT_EMPTY_TYPE, false,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "sip-server-dns", D6O_SIP_SERVERS_DNS, OPT_FQDN_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "sip-server-addr", D6O_SIP_SERVERS_ADDR, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "dns-servers", D6O_NAME_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
-    { "domain-search", D6O_DOMAIN_SEARCH, OPT_FQDN_TYPE, true, NO_RECORD_DEF },
-    { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(IA_PD_RECORDS) },
+      NO_RECORD_DEF, "" },
+    { "domain-search", D6O_DOMAIN_SEARCH, OPT_FQDN_TYPE, true, NO_RECORD_DEF, "" },
+    { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(IA_PD_RECORDS), "" },
     { "iaprefix", D6O_IAPREFIX, OPT_RECORD_TYPE, false,
-      RECORD_DEF(IA_PREFIX_RECORDS) },
+      RECORD_DEF(IA_PREFIX_RECORDS), "" },
     { "nis-servers", D6O_NIS_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "nisp-servers", D6O_NISP_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "nis-domain-name", D6O_NIS_DOMAIN_NAME, OPT_FQDN_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "nisp-domain-name", D6O_NISP_DOMAIN_NAME, OPT_FQDN_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "sntp-servers", D6O_SNTP_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "information-refresh-time", D6O_INFORMATION_REFRESH_TIME,
-      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "bcmcs-server-dns", D6O_BCMCS_SERVER_D, OPT_FQDN_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "bcmcs-server-addr", D6O_BCMCS_SERVER_A, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "geoconf-civic", D6O_GEOCONF_CIVIC, OPT_RECORD_TYPE, false,
-      RECORD_DEF(GEOCONF_CIVIC_RECORDS) },
+      RECORD_DEF(GEOCONF_CIVIC_RECORDS), "" },
     { "remote-id", D6O_REMOTE_ID, OPT_RECORD_TYPE, false,
-      RECORD_DEF(REMOTE_ID_RECORDS) },
+      RECORD_DEF(REMOTE_ID_RECORDS), "" },
     { "subscriber-id", D6O_SUBSCRIBER_ID, OPT_BINARY_TYPE, false,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "client-fqdn", D6O_CLIENT_FQDN, OPT_RECORD_TYPE, false,
-      RECORD_DEF(CLIENT_FQDN_RECORDS) },
+      RECORD_DEF(CLIENT_FQDN_RECORDS), "" },
     { "pana-agent", D6O_PANA_AGENT, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "new-posix-timezone", D6O_NEW_POSIX_TIMEZONE, OPT_STRING_TYPE, false,
-      NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
     { "new-tzdb-timezone", D6O_NEW_TZDB_TIMEZONE, OPT_STRING_TYPE, false,
-      NO_RECORD_DEF },
-    { "ero", D6O_ERO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
+      NO_RECORD_DEF, "" },
+    { "ero", D6O_ERO, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
     { "lq-query", D6O_LQ_QUERY, OPT_RECORD_TYPE, false,
-      RECORD_DEF(LQ_QUERY_RECORDS) },
-    { "client-data", D6O_CLIENT_DATA, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
-    { "clt-time", D6O_CLT_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+      RECORD_DEF(LQ_QUERY_RECORDS), "" },
+    { "client-data", D6O_CLIENT_DATA, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "" },
+    { "clt-time", D6O_CLT_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "lq-relay-data", D6O_LQ_RELAY_DATA, OPT_RECORD_TYPE, false,
-      RECORD_DEF(LQ_RELAY_DATA_RECORDS) },
+      RECORD_DEF(LQ_RELAY_DATA_RECORDS), "" },
     { "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
-      NO_RECORD_DEF }
+      NO_RECORD_DEF, "" }
 
     // @todo There is still a bunch of options for which we have to provide
     // definitions but we don't do it because they are not really
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 4833fb5..c868553 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -40,6 +40,7 @@ libdhcp___unittests_SOURCES += option_data_types_unittest.cc
 libdhcp___unittests_SOURCES += option_definition_unittest.cc
 libdhcp___unittests_SOURCES += option_custom_unittest.cc
 libdhcp___unittests_SOURCES += option_unittest.cc
+libdhcp___unittests_SOURCES += option_space_unittest.cc
 libdhcp___unittests_SOURCES += pkt4_unittest.cc
 libdhcp___unittests_SOURCES += pkt6_unittest.cc
 libdhcp___unittests_SOURCES += duid_unittest.cc
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index a59da12..1a87b13 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
@@ -68,12 +68,16 @@ public:
     /// used to create option instance.
     /// @param expected_type type of the option created by the
     /// factory function returned by the option definition.
+    /// @param encapsulates name of the option space being encapsulated
+    /// by the option.
     static void testStdOptionDefs4(const uint16_t code,
                                    const OptionBufferConstIter begin,
                                    const OptionBufferConstIter end,
-                                   const std::type_info& expected_type) {
+                                   const std::type_info& expected_type,
+                                   const std::string& encapsulates = "") {
         // Use V4 universe.
-        testStdOptionDefs(Option::V4, code, begin, end, expected_type);
+        testStdOptionDefs(Option::V4, code, begin, end, expected_type,
+                          encapsulates);
     }
 
     /// @brief Test DHCPv6 option definition.
@@ -88,12 +92,16 @@ public:
     /// used to create option instance.
     /// @param expected_type type of the option created by the
     /// factory function returned by the option definition.
+    /// @param encapsulates name of the option space being encapsulated
+    /// by the option.
     static void testStdOptionDefs6(const uint16_t code,
                                    const OptionBufferConstIter begin,
                                    const OptionBufferConstIter end,
-                                   const std::type_info& expected_type) {
+                                   const std::type_info& expected_type,
+                                   const std::string& encapsulates = "") {
         // Use V6 universe.
-        testStdOptionDefs(Option::V6, code, begin, end, expected_type);
+        testStdOptionDefs(Option::V6, code, begin, end, expected_type,
+                          encapsulates);
     }
 private:
 
@@ -109,11 +117,14 @@ private:
     /// used to create option instance.
     /// @param expected_type type of the option created by the
     /// factory function returned by the option definition.
+    /// @param encapsulates name of the option space being encapsulated
+    /// by the option.
     static void testStdOptionDefs(const Option::Universe u,
                                   const uint16_t code,
                                   const OptionBufferConstIter begin,
                                   const OptionBufferConstIter end,
-                                  const std::type_info& expected_type) {
+                                  const std::type_info& expected_type,
+                                  const std::string& encapsulates) {
         // Get all option definitions, we will use them to extract
         // the definition for a particular option code.
         // We don't have to initialize option definitions here because they
@@ -141,6 +152,9 @@ private:
         ASSERT_NO_THROW(def->validate())
             << "Option definition for the option code " << code
             << " is invalid";
+        // Check that the valid encapsulated option space name
+        // has been specified.
+        EXPECT_EQ(encapsulates, def->getEncapsulatedSpace());
         OptionPtr option;
         // Create the option.
         ASSERT_NO_THROW(option = def->optionFactory(u, code, begin, end))
@@ -259,7 +273,7 @@ TEST_F(LibDhcpTest, packOptions6) {
 
     OutputBuffer assembled(512);
 
-    EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
+    EXPECT_NO_THROW(LibDHCP::packOptions(assembled, opts));
     EXPECT_EQ(sizeof(v6packed), assembled.getLength());
     EXPECT_EQ(0, memcmp(assembled.getData(), v6packed, sizeof(v6packed)));
 }
@@ -648,7 +662,8 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
                                     typeid(Option4AddrLst));
 
     LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS, begin, end,
-                                    typeid(Option));
+                                    typeid(Option),
+                                    "vendor-encapsulated-options-space");
 
     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
                                     typeid(Option4AddrLst));
@@ -717,7 +732,7 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
                                     typeid(OptionCustom));
 
     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS, begin, end,
-                                    typeid(Option));
+                                    typeid(Option), "dhcp-agent-options-space");
 
     LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
                                     typeid(Option));
@@ -816,7 +831,8 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
                                     typeid(OptionCustom));
 
     LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, begin, end,
-                                    typeid(OptionCustom));
+                                    typeid(OptionInt<uint32_t>),
+                                    "vendor-opts-space");
 
     LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, begin, end,
                                     typeid(Option));
diff --git a/src/lib/dhcp/tests/option4_addrlst_unittest.cc b/src/lib/dhcp/tests/option4_addrlst_unittest.cc
index a8e60f6..0c1d9e6 100644
--- a/src/lib/dhcp/tests/option4_addrlst_unittest.cc
+++ b/src/lib/dhcp/tests/option4_addrlst_unittest.cc
@@ -155,7 +155,7 @@ TEST_F(Option4AddrLstTest, assembly1) {
 
     OutputBuffer buf(100);
     EXPECT_NO_THROW(
-        opt->pack4(buf);
+        opt->pack(buf);
     );
 
     ASSERT_EQ(6, opt->len());
@@ -198,7 +198,7 @@ TEST_F(Option4AddrLstTest, assembly4) {
 
     OutputBuffer buf(100);
     EXPECT_NO_THROW(
-        opt->pack4(buf);
+        opt->pack(buf);
     );
 
     ASSERT_EQ(18, opt->len()); // 2(header) + 4xsizeof(IPv4addr)
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
index 310c7bf..174bafb 100644
--- a/src/lib/dhcp/tests/option_definition_unittest.cc
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -53,38 +53,62 @@ public:
 TEST_F(OptionDefinitionTest, constructor) {
     // Specify the option data type as string. This should get converted
     // to enum value returned by getType().
-    OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
+    OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "string");
     EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
 
     EXPECT_EQ(1, opt_def1.getCode());
     EXPECT_EQ(OPT_STRING_TYPE,  opt_def1.getType());
     EXPECT_FALSE(opt_def1.getArrayType());
+    EXPECT_TRUE(opt_def1.getEncapsulatedSpace().empty());
     EXPECT_NO_THROW(opt_def1.validate());
 
     // Specify the option data type as an enum value.
-    OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
+    OptionDefinition opt_def2("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT,
                               OPT_EMPTY_TYPE);
     EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
     EXPECT_EQ(14, opt_def2.getCode());
     EXPECT_EQ(OPT_EMPTY_TYPE, opt_def2.getType());
     EXPECT_FALSE(opt_def2.getArrayType());
-    EXPECT_NO_THROW(opt_def1.validate());
+    EXPECT_TRUE(opt_def2.getEncapsulatedSpace().empty());
+    EXPECT_NO_THROW(opt_def2.validate());
+
+    // Specify encapsulated option space name and option data type
+    // as enum value.
+    OptionDefinition opt_def3("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
+                              OPT_UINT32_TYPE, "isc");
+    EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def3.getName());
+    EXPECT_EQ(D6O_VENDOR_OPTS, opt_def3.getCode());
+    EXPECT_EQ(OPT_UINT32_TYPE, opt_def3.getType());
+    EXPECT_FALSE(opt_def3.getArrayType());
+    EXPECT_EQ("isc", opt_def3.getEncapsulatedSpace());
+    EXPECT_NO_THROW(opt_def3.validate());
+
+    // Specify encapsulated option space name and option data type
+    // as string value.
+    OptionDefinition opt_def4("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
+                              "uint32", "isc");
+    EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def4.getName());
+    EXPECT_EQ(D6O_VENDOR_OPTS, opt_def4.getCode());
+    EXPECT_EQ(OPT_UINT32_TYPE, opt_def4.getType());
+    EXPECT_FALSE(opt_def4.getArrayType());
+    EXPECT_EQ("isc", opt_def4.getEncapsulatedSpace());
+    EXPECT_NO_THROW(opt_def4.validate());
 
     // Check if it is possible to set that option is an array.
-    OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
+    OptionDefinition opt_def5("OPTION_NIS_SERVERS", 27,
                               OPT_IPV6_ADDRESS_TYPE,
                               true);
-    EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
-    EXPECT_EQ(27, opt_def3.getCode());
-    EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def3.getType());
-    EXPECT_TRUE(opt_def3.getArrayType());
-    EXPECT_NO_THROW(opt_def3.validate());
+    EXPECT_EQ("OPTION_NIS_SERVERS", opt_def5.getName());
+    EXPECT_EQ(27, opt_def5.getCode());
+    EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def5.getType());
+    EXPECT_TRUE(opt_def5.getArrayType());
+    EXPECT_NO_THROW(opt_def5.validate());
 
     // The created object is invalid if invalid data type is specified but
     // constructor shouldn't throw exception. The object is validated after
     // it has been created.
     EXPECT_NO_THROW(
-        OptionDefinition opt_def4("OPTION_SERVERID",
+        OptionDefinition opt_def6("OPTION_SERVERID",
                                   OPT_UNKNOWN_TYPE + 10,
                                   OPT_STRING_TYPE);
     );
@@ -213,6 +237,11 @@ TEST_F(OptionDefinitionTest, validate) {
                                "record");
     opt_def16.addRecordField("uint8");
     opt_def16.addRecordField("string");
+
+    // Check invalid encapsulated option space name.
+    OptionDefinition opt_def17("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
+                               "uint32", "invalid%space%name");
+    EXPECT_THROW(opt_def17.validate(), MalformedOptionDefinition);
 }
 
 
diff --git a/src/lib/dhcp/tests/option_int_array_unittest.cc b/src/lib/dhcp/tests/option_int_array_unittest.cc
index 1aeb584..cd868d8 100644
--- a/src/lib/dhcp/tests/option_int_array_unittest.cc
+++ b/src/lib/dhcp/tests/option_int_array_unittest.cc
@@ -294,6 +294,52 @@ public:
         EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
     }
 
+    /// @brief Test ability to set all values.
+    ///
+    /// @tparam T numeric type to perform the test for.
+    template<typename T>
+    void setValuesTest() {
+        const uint16_t opt_code = 100;
+        // Create option with empty vector of values.
+        boost::shared_ptr<OptionIntArray<T> >
+            opt(new OptionIntArray<T>(Option::V6, opt_code));
+        // Initialize vector with some data and pass to the option.
+        std::vector<T> values;
+        for (int i = 0; i < 10; ++i) {
+            values.push_back(numeric_limits<uint8_t>::max() - i);
+        }
+        opt->setValues(values);
+
+        // Check if universe, option type and data was set correctly.
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        std::vector<T> returned_values = opt->getValues();
+        EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    }
+
+    /// @brief Test ability to add values one by one.
+    ///
+    /// @tparam T numeric type to perform the test for.
+    template<typename T>
+    void addValuesTest() {
+        const uint16_t opt_code = 100;
+        // Create option with empty vector of values.
+        boost::shared_ptr<OptionIntArray<T> >
+            opt(new OptionIntArray<T>(Option::V6, opt_code));
+        // Initialize vector with some data and add the same data
+        // to the option.
+        std::vector<T> values;
+        for (int i = 0; i < 10; ++i) {
+            values.push_back(numeric_limits<T>::max() - i);
+            opt->addValue(numeric_limits<T>::max() - i);
+        }
+
+        // Check if universe, option type and data was set correctly.
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        std::vector<T> returned_values = opt->getValues();
+        EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    }
 
     OptionBuffer buf_;     ///< Option buffer
     OutputBuffer out_buf_; ///< Output buffer
@@ -371,118 +417,51 @@ TEST_F(OptionIntArrayTest, bufferToInt32V6) {
 }
 
 TEST_F(OptionIntArrayTest, setValuesUint8) {
-    const uint16_t opt_code = 100;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<uint8_t> >
-        opt(new OptionIntArray<uint8_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<uint8_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<uint8_t>::max() - i);
-    }
-    opt->setValues(values);
-
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<uint8_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    setValuesTest<uint8_t>();
 }
 
 TEST_F(OptionIntArrayTest, setValuesInt8) {
-    const uint16_t opt_code = 100;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<int8_t> >
-        opt(new OptionIntArray<int8_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<int8_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<int8_t>::min() + i);
-    }
-    opt->setValues(values);
-
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<int8_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    setValuesTest<int8_t>();
 }
 
 TEST_F(OptionIntArrayTest, setValuesUint16) {
-    const uint16_t opt_code = 101;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<uint16_t> >
-        opt(new OptionIntArray<uint16_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<uint16_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<uint16_t>::max() - i);
-    }
-    opt->setValues(values);
-
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<uint16_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    setValuesTest<uint16_t>();
 }
 
 TEST_F(OptionIntArrayTest, setValuesInt16) {
-    const uint16_t opt_code = 101;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<int16_t> >
-        opt(new OptionIntArray<int16_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<int16_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<int16_t>::min() + i);
-    }
-    opt->setValues(values);
-
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<int16_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    setValuesTest<int16_t>();
 }
 
 TEST_F(OptionIntArrayTest, setValuesUint32) {
-    const uint32_t opt_code = 101;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<uint32_t> >
-        opt(new OptionIntArray<uint32_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<uint32_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<uint32_t>::max() - i);
-    }
-    opt->setValues(values);
-
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<uint32_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+    setValuesTest<uint16_t>();
 }
 
 TEST_F(OptionIntArrayTest, setValuesInt32) {
-    const uint32_t opt_code = 101;
-    // Create option with empty vector of values.
-    boost::shared_ptr<OptionIntArray<int32_t> >
-        opt(new OptionIntArray<int32_t>(Option::V6, opt_code));
-    // Initialize vector with some data and pass to the option.
-    std::vector<int32_t> values;
-    for (int i = 0; i < 10; ++i) {
-        values.push_back(numeric_limits<int32_t>::min() + i);
-    }
-    opt->setValues(values);
+    setValuesTest<int16_t>();
+}
 
-    // Check if universe, option type and data was set correctly.
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(opt_code, opt->getType());
-    std::vector<int32_t> returned_values = opt->getValues();
-    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+TEST_F(OptionIntArrayTest, addValuesUint8) {
+    addValuesTest<uint8_t>();
 }
 
+TEST_F(OptionIntArrayTest, addValuesInt8) {
+    addValuesTest<int8_t>();
+}
+
+TEST_F(OptionIntArrayTest, addValuesUint16) {
+    addValuesTest<uint16_t>();
+}
+
+TEST_F(OptionIntArrayTest, addValuesInt16) {
+    addValuesTest<int16_t>();
+}
+
+TEST_F(OptionIntArrayTest, addValuesUint32) {
+    addValuesTest<uint16_t>();
+}
+
+TEST_F(OptionIntArrayTest, addValuesInt32) {
+    addValuesTest<int16_t>();
+}
 
 } // anonymous namespace
diff --git a/src/lib/dhcp/tests/option_space_unittest.cc b/src/lib/dhcp/tests/option_space_unittest.cc
new file mode 100644
index 0000000..d3a6f53
--- /dev/null
+++ b/src/lib/dhcp/tests/option_space_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright (C) 2012, 2013 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 <dhcp/option_space.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dhcp;
+using namespace isc;
+
+namespace {
+
+// The purpose of this test is to verify that the constructor
+// creates an object with members initialized to correct values.
+TEST(OptionSpaceTest, constructor) {
+    // Create some option space.
+    OptionSpace space("isc", true);
+    EXPECT_EQ("isc", space.getName());
+    EXPECT_TRUE(space.isVendorSpace());
+
+    // Create another object with different values
+    // to check that the values will change.
+    OptionSpace space2("abc", false);
+    EXPECT_EQ("abc", space2.getName());
+    EXPECT_FALSE(space2.isVendorSpace());
+
+    // Verify that constructor throws exception if invalid
+    // option space name is provided.
+    EXPECT_THROW(OptionSpace("invalid%space.name"), InvalidOptionSpace);
+}
+
+// The purpose of this test is to verify that the vendor-space flag
+// can be overriden.
+TEST(OptionSpaceTest, setVendorSpace) {
+    OptionSpace space("isc", true);
+    EXPECT_EQ("isc", space.getName());
+    EXPECT_TRUE(space.isVendorSpace());
+
+    // Override the vendor space flag.
+    space.clearVendorSpace();
+    EXPECT_FALSE(space.isVendorSpace());
+}
+
+// The purpose of this test is to verify that the static function
+// to validate the option space name works correctly.
+TEST(OptionSpaceTest, validateName) {
+    // Positive test scenarios: letters, digits, dashes, underscores
+    // lower/upper case allowed.
+    EXPECT_TRUE(OptionSpace::validateName("abc"));
+    EXPECT_TRUE(OptionSpace::validateName("dash-allowed"));
+    EXPECT_TRUE(OptionSpace::validateName("two-dashes-allowed"));
+    EXPECT_TRUE(OptionSpace::validateName("underscore_allowed"));
+    EXPECT_TRUE(OptionSpace::validateName("underscore_three_times_allowed"));
+    EXPECT_TRUE(OptionSpace::validateName("digits0912"));
+    EXPECT_TRUE(OptionSpace::validateName("1234"));
+    EXPECT_TRUE(OptionSpace::validateName("UPPER_CASE_allowed"));
+
+    // Negative test scenarions: empty strings, dots, spaces are not
+    // allowed
+    EXPECT_FALSE(OptionSpace::validateName(""));
+    EXPECT_FALSE(OptionSpace::validateName(" "));
+    EXPECT_FALSE(OptionSpace::validateName(" isc "));
+    EXPECT_FALSE(OptionSpace::validateName("isc "));
+    EXPECT_FALSE(OptionSpace::validateName(" isc"));
+    EXPECT_FALSE(OptionSpace::validateName("isc with-space"));
+
+    // Hyphens and underscores are not allowed at the beginning
+    // and at the end of the option space name.
+    EXPECT_FALSE(OptionSpace::validateName("-isc"));
+    EXPECT_FALSE(OptionSpace::validateName("isc-"));
+    EXPECT_FALSE(OptionSpace::validateName("_isc"));
+    EXPECT_FALSE(OptionSpace::validateName("isc_"));
+
+    // Test other special characters
+    const char specials[] = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+                              '+', '=', '[', ']', '{', '}', ';', ':', '"', '\'',
+                              '\\', '|', '<','>', ',', '.', '?', '~', '`' };
+    for (int i = 0; i < sizeof(specials); ++i) {
+        std::ostringstream stream;
+        // Concatenate valid option space name: "abc" with an invalid character.
+        // That way we get option space names like: "abc!", "abc$" etc. It is
+        // expected that the validating function fails form them.
+        stream << "abc" << specials[i];
+        EXPECT_FALSE(OptionSpace::validateName(stream.str()))
+            << "Test failed for special character '" << specials[i] << "'.";
+    }
+}
+
+// The purpose of this test is to verify that the constructors of the
+// OptionSpace6 class set the class members to correct values.
+TEST(OptionSpace6Test, constructor) {
+    // Create some option space and do not specify enterprise number.
+    // In such case the vendor space flag is expected to be
+    // set to false.
+    OptionSpace6 space1("abcd");
+    EXPECT_EQ("abcd", space1.getName());
+    EXPECT_FALSE(space1.isVendorSpace());
+
+    // Create an option space and specify an enterprise number. In this
+    // case the vendor space flag is expected to be set to true and the
+    // enterprise number should be set to a desired value.
+    OptionSpace6 space2("abcd", 2145);
+    EXPECT_EQ("abcd", space2.getName());
+    EXPECT_TRUE(space2.isVendorSpace());
+    EXPECT_EQ(2145, space2.getEnterpriseNumber());
+
+    // Verify that constructors throw an exception when invalid option
+    // space name has been specified.
+    EXPECT_THROW(OptionSpace6("isc dhcp"), InvalidOptionSpace);
+    EXPECT_THROW(OptionSpace6("isc%dhcp", 2145), InvalidOptionSpace);
+}
+
+// The purpose of this test is to verify an option space can be marked
+// vendor option space and enterprise number can be set.
+TEST(OptionSpace6Test, setVendorSpace) {
+    OptionSpace6 space("isc");
+    EXPECT_EQ("isc", space.getName());
+    EXPECT_FALSE(space.isVendorSpace());
+
+    // Mark it vendor option space and set enterprise id.
+    space.setVendorSpace(1234);
+    EXPECT_TRUE(space.isVendorSpace());
+    EXPECT_EQ(1234, space.getEnterpriseNumber());
+
+    // Override the enterprise number to make sure and make sure that
+    // the new number is returned by the object.
+    space.setVendorSpace(2345);
+    EXPECT_TRUE(space.isVendorSpace());
+    EXPECT_EQ(2345, space.getEnterpriseNumber());
+
+    // Clear the vendor option space flag.
+    space.clearVendorSpace();
+    EXPECT_FALSE(space.isVendorSpace());
+}
+
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
index afa64d5..1fc49f1 100644
--- a/src/lib/dhcp/tests/option_unittest.cc
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -116,7 +116,7 @@ TEST_F(OptionTest, v4_data1) {
     // now store that option into a buffer
     OutputBuffer buf(100);
     EXPECT_NO_THROW(
-        opt->pack4(buf);
+        opt->pack(buf);
     );
 
     // check content of that buffer
@@ -173,7 +173,7 @@ TEST_F(OptionTest, v4_data2) {
     // now store that option into a buffer
     OutputBuffer buf(100);
     EXPECT_NO_THROW(
-        opt->pack4(buf);
+        opt->pack(buf);
     );
 
     // check content of that buffer
@@ -471,7 +471,7 @@ TEST_F(OptionTest, setUintX) {
     // verify setUint8
     opt1->setUint8(255);
     EXPECT_EQ(255, opt1->getUint8());
-    opt1->pack4(outBuf_);
+    opt1->pack(outBuf_);
     EXPECT_EQ(3, opt1->len());
     EXPECT_EQ(3, outBuf_.getLength());
     uint8_t exp1[] = {125, 1, 255};
@@ -480,7 +480,7 @@ TEST_F(OptionTest, setUintX) {
     // verify getUint16
     outBuf_.clear();
     opt2->setUint16(12345);
-    opt2->pack4(outBuf_);
+    opt2->pack(outBuf_);
     EXPECT_EQ(12345, opt2->getUint16());
     EXPECT_EQ(4, opt2->len());
     EXPECT_EQ(4, outBuf_.getLength());
@@ -490,7 +490,7 @@ TEST_F(OptionTest, setUintX) {
     // verify getUint32
     outBuf_.clear();
     opt4->setUint32(0x12345678);
-    opt4->pack4(outBuf_);
+    opt4->pack(outBuf_);
     EXPECT_EQ(0x12345678, opt4->getUint32());
     EXPECT_EQ(6, opt4->len());
     EXPECT_EQ(6, outBuf_.getLength());
@@ -505,7 +505,7 @@ TEST_F(OptionTest, setData) {
                               buf_.begin(), buf_.begin() + 10));
     buf_.resize(20, 1);
     opt1->setData(buf_.begin(), buf_.end());
-    opt1->pack4(outBuf_);
+    opt1->pack(outBuf_);
     ASSERT_EQ(outBuf_.getLength() - opt1->getHeaderLen(), buf_.size());
     const uint8_t* test_data = static_cast<const uint8_t*>(outBuf_.getData());
     EXPECT_TRUE(0 == memcmp(&buf_[0], test_data + opt1->getHeaderLen(),
@@ -518,7 +518,7 @@ TEST_F(OptionTest, setData) {
     outBuf_.clear();
     buf_.resize(5, 1);
     opt2->setData(buf_.begin(), buf_.end());
-    opt2->pack4(outBuf_);
+    opt2->pack(outBuf_);
     ASSERT_EQ(outBuf_.getLength() - opt1->getHeaderLen(), buf_.size());
     test_data = static_cast<const uint8_t*>(outBuf_.getData());
     EXPECT_TRUE(0 == memcmp(&buf_[0], test_data + opt1->getHeaderLen(),
diff --git a/src/lib/dhcpsrv/.gitignore b/src/lib/dhcpsrv/.gitignore
new file mode 100644
index 0000000..0b02c01
--- /dev/null
+++ b/src/lib/dhcpsrv/.gitignore
@@ -0,0 +1,2 @@
+/dhcpsrv_messages.cc
+/dhcpsrv_messages.h
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
index cc5daec..e721267 100644
--- a/src/lib/dhcpsrv/Makefile.am
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -1,6 +1,6 @@
 SUBDIRS = . tests
 
-AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib -DDHCP_DATA_DIR="\"$(localstatedir)\""
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 if HAVE_MYSQL
 AM_CPPFLAGS += $(MYSQL_CPPFLAGS)
@@ -33,6 +33,7 @@ lib_LTLIBRARIES = libb10-dhcpsrv.la
 libb10_dhcpsrv_la_SOURCES  =
 libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
 libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
+libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
 libb10_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
 libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
 libb10_dhcpsrv_la_SOURCES += dhcp_config_parser.h
@@ -42,7 +43,6 @@ libb10_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
 if HAVE_MYSQL
 libb10_dhcpsrv_la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
 endif
-libb10_dhcpsrv_la_SOURCES += option_space.cc option_space.h
 libb10_dhcpsrv_la_SOURCES += option_space_container.h
 libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
 libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
index 7a64dac..bcb7851 100644
--- a/src/lib/dhcpsrv/alloc_engine.cc
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 
 #include <cstring>
@@ -169,95 +170,104 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
                               const IOAddress& hint,
                               bool fake_allocation /* = false */ ) {
 
-    // That check is not necessary. We create allocator in AllocEngine
-    // constructor
-    if (!allocator_) {
-        isc_throw(InvalidOperation, "No allocator selected");
-    }
-
-    // check if there's existing lease for that subnet/duid/iaid combination.
-    Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
-    if (existing) {
-        // we have a lease already. This is a returning client, probably after
-        // his reboot.
-        return (existing);
-    }
+    try {
+        // That check is not necessary. We create allocator in AllocEngine
+        // constructor
+        if (!allocator_) {
+            isc_throw(InvalidOperation, "No allocator selected");
+        }
 
-    // check if the hint is in pool and is available
-    if (subnet->inPool(hint)) {
-        existing = LeaseMgrFactory::instance().getLease6(hint);
-        if (!existing) {
-            /// @todo: check if the hint is reserved once we have host support
-            /// implemented
+        // check if there's existing lease for that subnet/duid/iaid combination.
+        Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
+        if (existing) {
+            // we have a lease already. This is a returning client, probably after
+            // his reboot.
+            return (existing);
+        }
 
-            // the hint is valid and not currently used, let's create a lease for it
-            Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, fake_allocation);
+        // check if the hint is in pool and is available
+        if (subnet->inPool(hint)) {
+            existing = LeaseMgrFactory::instance().getLease6(hint);
+            if (!existing) {
+                /// @todo: check if the hint is reserved once we have host support
+                /// implemented
+
+                // the hint is valid and not currently used, let's create a lease for it
+                Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, fake_allocation);
+
+                // It can happen that the lease allocation failed (we could have lost
+                // the race condition. That means that the hint is lo longer usable and
+                // we need to continue the regular allocation path.
+                if (lease) {
+                    return (lease);
+                }
+            } else {
+                if (existing->expired()) {
+                    return (reuseExpiredLease(existing, subnet, duid, iaid,
+                                              fake_allocation));
+                }
 
-            // It can happen that the lease allocation failed (we could have lost
-            // the race condition. That means that the hint is lo longer usable and
-            // we need to continue the regular allocation path.
-            if (lease) {
-                return (lease);
             }
-        } else {
-            if (existing->expired()) {
-                return (reuseExpiredLease(existing, subnet, duid, iaid,
-                                          fake_allocation));
-            }
-
         }
-    }
 
-    // Hint is in the pool but is not available. Search the pool until first of
-    // the following occurs:
-    // - we find a free address
-    // - we find an address for which the lease has expired
-    // - we exhaust number of tries
-    //
-    // @todo: Current code does not handle pool exhaustion well. It will be
-    // improved. Current problems:
-    // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
-    // 10 addresses), we will iterate over it 100 times before giving up
-    // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
-    // 3. the whole concept of infinite attempts is just asking for infinite loop
-    // We may consider some form or reference counting (this pool has X addresses
-    // left), but this has one major problem. We exactly control allocation
-    // moment, but we currently do not control expiration time at all
-
-    unsigned int i = attempts_;
-    do {
-        IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
-
-        /// @todo: check if the address is reserved once we have host support
-        /// implemented
-
-        Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
-        if (!existing) {
-            // there's no existing lease for selected candidate, so it is
-            // free. Let's allocate it.
-            Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
-                                          fake_allocation);
-            if (lease) {
-                return (lease);
-            }
+        // Hint is in the pool but is not available. Search the pool until first of
+        // the following occurs:
+        // - we find a free address
+        // - we find an address for which the lease has expired
+        // - we exhaust number of tries
+        //
+        // @todo: Current code does not handle pool exhaustion well. It will be
+        // improved. Current problems:
+        // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
+        // 10 addresses), we will iterate over it 100 times before giving up
+        // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
+        // 3. the whole concept of infinite attempts is just asking for infinite loop
+        // We may consider some form or reference counting (this pool has X addresses
+        // left), but this has one major problem. We exactly control allocation
+        // moment, but we currently do not control expiration time at all
+
+        unsigned int i = attempts_;
+        do {
+            IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
+
+            /// @todo: check if the address is reserved once we have host support
+            /// implemented
 
-            // Although the address was free just microseconds ago, it may have
-            // been taken just now. If the lease insertion fails, we continue
-            // allocation attempts.
-        } else {
-            if (existing->expired()) {
-                return (reuseExpiredLease(existing, subnet, duid, iaid,
-                                          fake_allocation));
+            Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
+            if (!existing) {
+                // there's no existing lease for selected candidate, so it is
+                // free. Let's allocate it.
+                Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
+                                              fake_allocation);
+                if (lease) {
+                    return (lease);
+                }
+
+                // Although the address was free just microseconds ago, it may have
+                // been taken just now. If the lease insertion fails, we continue
+                // allocation attempts.
+            } else {
+                if (existing->expired()) {
+                    return (reuseExpiredLease(existing, subnet, duid, iaid,
+                                              fake_allocation));
+                }
             }
-        }
 
-        // continue trying allocation until we run out of attempts
-        // (or attempts are set to 0, which means infinite)
-        --i;
-    } while ( i || !attempts_);
+            // Continue trying allocation until we run out of attempts
+            // (or attempts are set to 0, which means infinite)
+            --i;
+        } while ((i > 0) || !attempts_);
 
-    isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
-              << " tries");
+        // Unable to allocate an address, return an empty lease.
+        LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_FAIL).arg(attempts_);
+
+    } catch (const isc::Exception& e) {
+
+        // Some other error, return an empty lease.
+        LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_ERROR).arg(e.what());
+    }
+
+    return (Lease6Ptr());
 }
 
 Lease4Ptr
@@ -267,115 +277,123 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
                               const IOAddress& hint,
                               bool fake_allocation /* = false */ ) {
 
-    // Allocator is always created in AllocEngine constructor and there is
-    // currently no other way to set it, so that check is not really necessary.
-    if (!allocator_) {
-        isc_throw(InvalidOperation, "No allocator selected");
-    }
-
-    // Check if there's existing lease for that subnet/clientid/hwaddr combination.
-    Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(hwaddr->hwaddr_, subnet->getID());
-    if (existing) {
-        // We have a lease already. This is a returning client, probably after
-        // its reboot.
-        existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
-        if (existing) {
-            return (existing);
+    try {
+        // Allocator is always created in AllocEngine constructor and there is
+        // currently no other way to set it, so that check is not really necessary.
+        if (!allocator_) {
+            isc_throw(InvalidOperation, "No allocator selected");
         }
 
-        // If renewal failed (e.g. the lease no longer matches current configuration)
-        // let's continue the allocation process
-    }
-
-    if (clientid) {
-        existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
+        // Check if there's existing lease for that subnet/clientid/hwaddr combination.
+        Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(hwaddr->hwaddr_, subnet->getID());
         if (existing) {
-            // we have a lease already. This is a returning client, probably after
+            // We have a lease already. This is a returning client, probably after
             // its reboot.
             existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
-            // @todo: produce a warning. We haven't found him using MAC address, but
-            // we found him using client-id
             if (existing) {
                 return (existing);
             }
+
+            // If renewal failed (e.g. the lease no longer matches current configuration)
+            // let's continue the allocation process
         }
-    }
 
-    // check if the hint is in pool and is available
-    if (subnet->inPool(hint)) {
-        existing = LeaseMgrFactory::instance().getLease4(hint);
-        if (!existing) {
-            /// @todo: Check if the hint is reserved once we have host support
-            /// implemented
+        if (clientid) {
+            existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
+            if (existing) {
+                // we have a lease already. This is a returning client, probably after
+                // its reboot.
+                existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
+                // @todo: produce a warning. We haven't found him using MAC address, but
+                // we found him using client-id
+                if (existing) {
+                    return (existing);
+                }
+            }
+        }
 
-            // The hint is valid and not currently used, let's create a lease for it
-            Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, hint, fake_allocation);
+        // check if the hint is in pool and is available
+        if (subnet->inPool(hint)) {
+            existing = LeaseMgrFactory::instance().getLease4(hint);
+            if (!existing) {
+                /// @todo: Check if the hint is reserved once we have host support
+                /// implemented
+
+                // The hint is valid and not currently used, let's create a lease for it
+                Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, hint, fake_allocation);
+
+                // It can happen that the lease allocation failed (we could have lost
+                // the race condition. That means that the hint is lo longer usable and
+                // we need to continue the regular allocation path.
+                if (lease) {
+                    return (lease);
+                }
+            } else {
+                if (existing->expired()) {
+                    return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
+                                              fake_allocation));
+                }
 
-            // It can happen that the lease allocation failed (we could have lost
-            // the race condition. That means that the hint is lo longer usable and
-            // we need to continue the regular allocation path.
-            if (lease) {
-                return (lease);
             }
-        } else {
-            if (existing->expired()) {
-                return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
-                                          fake_allocation));
-            }
-
         }
-    }
 
-    // Hint is in the pool but is not available. Search the pool until first of
-    // the following occurs:
-    // - we find a free address
-    // - we find an address for which the lease has expired
-    // - we exhaust the number of tries
-    //
-    // @todo: Current code does not handle pool exhaustion well. It will be
-    // improved. Current problems:
-    // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
-    // 10 addresses), we will iterate over it 100 times before giving up
-    // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
-    // 3. the whole concept of infinite attempts is just asking for infinite loop
-    // We may consider some form or reference counting (this pool has X addresses
-    // left), but this has one major problem. We exactly control allocation
-    // moment, but we currently do not control expiration time at all
-
-    unsigned int i = attempts_;
-    do {
-        IOAddress candidate = allocator_->pickAddress(subnet, clientid, hint);
-
-        /// @todo: check if the address is reserved once we have host support
-        /// implemented
-
-        Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(candidate);
-        if (!existing) {
-            // there's no existing lease for selected candidate, so it is
-            // free. Let's allocate it.
-            Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, candidate,
-                                          fake_allocation);
-            if (lease) {
-                return (lease);
-            }
+        // Hint is in the pool but is not available. Search the pool until first of
+        // the following occurs:
+        // - we find a free address
+        // - we find an address for which the lease has expired
+        // - we exhaust the number of tries
+        //
+        // @todo: Current code does not handle pool exhaustion well. It will be
+        // improved. Current problems:
+        // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
+        // 10 addresses), we will iterate over it 100 times before giving up
+        // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
+        // 3. the whole concept of infinite attempts is just asking for infinite loop
+        // We may consider some form or reference counting (this pool has X addresses
+        // left), but this has one major problem. We exactly control allocation
+        // moment, but we currently do not control expiration time at all
+
+        unsigned int i = attempts_;
+        do {
+            IOAddress candidate = allocator_->pickAddress(subnet, clientid, hint);
+
+            /// @todo: check if the address is reserved once we have host support
+            /// implemented
 
-            // Although the address was free just microseconds ago, it may have
-            // been taken just now. If the lease insertion fails, we continue
-            // allocation attempts.
-        } else {
-            if (existing->expired()) {
-                return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
-                                          fake_allocation));
+            Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(candidate);
+            if (!existing) {
+                // there's no existing lease for selected candidate, so it is
+                // free. Let's allocate it.
+                Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, candidate,
+                                              fake_allocation);
+                if (lease) {
+                    return (lease);
+                }
+
+                // Although the address was free just microseconds ago, it may have
+                // been taken just now. If the lease insertion fails, we continue
+                // allocation attempts.
+            } else {
+                if (existing->expired()) {
+                    return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
+                                              fake_allocation));
+                }
             }
-        }
 
-        // Continue trying allocation until we run out of attempts
-        // (or attempts are set to 0, which means infinite)
-        --i;
-    } while ( i || !attempts_);
+            // Continue trying allocation until we run out of attempts
+            // (or attempts are set to 0, which means infinite)
+            --i;
+        } while ((i > 0) || !attempts_);
 
-    isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
-              << " tries");
+        // Unable to allocate an address, return an empty lease.
+        LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_FAIL).arg(attempts_);
+
+    } catch (const isc::Exception& e) {
+
+        // Some other error, return an empty lease.
+        LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_ERROR).arg(e.what());
+    }
+    return (Lease4Ptr());
 }
 
 Lease4Ptr AllocEngine::renewLease4(const SubnetPtr& subnet,
diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h
index c6cbc35..7e3d136 100644
--- a/src/lib/dhcpsrv/alloc_engine.h
+++ b/src/lib/dhcpsrv/alloc_engine.h
@@ -214,8 +214,8 @@ protected:
     /// @param clientid client identifier
     /// @param hwaddr client's hardware address
     /// @param lease lease to be renewed
-    /// @param renewed lease (typically the same passed as lease parameter)
-    ///        or NULL if the lease cannot be renewed
+    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    ///        an address for DISCOVER that is not really allocated (true)
     Lease4Ptr
     renewLease4(const SubnetPtr& subnet,
                 const ClientIdPtr& clientid,
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index c6a190f..b5e83e3 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -248,7 +248,16 @@ void CfgMgr::deleteSubnets6() {
     subnets6_.clear();
 }
 
-CfgMgr::CfgMgr() {
+std::string CfgMgr::getDataDir() {
+    return (datadir_);
+}
+
+
+CfgMgr::CfgMgr()
+    :datadir_(DHCP_DATA_DIR) {
+    // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
+    // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
+    // See AM_CPPFLAGS definition in Makefile.am
 }
 
 CfgMgr::~CfgMgr() {
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index bc4ffde..f4eecb5 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -18,7 +18,7 @@
 #include <asiolink/io_address.h>
 #include <dhcp/option.h>
 #include <dhcp/option_definition.h>
-#include <dhcpsrv/option_space.h>
+#include <dhcp/option_space.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/subnet.h>
@@ -230,6 +230,14 @@ public:
     /// completely new?
     void deleteSubnets4();
 
+
+    /// @brief returns path do the data directory
+    ///
+    /// This method returns a path to writeable directory that DHCP servers
+    /// can store data in.
+    /// @return data directory
+    std::string getDataDir();
+
 protected:
 
     /// @brief Protected constructor.
@@ -274,6 +282,8 @@ private:
     /// @brief Container for defined DHCPv4 option spaces.
     OptionSpaceCollection spaces4_;
 
+    /// @brief directory where data files (e.g. server-id) are stored
+    std::string datadir_;
 };
 
 } // namespace isc::dhcp
diff --git a/src/lib/dhcpsrv/database_backends.dox b/src/lib/dhcpsrv/database_backends.dox
index a3b3b0c..43594fd 100644
--- a/src/lib/dhcpsrv/database_backends.dox
+++ b/src/lib/dhcpsrv/database_backends.dox
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 /**
   @page dhcpDatabaseBackends DHCP Database Back-Ends
 
diff --git a/src/lib/dhcpsrv/dbaccess_parser.cc b/src/lib/dhcpsrv/dbaccess_parser.cc
new file mode 100644
index 0000000..d29cf54
--- /dev/null
+++ b/src/lib/dhcpsrv/dbaccess_parser.cc
@@ -0,0 +1,116 @@
+// Copyright (C) 2012-2013  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 <dhcpsrv/dbaccess_parser.h>
+#include <dhcpsrv/dhcpsrv_log.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+
+#include <boost/foreach.hpp>
+
+#include <map>
+#include <string>
+#include <utility>
+
+using namespace std;
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+
+// Factory function to build the parser
+DbAccessParser::DbAccessParser(const std::string& param_name) : values_()
+{
+    if (param_name != "lease-database") {
+        LOG_WARN(dhcpsrv_logger, DHCPSRV_UNEXPECTED_NAME).arg(param_name);
+    }
+}
+
+// Parse the configuration and check that the various keywords are consistent.
+void
+DbAccessParser::build(isc::data::ConstElementPtr config_value) {
+
+    // To cope with incremental updates, the strategy is:
+    // 1. Take a copy of the stored keyword/value pairs.
+    // 2. Update the copy with the passed keywords.
+    // 3. Perform validation checks on the updated keyword/value pairs.
+    // 4. If all is OK, update the stored keyword/value pairs.
+
+    // 1. Take a copy of the stored keyword/value pairs.
+    std::map<string, string> values_copy = values_;
+
+    // 2. Update the copy with the passed keywords.
+    BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
+        values_copy[param.first] = param.second->stringValue();
+    }
+
+    // 3. Perform validation checks on the updated set of keyword/values.
+    //
+    // a. Check if the "type" keyword exists and thrown an exception if not.
+    StringPairMap::const_iterator type_ptr = values_copy.find("type");
+    if (type_ptr == values_copy.end()) {
+        isc_throw(TypeKeywordMissing, "lease database access parameters must "
+                  "include the keyword 'type' to determine type of database "
+                  "to be accessed");
+    }
+
+    // b. Check if the 'type; keyword known and throw an exception if not.
+    string dbtype = type_ptr->second;
+    if ((dbtype != "memfile") && (dbtype != "mysql")) {
+        isc_throw(BadValue, "unknown backend database type: " << dbtype);
+    }
+
+    // 4. If all is OK, update the stored keyword/value pairs.  We do this by
+    // swapping contents - values_copy is destroyed immediately after the
+    // operation (when the method exits), so we are not interested in its new
+    // value.
+    values_.swap(values_copy);
+}
+
+// Create the database access string
+std::string
+DbAccessParser::getDbAccessString() const {
+
+    // Construct the database access string from all keywords and values in the
+    // parameter map where the value is not null.
+    string dbaccess;
+    BOOST_FOREACH(StringPair keyval, values_) {
+        if (!keyval.second.empty()) {
+
+            // Separate keyword/value pair from predecessor (if there is one).
+            if (!dbaccess.empty()) {
+                dbaccess += std::string(" ");
+            }
+
+            // Add the keyword/value pair to the access string.
+            dbaccess += (keyval.first + std::string("=") + keyval.second);
+        }
+    }
+
+    return (dbaccess);
+}
+
+// Commit the changes - reopen the database with the new parameters
+void
+DbAccessParser::commit() {
+    // Close current lease manager database.
+    LeaseMgrFactory::destroy();
+
+    // ... and open the new database using the access string.
+    LeaseMgrFactory::create(getDbAccessString());
+}
+
+};  // namespace dhcp
+};  // namespace isc
+
diff --git a/src/lib/dhcpsrv/dbaccess_parser.h b/src/lib/dhcpsrv/dbaccess_parser.h
new file mode 100644
index 0000000..140f11d
--- /dev/null
+++ b/src/lib/dhcpsrv/dbaccess_parser.h
@@ -0,0 +1,133 @@
+// Copyright (C) 2012-2013  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 DBACCESS_PARSER_H
+#define DBACCESS_PARSER_H
+
+#include <cc/data.h>
+#include <dhcpsrv/dhcp_config_parser.h>
+#include <exceptions/exceptions.h>
+
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown when 'type' keyword is missing from string
+///
+/// This condition is checked, but should never occur because 'type' is marked
+/// as mandatory in the .spec file for the server.
+class TypeKeywordMissing : public isc::Exception {
+public:
+    TypeKeywordMissing(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// @brief Parse Lease Database Parameters
+///
+/// This class is the parser for the lease database configuration.  This is a
+/// map under the top-level "lease-database" element, and comprises a map of
+/// strings.
+///
+/// Only the "type" sub-element is mandatory: the remaining sub-elements 
+/// depend on the datbase chosen.
+class DbAccessParser: public DhcpConfigParser {
+public:
+    /// @brief Keyword and associated value
+    typedef std::pair<std::string, std::string> StringPair;
+
+    /// @brief Keyword/value collection of database access parameters
+    typedef std::map<std::string, std::string> StringPairMap;
+
+    /// @brief Constructor
+    ///
+    /// @param param_name Name of the parameter under which the database
+    ///        access details are held.
+    DbAccessParser(const std::string& param_name);
+
+    /// The destructor.
+    virtual ~DbAccessParser()
+    {}
+
+    /// @brief Prepare configuration value.
+    ///
+    /// Parses the set of strings forming the database access specification and
+    /// checks that all are OK.  In particular it checks:
+    ///
+    /// - "type" is "memfile" or "mysql"
+    /// - If "type" is "memfile", checks that no other values are present: if
+    ///   they are, logs a warning that they will be ignored.
+    ///
+    /// Once all has been validated, constructs the database access string
+    /// expected by the lease manager.
+    ///
+    /// @param config_value The configuration value for the "lease-database"
+    ///        identifier.
+    ///
+    /// @throw isc::BadValue The 'type' keyword contains an unknown database
+    ///        type.
+    /// @throw isc::dhcp::MissingTypeKeyword The 'type' keyword is missing from
+    ///        the list of database access keywords.
+    virtual void build(isc::data::ConstElementPtr config_value);
+
+    /// @brief Apply the prepared configuration value to the server.
+    ///
+    /// With the string validated, this closes the currently open database (if
+    /// any), then opens a database corresponding to the stored string.
+    ///
+    /// This method is expected to be called after \c build(), and only once.
+    /// The result is undefined otherwise.
+    virtual void commit();
+
+    /// @brief Factory method to create parser
+    ///
+    /// Creates an instance of this parser.
+    ///
+    /// @param name Name of the parameter used to access the configuration.
+    ///
+    /// @return Pointer to a DbAccessParser.  The caller is responsible for
+    ///         destroying the parser after use.
+    static DhcpConfigParser* factory(const std::string& param_name) {
+        return (new DbAccessParser(param_name));
+    }
+
+protected:
+    /// @brief Get database access parameters
+    ///
+    /// Used in testing to check that the configuration information has been
+    /// parsed correctly.
+    ///
+    /// @return Reference to the internal map of keyword/value pairs
+    ///         representing database access information.  This is valid only
+    ///         for so long as the the parser remains in existence.
+    const StringPairMap& getDbAccessParameters() const {
+        return (values_);
+    }
+
+    /// @brief Construct dbtabase access string
+    ///
+    /// Constructs the database access string from the stored parameters.
+    ///
+    /// @return Database access string
+    std::string getDbAccessString() const;
+
+private:
+    std::map<std::string, std::string> values_; ///< Stored parameter values
+};
+
+};  // namespace dhcp
+};  // namespace isc
+
+
+#endif // DBACCESS_PARSER_H
diff --git a/src/lib/dhcpsrv/dhcp_config_parser.h b/src/lib/dhcpsrv/dhcp_config_parser.h
index d3d05f6..44cf519 100644
--- a/src/lib/dhcpsrv/dhcp_config_parser.h
+++ b/src/lib/dhcpsrv/dhcp_config_parser.h
@@ -46,6 +46,9 @@ typedef boost::shared_ptr<DhcpConfigParser> ParserPtr;
 /// This container is used to store pointer to parsers for a given scope.
 typedef std::vector<ParserPtr> ParserCollection;
 
+/// @brief Combination of parameter name and configuration contents
+typedef std::pair<std::string, isc::data::ConstElementPtr> ConfigPair;
+
 /// @brief Base abstract class for all DHCP parsers
 ///
 /// Each instance of a class derived from this class parses one specific config
diff --git a/src/lib/dhcpsrv/dhcpdb_create.mysql b/src/lib/dhcpsrv/dhcpdb_create.mysql
index 695091d..f0da337 100644
--- a/src/lib/dhcpsrv/dhcpdb_create.mysql
+++ b/src/lib/dhcpsrv/dhcpdb_create.mysql
@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium.
+# Copyright (C) 2012-2013  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
@@ -39,6 +39,14 @@ CREATE TABLE lease4 (
     subnet_id INT UNSIGNED                      # Subnet identification
     ) ENGINE = INNODB;
 
+
+# Create search indexes for lease4 table 
+# index by hwaddr and subnet_id
+CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id);
+
+# index by client_id and subnet_id
+CREATE INDEX lease4_by_client_id_subnet_id ON lease4 (client_id, subnet_id);
+
 # Holds the IPv6 leases.
 # N.B. The use of a VARCHAR for the address is temporary for development:
 # it will eventually be replaced by BINARY(16).
@@ -55,6 +63,10 @@ CREATE TABLE lease6 (
     prefix_len TINYINT UNSIGNED                 # For IA_PD only
     ) ENGINE = INNODB;
 
+# Create search indexes for lease4 table 
+# index by iaid, subnet_id, and duid 
+CREATE INDEX lease6_by_iaid_subnet_id_duid ON lease6 (iaid, subnet_id, duid);
+
 # ... and a definition of lease6 types.  This table is a convenience for
 # users of the database - if they want to view the lease table and use the
 # type names, they can join this table with the lease6 table
diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes
index 8a7610b..21a7c79 100644
--- a/src/lib/dhcpsrv/dhcpsrv_messages.mes
+++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2013  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,6 +14,46 @@
 
 $NAMESPACE isc::dhcp
 
+% DHCPSRV_ADDRESS4_ALLOC_ERROR error during attempt to allocate an IPv4 address: %1
+An error occurred during an attempt to allocate an IPv4 address, the
+reason for the failure being contained in the message.  The server will
+return a message to the client refusing a lease.
+
+% DHCPSRV_ADDRESS4_ALLOC_FAIL failed to allocate an IPv4 address after %1 attempt(s)
+THE DHCP allocation engine gave up trying to allocate an IPv4 address
+after the specified number of attempts.  This probably means that the
+address pool from which the allocation is being attempted is either
+empty, or very nearly empty.  As a result, the client will have been
+refused a lease.
+
+This message may indicate that your address pool is too small for the
+number of clients you are trying to service and should be expanded.
+Alternatively, if the you know that the number of concurrently active
+clients is less than the addresses you have available, you may want to
+consider reducing the lease lifetime.  In this way, addresses allocated
+to clients that are no longer active on the network will become available
+available sooner.
+
+% DHCPSRV_ADDRESS6_ALLOC_ERROR error during attempt to allocate an IPv6 address: %1
+An error occurred during an attempt to allocate an IPv6 address, the
+reason for the failure being contained in the message.  The server will
+return a message to the client refusing a lease.
+
+% DHCPSRV_ADDRESS6_ALLOC_FAIL failed to allocate an IPv6 address after %1 attempt(s)
+The DHCP allocation engine gave up trying to allocate an IPv6 address
+after the specified number of attempts.  This probably means that the
+address pool from which the allocation is being attempted is either
+empty, or very nearly empty.  As a result, the client will have been
+refused a lease.
+
+This message may indicate that your address pool is too small for the
+number of clients you are trying to service and should be expanded.
+Alternatively, if the you know that the number of concurrently active
+clients is less than the addresses you have available, you may want to
+consider reducing the lease lifetime.  In this way, addresses allocated
+to clients that are no longer active on the network will become available
+available sooner.
+
 % DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1
 A debug message reported when the DHCP configuration manager is adding the
 specified IPv4 subnet to its database.
@@ -61,10 +101,18 @@ returned the specified IPv6 subnet when given the address hint specified
 as the address is within the subnet.
 
 % DHCPSRV_CFGMGR_SUBNET6_IFACE selected subnet %1 for packet received over interface %2
-This is a debug message reporting that the DHCP configuration manager has
-returned the specified IPv6 subnet for a packet received over given interface.
-This particular subnet was selected, because it was specified as being directly
-reachable over given interface. (see 'interface' parameter in subnet6 definition).
+This is a debug message reporting that the DHCP configuration manager
+has returned the specified IPv6 subnet for a packet received over
+given interface.  This particular subnet was selected, because it
+was specified as being directly reachable over given interface. (see
+'interface' parameter in subnet6 definition).
+
+% DHCPSRV_CLOSE_DB closing currently open %1 database
+This is a debug message, issued when the DHCP server closes the currently
+open lease database.  It is issued at program shutdown and whenever
+the database access parameters are changed: in the latter case, the
+server closes the currently open database, and opens a database using
+the new parameters.
 
 % DHCPSRV_INVALID_ACCESS invalid database access string: %1
 This is logged when an attempt has been made to parse a database access string
@@ -80,7 +128,7 @@ with the specified address to the memory file backend database.
 A debug message issued when the server is about to add an IPv6 lease
 with the specified address to the memory file backend database.
 
-% DHCPSRV_MEMFILE_COMMIT commiting to memory file database
+% DHCPSRV_MEMFILE_COMMIT committing to memory file database
 The code has issued a commit call.  For the memory file database, this is
 a no-op.
 
@@ -149,6 +197,13 @@ lease from the memory file database for the specified address.
 A debug message issued when the server is attempting to update IPv6
 lease from the memory file database for the specified address.
 
+% DHCPSRV_MEMFILE_WARNING using early version of memfile lease database - leases will be lost after a restart
+This warning message is issued when the 'memfile' lease database is
+opened.  The current version of memfile does not store anything
+to disk, so lease information will be lost in the event of a restart.
+Using this version of memfile in a production environment is NOT
+recommended.
+
 % DHCPSRV_MYSQL_ADD_ADDR4 adding IPv4 lease with address %1
 A debug message issued when the server is about to add an IPv4 lease
 with the specified address to the MySQL backend database.
@@ -157,7 +212,7 @@ with the specified address to the MySQL backend database.
 A debug message issued when the server is about to add an IPv6 lease
 with the specified address to the MySQL backend database.
 
-% DHCPSRV_MYSQL_COMMIT commiting to MySQl database
+% DHCPSRV_MYSQL_COMMIT committing to MySQL database
 The code has issued a commit call.  All outstanding transactions will be
 committed to the database.  Note that depending on the MySQL settings,
 the commital may not include a write to disk.
@@ -232,6 +287,13 @@ a database backend, but where no 'type' keyword has been included in
 the access string.  The access string (less any passwords) is included
 in the message.
 
+% DHCPSRV_UNEXPECTED_NAME database access parameters passed through '%1', expected 'lease-database'
+The parameters for access the lease database were passed to the server through
+the named configuration parameter, but the code was expecting them to be
+passed via the parameter named "lease-database".  If the database opens
+successfully, there is no impact on server operation.  However, as this does
+indicate an error in the source code, please submit a bug report.
+
 % DHCPSRV_UNKNOWN_DB unknown database type: %1
 The database access string specified a database type (given in the
 message) that is unknown to the software.  This is a configuration error.
diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc
index 6608b14..2310dd4 100644
--- a/src/lib/dhcpsrv/lease_mgr.cc
+++ b/src/lib/dhcpsrv/lease_mgr.cc
@@ -113,11 +113,22 @@ Lease4::toText() const {
 
 bool
 Lease4::operator==(const Lease4& other) const {
+    if ( (client_id_ && !other.client_id_) ||
+         (!client_id_ && other.client_id_) ) {
+        // One lease has client-id, but the other doesn't
+        return false;
+    }
+
+    if (client_id_ && other.client_id_ &&
+        *client_id_ != *other.client_id_) {
+        // Different client-ids
+        return false;
+    }
+
     return (
         addr_ == other.addr_ &&
         ext_ == other.ext_ &&
         hwaddr_ == other.hwaddr_ &&
-        *client_id_ == *other.client_id_ &&
         t1_ == other.t1_ &&
         t2_ == other.t2_ &&
         valid_lft_ == other.valid_lft_ &&
diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h
index f781576..e6aaa51 100644
--- a/src/lib/dhcpsrv/lease_mgr.h
+++ b/src/lib/dhcpsrv/lease_mgr.h
@@ -114,9 +114,18 @@ public:
 /// leases.
 struct Lease {
 
+    /// @brief Constructor
+    ///
+    /// @param addr IP address
+    /// @param t1 renewal time
+    /// @param t2 rebinding time
+    /// @param valid_lft Lifetime of the lease
+    /// @param subnet_id Subnet identification
+    /// @param cltt Client last transmission time
     Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2,
           uint32_t valid_lft, SubnetID subnet_id, time_t cltt);
 
+    /// @brief Destructor
     virtual ~Lease() {}
 
     /// @brief IPv4 ot IPv6 address
@@ -226,13 +235,14 @@ struct Lease4 : public Lease {
 
     /// @brief Constructor
     ///
-    /// @param addr IPv4 address as unsigned 32-bit integer in network byte
-    ///        order.
+    /// @param addr IPv4 address.
     /// @param hwaddr Hardware address buffer
     /// @param hwaddr_len Length of hardware address buffer
     /// @param clientid Client identification buffer
     /// @param clientid_len Length of client identification buffer
     /// @param valid_lft Lifetime of the lease
+    /// @param t1 renewal time
+    /// @param t2 rebinding time
     /// @param cltt Client last transmission time
     /// @param subnet_id Subnet identification
     Lease4(const isc::asiolink::IOAddress& addr, const uint8_t* hwaddr, size_t hwaddr_len,
diff --git a/src/lib/dhcpsrv/lease_mgr_factory.cc b/src/lib/dhcpsrv/lease_mgr_factory.cc
index 9fd276d..ede0dba 100644
--- a/src/lib/dhcpsrv/lease_mgr_factory.cc
+++ b/src/lib/dhcpsrv/lease_mgr_factory.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -120,15 +120,13 @@ LeaseMgrFactory::create(const std::string& dbaccess) {
     // Yes, check what it is.
 #ifdef HAVE_MYSQL
     if (parameters[type] == string("mysql")) {
-        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_MYSQL_DB)
-            .arg(redacted);
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_DB).arg(redacted);
         getLeaseMgrPtr().reset(new MySqlLeaseMgr(parameters));
         return;
     }
 #endif
     if (parameters[type] == string("memfile")) {
-        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_MEMFILE_DB)
-            .arg(redacted);
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_DB).arg(redacted);
         getLeaseMgrPtr().reset(new Memfile_LeaseMgr(parameters));
         return;
     }
@@ -141,6 +139,12 @@ LeaseMgrFactory::create(const std::string& dbaccess) {
 
 void
 LeaseMgrFactory::destroy() {
+    // Destroy current lease manager.  This is a no-op if no lease manager
+    // is available.
+    if (getLeaseMgrPtr()) {
+        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CLOSE_DB)
+            .arg(getLeaseMgrPtr()->getType());
+    }
     getLeaseMgrPtr().reset();
 }
 
diff --git a/src/lib/dhcpsrv/libdhcpsrv.dox b/src/lib/dhcpsrv/libdhcpsrv.dox
index bb4a8ec..e3d3429 100644
--- a/src/lib/dhcpsrv/libdhcpsrv.dox
+++ b/src/lib/dhcpsrv/libdhcpsrv.dox
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 /**
  @page libdhcpsrv libdhcpsrv - Server DHCP library
 
@@ -83,4 +97,4 @@ returning clients are almost guaranteed to get a different address. Another
 drawback is that with almost depleted pools it is increasingly difficult to
 "guess" an address that is free. This allocator is currently not implemented.
 
-*/
\ No newline at end of file
+*/
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc
index 34f21e9..e5846eb 100644
--- a/src/lib/dhcpsrv/memfile_lease_mgr.cc
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -22,8 +22,7 @@ using namespace isc::dhcp;
 
 Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
     : LeaseMgr(parameters) {
-    std::cout << "Warning: Using memfile database backend. It is usable for limited"
-              << " testing only. Leases will be lost after restart." << std::endl;
+    LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_WARNING);
 }
 
 Memfile_LeaseMgr::~Memfile_LeaseMgr() {
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
index 292df61..6b6cde5 100644
--- a/src/lib/dhcpsrv/mysql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -338,12 +338,25 @@ public:
         bind_[1].length = &hwaddr_length_;
 
         // client_id: varbinary(128)
-        client_id_ = lease_->client_id_->getClientId();
-        client_id_length_ = client_id_.size();
-        bind_[2].buffer_type = MYSQL_TYPE_BLOB;
-        bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
-        bind_[2].buffer_length = client_id_length_;
-        bind_[2].length = &client_id_length_;
+        if (lease_->client_id_) {
+            client_id_ = lease_->client_id_->getClientId();
+            client_id_length_ = client_id_.size();
+            bind_[2].buffer_type = MYSQL_TYPE_BLOB;
+            bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
+            bind_[2].buffer_length = client_id_length_;
+            bind_[2].length = &client_id_length_;
+        } else {
+            bind_[2].buffer_type = MYSQL_TYPE_NULL;
+
+            // According to http://dev.mysql.com/doc/refman/5.5/en/
+            // c-api-prepared-statement-data-structures.html, the other
+            // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
+            // but let's set them to some sane values in case earlier versions
+            // didn't have that assumption.
+            static my_bool no_clientid = MLM_TRUE;
+            bind_[2].buffer = NULL;
+            bind_[2].is_null = &no_clientid;
+        }
 
         // valid lifetime: unsigned int
         bind_[3].buffer_type = MYSQL_TYPE_LONG;
diff --git a/src/lib/dhcpsrv/option_space.cc b/src/lib/dhcpsrv/option_space.cc
deleted file mode 100644
index 0e802a7..0000000
--- a/src/lib/dhcpsrv/option_space.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (C) 2012, 2013 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 <dhcpsrv/option_space.h>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-
-namespace isc {
-namespace dhcp {
-
-OptionSpace::OptionSpace(const std::string& name, const bool vendor_space)
-    : name_(name), vendor_space_(vendor_space) {
-    //  Check that provided option space name is valid.
-    if (!validateName(name_)) {
-        isc_throw(InvalidOptionSpace, "Invalid option space name "
-                  << name_);
-    }
-}
-
-bool
-OptionSpace::validateName(const std::string& name) {
-
-    using namespace boost::algorithm;
-
-    // Allowed characters are: lower or upper case letters, digits,
-    // underscores and hyphens. Empty option spaces are not allowed.
-    if (all(name, boost::is_from_range('a', 'z') ||
-            boost::is_from_range('A', 'Z') ||
-            boost::is_digit() ||
-            boost::is_any_of(std::string("-_"))) &&
-        !name.empty() &&
-        // Hyphens and underscores are not allowed at the beginning
-        // and at the end of the option space name.
-        !all(find_head(name, 1), boost::is_any_of(std::string("-_"))) &&
-        !all(find_tail(name, 1), boost::is_any_of(std::string("-_")))) {
-        return (true);
-
-    }
-    return (false);
-}
-
-OptionSpace6::OptionSpace6(const std::string& name)
-    : OptionSpace(name),
-      enterprise_number_(0) {
-}
-
-OptionSpace6::OptionSpace6(const std::string& name,
-                           const uint32_t enterprise_number)
-    : OptionSpace(name, true),
-      enterprise_number_(enterprise_number) {
-}
-
-void
-OptionSpace6::setVendorSpace(const uint32_t enterprise_number) {
-    enterprise_number_ = enterprise_number;
-    OptionSpace::setVendorSpace();
-}
-
-} // end of isc::dhcp namespace
-} // end of isc namespace
diff --git a/src/lib/dhcpsrv/option_space.h b/src/lib/dhcpsrv/option_space.h
deleted file mode 100644
index 9eebd76..0000000
--- a/src/lib/dhcpsrv/option_space.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (C) 2012, 2013 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_SPACE_H
-#define OPTION_SPACE_H
-
-#include <exceptions/exceptions.h>
-#include <boost/shared_ptr.hpp>
-#include <map>
-#include <stdint.h>
-#include <string>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief Exception to be thrown when invalid option space
-/// is specified.
-class InvalidOptionSpace : public Exception {
-public:
-    InvalidOptionSpace(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) { };
-};
-
-/// OptionSpace forward declaration.
-class OptionSpace;
-/// A pointer to OptionSpace object.
-typedef boost::shared_ptr<OptionSpace> OptionSpacePtr;
-/// A collection of option spaces.
-typedef std::map<std::string, OptionSpacePtr> OptionSpaceCollection;
-
-/// @brief DHCP option space.
-///
-/// This class represents single option space. The option spaces are used
-/// to group DHCP options having unique option codes. The special type
-/// of the option space is so called "vendor specific option space".
-/// It groups sub-options being sent within Vendor Encapsulated Options.
-/// For DHCPv4 it is the option with code 43. The option spaces are
-/// assigned to option instances represented by isc::dhcp::Option and
-/// other classes derived from it. Each particular option may belong to
-/// multiple option spaces.
-/// This class may be used to represent any DHCPv4 option space. If the
-/// option space is to group DHCPv4 Vendor Encapsulated Options then
-/// "vendor space" flag must be set using \ref OptionSpace::setVendorSpace
-/// or the argument passed to the constructor. In theory, this class can
-/// be also used to represent non-vendor specific DHCPv6 option space
-/// but this is discouraged. For DHCPv6 option spaces the OptionSpace6
-/// class should be used instead.
-///
-/// @note this class is intended to be used to represent DHCPv4 option
-/// spaces only. However, it hasn't been called OptionSpace4 (that would
-/// suggest that it is specific to DHCPv4) because it can be also
-/// used to represent some DHCPv6 option spaces and is a base class
-/// for \ref OptionSpace6. Thus, if one declared the container as follows:
-/// @code
-/// std::vector<OptionSpace4> container;
-/// @endcode
-/// it would suggest that the container holds DHCPv4 option spaces while
-/// it could hold both DHCPv4 and DHCPv6 option spaces as the OptionSpace6
-/// object could be upcast to OptionSpace4. This confusion does not appear
-/// when OptionSpace is used as a name for the base class.
-class OptionSpace {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param name option space name.
-    /// @param vendor_space boolean value that indicates that the object
-    /// describes the vendor specific option space.
-    ///
-    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
-    /// contains invalid characters or is empty. This constructor uses
-    /// \ref validateName function to check that the specified name is
-    /// correct.
-    OptionSpace(const std::string& name, const bool vendor_space = false);
-
-    /// @brief Return option space name.
-    ///
-    /// @return option space name.
-    const std::string& getName() const { return (name_); }
-
-    /// @brief Mark option space as non-vendor space.
-    void clearVendorSpace() {
-        vendor_space_ = false;
-    }
-
-    /// @brief Check if option space is vendor specific.
-    ///
-    /// @return boolean value that indicates if the object describes
-    /// the vendor specific option space.
-    bool isVendorSpace() const { return (vendor_space_); }
-
-    /// @brief Mark option space as vendor specific.
-    void setVendorSpace() {
-        vendor_space_ = true;
-    }
-
-    /// @brief Checks that the provided option space name is valid.
-    ///
-    /// It is expected that option space name consists of upper or
-    /// lower case letters or digits. Also, it may contain underscores
-    /// or dashes. Other characters are prohibited. The empty option
-    /// space names are invalid.
-    ///
-    /// @param name option space name to be validated.
-    ///
-    /// @return true if the option space is valid, else it returns false.
-    static bool validateName(const std::string& name);
-
-private:
-    std::string name_;  ///< Holds option space name.
-
-    bool vendor_space_; ///< Is this the vendor space?
-
-};
-
-/// @brief DHCPv6 option space with enterprise number assigned.
-///
-/// This class extends the base class with the support for enterprise numbers.
-/// The enterprise numbers are assigned by IANA to various organizations
-/// and they are carried as uint32_t integers in DHCPv6 Vendor Specific
-/// Information Options (VSIO). For more information refer to RFC3315.
-/// All option spaces that group VSIO options must have enterprise number
-/// set. It can be set using a constructor or \ref setVendorSpace function.
-/// The extra functionality of this class (enterprise numbers) allows to
-/// represent DHCPv6 vendor-specific option spaces but this class is also
-/// intended to be used for all other DHCPv6 option spaces. That way all
-/// DHCPv6 option spaces can be stored in the container holding OptionSpace6
-/// objects. Also, it is easy to mark vendor-specific option space as non-vendor
-/// specific option space (and the other way around) without a need to cast
-/// between OptionSpace and OptionSpace6 types.
-class OptionSpace6 : public OptionSpace {
-public:
-
-    /// @brief Constructor for non-vendor-specific options.
-    ///
-    /// This constructor marks option space as non-vendor specific.
-    ///
-    /// @param name option space name.
-    ///
-    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
-    /// contains invalid characters or is empty. This constructor uses
-    /// \ref OptionSpace::validateName function to check that the specified
-    /// name is correct.
-    OptionSpace6(const std::string& name);
-
-    /// @brief Constructor for vendor-specific options.
-    ///
-    /// This constructor marks option space as vendor specific and sets
-    /// enterprise number to a given value.
-    ///
-    /// @param name option space name.
-    /// @param enterprise_number enterprise number.
-    ///
-    /// @throw isc::dhcp::InvalidOptionSpace if given option space name
-    /// contains invalid characters or is empty. This constructor uses
-    /// \ref OptionSpace::validateName function to check that the specified
-    /// name is correct.
-    OptionSpace6(const std::string& name, const uint32_t enterprise_number);
-
-    /// @brief Return enterprise number for the option space.
-    ///
-    /// @return enterprise number.
-    uint32_t getEnterpriseNumber() const { return (enterprise_number_); }
-
-    /// @brief Mark option space as vendor specific.
-    ///
-    /// @param enterprise_number enterprise number.
-    void setVendorSpace(const uint32_t enterprise_number);
-
-private:
-    
-    uint32_t enterprise_number_; ///< IANA assigned enterprise number.
-};
-
-} // namespace isc::dhcp
-} // namespace isc
-
-#endif // OPTION_SPACE_H
diff --git a/src/lib/dhcpsrv/option_space_container.h b/src/lib/dhcpsrv/option_space_container.h
index f90bedd..ba16fbb 100644
--- a/src/lib/dhcpsrv/option_space_container.h
+++ b/src/lib/dhcpsrv/option_space_container.h
@@ -41,7 +41,7 @@ public:
     /// @brief Adds a new item to the option_space.
     ///
     /// @param item reference to the item being added.
-    /// @param name of the option space.
+    /// @param option_space name of the option space.
     void addItem(const ItemType& item, const std::string& option_space) {
         ItemsContainerPtr items = getItems(option_space);
         items->push_back(item);
diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc
index 3548762..7b8a4ea 100644
--- a/src/lib/dhcpsrv/pool.cc
+++ b/src/lib/dhcpsrv/pool.cc
@@ -102,8 +102,9 @@ Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
         isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
     }
 
-    // check if the prefix length is sane
-    if (prefix_len == 0 || prefix_len > 128) {
+    // check if the prefix length is sane (we use the member variable only
+    // for silencing some compilers; see #2705 and #2789).
+    if (prefix_len_ == 0 || prefix_len_ > 128) {
         isc_throw(BadValue, "Invalid prefix length");
     }
 
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index 0443a33..daf3f9e 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <asiolink/io_address.h>
+#include <dhcp/option_space.h>
 #include <dhcpsrv/addr_utilities.h>
 #include <dhcpsrv/subnet.h>
 
@@ -44,14 +45,12 @@ bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
 }
 
 void
-Subnet::addOption(OptionPtr& option, bool persistent,
+Subnet::addOption(const OptionPtr& option, bool persistent,
                   const std::string& option_space) {
-    // @todo Once the #2313 is merged we need to use the OptionSpace object to
-    // validate the option space name here. For now, let's check that the name
-    // is not empty as the empty namespace has a special meaning here - it is
-    // returned when desired namespace is not found when getOptions is called.
-    if (option_space.empty()) {
-        isc_throw(isc::BadValue, "option space name must not be empty");
+    // Check that the option space name is valid.
+    if (!OptionSpace::validateName(option_space)) {
+        isc_throw(isc::BadValue, "invalid option space name: '"
+                  << option_space << "'");
     }
     validateOption(option);
 
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
index 471fb03..cf29450 100644
--- a/src/lib/dhcpsrv/subnet.h
+++ b/src/lib/dhcpsrv/subnet.h
@@ -69,7 +69,7 @@ public:
         ///
         /// @param opt option
         /// @param persist if true option is always sent.
-        OptionDescriptor(OptionPtr& opt, bool persist)
+        OptionDescriptor(const OptionPtr& opt, bool persist)
             : option(opt), persistent(persist) {};
 
         /// @brief Constructor
@@ -225,7 +225,7 @@ public:
     /// @param option_space name of the option space to add an option to.
     ///
     /// @throw isc::BadValue if invalid option provided.
-    void addOption(OptionPtr& option, bool persistent,
+    void addOption(const OptionPtr& option, bool persistent,
                    const std::string& option_space);
 
     /// @brief Delete all options configured for the subnet.
diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am
index dfe3e78..e19fd87 100644
--- a/src/lib/dhcpsrv/tests/Makefile.am
+++ b/src/lib/dhcpsrv/tests/Makefile.am
@@ -30,13 +30,13 @@ libdhcpsrv_unittests_SOURCES  = run_unittests.cc
 libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
 libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
 libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
 libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
 if HAVE_MYSQL
 libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc
 endif
-libdhcpsrv_unittests_SOURCES += option_space_unittest.cc
 libdhcpsrv_unittests_SOURCES += pool_unittest.cc
 libdhcpsrv_unittests_SOURCES += schema_copy.h
 libdhcpsrv_unittests_SOURCES += subnet_unittest.cc
@@ -63,6 +63,8 @@ endif
 
 libdhcpsrv_unittests_LDADD  = $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index 078998d..ddc0f62 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -461,9 +461,9 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
 
     // There is just a single address in the pool and allocated it to someone
     // else, so the allocation should fail
-
-    EXPECT_THROW(engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),false),
-                 AllocFailed);
+    Lease6Ptr lease2 = engine->allocateAddress6(subnet_, duid_, iaid_,
+                                                IOAddress("::"), false);
+    EXPECT_FALSE(lease2);
 }
 
 // This test checks if an expired lease can be reused in SOLICIT (fake allocation)
@@ -838,8 +838,9 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
     // There is just a single address in the pool and allocated it to someone
     // else, so the allocation should fail
 
-    EXPECT_THROW(engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),false),
-                 AllocFailed);
+    Lease4Ptr lease2 = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+                                                IOAddress("0.0.0.0"), false);
+    EXPECT_FALSE(lease2);
 }
 
 // This test checks if an expired lease can be reused in DISCOVER (fake allocation)
diff --git a/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc b/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc
new file mode 100644
index 0000000..24cfb1a
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc
@@ -0,0 +1,434 @@
+// Copyright (C) 2012-2013 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 <dhcpsrv/dbaccess_parser.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <config/ccsession.h>
+#include <gtest/gtest.h>
+
+#include <map>
+#include <string>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace {
+
+/// @brief Database Access Parser test fixture class
+class DbAccessParserTest : public ::testing::Test {
+public:
+    /// @brief Constructor
+    ///
+    /// Just make sure that the lease database is closed before every test
+    /// (the first in particular).
+    DbAccessParserTest() {
+        LeaseMgrFactory::destroy();
+    }
+    /// @brief Destructor
+    ///
+    /// Just make sure that the lease database is closed after every test
+    /// (the last in particular).
+    ~DbAccessParserTest() {
+        LeaseMgrFactory::destroy();
+    }
+
+    /// @brief Build JSON String
+    ///
+    /// Given a array of "const char*" strings representing in order, keyword,
+    /// value, keyword, value, ... and terminated by a NULL, return a string
+    /// that represents the JSON map for the keywords and values.
+    ///
+    /// E.g. given the array of strings: alpha, one, beta, two, NULL, it would
+    /// return the string '{ "alpha": "one", "beta": "two" }'
+    ///
+    /// @param keyval Array of "const char*" strings in the order keyword,
+    ///        value, keyword, value ...  A NULL entry terminates the list.
+    ///
+    /// @return JSON map for the keyword value array.
+    std::string toJson(const char* keyval[]) {
+        const std::string quote = "\"";
+        const std::string colon = ":";
+        const std::string space = " ";
+
+        string result = "{ ";
+
+        for (size_t i = 0; keyval[i] != NULL; i+= 2) {
+            // Get the value.  This should not be NULL.  As ASSERT_NE will
+            // cause a return - which gives compilation problems as a return
+            // statement is expected to return a string - use EXPECT_NE and
+            // explicitly return if the expected array is incorrect.
+            EXPECT_NE(static_cast<const char*>(NULL), keyval[i + 1]) <<
+                "Supplied reference keyword/value list does not contain values "
+                "for all keywords";
+            if (keyval[i + 1] == NULL) {
+                return (std::string(""));
+            }
+
+            // Add the separating comma if not the first.
+            if (i != 0) {
+                result += ", ";
+            }
+
+            // Add the keyword and value - make sure that they are quoted.
+            result += quote + keyval[i] + quote + colon + space +
+                      quote + keyval[i + 1] + quote;
+        }
+
+        // Add the terminating brace
+        result += " }";
+
+        return (result);
+    }
+
+    /// @brief Check for Keywords
+    ///
+    /// Takes a database access string and checks it against a list of keywords
+    /// and values.  It checks that:
+    ///
+    /// a. Every keyword in the string appears once and only once in the
+    ///    list.
+    /// b. Every keyword in the list appears in the string.
+    /// c. Every keyword's value is the same as that in the string.
+    ///
+    /// To parse the access string, we use the parsing function in the
+    /// DHCP lease manager.
+    ///
+    /// @param trace_string String that will be used to set the value of a
+    ///        SCOPED_TRACE for this call.
+    /// @param dbaccess set of database access parameters to check
+    /// @param keyval Array of "const char*" strings in the order keyword,
+    ///        value, keyword, value ...  A NULL entry terminates the list.
+    void checkAccessString(const char* trace_string,
+                           const DbAccessParser::StringPairMap& parameters,
+                           const char* keyval[]) {
+        SCOPED_TRACE(trace_string);
+
+        // Construct a map of keyword value pairs.
+        std::map<string, string> expected;
+        size_t expected_count = 0;
+        for (size_t i = 0; keyval[i] != NULL; i += 2) {
+            // Get the value.  This should not be NULL
+            ASSERT_NE(static_cast<const char*>(NULL), keyval[i + 1]) <<
+                "Supplied reference keyword/value list does not contain values "
+                "for all keywords";
+            expected[keyval[i]] = keyval[i + 1];
+
+            // One more keyword processed
+            ++expected_count;
+        }
+
+        // Check no duplicates in the test set of reference keywords.
+        ASSERT_EQ(expected_count, expected.size()) << 
+            "Supplied reference keyword/value list contains duplicate keywords";
+
+        // The passed parameter map should have the same number of entries as
+        // the reference set of keywords.
+        EXPECT_EQ(expected_count, parameters.size());
+
+        // Check that the keywords and keyword values are the same: loop
+        // through the keywords in the database access string.
+        for (LeaseMgr::ParameterMap::const_iterator actual = parameters.begin();
+             actual != parameters.end(); ++actual) {
+
+            // Does the keyword exist in the set of expected keywords?
+            std::map<string, string>::iterator corresponding =
+                expected.find(actual->first);
+            ASSERT_TRUE(corresponding != expected.end());
+
+            // Keyword exists, is the value the same?
+            EXPECT_EQ(corresponding->second, actual->second);
+        }
+    }
+};
+
+
+/// @brief Version of parser with protected methods public
+///
+/// Some of the methods in DbAccessParser are not required to be public in
+/// BIND 10.  Instead of being declared "private", they are declared "protected"
+/// so that they can be accessed through a derived class in the unit tests.
+class TestDbAccessParser : public DbAccessParser {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @brief Keyword/value collection of ddatabase access parameters
+    TestDbAccessParser(const std::string& param_name)
+        : DbAccessParser(param_name)
+    {}
+
+    /// @brief Destructor
+    virtual ~TestDbAccessParser()
+    {}
+
+    /// Allow use of superclass's protected functions.
+    using DbAccessParser::getDbAccessParameters;
+    using DbAccessParser::getDbAccessString;
+
+    /// @brief Get database access parameters
+    ///
+    /// Used in testing to check that the configuration information has been
+    /// parsed corrected.
+    ///
+    /// @return Map of keyword/value pairs representing database access
+    ///         information.
+    const StringPairMap& getDbAccessParameters() const {
+        return (DbAccessParser::getDbAccessParameters());
+    }
+
+    /// @brief Construct database access string
+    ///
+    /// Constructs the database access string from the stored parameters.
+    ///
+    /// @return Database access string
+    std::string getDbAccessString() const {
+        return (DbAccessParser::getDbAccessString());
+    }
+};
+
+// Check that the parser works with a simple configuration.
+TEST_F(DbAccessParserTest, validTypeMemfile) {
+    const char* config[] = {"type", "memfile",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
+}
+
+// Check that the parser works with a simple configuration that
+// includes empty elements.
+TEST_F(DbAccessParserTest, emptyKeyword) {
+    const char* config[] = {"type", "memfile",
+                            "name", "",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
+}
+
+// Check that the parser works with a valid MySQL configuration
+TEST_F(DbAccessParserTest, validTypeMysql) {
+    const char* config[] = {"type",     "mysql",
+                            "host",     "erewhon",
+                            "user",     "kea",
+                            "password", "keapassword",
+                            "name",     "keatest",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Valid mysql", parser.getDbAccessParameters(), config);
+}
+
+// A missing 'type' keyword should cause an exception to be thrown.
+TEST_F(DbAccessParserTest, missingTypeKeyword) {
+    const char* config[] = {"host",     "erewhon",
+                            "user",     "kea",
+                            "password", "keapassword",
+                            "name",     "keatest",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_THROW(parser.build(json_elements), TypeKeywordMissing);
+}
+
+// Check that the factory function works.
+TEST_F(DbAccessParserTest, factory) {
+
+    // Check that the parser is built through the factory.
+    boost::scoped_ptr<DhcpConfigParser> parser(
+        DbAccessParser::factory("lease-database"));
+    EXPECT_TRUE(parser);
+    DbAccessParser* dbap = dynamic_cast<DbAccessParser*>(parser.get());
+    EXPECT_NE(static_cast<DbAccessParser*>(NULL), dbap);
+}
+
+// Check reconfiguration.  Checks that incremental changes applied to the
+// database configuration are incremental.
+TEST_F(DbAccessParserTest, incrementalChanges) {
+    const char* config1[] = {"type", "memfile",
+                             NULL};
+
+    // Applying config2 will cause a wholesale change.
+    const char* config2[] = {"type",     "mysql",
+                             "host",     "erewhon",
+                             "user",     "kea",
+                             "password", "keapassword",
+                             "name",     "keatest",
+                             NULL};
+
+    // Applying incremental2 should cause a change to config3.
+    const char* incremental2[] = {"user",     "me",
+                                  "password", "meagain",
+                                  NULL};
+    const char* config3[] = {"type",     "mysql",
+                             "host",     "erewhon",
+                             "user",     "me",
+                             "password", "meagain",
+                             "name",     "keatest",
+                             NULL};
+
+    // incremental3 will cause an exception.  There should be no change
+    // to the returned value.
+    const char* incremental3[] = {"type",     "invalid",
+                                  "user",     "you",
+                                  "password", "youagain",
+                                  NULL};
+
+    // incremental4 is a compatible change and should cause a transition
+    // to config4.
+    const char* incremental4[] = {"user",     "them",
+                                  "password", "",
+                                  NULL};
+    const char* config4[] = {"type",     "mysql",
+                             "host",     "erewhon",
+                             "user",     "them",
+                             "password", "",
+                             "name",     "keatest",
+                             NULL};
+
+    TestDbAccessParser parser("lease-database");
+
+    // First configuration string should cause a representation of that string
+    // to be held.
+    string json_config = toJson(config1);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Initial configuration", parser.getDbAccessParameters(),
+                      config1);
+
+    // Applying a wholesale change will cause the access string to change
+    // to a representation of the new configuration.
+    json_config = toJson(config2);
+    json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Subsequent configuration", parser.getDbAccessParameters(),
+                      config2);
+
+    // Applying an incremental change will cause the representation to change
+    // incrementally.
+    json_config = toJson(incremental2);
+    json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Incremental configuration", parser.getDbAccessParameters(),
+                      config3);
+
+    // Applying the next incremental change should cause an exception to be
+    // thrown and there be no change to the access string.
+    json_config = toJson(incremental3);
+    json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    EXPECT_THROW(parser.build(json_elements), BadValue);
+    checkAccessString("Incompatible incremental change", parser.getDbAccessParameters(),
+                      config3);
+
+    // Applying an incremental change will cause the representation to change
+    // incrementally.
+    json_config = toJson(incremental4);
+    json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    EXPECT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Compatible incremental change", parser.getDbAccessParameters(),
+                      config4);
+}
+
+// Check that the database access string is constructed correctly.
+TEST_F(DbAccessParserTest, getDbAccessString) {
+    const char* config[] = {"type",     "mysql",
+                            "host",     "" ,
+                            "name",     "keatest",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_NO_THROW(parser.build(json_elements));
+
+    // Get the database access string
+    std::string dbaccess = parser.getDbAccessString();
+
+    // String should be either "type=mysql name=keatest" or
+    // "name=keatest type=mysql". The "host" entry is null, so should not be
+    // output.
+    EXPECT_TRUE((dbaccess == "type=mysql name=keatest") ||
+                (dbaccess == "name=keatest type=mysql"));
+}
+
+// Check that the "commit" function actually opens the database.  We will
+// only do this for the "memfile" database, as that does not assume that the
+// test has been built with MySQL support.
+TEST_F(DbAccessParserTest, commit) {
+
+    // Verify that no lease database is open
+    EXPECT_THROW({
+            LeaseMgr& manager = LeaseMgrFactory::instance();
+            manager.getType();  // Never executed but satisfies compiler
+            }, isc::dhcp::NoLeaseManager);
+
+    // Set up the parser to open the memfile database.
+    const char* config[] = {"type", "memfile",
+                            NULL};
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database");
+    EXPECT_NO_THROW(parser.build(json_elements));
+
+    // Ensure that the access string is as expected.
+    EXPECT_EQ(std::string("type=memfile"), parser.getDbAccessString());
+
+    // Committal of the parser changes should open the database.
+    EXPECT_NO_THROW(parser.commit());
+
+    // Verify by checking the type of database open.
+    std::string dbtype;
+    EXPECT_NO_THROW(dbtype = LeaseMgrFactory::instance().getType());
+    EXPECT_EQ(std::string("memfile"), dbtype);
+}
+
+};  // Anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/option_space_unittest.cc b/src/lib/dhcpsrv/tests/option_space_unittest.cc
deleted file mode 100644
index f8d75c8..0000000
--- a/src/lib/dhcpsrv/tests/option_space_unittest.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (C) 2012, 2013 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 <dhcpsrv/option_space.h>
-
-#include <gtest/gtest.h>
-
-using namespace isc::dhcp;
-using namespace isc;
-
-namespace {
-
-// The purpose of this test is to verify that the constructor
-// creates an object with members initialized to correct values.
-TEST(OptionSpaceTest, constructor) {
-    // Create some option space.
-    OptionSpace space("isc", true);
-    EXPECT_EQ("isc", space.getName());
-    EXPECT_TRUE(space.isVendorSpace());
-
-    // Create another object with different values
-    // to check that the values will change.
-    OptionSpace space2("abc", false);
-    EXPECT_EQ("abc", space2.getName());
-    EXPECT_FALSE(space2.isVendorSpace());
-
-    // Verify that constructor throws exception if invalid
-    // option space name is provided.
-    EXPECT_THROW(OptionSpace("invalid%space.name"), InvalidOptionSpace);
-}
-
-// The purpose of this test is to verify that the vendor-space flag
-// can be overriden.
-TEST(OptionSpaceTest, setVendorSpace) {
-    OptionSpace space("isc", true);
-    EXPECT_EQ("isc", space.getName());
-    EXPECT_TRUE(space.isVendorSpace());
-
-    // Override the vendor space flag.
-    space.clearVendorSpace();
-    EXPECT_FALSE(space.isVendorSpace());
-}
-
-// The purpose of this test is to verify that the static function
-// to validate the option space name works correctly.
-TEST(OptionSpaceTest, validateName) {
-    // Positive test scenarios: letters, digits, dashes, underscores
-    // lower/upper case allowed.
-    EXPECT_TRUE(OptionSpace::validateName("abc"));
-    EXPECT_TRUE(OptionSpace::validateName("dash-allowed"));
-    EXPECT_TRUE(OptionSpace::validateName("two-dashes-allowed"));
-    EXPECT_TRUE(OptionSpace::validateName("underscore_allowed"));
-    EXPECT_TRUE(OptionSpace::validateName("underscore_three_times_allowed"));
-    EXPECT_TRUE(OptionSpace::validateName("digits0912"));
-    EXPECT_TRUE(OptionSpace::validateName("1234"));
-    EXPECT_TRUE(OptionSpace::validateName("UPPER_CASE_allowed"));
-
-    // Negative test scenarions: empty strings, dots, spaces are not
-    // allowed
-    EXPECT_FALSE(OptionSpace::validateName(""));
-    EXPECT_FALSE(OptionSpace::validateName(" "));
-    EXPECT_FALSE(OptionSpace::validateName(" isc "));
-    EXPECT_FALSE(OptionSpace::validateName("isc "));
-    EXPECT_FALSE(OptionSpace::validateName(" isc"));
-    EXPECT_FALSE(OptionSpace::validateName("isc with-space"));
-
-    // Hyphens and underscores are not allowed at the beginning
-    // and at the end of the option space name.
-    EXPECT_FALSE(OptionSpace::validateName("-isc"));
-    EXPECT_FALSE(OptionSpace::validateName("isc-"));
-    EXPECT_FALSE(OptionSpace::validateName("_isc"));
-    EXPECT_FALSE(OptionSpace::validateName("isc_"));
-
-    // Test other special characters
-    const char specials[] = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
-                              '+', '=', '[', ']', '{', '}', ';', ':', '"', '\'',
-                              '\\', '|', '<','>', ',', '.', '?', '~', '`' };
-    for (int i = 0; i < sizeof(specials); ++i) {
-        std::ostringstream stream;
-        // Concatenate valid option space name: "abc" with an invalid character.
-        // That way we get option space names like: "abc!", "abc$" etc. It is
-        // expected that the validating function fails form them.
-        stream << "abc" << specials[i];
-        EXPECT_FALSE(OptionSpace::validateName(stream.str()))
-            << "Test failed for special character '" << specials[i] << "'.";
-    }
-}
-
-// The purpose of this test is to verify that the constructors of the
-// OptionSpace6 class set the class members to correct values.
-TEST(OptionSpace6Test, constructor) {
-    // Create some option space and do not specify enterprise number.
-    // In such case the vendor space flag is expected to be
-    // set to false.
-    OptionSpace6 space1("abcd");
-    EXPECT_EQ("abcd", space1.getName());
-    EXPECT_FALSE(space1.isVendorSpace());
-
-    // Create an option space and specify an enterprise number. In this
-    // case the vendor space flag is expected to be set to true and the
-    // enterprise number should be set to a desired value.
-    OptionSpace6 space2("abcd", 2145);
-    EXPECT_EQ("abcd", space2.getName());
-    EXPECT_TRUE(space2.isVendorSpace());
-    EXPECT_EQ(2145, space2.getEnterpriseNumber());
-
-    // Verify that constructors throw an exception when invalid option
-    // space name has been specified.
-    EXPECT_THROW(OptionSpace6("isc dhcp"), InvalidOptionSpace);
-    EXPECT_THROW(OptionSpace6("isc%dhcp", 2145), InvalidOptionSpace);
-}
-
-// The purpose of this test is to verify an option space can be marked
-// vendor option space and enterprise number can be set.
-TEST(OptionSpace6Test, setVendorSpace) {
-    OptionSpace6 space("isc");
-    EXPECT_EQ("isc", space.getName());
-    EXPECT_FALSE(space.isVendorSpace());
-
-    // Mark it vendor option space and set enterprise id.
-    space.setVendorSpace(1234);
-    EXPECT_TRUE(space.isVendorSpace());
-    EXPECT_EQ(1234, space.getEnterpriseNumber());
-
-    // Override the enterprise number to make sure and make sure that
-    // the new number is returned by the object.
-    space.setVendorSpace(2345);
-    EXPECT_TRUE(space.isVendorSpace());
-    EXPECT_EQ(2345, space.getEnterpriseNumber());
-
-    // Clear the vendor option space flag.
-    space.clearVendorSpace();
-    EXPECT_FALSE(space.isVendorSpace());
-}
-
-
-}; // end of anonymous namespace
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 286bd8c..bbf33ed 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -8,6 +8,10 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES += rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc
+# These two are created with rrtype/class.h, so not explicitly listed in
+# BUILT_SOURCES.
+CLEANFILES += python/rrtype_constants_inc.cc
+CLEANFILES += python/rrclass_constants_inc.cc
 
 EXTRA_DIST = rrclass-placeholder.h
 EXTRA_DIST += rrparamregistry-placeholder.cc
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index fc63d73..b385bf4 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -33,16 +33,43 @@ import sys
 # Example:
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
 new_rdata_factory_users = [('aaaa', 'in'),
+                           ('cname', 'generic'),
+                           ('dname', 'generic'),
                            ('hinfo', 'generic'),
                            ('naptr', 'generic'),
+                           ('mx', 'generic'),
+                           ('ns', 'generic'),
+                           ('ptr', 'generic'),
                            ('soa', 'generic'),
                            ('spf', 'generic'),
+                           ('srv', 'in'),
                            ('txt', 'generic')
                           ]
 
-re_typecode = re.compile('([\da-z]+)_(\d+)')
+re_typecode = re.compile('([\da-z\-]+)_(\d+)')
 classcode2txt = {}
 typecode2txt = {}
+# For meta types and types well-known but not implemented.  This is a dict from
+# type code values (as string) to textual mnemonic.
+meta_types = {
+    # Real meta types.  We won't have Rdata implement for them, but we need
+    # RRType constants.
+    '251': 'ixfr', '252': 'axfr', '255': 'any',
+    # Obsolete types.  We probalby won't implement Rdata for them, but it's
+    # better to have RRType constants.
+    '3': 'md', '4': 'mf', '7': 'mb', '8': 'mg', '9': 'mr', '30': 'nxt',
+    '38': 'a6', '254': 'maila',
+    # Types officially assigned but not yet supported in our implementation.
+    '10': 'null', '11': 'wks', '19': 'x25', '21': 'rt', '22': 'nsap',
+    '23': 'nsap-ptr', '24': 'sig', '20': 'isdn', '25': 'key', '26': 'px',
+    '27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl',
+    '45': 'ipseckey', '52': 'tlsa', '55': 'hip', '103': 'unspec',
+    '104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp', '249':  'tkey',
+    '253': 'mailb', '256': 'uri', '257': 'caa'
+    }
+# Classes that don't have any known types.  This is a dict from type code
+# values (as string) to textual mnemonic.
+meta_classes = {'254': 'none'}
 typeandclass = []
 generic_code = 65536            # something larger than any code value
 rdata_declarations = ''
@@ -185,11 +212,11 @@ def import_definitions(classcode2txt, typecode2txt, typeandclass):
                     type_code = m.group(2)
                     if not type_code in typecode2txt:
                         typecode2txt[type_code] = type_txt
-                    if re.search('\cc$', file):
+                    if re.search('\.cc$', file):
                         if rdatadef_mtime < getmtime(file):
                             rdatadef_mtime = getmtime(file)
                         class_definitions += import_classdef(class_txt, file)
-                    elif re.search('\h$', file):
+                    elif re.search('\.h$', file):
                         if rdatahdr_mtime < getmtime(file):
                             rdatahdr_mtime = getmtime(file)
                         rdata_declarations += import_classheader(class_txt,
@@ -255,36 +282,66 @@ class MasterLoaderCallbacks;
 def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
     placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
     outputfile = '@builddir@/' + fileprefix + '.h'
+    py_outputfile = '@builddir@/python/' + fileprefix + '_constants_inc.cc'
     upper_key = type_or_class.upper() # TYPE or CLASS
     lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
     cap_key = type_or_class           # Type or Class
 
-    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+    # We only decide whether to generate files for libdns++ files; Python
+    # files are generated if and only if libdns++ files are generated.
+    # In practice it should be sufficient.
+    if (not need_generate(outputfile, basemtime) and
+        getmtime(outputfile) > getmtime(placeholder)):
         print('skip generating ' + outputfile)
         return
 
-    declarationtxt = ''
-    deftxt = ''
-    for code in code2txt.keys():
-        codetxt = code2txt[code].upper()
-        declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
-        deftxt += '''inline const RR''' + cap_key + '''&
-RR''' + cap_key + '''::''' + codetxt + '''() {
-    static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
+    # Create a list of (code, code-text) pairs, where code-text is generally
+    # upper-cased, with applying speicial filters when necessary.
+    def convert(code_txt):
+        # Workaround by heuristics: there's a "NULL" RR type, but it would
+        # cause conflict with the C/C++ macro.  We use Null as a special case.
+        if code_txt == 'null':
+            return 'Null'
+        # Likewise, convert "nsap-ptr" to "NSAP_PTR" as a dash cannot be part
+        # of a C/C++ variable.
+        if code_txt == 'nsap-ptr':
+            return 'NSAP_PTR'
+        return code_txt.upper()
+    codes = [ (code, convert(txt)) for code, txt in code2txt.items() ]
+
+    # Dump source code for libdns++
+    with  open(placeholder, 'r') as header_temp:
+        with open(outputfile, 'w') as header_out:
+            header_out.write(heading_txt)
+            for line in header_temp:
+                header_out.write(line)
+                if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key +
+                            '_DECLARATIONS$', line):
+                    for code in codes:
+                        header_out.write(' ' * 4 + 'static const RR' +
+                                         cap_key + '& ' + code[1] + '();\n')
+                if re.match('// BEGIN_WELL_KNOWN_' + upper_key +
+                            '_DEFINITIONS$', line):
+                    for code in codes:
+                        header_out.write('''inline const RR''' + cap_key +
+                                         '''&
+RR''' + cap_key + '''::''' + code[1] + '''() {
+    static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code[0] + ''');
     return (''' + lower_key + ''');
 }\n
-'''
-    header_temp = open(placeholder, 'r')
-    header_out = open(outputfile, 'w')
-    header_out.write(heading_txt)
-    for line in header_temp.readlines():
-        header_out.write(line)
-        if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
-            header_out.write(declarationtxt)
-        if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
-            header_out.write('\n' + deftxt)
-    header_out.close()
-    header_temp.close()
+''')
+
+    # Dump source code snippet for isc.dns Python module
+    with open(py_outputfile, 'w') as py_out:
+        py_out.write("    // auto-generated by ../gen-rdatacode.py."
+                     "  Don't edit this file.\n")
+        py_out.write("\n")
+        for code in codes:
+            py_out.write('''\
+    installClassVariable(''' + lower_key + '''_type, "''' + code[1] + '''",
+                         createRR''' + cap_key + '''Object(RR''' + \
+        cap_key + '''::''' + code[1] + '''()));
+''')
 
 def generate_rrparam(fileprefix, basemtime):
     placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
@@ -331,6 +388,16 @@ def generate_rrparam(fileprefix, basemtime):
             typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
             typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
 
+    typeandclassparams += indent + '// Meta and non-implemented RR types\n'
+    for type_code, type_txt in meta_types.items():
+        typeandclassparams += indent + \
+            'addType("' + type_txt.upper() + '", ' + type_code + ');\n'
+
+    typeandclassparams += indent + '// Meta classes\n'
+    for cls_code, cls_txt in meta_classes.items():
+        typeandclassparams += indent + \
+            'addClass("' + cls_txt.upper() + '", ' + cls_code + ');\n'
+
     rrparam_temp = open(placeholder, 'r')
     rrparam_out = open(outputfile, 'w')
     rrparam_out.write(heading_txt)
@@ -347,9 +414,14 @@ if __name__ == "__main__":
         generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
         generate_rdatahdr('@builddir@/rdataclass.h', heading_txt,
                           rdata_declarations, rdatahdr_mtime)
-        generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
+
+        # merge auto-generated types/classes with meta maps and generate the
+        # corresponding code.
+        generate_typeclasscode('rrtype', rdatahdr_mtime,
+                               dict(typecode2txt, **meta_types), 'Type')
         generate_typeclasscode('rrclass', classdir_mtime,
-                               classcode2txt, 'Class')
+                               dict(classcode2txt, **meta_classes), 'Class')
+
         generate_rrparam('rrparamregistry', rdatahdr_mtime)
     except:
         sys.stderr.write('Code generation failed due to exception: %s\n' %
diff --git a/src/lib/dns/master_loader.cc b/src/lib/dns/master_loader.cc
index 29e7e1d..1c822ea 100644
--- a/src/lib/dns/master_loader.cc
+++ b/src/lib/dns/master_loader.cc
@@ -54,6 +54,7 @@ public:
 
 } // end unnamed namespace
 
+// cppcheck-suppress noConstructor
 class MasterLoader::MasterLoaderImpl {
 public:
     MasterLoaderImpl(const char* master_file,
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index 079033a..ff00374 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -227,7 +227,6 @@ stringParse(Iterator s, Iterator send, bool downcase, Offsets& offsets,
                 isc_throw(BadLabelType,
                           "invalid label type in " << string(orig_s, send));
             }
-            state = ft_escape;
             // FALLTHROUGH
         case ft_escape:
             if (!isdigit(c & 0xff)) {
diff --git a/src/lib/dns/python/.gitignore b/src/lib/dns/python/.gitignore
new file mode 100644
index 0000000..025ddd1
--- /dev/null
+++ b/src/lib/dns/python/.gitignore
@@ -0,0 +1,2 @@
+/rrclass_constants_inc.cc
+/rrtype_constants_inc.cc
diff --git a/src/lib/dns/python/message_python_inc.cc b/src/lib/dns/python/message_python_inc.cc
index e1fd23d..5472695 100644
--- a/src/lib/dns/python/message_python_inc.cc
+++ b/src/lib/dns/python/message_python_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2011-2012  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.
+
 namespace {
 const char* const Message_fromWire_doc = "\
 from_wire(data, options=PARSE_DEFAULT)\n\
diff --git a/src/lib/dns/python/nsec3hash_python_inc.cc b/src/lib/dns/python/nsec3hash_python_inc.cc
index 7d0dfd4..576be75 100644
--- a/src/lib/dns/python/nsec3hash_python_inc.cc
+++ b/src/lib/dns/python/nsec3hash_python_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 namespace {
 // Modifications
 //   - removed intermediate details note, mainly for brevity
diff --git a/src/lib/dns/python/opcode_python.cc b/src/lib/dns/python/opcode_python.cc
index 50436a9..8d40d9d 100644
--- a/src/lib/dns/python/opcode_python.cc
+++ b/src/lib/dns/python/opcode_python.cc
@@ -43,62 +43,12 @@ void Opcode_destroy(s_Opcode* const self);
 PyObject* Opcode_getCode(const s_Opcode* const self);
 PyObject* Opcode_toText(const s_Opcode* const self);
 PyObject* Opcode_str(PyObject* self);
-PyObject* Opcode_QUERY(const s_Opcode* self);
-PyObject* Opcode_IQUERY(const s_Opcode* self);
-PyObject* Opcode_STATUS(const s_Opcode* self);
-PyObject* Opcode_RESERVED3(const s_Opcode* self);
-PyObject* Opcode_NOTIFY(const s_Opcode* self);
-PyObject* Opcode_UPDATE(const s_Opcode* self);
-PyObject* Opcode_RESERVED6(const s_Opcode* self);
-PyObject* Opcode_RESERVED7(const s_Opcode* self);
-PyObject* Opcode_RESERVED8(const s_Opcode* self);
-PyObject* Opcode_RESERVED9(const s_Opcode* self);
-PyObject* Opcode_RESERVED10(const s_Opcode* self);
-PyObject* Opcode_RESERVED11(const s_Opcode* self);
-PyObject* Opcode_RESERVED12(const s_Opcode* self);
-PyObject* Opcode_RESERVED13(const s_Opcode* self);
-PyObject* Opcode_RESERVED14(const s_Opcode* self);
-PyObject* Opcode_RESERVED15(const s_Opcode* self);
-PyObject* Opcode_richcmp(const s_Opcode* const self,
-                         const s_Opcode* const other, int op);
 
 PyMethodDef Opcode_methods[] = {
     { "get_code", reinterpret_cast<PyCFunction>(Opcode_getCode), METH_NOARGS,
       "Returns the code value" },
     { "to_text", reinterpret_cast<PyCFunction>(Opcode_toText), METH_NOARGS,
       "Returns the text representation" },
-    { "QUERY", reinterpret_cast<PyCFunction>(Opcode_QUERY),
-      METH_NOARGS | METH_STATIC, "Creates a QUERY Opcode" },
-    { "IQUERY", reinterpret_cast<PyCFunction>(Opcode_IQUERY),
-      METH_NOARGS | METH_STATIC, "Creates a IQUERY Opcode" },
-    { "STATUS", reinterpret_cast<PyCFunction>(Opcode_STATUS),
-      METH_NOARGS | METH_STATIC, "Creates a STATUS Opcode" },
-    { "RESERVED3", reinterpret_cast<PyCFunction>(Opcode_RESERVED3),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED3 Opcode" },
-    { "NOTIFY", reinterpret_cast<PyCFunction>(Opcode_NOTIFY),
-      METH_NOARGS | METH_STATIC, "Creates a NOTIFY Opcode" },
-    { "UPDATE", reinterpret_cast<PyCFunction>(Opcode_UPDATE),
-      METH_NOARGS | METH_STATIC, "Creates a UPDATE Opcode" },
-    { "RESERVED6", reinterpret_cast<PyCFunction>(Opcode_RESERVED6),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED6 Opcode" },
-    { "RESERVED7", reinterpret_cast<PyCFunction>(Opcode_RESERVED7),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED7 Opcode" },
-    { "RESERVED8", reinterpret_cast<PyCFunction>(Opcode_RESERVED8),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED8 Opcode" },
-    { "RESERVED9", reinterpret_cast<PyCFunction>(Opcode_RESERVED9),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED9 Opcode" },
-    { "RESERVED10", reinterpret_cast<PyCFunction>(Opcode_RESERVED10),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED10 Opcode" },
-    { "RESERVED11", reinterpret_cast<PyCFunction>(Opcode_RESERVED11),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED11 Opcode" },
-    { "RESERVED12", reinterpret_cast<PyCFunction>(Opcode_RESERVED12),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED12 Opcode" },
-    { "RESERVED13", reinterpret_cast<PyCFunction>(Opcode_RESERVED13),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED13 Opcode" },
-    { "RESERVED14", reinterpret_cast<PyCFunction>(Opcode_RESERVED14),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED14 Opcode" },
-    { "RESERVED15", reinterpret_cast<PyCFunction>(Opcode_RESERVED15),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED15 Opcode" },
     { NULL, NULL, 0, NULL }
 };
 
@@ -156,96 +106,6 @@ Opcode_str(PyObject* self) {
 }
 
 PyObject*
-Opcode_createStatic(const Opcode& opcode) {
-    s_Opcode* ret = PyObject_New(s_Opcode, &opcode_type);
-    if (ret != NULL) {
-        ret->cppobj = &opcode;
-        ret->static_code = true;
-    }
-    return (ret);
-}
-
-PyObject*
-Opcode_QUERY(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::QUERY()));
-}
-
-PyObject*
-Opcode_IQUERY(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::IQUERY()));
-}
-
-PyObject*
-Opcode_STATUS(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::STATUS()));
-}
-
-PyObject*
-Opcode_RESERVED3(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED3()));
-}
-
-PyObject*
-Opcode_NOTIFY(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::NOTIFY()));
-}
-
-PyObject*
-Opcode_UPDATE(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::UPDATE()));
-}
-
-PyObject*
-Opcode_RESERVED6(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED6()));
-}
-
-PyObject*
-Opcode_RESERVED7(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED7()));
-}
-
-PyObject*
-Opcode_RESERVED8(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED8()));
-}
-
-PyObject*
-Opcode_RESERVED9(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED9()));
-}
-
-PyObject*
-Opcode_RESERVED10(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED10()));
-}
-
-PyObject*
-Opcode_RESERVED11(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED11()));
-}
-
-PyObject*
-Opcode_RESERVED12(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED12()));
-}
-
-PyObject*
-Opcode_RESERVED13(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED13()));
-}
-
-PyObject*
-Opcode_RESERVED14(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED14()));
-}
-
-PyObject*
-Opcode_RESERVED15(const s_Opcode*) {
-    return (Opcode_createStatic(Opcode::RESERVED15()));
-}
-
-PyObject*
 Opcode_richcmp(const s_Opcode* const self, const s_Opcode* const other,
                const int op)
 {
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index c75c737..30dc090 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -294,38 +294,83 @@ initModulePart_Opcode(PyObject* mod) {
         return (false);
     }
 
-    addClassVariable(opcode_type, "QUERY_CODE",
-                     Py_BuildValue("h", Opcode::QUERY_CODE));
-    addClassVariable(opcode_type, "IQUERY_CODE",
-                     Py_BuildValue("h", Opcode::IQUERY_CODE));
-    addClassVariable(opcode_type, "STATUS_CODE",
-                     Py_BuildValue("h", Opcode::STATUS_CODE));
-    addClassVariable(opcode_type, "RESERVED3_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED3_CODE));
-    addClassVariable(opcode_type, "NOTIFY_CODE",
-                     Py_BuildValue("h", Opcode::NOTIFY_CODE));
-    addClassVariable(opcode_type, "UPDATE_CODE",
-                     Py_BuildValue("h", Opcode::UPDATE_CODE));
-    addClassVariable(opcode_type, "RESERVED6_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED6_CODE));
-    addClassVariable(opcode_type, "RESERVED7_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED7_CODE));
-    addClassVariable(opcode_type, "RESERVED8_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED8_CODE));
-    addClassVariable(opcode_type, "RESERVED9_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED9_CODE));
-    addClassVariable(opcode_type, "RESERVED10_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED10_CODE));
-    addClassVariable(opcode_type, "RESERVED11_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED11_CODE));
-    addClassVariable(opcode_type, "RESERVED12_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED12_CODE));
-    addClassVariable(opcode_type, "RESERVED13_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED13_CODE));
-    addClassVariable(opcode_type, "RESERVED14_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED14_CODE));
-    addClassVariable(opcode_type, "RESERVED15_CODE",
-                     Py_BuildValue("h", Opcode::RESERVED15_CODE));
+    try {
+        installClassVariable(opcode_type, "QUERY_CODE",
+                             Py_BuildValue("h", Opcode::QUERY_CODE));
+        installClassVariable(opcode_type, "IQUERY_CODE",
+                             Py_BuildValue("h", Opcode::IQUERY_CODE));
+        installClassVariable(opcode_type, "STATUS_CODE",
+                             Py_BuildValue("h", Opcode::STATUS_CODE));
+        installClassVariable(opcode_type, "RESERVED3_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED3_CODE));
+        installClassVariable(opcode_type, "NOTIFY_CODE",
+                             Py_BuildValue("h", Opcode::NOTIFY_CODE));
+        installClassVariable(opcode_type, "UPDATE_CODE",
+                             Py_BuildValue("h", Opcode::UPDATE_CODE));
+        installClassVariable(opcode_type, "RESERVED6_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED6_CODE));
+        installClassVariable(opcode_type, "RESERVED7_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED7_CODE));
+        installClassVariable(opcode_type, "RESERVED8_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED8_CODE));
+        installClassVariable(opcode_type, "RESERVED9_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED9_CODE));
+        installClassVariable(opcode_type, "RESERVED10_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED10_CODE));
+        installClassVariable(opcode_type, "RESERVED11_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED11_CODE));
+        installClassVariable(opcode_type, "RESERVED12_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED12_CODE));
+        installClassVariable(opcode_type, "RESERVED13_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED13_CODE));
+        installClassVariable(opcode_type, "RESERVED14_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED14_CODE));
+        installClassVariable(opcode_type, "RESERVED15_CODE",
+                             Py_BuildValue("h", Opcode::RESERVED15_CODE));
+
+        installClassVariable(opcode_type, "QUERY",
+                             createOpcodeObject(Opcode::QUERY()));
+        installClassVariable(opcode_type, "IQUERY",
+                             createOpcodeObject(Opcode::IQUERY()));
+        installClassVariable(opcode_type, "STATUS",
+                             createOpcodeObject(Opcode::STATUS()));
+        installClassVariable(opcode_type, "RESERVED3",
+                             createOpcodeObject(Opcode::RESERVED3()));
+        installClassVariable(opcode_type, "NOTIFY",
+                             createOpcodeObject(Opcode::NOTIFY()));
+        installClassVariable(opcode_type, "UPDATE",
+                             createOpcodeObject(Opcode::UPDATE()));
+        installClassVariable(opcode_type, "RESERVED6",
+                             createOpcodeObject(Opcode::RESERVED6()));
+        installClassVariable(opcode_type, "RESERVED7",
+                             createOpcodeObject(Opcode::RESERVED7()));
+        installClassVariable(opcode_type, "RESERVED8",
+                             createOpcodeObject(Opcode::RESERVED8()));
+        installClassVariable(opcode_type, "RESERVED9",
+                             createOpcodeObject(Opcode::RESERVED9()));
+        installClassVariable(opcode_type, "RESERVED10",
+                             createOpcodeObject(Opcode::RESERVED10()));
+        installClassVariable(opcode_type, "RESERVED11",
+                             createOpcodeObject(Opcode::RESERVED11()));
+        installClassVariable(opcode_type, "RESERVED12",
+                             createOpcodeObject(Opcode::RESERVED12()));
+        installClassVariable(opcode_type, "RESERVED13",
+                             createOpcodeObject(Opcode::RESERVED13()));
+        installClassVariable(opcode_type, "RESERVED14",
+                             createOpcodeObject(Opcode::RESERVED14()));
+        installClassVariable(opcode_type, "RESERVED15",
+                             createOpcodeObject(Opcode::RESERVED15()));
+    } catch (const std::exception& ex) {
+        const std::string ex_what =
+            "Unexpected failure in Opcode initialization: " +
+            std::string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in Opcode initialization");
+        return (false);
+    }
 
     return (true);
 }
@@ -341,40 +386,87 @@ initModulePart_Rcode(PyObject* mod) {
         return (false);
     }
 
-    addClassVariable(rcode_type, "NOERROR_CODE",
-                     Py_BuildValue("h", Rcode::NOERROR_CODE));
-    addClassVariable(rcode_type, "FORMERR_CODE",
-                     Py_BuildValue("h", Rcode::FORMERR_CODE));
-    addClassVariable(rcode_type, "SERVFAIL_CODE",
-                     Py_BuildValue("h", Rcode::SERVFAIL_CODE));
-    addClassVariable(rcode_type, "NXDOMAIN_CODE",
-                     Py_BuildValue("h", Rcode::NXDOMAIN_CODE));
-    addClassVariable(rcode_type, "NOTIMP_CODE",
-                     Py_BuildValue("h", Rcode::NOTIMP_CODE));
-    addClassVariable(rcode_type, "REFUSED_CODE",
-                     Py_BuildValue("h", Rcode::REFUSED_CODE));
-    addClassVariable(rcode_type, "YXDOMAIN_CODE",
-                     Py_BuildValue("h", Rcode::YXDOMAIN_CODE));
-    addClassVariable(rcode_type, "YXRRSET_CODE",
-                     Py_BuildValue("h", Rcode::YXRRSET_CODE));
-    addClassVariable(rcode_type, "NXRRSET_CODE",
-                     Py_BuildValue("h", Rcode::NXRRSET_CODE));
-    addClassVariable(rcode_type, "NOTAUTH_CODE",
-                     Py_BuildValue("h", Rcode::NOTAUTH_CODE));
-    addClassVariable(rcode_type, "NOTZONE_CODE",
-                     Py_BuildValue("h", Rcode::NOTZONE_CODE));
-    addClassVariable(rcode_type, "RESERVED11_CODE",
-                     Py_BuildValue("h", Rcode::RESERVED11_CODE));
-    addClassVariable(rcode_type, "RESERVED12_CODE",
-                     Py_BuildValue("h", Rcode::RESERVED12_CODE));
-    addClassVariable(rcode_type, "RESERVED13_CODE",
-                     Py_BuildValue("h", Rcode::RESERVED13_CODE));
-    addClassVariable(rcode_type, "RESERVED14_CODE",
-                     Py_BuildValue("h", Rcode::RESERVED14_CODE));
-    addClassVariable(rcode_type, "RESERVED15_CODE",
-                     Py_BuildValue("h", Rcode::RESERVED15_CODE));
-    addClassVariable(rcode_type, "BADVERS_CODE",
-                     Py_BuildValue("h", Rcode::BADVERS_CODE));
+    try {
+        installClassVariable(rcode_type, "NOERROR_CODE",
+                             Py_BuildValue("h", Rcode::NOERROR_CODE));
+        installClassVariable(rcode_type, "FORMERR_CODE",
+                             Py_BuildValue("h", Rcode::FORMERR_CODE));
+        installClassVariable(rcode_type, "SERVFAIL_CODE",
+                             Py_BuildValue("h", Rcode::SERVFAIL_CODE));
+        installClassVariable(rcode_type, "NXDOMAIN_CODE",
+                             Py_BuildValue("h", Rcode::NXDOMAIN_CODE));
+        installClassVariable(rcode_type, "NOTIMP_CODE",
+                             Py_BuildValue("h", Rcode::NOTIMP_CODE));
+        installClassVariable(rcode_type, "REFUSED_CODE",
+                             Py_BuildValue("h", Rcode::REFUSED_CODE));
+        installClassVariable(rcode_type, "YXDOMAIN_CODE",
+                             Py_BuildValue("h", Rcode::YXDOMAIN_CODE));
+        installClassVariable(rcode_type, "YXRRSET_CODE",
+                             Py_BuildValue("h", Rcode::YXRRSET_CODE));
+        installClassVariable(rcode_type, "NXRRSET_CODE",
+                             Py_BuildValue("h", Rcode::NXRRSET_CODE));
+        installClassVariable(rcode_type, "NOTAUTH_CODE",
+                             Py_BuildValue("h", Rcode::NOTAUTH_CODE));
+        installClassVariable(rcode_type, "NOTZONE_CODE",
+                             Py_BuildValue("h", Rcode::NOTZONE_CODE));
+        installClassVariable(rcode_type, "RESERVED11_CODE",
+                             Py_BuildValue("h", Rcode::RESERVED11_CODE));
+        installClassVariable(rcode_type, "RESERVED12_CODE",
+                             Py_BuildValue("h", Rcode::RESERVED12_CODE));
+        installClassVariable(rcode_type, "RESERVED13_CODE",
+                             Py_BuildValue("h", Rcode::RESERVED13_CODE));
+        installClassVariable(rcode_type, "RESERVED14_CODE",
+                             Py_BuildValue("h", Rcode::RESERVED14_CODE));
+        installClassVariable(rcode_type, "RESERVED15_CODE",
+                             Py_BuildValue("h", Rcode::RESERVED15_CODE));
+        installClassVariable(rcode_type, "BADVERS_CODE",
+                             Py_BuildValue("h", Rcode::BADVERS_CODE));
+
+        installClassVariable(rcode_type, "NOERROR",
+                             createRcodeObject(Rcode::NOERROR()));
+        installClassVariable(rcode_type, "FORMERR",
+                             createRcodeObject(Rcode::FORMERR()));
+        installClassVariable(rcode_type, "SERVFAIL",
+                             createRcodeObject(Rcode::SERVFAIL()));
+        installClassVariable(rcode_type, "NXDOMAIN",
+                             createRcodeObject(Rcode::NXDOMAIN()));
+        installClassVariable(rcode_type, "NOTIMP",
+                             createRcodeObject(Rcode::NOTIMP()));
+        installClassVariable(rcode_type, "REFUSED",
+                             createRcodeObject(Rcode::REFUSED()));
+        installClassVariable(rcode_type, "YXDOMAIN",
+                             createRcodeObject(Rcode::YXDOMAIN()));
+        installClassVariable(rcode_type, "YXRRSET",
+                             createRcodeObject(Rcode::YXRRSET()));
+        installClassVariable(rcode_type, "NXRRSET",
+                             createRcodeObject(Rcode::NXRRSET()));
+        installClassVariable(rcode_type, "NOTAUTH",
+                             createRcodeObject(Rcode::NOTAUTH()));
+        installClassVariable(rcode_type, "NOTZONE",
+                             createRcodeObject(Rcode::NOTZONE()));
+        installClassVariable(rcode_type, "RESERVED11",
+                             createRcodeObject(Rcode::RESERVED11()));
+        installClassVariable(rcode_type, "RESERVED12",
+                             createRcodeObject(Rcode::RESERVED12()));
+        installClassVariable(rcode_type, "RESERVED13",
+                             createRcodeObject(Rcode::RESERVED13()));
+        installClassVariable(rcode_type, "RESERVED14",
+                             createRcodeObject(Rcode::RESERVED14()));
+        installClassVariable(rcode_type, "RESERVED15",
+                             createRcodeObject(Rcode::RESERVED15()));
+        installClassVariable(rcode_type, "BADVERS",
+                             createRcodeObject(Rcode::BADVERS()));
+    } catch (const std::exception& ex) {
+        const std::string ex_what =
+            "Unexpected failure in Rcode initialization: " +
+            std::string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in Rcode initialization");
+        return (false);
+    }
 
     return (true);
 }
@@ -432,6 +524,9 @@ initModulePart_RRClass(PyObject* mod) {
                                                   NULL, NULL);
         PyObjectContainer(po_IncompleteRRClass).installToModule(
             mod, "IncompleteRRClass");
+
+        // Incorporate auto-generated RRClass constants
+#include <dns/python/rrclass_constants_inc.cc>
     } catch (const std::exception& ex) {
         const std::string ex_what =
             "Unexpected failure in RRClass initialization: " +
@@ -518,6 +613,9 @@ initModulePart_RRType(PyObject* mod) {
                                                  NULL, NULL);
         PyObjectContainer(po_IncompleteRRType).installToModule(
             mod, "IncompleteRRType");
+
+        // Incorporate auto-generated RRType constants
+#include <dns/python/rrtype_constants_inc.cc>
     } catch (const std::exception& ex) {
         const std::string ex_what =
             "Unexpected failure in RRType initialization: " +
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
index 42b48e7..67b45e7 100644
--- a/src/lib/dns/python/rcode_python.cc
+++ b/src/lib/dns/python/rcode_python.cc
@@ -55,23 +55,6 @@ PyObject* Rcode_getCode(const s_Rcode* const self);
 PyObject* Rcode_getExtendedCode(const s_Rcode* const self);
 PyObject* Rcode_toText(const s_Rcode* const self);
 PyObject* Rcode_str(PyObject* self);
-PyObject* Rcode_NOERROR(const s_Rcode* self);
-PyObject* Rcode_FORMERR(const s_Rcode* self);
-PyObject* Rcode_SERVFAIL(const s_Rcode* self);
-PyObject* Rcode_NXDOMAIN(const s_Rcode* self);
-PyObject* Rcode_NOTIMP(const s_Rcode* self);
-PyObject* Rcode_REFUSED(const s_Rcode* self);
-PyObject* Rcode_YXDOMAIN(const s_Rcode* self);
-PyObject* Rcode_YXRRSET(const s_Rcode* self);
-PyObject* Rcode_NXRRSET(const s_Rcode* self);
-PyObject* Rcode_NOTAUTH(const s_Rcode* self);
-PyObject* Rcode_NOTZONE(const s_Rcode* self);
-PyObject* Rcode_RESERVED11(const s_Rcode* self);
-PyObject* Rcode_RESERVED12(const s_Rcode* self);
-PyObject* Rcode_RESERVED13(const s_Rcode* self);
-PyObject* Rcode_RESERVED14(const s_Rcode* self);
-PyObject* Rcode_RESERVED15(const s_Rcode* self);
-PyObject* Rcode_BADVERS(const s_Rcode* self);
 PyObject* Rcode_richcmp(const s_Rcode* const self,
                          const s_Rcode* const other, int op);
 
@@ -83,40 +66,6 @@ PyMethodDef Rcode_methods[] = {
       "Returns the upper 8-bit part of the extended code value" },
     { "to_text", reinterpret_cast<PyCFunction>(Rcode_toText), METH_NOARGS,
       "Returns the text representation" },
-    { "NOERROR", reinterpret_cast<PyCFunction>(Rcode_NOERROR),
-      METH_NOARGS | METH_STATIC, "Creates a NOERROR Rcode" },
-    { "FORMERR", reinterpret_cast<PyCFunction>(Rcode_FORMERR),
-      METH_NOARGS | METH_STATIC, "Creates a FORMERR Rcode" },
-    { "SERVFAIL", reinterpret_cast<PyCFunction>(Rcode_SERVFAIL),
-      METH_NOARGS | METH_STATIC, "Creates a SERVFAIL Rcode" },
-    { "NXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_NXDOMAIN),
-      METH_NOARGS | METH_STATIC, "Creates a NXDOMAIN Rcode" },
-    { "NOTIMP", reinterpret_cast<PyCFunction>(Rcode_NOTIMP),
-      METH_NOARGS | METH_STATIC, "Creates a NOTIMP Rcode" },
-    { "REFUSED", reinterpret_cast<PyCFunction>(Rcode_REFUSED),
-      METH_NOARGS | METH_STATIC, "Creates a REFUSED Rcode" },
-    { "YXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_YXDOMAIN),
-      METH_NOARGS | METH_STATIC, "Creates a YXDOMAIN Rcode" },
-    { "YXRRSET", reinterpret_cast<PyCFunction>(Rcode_YXRRSET),
-      METH_NOARGS | METH_STATIC, "Creates a YYRRSET Rcode" },
-    { "NXRRSET", reinterpret_cast<PyCFunction>(Rcode_NXRRSET),
-      METH_NOARGS | METH_STATIC, "Creates a NXRRSET Rcode" },
-    { "NOTAUTH", reinterpret_cast<PyCFunction>(Rcode_NOTAUTH),
-      METH_NOARGS | METH_STATIC, "Creates a NOTAUTH Rcode" },
-    { "NOTZONE", reinterpret_cast<PyCFunction>(Rcode_NOTZONE),
-      METH_NOARGS | METH_STATIC, "Creates a NOTZONE Rcode" },
-    { "RESERVED11", reinterpret_cast<PyCFunction>(Rcode_RESERVED11),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED11 Rcode" },
-    { "RESERVED12", reinterpret_cast<PyCFunction>(Rcode_RESERVED12),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED12 Rcode" },
-    { "RESERVED13", reinterpret_cast<PyCFunction>(Rcode_RESERVED13),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED13 Rcode" },
-    { "RESERVED14", reinterpret_cast<PyCFunction>(Rcode_RESERVED14),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED14 Rcode" },
-    { "RESERVED15", reinterpret_cast<PyCFunction>(Rcode_RESERVED15),
-      METH_NOARGS | METH_STATIC, "Creates a RESERVED15 Rcode" },
-    { "BADVERS", reinterpret_cast<PyCFunction>(Rcode_BADVERS),
-      METH_NOARGS | METH_STATIC, "Creates a BADVERS Rcode" },
     { NULL, NULL, 0, NULL }
 };
 
@@ -193,101 +142,6 @@ Rcode_str(PyObject* self) {
 }
 
 PyObject*
-Rcode_createStatic(const Rcode& rcode) {
-    s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
-    if (ret != NULL) {
-        ret->cppobj = &rcode;
-        ret->static_code = true;
-    }
-    return (ret);
-}
-
-PyObject*
-Rcode_NOERROR(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NOERROR()));
-}
-
-PyObject*
-Rcode_FORMERR(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::FORMERR()));
-}
-
-PyObject*
-Rcode_SERVFAIL(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::SERVFAIL()));
-}
-
-PyObject*
-Rcode_NXDOMAIN(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NXDOMAIN()));
-}
-
-PyObject*
-Rcode_NOTIMP(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NOTIMP()));
-}
-
-PyObject*
-Rcode_REFUSED(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::REFUSED()));
-}
-
-PyObject*
-Rcode_YXDOMAIN(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::YXDOMAIN()));
-}
-
-PyObject*
-Rcode_YXRRSET(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::YXRRSET()));
-}
-
-PyObject*
-Rcode_NXRRSET(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NXRRSET()));
-}
-
-PyObject*
-Rcode_NOTAUTH(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NOTAUTH()));
-}
-
-PyObject*
-Rcode_NOTZONE(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::NOTZONE()));
-}
-
-PyObject*
-Rcode_RESERVED11(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::RESERVED11()));
-}
-
-PyObject*
-Rcode_RESERVED12(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::RESERVED12()));
-}
-
-PyObject*
-Rcode_RESERVED13(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::RESERVED13()));
-}
-
-PyObject*
-Rcode_RESERVED14(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::RESERVED14()));
-}
-
-PyObject*
-Rcode_RESERVED15(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::RESERVED15()));
-}
-
-PyObject*
-Rcode_BADVERS(const s_Rcode*) {
-    return (Rcode_createStatic(Rcode::BADVERS()));
-}
-
-PyObject*
 Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
               const int op)
 {
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index a566f47..d62c88d 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -54,13 +54,6 @@ PyObject* RRClass_getCode(s_RRClass* self);
 PyObject* RRClass_richcmp(s_RRClass* self, s_RRClass* other, int op);
 Py_hash_t RRClass_hash(PyObject* pyself);
 
-// Static function for direct class creation
-PyObject* RRClass_IN(s_RRClass *self);
-PyObject* RRClass_CH(s_RRClass *self);
-PyObject* RRClass_HS(s_RRClass *self);
-PyObject* RRClass_NONE(s_RRClass *self);
-PyObject* RRClass_ANY(s_RRClass *self);
-
 typedef CPPPyObjectContainer<s_RRClass, RRClass> RRClassContainer;
 
 // This list contains the actual set of functions we have in
@@ -81,11 +74,6 @@ PyMethodDef RRClass_methods[] = {
       "returned" },
     { "get_code", reinterpret_cast<PyCFunction>(RRClass_getCode), METH_NOARGS,
       "Returns the class code as an integer" },
-    { "IN", reinterpret_cast<PyCFunction>(RRClass_IN), METH_NOARGS | METH_STATIC, "Creates an IN RRClass" },
-    { "CH", reinterpret_cast<PyCFunction>(RRClass_CH), METH_NOARGS | METH_STATIC, "Creates a CH RRClass" },
-    { "HS", reinterpret_cast<PyCFunction>(RRClass_HS), METH_NOARGS | METH_STATIC, "Creates an HS RRClass" },
-    { "NONE", reinterpret_cast<PyCFunction>(RRClass_NONE), METH_NOARGS | METH_STATIC, "Creates a NONE RRClass" },
-    { "ANY", reinterpret_cast<PyCFunction>(RRClass_ANY), METH_NOARGS | METH_STATIC, "Creates an ANY RRClass" },
     { NULL, NULL, 0, NULL }
 };
 
@@ -234,37 +222,6 @@ RRClass_richcmp(s_RRClass* self, s_RRClass* other, int op) {
         Py_RETURN_FALSE;
 }
 
-//
-// Common function for RRClass_IN/CH/etc.
-//
-PyObject* RRClass_createStatic(RRClass stc) {
-    s_RRClass* ret = PyObject_New(s_RRClass, &rrclass_type);
-    if (ret != NULL) {
-        ret->cppobj = new RRClass(stc);
-    }
-    return (ret);
-}
-
-PyObject* RRClass_IN(s_RRClass*) {
-    return (RRClass_createStatic(RRClass::IN()));
-}
-
-PyObject* RRClass_CH(s_RRClass*) {
-    return (RRClass_createStatic(RRClass::CH()));
-}
-
-PyObject* RRClass_HS(s_RRClass*) {
-    return (RRClass_createStatic(RRClass::HS()));
-}
-
-PyObject* RRClass_NONE(s_RRClass*) {
-    return (RRClass_createStatic(RRClass::NONE()));
-}
-
-PyObject* RRClass_ANY(s_RRClass*) {
-    return (RRClass_createStatic(RRClass::ANY()));
-}
-
 Py_hash_t
 RRClass_hash(PyObject* pyself) {
     const s_RRClass* const self = static_cast<s_RRClass*>(pyself);
diff --git a/src/lib/dns/python/rrset_collection_python.cc b/src/lib/dns/python/rrset_collection_python.cc
index df313f7..cfdcdae 100644
--- a/src/lib/dns/python/rrset_collection_python.cc
+++ b/src/lib/dns/python/rrset_collection_python.cc
@@ -55,10 +55,23 @@ setTypeError(PyObject* pobj, const char* var_name, const char* type_name) {
 }
 }
 
+// RRsetCollectionBase: the base RRsetCollection class in Python.
 //
-// RRsetCollectionBase
-//
-
+// Any derived RRsetCollection class is supposed to be inherited from this
+// class:
+// - If the derived class is implemented via a C++ wrapper (associated with
+//   a C++ implementation of RRsetCollection), its PyTypeObject should
+//   specify rrset_collection_base_type for tp_base.  Its C/C++-representation
+//   of objects should be compatible with s_RRsetCollection, and the wrapper
+//   should set its cppobj member to point to the corresponding C++
+//   RRsetCollection object.  Normally it doesn't have to provide Python
+//   wrapper of find(); the Python interpreter will then call find() on
+//   the base class, which ensures that the corresponding C++ version of
+//   find() will be used.
+// - If the derived class is implemented purely in Python, it must implement
+//   find() in Python within the class.  As explained in the first bullet,
+//   the base class method is generally expected to be used only for C++
+//   wrapper of RRsetCollection derived class.
 namespace {
 int
 RRsetCollectionBase_init(PyObject*, PyObject*, PyObject*) {
@@ -70,8 +83,13 @@ RRsetCollectionBase_init(PyObject*, PyObject*, PyObject*) {
 void
 RRsetCollectionBase_destroy(PyObject* po_self) {
     s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
-    delete self->cppobj;
-    self->cppobj = NULL;
+
+    // Any C++-wrapper of derived RRsetCollection class should have its own
+    // destroy function (as it may manage cppobj in its own way);
+    // Python-only derived classes shouldn't set cppobj (which is
+    // 0-initialized).  So this assertion must hold.
+    assert(self->cppobj == NULL);
+
     Py_TYPE(self)->tp_free(self);
 }
 
@@ -79,6 +97,9 @@ PyObject*
 RRsetCollectionBase_find(PyObject* po_self, PyObject* args) {
     s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
 
+    // If this function is called with cppobj being NULL, this means
+    // a pure-Python derived class skips implementing its own find().
+    // This is an error (see general description above).
     if (self->cppobj == NULL) {
         PyErr_Format(PyExc_TypeError, "find() is not implemented in the "
                      "derived RRsetCollection class");
@@ -108,6 +129,9 @@ RRsetCollectionBase_find(PyObject* po_self, PyObject* args) {
             }
             Py_RETURN_NONE;
         }
+    } catch (const RRsetCollectionError& ex) {
+        PyErr_SetString(po_RRsetCollectionError, ex.what());
+        return (NULL);
     } catch (const std::exception& ex) {
         const string ex_what = "Unexpected failure in "
             "RRsetCollectionBase.find: " + string(ex.what());
@@ -137,6 +161,9 @@ PyMethodDef RRsetCollectionBase_methods[] = {
 namespace isc {
 namespace dns {
 namespace python {
+// Definition of class specific exception(s)
+PyObject* po_RRsetCollectionError;
+
 // This defines the complete type for reflection in python and
 // parsing of PyObject* to s_RRsetCollection
 // Most of the functions are not actually implemented and NULL here.
@@ -193,18 +220,27 @@ PyTypeObject rrset_collection_base_type = {
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_RRsetCollectionBase(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(&rrset_collection_base_type) < 0) {
+    if (!initClass(rrset_collection_base_type, "RRsetCollectionBase", mod)) {
         return (false);
     }
-    void* p = &rrset_collection_base_type;
-    if (PyModule_AddObject(mod, "RRsetCollectionBase",
-                           static_cast<PyObject*>(p)) < 0) {
+
+    try {
+        po_RRsetCollectionError =
+            PyErr_NewException("dns.RRsetCollectionError",
+                               po_IscException, NULL);
+        PyObjectContainer(po_RRsetCollectionError).installToModule(
+            mod, "RRsetCollectionError");
+    } catch (const std::exception& ex) {
+        const std::string ex_what =
+            "Unexpected failure in RRsetCollectionBase initialization: " +
+            std::string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "RRsetCollectionBase initialization");
         return (false);
     }
-    Py_INCREF(&rrset_collection_base_type);
 
     return (true);
 }
@@ -405,18 +441,9 @@ PyTypeObject rrset_collection_type = {
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_RRsetCollection(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(&rrset_collection_type) < 0) {
-        return (false);
-    }
-    void* p = &rrset_collection_type;
-    if (PyModule_AddObject(mod, "RRsetCollection",
-                           static_cast<PyObject*>(p)) < 0) {
+    if (!initClass(rrset_collection_type, "RRsetCollection", mod)) {
         return (false);
     }
-    Py_INCREF(&rrset_collection_type);
 
     return (true);
 }
diff --git a/src/lib/dns/python/rrset_collection_python.h b/src/lib/dns/python/rrset_collection_python.h
index 98cb84b..ea442bb 100644
--- a/src/lib/dns/python/rrset_collection_python.h
+++ b/src/lib/dns/python/rrset_collection_python.h
@@ -23,10 +23,13 @@ class RRsetCollectionBase;
 
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
+// The s_* Class simply covers one instantiation of the object.
 // This structure will be commonly used for all derived classes of
 // RRsetCollectionBase.  cppobj will point to an instance of the specific
-// derived class.
+// derived class of (C++) RRsetCollectionBase.
+//
+// A C++ wrapper for Python version of RRsetCollection should set this
+// variable, and skip the implementation of C++ wrapper of find() method.
 class s_RRsetCollection : public PyObject {
 public:
     s_RRsetCollection() : cppobj(NULL) {}
@@ -39,6 +42,9 @@ extern PyTypeObject rrset_collection_base_type;
 // Python type information for dns.RRsetCollection
 extern PyTypeObject rrset_collection_type;
 
+// Class specific exceptions
+extern PyObject* po_RRsetCollectionError;
+
 bool initModulePart_RRsetCollectionBase(PyObject* mod);
 bool initModulePart_RRsetCollection(PyObject* mod);
 
diff --git a/src/lib/dns/python/rrset_collection_python_inc.cc b/src/lib/dns/python/rrset_collection_python_inc.cc
index 5c1e532..baf8ec8 100644
--- a/src/lib/dns/python/rrset_collection_python_inc.cc
+++ b/src/lib/dns/python/rrset_collection_python_inc.cc
@@ -1,7 +1,7 @@
 namespace {
 // Modifications
 //   - libdns++ => isc.dns, libdatasrc => isc.datasrc
-//   - note about the constructor.
+//   - note about the direct construction.
 //   - add note about iteration
 const char* const RRsetCollectionBase_doc = "\
 Generic class to represent a set of RRsets.\n\
@@ -18,8 +18,8 @@ maybe class) and a way to iterate over all RRsets.\n\
 See RRsetCollection for a simple isc.dns implementation. Other modules\n\
 such as isc.datasrc will have another implementation.\n\
 \n\
-This base class cannot be directly instantiated, so no constructor is\n\
-defined.\n\
+This base class cannot be directly instantiated.  Such an attempt will\n\
+result in a TypeError exception.\n\
 \n\
 ";
 
@@ -36,6 +36,41 @@ Returns the RRset in the collection that exactly matches the given\n\
 name, rrclass and rrtype. If no matching RRset is found, None is\n\
 returned.\n\
 \n\
+This method's implementations currently are not specified to handle\n\
+RRTypes such as RRSIG and NSEC3. This interface may be refined to\n\
+clarify this point in the future, and perhaps, provide additional API\n\
+for these RRType.\n\
+\n\
+As for RRSIG, there are some fundamental open questions. For example,\n\
+it's not clear whether we want to return all RRSIGs of the given name\n\
+covering any RR types (in which case, we need to figure out how), or\n\
+we need to extend the interface so we can specify the covered type. A\n\
+specific derived implementation may return something if type RRSIG is\n\
+specified, but this is not specified here at the base class level. So,\n\
+for RRSIGs the behavior should be assumed as undefined.\n\
+\n\
+As for NSEC3, it's not clear whether owner names (which included\n\
+hashed labels) are the best choice of search key, because in many\n\
+cases, what the application wants to find is an NSEC3 that has the\n\
+hash of some particular \"normal\" domain names. Also, if the\n\
+underlying implementation encapsulates a single zone, NSEC3 records\n\
+conceptually belong to a separate name space, which may cause\n\
+implementation difficulty.\n\
+\n\
+Behavior with meta types such as ANY and AXFR are also undefined. A\n\
+specific implementation may return something for these. But, unlike\n\
+the case of RRSIGs, these types of RRsets are not expected to be added\n\
+to any implementation of collection in the first place (by the\n\
+definition of \"meta types\"), so querying for such types is\n\
+basically an invalid operation. The API doesn't require\n\
+implementations to check this condition and reject it, so the behavior\n\
+is undefined. This interface will not be refined in future versions\n\
+for these meta types.\n\
+\n\
+Exceptions:\n\
+  RRsetCollectionError if find() results in some implementation-\n\
+             specific error.\n\
+\n\
 Parameters:\n\
   name       (isc.dns.Name) The name of the RRset to search for.\n\
   rrtype     (isc.dns.RRType) The type of the RRset to search for.\n\
@@ -79,18 +114,18 @@ RRsetCollection(filename, origin, rrclass)\n\
       origin     (isc.dns.Name) The zone origin.\n\
       rrclass    (isc.dns.RRClass) The zone class.\n\
 \n\
-RRsetCollection(input_stream, origin, rrclass)\n\
+RRsetCollection(input, origin, rrclass)\n\
 \n\
     Constructor.\n\
 \n\
     This constructor is similar to the previous one, but instead of\n\
-    taking a filename to load a zone from, it takes a byte object,\n\
+    taking a filename to load a zone from, it takes a bytes object,\n\
     representing the zone contents in text.\n\
     The constructor throws IscException if there is an error\n\
     during loading.\n\
 \n\
     Parameters:\n\
-      input      (byte) Textual representation of the zone.\n\
+      input      (bytes) Textual representation of the zone.\n\
       origin     (isc.dns.Name) The zone origin.\n\
       rrclass    (isc.dns.RRClass) The zone class.\n\
 \n\
@@ -121,7 +156,7 @@ find(name, rrclass, rrtype) -> isc.dns.RRset\n\
 Find a matching RRset in the collection.\n\
 \n\
 Returns the RRset in the collection that exactly matches the given\n\
-name, rrclass and rrtype. If no matching RRset is found, NULL is\n\
+name, rrclass and rrtype. If no matching RRset is found, None is\n\
 returned.\n\
 \n\
 Parameters:\n\
@@ -129,7 +164,7 @@ Parameters:\n\
   rrclass    The class of the RRset to search for.\n\
   rrtype     The type of the RRset to search for.\n\
 \n\
-Return Value(s): The RRset if found, NULL otherwise.\n\
+Return Value(s): The RRset if found, None otherwise.\n\
 ";
 
 // Modifications
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index 97b66d4..bf705cc 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -50,25 +50,6 @@ PyObject* RRType_toWire(s_RRType* self, PyObject* args);
 PyObject* RRType_getCode(s_RRType* self);
 PyObject* RRType_richcmp(s_RRType* self, s_RRType* other, int op);
 Py_hash_t RRType_hash(PyObject* pyself);
-PyObject* RRType_NSEC3PARAM(s_RRType *self);
-PyObject* RRType_DNAME(s_RRType *self);
-PyObject* RRType_PTR(s_RRType *self);
-PyObject* RRType_MX(s_RRType *self);
-PyObject* RRType_DNSKEY(s_RRType *self);
-PyObject* RRType_TXT(s_RRType *self);
-PyObject* RRType_RRSIG(s_RRType *self);
-PyObject* RRType_NSEC(s_RRType *self);
-PyObject* RRType_AAAA(s_RRType *self);
-PyObject* RRType_DS(s_RRType *self);
-PyObject* RRType_OPT(s_RRType *self);
-PyObject* RRType_A(s_RRType *self);
-PyObject* RRType_NS(s_RRType *self);
-PyObject* RRType_CNAME(s_RRType *self);
-PyObject* RRType_SOA(s_RRType *self);
-PyObject* RRType_NSEC3(s_RRType *self);
-PyObject* RRType_IXFR(s_RRType *self);
-PyObject* RRType_AXFR(s_RRType *self);
-PyObject* RRType_ANY(s_RRType *self);
 
 typedef CPPPyObjectContainer<s_RRType, RRType> RRTypeContainer;
 
@@ -90,25 +71,6 @@ PyMethodDef RRType_methods[] = {
       "returned" },
     { "get_code", reinterpret_cast<PyCFunction>(RRType_getCode), METH_NOARGS,
       "Returns the type code as an integer" },
-    { "NSEC3PARAM", reinterpret_cast<PyCFunction>(RRType_NSEC3PARAM), METH_NOARGS | METH_STATIC, "Creates an NSEC3PARAM RRType" },
-    { "DNAME", reinterpret_cast<PyCFunction>(RRType_DNAME), METH_NOARGS | METH_STATIC, "Creates a DNAME RRType" },
-    { "PTR", reinterpret_cast<PyCFunction>(RRType_PTR), METH_NOARGS | METH_STATIC, "Creates a PTR RRType" },
-    { "MX", reinterpret_cast<PyCFunction>(RRType_MX), METH_NOARGS | METH_STATIC, "Creates an MX RRType" },
-    { "DNSKEY", reinterpret_cast<PyCFunction>(RRType_DNSKEY), METH_NOARGS | METH_STATIC, "Creates a DNSKEY RRType" },
-    { "TXT", reinterpret_cast<PyCFunction>(RRType_TXT), METH_NOARGS | METH_STATIC, "Creates a TXT RRType" },
-    { "RRSIG", reinterpret_cast<PyCFunction>(RRType_RRSIG), METH_NOARGS | METH_STATIC, "Creates a RRSIG RRType" },
-    { "NSEC", reinterpret_cast<PyCFunction>(RRType_NSEC), METH_NOARGS | METH_STATIC, "Creates a NSEC RRType" },
-    { "AAAA", reinterpret_cast<PyCFunction>(RRType_AAAA), METH_NOARGS | METH_STATIC, "Creates an AAAA RRType" },
-    { "DS", reinterpret_cast<PyCFunction>(RRType_DS), METH_NOARGS | METH_STATIC, "Creates a DS RRType" },
-    { "OPT", reinterpret_cast<PyCFunction>(RRType_OPT), METH_NOARGS | METH_STATIC, "Creates an OPT RRType" },
-    { "A", reinterpret_cast<PyCFunction>(RRType_A), METH_NOARGS | METH_STATIC, "Creates an A RRType" },
-    { "NS", reinterpret_cast<PyCFunction>(RRType_NS), METH_NOARGS | METH_STATIC, "Creates an NS RRType" },
-    { "CNAME", reinterpret_cast<PyCFunction>(RRType_CNAME), METH_NOARGS | METH_STATIC, "Creates a CNAME RRType" },
-    { "SOA", reinterpret_cast<PyCFunction>(RRType_SOA), METH_NOARGS | METH_STATIC, "Creates a SOA RRType" },
-    { "NSEC3", reinterpret_cast<PyCFunction>(RRType_NSEC3), METH_NOARGS | METH_STATIC, "Creates an NSEC3 RRType" },
-    { "IXFR", reinterpret_cast<PyCFunction>(RRType_IXFR), METH_NOARGS | METH_STATIC, "Creates an IXFR RRType" },
-    { "AXFR", reinterpret_cast<PyCFunction>(RRType_AXFR), METH_NOARGS | METH_STATIC, "Creates an AXFR RRType" },
-    { "ANY", reinterpret_cast<PyCFunction>(RRType_ANY), METH_NOARGS | METH_STATIC, "Creates an ANY RRType" },
     { NULL, NULL, 0, NULL }
 };
 
@@ -263,112 +225,6 @@ RRType_richcmp(s_RRType* self, s_RRType* other, int op) {
         Py_RETURN_FALSE;
 }
 
-//
-// Common function for RRType_A/NS/etc.
-//
-PyObject* RRType_createStatic(RRType stc) {
-    s_RRType* ret = PyObject_New(s_RRType, &rrtype_type);
-    if (ret != NULL) {
-        ret->cppobj = new RRType(stc);
-    }
-    return (ret);
-}
-
-PyObject*
-RRType_NSEC3PARAM(s_RRType*) {
-    return (RRType_createStatic(RRType::NSEC3PARAM()));
-}
-
-PyObject*
-RRType_DNAME(s_RRType*) {
-    return (RRType_createStatic(RRType::DNAME()));
-}
-
-PyObject*
-RRType_PTR(s_RRType*) {
-    return (RRType_createStatic(RRType::PTR()));
-}
-
-PyObject*
-RRType_MX(s_RRType*) {
-    return (RRType_createStatic(RRType::MX()));
-}
-
-PyObject*
-RRType_DNSKEY(s_RRType*) {
-    return (RRType_createStatic(RRType::DNSKEY()));
-}
-
-PyObject*
-RRType_TXT(s_RRType*) {
-    return (RRType_createStatic(RRType::TXT()));
-}
-
-PyObject*
-RRType_RRSIG(s_RRType*) {
-    return (RRType_createStatic(RRType::RRSIG()));
-}
-
-PyObject*
-RRType_NSEC(s_RRType*) {
-    return (RRType_createStatic(RRType::NSEC()));
-}
-
-PyObject*
-RRType_AAAA(s_RRType*) {
-    return (RRType_createStatic(RRType::AAAA()));
-}
-
-PyObject*
-RRType_DS(s_RRType*) {
-    return (RRType_createStatic(RRType::DS()));
-}
-
-PyObject*
-RRType_OPT(s_RRType*) {
-    return (RRType_createStatic(RRType::OPT()));
-}
-
-PyObject*
-RRType_A(s_RRType*) {
-    return (RRType_createStatic(RRType::A()));
-}
-
-PyObject*
-RRType_NS(s_RRType*) {
-    return (RRType_createStatic(RRType::NS()));
-}
-
-PyObject*
-RRType_CNAME(s_RRType*) {
-    return (RRType_createStatic(RRType::CNAME()));
-}
-
-PyObject*
-RRType_SOA(s_RRType*) {
-    return (RRType_createStatic(RRType::SOA()));
-}
-
-PyObject*
-RRType_NSEC3(s_RRType*) {
-    return (RRType_createStatic(RRType::NSEC3()));
-}
-
-PyObject*
-RRType_IXFR(s_RRType*) {
-    return (RRType_createStatic(RRType::IXFR()));
-}
-
-PyObject*
-RRType_AXFR(s_RRType*) {
-    return (RRType_createStatic(RRType::AXFR()));
-}
-
-PyObject*
-RRType_ANY(s_RRType*) {
-    return (RRType_createStatic(RRType::ANY()));
-}
-
 Py_hash_t
 RRType_hash(PyObject* pyself) {
     const s_RRType* const self = static_cast<s_RRType*>(pyself);
diff --git a/src/lib/dns/python/tests/edns_python_test.py b/src/lib/dns/python/tests/edns_python_test.py
index b249213..150dfd6 100644
--- a/src/lib/dns/python/tests/edns_python_test.py
+++ b/src/lib/dns/python/tests/edns_python_test.py
@@ -108,8 +108,8 @@ class EDNSTest(unittest.TestCase):
 
     def test_towire_renderer(self):
         renderer = MessageRenderer()
-        extrcode_noerror = Rcode.NOERROR().get_extended_code()
-        extrcode_badvers = Rcode.BADVERS().get_extended_code()
+        extrcode_noerror = Rcode.NOERROR.get_extended_code()
+        extrcode_badvers = Rcode.BADVERS.get_extended_code()
 
         self.assertEqual(1, self.edns_base.to_wire(renderer, extrcode_noerror))
         wiredata = read_wire_data("edns_toWire1.wire")
@@ -148,7 +148,7 @@ class EDNSTest(unittest.TestCase):
         self.assertEqual(0, renderer.get_length())
 
     def test_towire_buffer(self):
-        extrcode_noerror = Rcode.NOERROR().get_extended_code()
+        extrcode_noerror = Rcode.NOERROR.get_extended_code()
 
         obuffer = bytes()
         obuffer = self.edns_base.to_wire(obuffer, extrcode_noerror)
diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py
index b9c0d5c..bf39a83 100644
--- a/src/lib/dns/python/tests/message_python_test.py
+++ b/src/lib/dns/python/tests/message_python_test.py
@@ -59,8 +59,8 @@ LONG_TXT4 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef012
 def create_message():
     message_render = Message(Message.RENDER)
     message_render.set_qid(0x1035)
-    message_render.set_opcode(Opcode.QUERY())
-    message_render.set_rcode(Rcode.NOERROR())
+    message_render.set_opcode(Opcode.QUERY)
+    message_render.set_rcode(Rcode.NOERROR)
     message_render.set_header_flag(Message.HEADERFLAG_QR)
     message_render.set_header_flag(Message.HEADERFLAG_RD)
     message_render.set_header_flag(Message.HEADERFLAG_AA)
@@ -161,7 +161,7 @@ class MessageTest(unittest.TestCase):
     def test_set_rcode(self):
         self.assertRaises(TypeError, self.r.set_rcode, "wrong")
 
-        rcode = Rcode.BADVERS()
+        rcode = Rcode.BADVERS
         self.r.set_rcode(rcode)
         self.assertEqual(rcode, self.r.get_rcode())
 
@@ -173,7 +173,7 @@ class MessageTest(unittest.TestCase):
     def test_set_opcode(self):
         self.assertRaises(TypeError, self.r.set_opcode, "wrong")
 
-        opcode = Opcode.IQUERY()
+        opcode = Opcode.IQUERY
         self.r.set_opcode(opcode)
         self.assertEqual(opcode, self.r.get_opcode())
 
@@ -304,8 +304,8 @@ class MessageTest(unittest.TestCase):
         self.assertRaises(TypeError, self.r.clear, 3)
 
     def test_clear_question_section(self):
-        self.r.add_question(Question(Name("www.example.com"), RRClass.IN(),
-                                     RRType.A()))
+        self.r.add_question(Question(Name("www.example.com"), RRClass.IN,
+                                     RRType.A))
         self.assertEqual(1, self.r.get_rr_count(Message.SECTION_QUESTION))
         self.r.clear_section(Message.SECTION_QUESTION)
         self.assertEqual(0, self.r.get_rr_count(Message.SECTION_QUESTION))
@@ -336,19 +336,19 @@ class MessageTest(unittest.TestCase):
                          renderer.get_data())
 
     def test_to_wire_without_opcode(self):
-        self.r.set_rcode(Rcode.NOERROR())
+        self.r.set_rcode(Rcode.NOERROR)
         self.assertRaises(InvalidMessageOperation, self.r.to_wire,
                           MessageRenderer())
 
     def test_to_wire_without_rcode(self):
-        self.r.set_opcode(Opcode.QUERY())
+        self.r.set_opcode(Opcode.QUERY)
         self.assertRaises(InvalidMessageOperation, self.r.to_wire,
                           MessageRenderer())
 
     def __common_tsigmessage_setup(self, flags=[Message.HEADERFLAG_RD],
                                    rrtype=RRType("A"), answer_data=None):
-        self.r.set_opcode(Opcode.QUERY())
-        self.r.set_rcode(Rcode.NOERROR())
+        self.r.set_opcode(Opcode.QUERY)
+        self.r.set_rcode(Rcode.NOERROR)
         for flag in flags:
             self.r.set_header_flag(flag)
         if answer_data is not None:
@@ -407,8 +407,8 @@ class MessageTest(unittest.TestCase):
         self.__common_tsig_checks("message_toWire4.wire")
 
     def test_to_wire_tsig_truncation3(self):
-        self.r.set_opcode(Opcode.QUERY())
-        self.r.set_rcode(Rcode.NOERROR())
+        self.r.set_opcode(Opcode.QUERY)
+        self.r.set_rcode(Rcode.NOERROR)
         for i in range(1, 68):
             self.r.add_question(Question(Name("www.example.com"),
                                          RRClass("IN"), RRType(i)))
@@ -469,11 +469,11 @@ test.example.com. 3600 IN A 192.0.2.2
         self.assertEqual(msg_str, str(message_render))
 
     def test_to_text_without_opcode(self):
-        self.r.set_rcode(Rcode.NOERROR())
+        self.r.set_rcode(Rcode.NOERROR)
         self.assertRaises(InvalidMessageOperation, self.r.to_text)
 
     def test_to_text_without_rcode(self):
-        self.r.set_opcode(Opcode.QUERY())
+        self.r.set_opcode(Opcode.QUERY)
         self.assertRaises(InvalidMessageOperation, self.r.to_text)
 
     def test_from_wire(self):
@@ -488,8 +488,8 @@ test.example.com. 3600 IN A 192.0.2.2
         message_parse = Message(0)
         factoryFromFile(message_parse, "message_fromWire1")
         self.assertEqual(0x1035, message_parse.get_qid())
-        self.assertEqual(Opcode.QUERY(), message_parse.get_opcode())
-        self.assertEqual(Rcode.NOERROR(), message_parse.get_rcode())
+        self.assertEqual(Opcode.QUERY, message_parse.get_opcode())
+        self.assertEqual(Rcode.NOERROR, message_parse.get_rcode())
         self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_QR))
         self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_RD))
         self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_AA))
@@ -568,7 +568,7 @@ test.example.com. 3600 IN A 192.0.2.2
         # Extended Rcode = BADVERS
         message_parse = Message(Message.PARSE)
         factoryFromFile(message_parse, "message_fromWire10.wire")
-        self.assertEqual(Rcode.BADVERS(), message_parse.get_rcode())
+        self.assertEqual(Rcode.BADVERS, message_parse.get_rcode())
 
         # Maximum extended Rcode
         message_parse.clear(Message.PARSE)
diff --git a/src/lib/dns/python/tests/messagerenderer_python_test.py b/src/lib/dns/python/tests/messagerenderer_python_test.py
index 5362496..8d5f26f 100644
--- a/src/lib/dns/python/tests/messagerenderer_python_test.py
+++ b/src/lib/dns/python/tests/messagerenderer_python_test.py
@@ -31,8 +31,8 @@ class MessageRendererTest(unittest.TestCase):
 
         message = Message(Message.RENDER)
         message.set_qid(123)
-        message.set_opcode(Opcode.QUERY())
-        message.set_rcode(Rcode.NOERROR())
+        message.set_opcode(Opcode.QUERY)
+        message.set_rcode(Rcode.NOERROR)
         message.add_question(Question(name, c, t))
 
         self.message1 = message
@@ -40,8 +40,8 @@ class MessageRendererTest(unittest.TestCase):
         message.set_qid(123)
         message.set_header_flag(Message.HEADERFLAG_AA, True)
         message.set_header_flag(Message.HEADERFLAG_QR, True)
-        message.set_opcode(Opcode.QUERY())
-        message.set_rcode(Rcode.NOERROR())
+        message.set_opcode(Opcode.QUERY)
+        message.set_rcode(Rcode.NOERROR)
         message.add_question(Question(name, c, t))
         rrset = RRset(name, c, t, ttl)
         rrset.add_rdata(Rdata(t, c, "192.0.2.98"))
diff --git a/src/lib/dns/python/tests/nsec3hash_python_test.py b/src/lib/dns/python/tests/nsec3hash_python_test.py
index 1a247d0..320529a 100644
--- a/src/lib/dns/python/tests/nsec3hash_python_test.py
+++ b/src/lib/dns/python/tests/nsec3hash_python_test.py
@@ -24,9 +24,9 @@ class NSEC3HashTest(unittest.TestCase):
 
     def setUp(self):
         self.nsec3_common = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"
-        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM, RRClass.IN,
                                          "1 0 12 aabbccdd"))
-        self.test_hash_nsec3 = NSEC3Hash(Rdata(RRType.NSEC3(), RRClass.IN(),
+        self.test_hash_nsec3 = NSEC3Hash(Rdata(RRType.NSEC3, RRClass.IN,
                                                "1 0 12 aabbccdd " +
                                                self.nsec3_common))
     def test_bad_construct(self):
@@ -37,20 +37,20 @@ class NSEC3HashTest(unittest.TestCase):
         self.assertRaises(TypeError, NSEC3Hash, "1 0 12 aabbccdd")
 
         # additional parameter
-        self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.NSEC3PARAM(),
-                                                      RRClass.IN(),
+        self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.NSEC3PARAM,
+                                                      RRClass.IN,
                                                       "1 0 12 aabbccdd"), 1)
 
         # Invaid type of RDATA
-        self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.A(), RRClass.IN(),
+        self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.A, RRClass.IN,
                                                       "192.0.2.1"))
 
     def test_unknown_algorithm(self):
         self.assertRaises(UnknownNSEC3HashAlgorithm, NSEC3Hash,
-                          Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+                          Rdata(RRType.NSEC3PARAM, RRClass.IN,
                                 "2 0 12 aabbccdd"))
         self.assertRaises(UnknownNSEC3HashAlgorithm, NSEC3Hash,
-                          Rdata(RRType.NSEC3(), RRClass.IN(),
+                          Rdata(RRType.NSEC3, RRClass.IN,
                                 "2 0 12 aabbccdd " + self.nsec3_common))
 
     def calculate_check(self, hash):
@@ -71,15 +71,15 @@ class NSEC3HashTest(unittest.TestCase):
 
         # Using unusually large iterations, something larger than the 8-bit
         #range.  (expected hash value generated by BIND 9's dnssec-signzone)
-        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
-                                         RRClass.IN(), "1 0 256 AABBCCDD"))
+        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM,
+                                         RRClass.IN, "1 0 256 AABBCCDD"))
         self.assertEqual("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3",
                          self.test_hash.calculate(Name("example.org")))
 
         # Some boundary cases: 0-iteration and empty salt.  Borrowed from the
         # .com zone data.
-        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
-                                         RRClass.IN(),"1 0 0 -"))
+        self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM,
+                                         RRClass.IN,"1 0 0 -"))
         self.assertEqual("CK0POJMG874LJREF7EFN8430QVIT8BSM",
                          self.test_hash.calculate(Name("com")))
 
@@ -90,39 +90,39 @@ class NSEC3HashTest(unittest.TestCase):
 
     def check_match(self, hash, rrtype, postfix):
         # If all parameters match, it's considered to be matched.
-        self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN,
                                          "1 0 12 aabbccdd" + postfix)))
         # Algorithm doesn't match
-        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
                                           "2 0 12 aabbccdd" + postfix)))
         # Iterations doesn't match
-        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
                                           "1 0 1 aabbccdd" + postfix)))
         # Salt doesn't match
-        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
                                           "1 0 12 aabbccde" + postfix)))
         # Salt doesn't match: the other has an empty salt
-        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
                                           "1 0 12 -" + postfix)))
         # Flag doesn't matter
-        self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN(),
+        self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN,
                                          "1 1 12 aabbccdd" + postfix)))
 
     def test_match(self):
-        self.check_match(self.test_hash, RRType.NSEC3(),
+        self.check_match(self.test_hash, RRType.NSEC3,
                          " " + self.nsec3_common)
-        self.check_match(self.test_hash_nsec3, RRType.NSEC3(),
+        self.check_match(self.test_hash_nsec3, RRType.NSEC3,
                          " " + self.nsec3_common)
-        self.check_match(self.test_hash, RRType.NSEC3PARAM(), "")
-        self.check_match(self.test_hash_nsec3, RRType.NSEC3PARAM(), "")
+        self.check_match(self.test_hash, RRType.NSEC3PARAM, "")
+        self.check_match(self.test_hash_nsec3, RRType.NSEC3PARAM, "")
 
         # bad parameter checks
         self.assertRaises(TypeError, self.test_hash.match, 1)
         self.assertRaises(TypeError, self.test_hash.match,
-                          Rdata(RRType.NSEC3(), RRClass.IN(),
+                          Rdata(RRType.NSEC3, RRClass.IN,
                                 "1 0 12 aabbccdd " + self.nsec3_common), 1)
         self.assertRaises(TypeError, self.test_hash.match,
-                          Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
+                          Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/opcode_python_test.py b/src/lib/dns/python/tests/opcode_python_test.py
index 84f449f..d938aa6 100644
--- a/src/lib/dns/python/tests/opcode_python_test.py
+++ b/src/lib/dns/python/tests/opcode_python_test.py
@@ -34,53 +34,53 @@ class OpcodeTest(unittest.TestCase):
         self.assertEqual(Opcode.UPDATE_CODE, Opcode(5).get_code())
         self.assertEqual(Opcode.RESERVED15_CODE, Opcode(15).get_code())
 
-        self.assertEqual(Opcode.QUERY_CODE, Opcode.QUERY().get_code())
-        self.assertEqual(Opcode.IQUERY_CODE, Opcode.IQUERY().get_code())
-        self.assertEqual(Opcode.NOTIFY_CODE, Opcode.NOTIFY().get_code())
-        self.assertEqual(Opcode.UPDATE_CODE, Opcode.UPDATE().get_code())
-        self.assertEqual(Opcode.RESERVED15_CODE, Opcode.RESERVED15().get_code())
+        self.assertEqual(Opcode.QUERY_CODE, Opcode.QUERY.get_code())
+        self.assertEqual(Opcode.IQUERY_CODE, Opcode.IQUERY.get_code())
+        self.assertEqual(Opcode.NOTIFY_CODE, Opcode.NOTIFY.get_code())
+        self.assertEqual(Opcode.UPDATE_CODE, Opcode.UPDATE.get_code())
+        self.assertEqual(Opcode.RESERVED15_CODE, Opcode.RESERVED15.get_code())
 
     def test_get_code(self):
-        self.assertEqual(0, Opcode.QUERY().get_code())
-        self.assertEqual(1, Opcode.IQUERY().get_code())
-        self.assertEqual(2, Opcode.STATUS().get_code())
-        self.assertEqual(3, Opcode.RESERVED3().get_code())
-        self.assertEqual(4, Opcode.NOTIFY().get_code())
-        self.assertEqual(5, Opcode.UPDATE().get_code())
-        self.assertEqual(6, Opcode.RESERVED6().get_code())
-        self.assertEqual(7, Opcode.RESERVED7().get_code())
-        self.assertEqual(8, Opcode.RESERVED8().get_code())
-        self.assertEqual(9, Opcode.RESERVED9().get_code())
-        self.assertEqual(10, Opcode.RESERVED10().get_code())
-        self.assertEqual(11, Opcode.RESERVED11().get_code())
-        self.assertEqual(12, Opcode.RESERVED12().get_code())
-        self.assertEqual(13, Opcode.RESERVED13().get_code())
-        self.assertEqual(14, Opcode.RESERVED14().get_code())
-        self.assertEqual(15, Opcode.RESERVED15().get_code())
+        self.assertEqual(0, Opcode.QUERY.get_code())
+        self.assertEqual(1, Opcode.IQUERY.get_code())
+        self.assertEqual(2, Opcode.STATUS.get_code())
+        self.assertEqual(3, Opcode.RESERVED3.get_code())
+        self.assertEqual(4, Opcode.NOTIFY.get_code())
+        self.assertEqual(5, Opcode.UPDATE.get_code())
+        self.assertEqual(6, Opcode.RESERVED6.get_code())
+        self.assertEqual(7, Opcode.RESERVED7.get_code())
+        self.assertEqual(8, Opcode.RESERVED8.get_code())
+        self.assertEqual(9, Opcode.RESERVED9.get_code())
+        self.assertEqual(10, Opcode.RESERVED10.get_code())
+        self.assertEqual(11, Opcode.RESERVED11.get_code())
+        self.assertEqual(12, Opcode.RESERVED12.get_code())
+        self.assertEqual(13, Opcode.RESERVED13.get_code())
+        self.assertEqual(14, Opcode.RESERVED14.get_code())
+        self.assertEqual(15, Opcode.RESERVED15.get_code())
 
     def test_to_text(self):
-        self.assertEqual("QUERY", Opcode.QUERY().to_text())
-        self.assertEqual("QUERY", str(Opcode.QUERY()))
-        self.assertEqual("IQUERY", Opcode.IQUERY().to_text())
-        self.assertEqual("STATUS", Opcode.STATUS().to_text())
-        self.assertEqual("RESERVED3", Opcode.RESERVED3().to_text())
-        self.assertEqual("NOTIFY", Opcode.NOTIFY().to_text())
-        self.assertEqual("UPDATE", Opcode.UPDATE().to_text())
-        self.assertEqual("RESERVED6", Opcode.RESERVED6().to_text())
-        self.assertEqual("RESERVED7", Opcode.RESERVED7().to_text())
-        self.assertEqual("RESERVED8", Opcode.RESERVED8().to_text())
-        self.assertEqual("RESERVED9", Opcode.RESERVED9().to_text())
-        self.assertEqual("RESERVED10", Opcode.RESERVED10().to_text())
-        self.assertEqual("RESERVED11", Opcode.RESERVED11().to_text())
-        self.assertEqual("RESERVED12", Opcode.RESERVED12().to_text())
-        self.assertEqual("RESERVED13", Opcode.RESERVED13().to_text())
-        self.assertEqual("RESERVED14", Opcode.RESERVED14().to_text())
-        self.assertEqual("RESERVED15", Opcode.RESERVED15().to_text())
+        self.assertEqual("QUERY", Opcode.QUERY.to_text())
+        self.assertEqual("QUERY", str(Opcode.QUERY))
+        self.assertEqual("IQUERY", Opcode.IQUERY.to_text())
+        self.assertEqual("STATUS", Opcode.STATUS.to_text())
+        self.assertEqual("RESERVED3", Opcode.RESERVED3.to_text())
+        self.assertEqual("NOTIFY", Opcode.NOTIFY.to_text())
+        self.assertEqual("UPDATE", Opcode.UPDATE.to_text())
+        self.assertEqual("RESERVED6", Opcode.RESERVED6.to_text())
+        self.assertEqual("RESERVED7", Opcode.RESERVED7.to_text())
+        self.assertEqual("RESERVED8", Opcode.RESERVED8.to_text())
+        self.assertEqual("RESERVED9", Opcode.RESERVED9.to_text())
+        self.assertEqual("RESERVED10", Opcode.RESERVED10.to_text())
+        self.assertEqual("RESERVED11", Opcode.RESERVED11.to_text())
+        self.assertEqual("RESERVED12", Opcode.RESERVED12.to_text())
+        self.assertEqual("RESERVED13", Opcode.RESERVED13.to_text())
+        self.assertEqual("RESERVED14", Opcode.RESERVED14.to_text())
+        self.assertEqual("RESERVED15", Opcode.RESERVED15.to_text())
 
     def test_richcmp(self):
-        o1 = Opcode.QUERY()
-        o2 = Opcode.NOTIFY()
-        o3 = Opcode.NOTIFY()
+        o1 = Opcode.QUERY
+        o2 = Opcode.NOTIFY
+        o3 = Opcode.NOTIFY
         self.assertTrue(o2 == o3)
         self.assertFalse(o2 != o3)
         self.assertTrue(o1 != o2)
diff --git a/src/lib/dns/python/tests/rcode_python_test.py b/src/lib/dns/python/tests/rcode_python_test.py
index 77fed3a..c4a8067 100644
--- a/src/lib/dns/python/tests/rcode_python_test.py
+++ b/src/lib/dns/python/tests/rcode_python_test.py
@@ -54,36 +54,36 @@ class RcodeTest(unittest.TestCase):
         self.assertEqual(Rcode.RESERVED15_CODE, Rcode(15).get_code())
         self.assertEqual(Rcode.BADVERS_CODE, Rcode(16).get_code())
 
-        self.assertEqual(Rcode.NOERROR_CODE, Rcode.NOERROR().get_code())
-        self.assertEqual(Rcode.FORMERR_CODE, Rcode.FORMERR().get_code())
-        self.assertEqual(Rcode.NOTIMP_CODE, Rcode.NOTIMP().get_code())
-        self.assertEqual(Rcode.REFUSED_CODE, Rcode.REFUSED().get_code())
-        self.assertEqual(Rcode.RESERVED15_CODE, Rcode.RESERVED15().get_code())
-        self.assertEqual(Rcode.BADVERS_CODE, Rcode.BADVERS().get_code())
+        self.assertEqual(Rcode.NOERROR_CODE, Rcode.NOERROR.get_code())
+        self.assertEqual(Rcode.FORMERR_CODE, Rcode.FORMERR.get_code())
+        self.assertEqual(Rcode.NOTIMP_CODE, Rcode.NOTIMP.get_code())
+        self.assertEqual(Rcode.REFUSED_CODE, Rcode.REFUSED.get_code())
+        self.assertEqual(Rcode.RESERVED15_CODE, Rcode.RESERVED15.get_code())
+        self.assertEqual(Rcode.BADVERS_CODE, Rcode.BADVERS.get_code())
 
     def test_get_code(self):
-        self.assertEqual(0, Rcode.NOERROR().get_code())
-        self.assertEqual(1, Rcode.FORMERR().get_code())
-        self.assertEqual(2, Rcode.SERVFAIL().get_code())
-        self.assertEqual(3, Rcode.NXDOMAIN().get_code())
-        self.assertEqual(4, Rcode.NOTIMP().get_code())
-        self.assertEqual(5, Rcode.REFUSED().get_code())
-        self.assertEqual(6, Rcode.YXDOMAIN().get_code())
-        self.assertEqual(7, Rcode.YXRRSET().get_code())
-        self.assertEqual(8, Rcode.NXRRSET().get_code())
-        self.assertEqual(9, Rcode.NOTAUTH().get_code())
-        self.assertEqual(10, Rcode.NOTZONE().get_code())
-        self.assertEqual(11, Rcode.RESERVED11().get_code())
-        self.assertEqual(12, Rcode.RESERVED12().get_code())
-        self.assertEqual(13, Rcode.RESERVED13().get_code())
-        self.assertEqual(14, Rcode.RESERVED14().get_code())
-        self.assertEqual(15, Rcode.RESERVED15().get_code())
-        self.assertEqual(16, Rcode.BADVERS().get_code())
+        self.assertEqual(0, Rcode.NOERROR.get_code())
+        self.assertEqual(1, Rcode.FORMERR.get_code())
+        self.assertEqual(2, Rcode.SERVFAIL.get_code())
+        self.assertEqual(3, Rcode.NXDOMAIN.get_code())
+        self.assertEqual(4, Rcode.NOTIMP.get_code())
+        self.assertEqual(5, Rcode.REFUSED.get_code())
+        self.assertEqual(6, Rcode.YXDOMAIN.get_code())
+        self.assertEqual(7, Rcode.YXRRSET.get_code())
+        self.assertEqual(8, Rcode.NXRRSET.get_code())
+        self.assertEqual(9, Rcode.NOTAUTH.get_code())
+        self.assertEqual(10, Rcode.NOTZONE.get_code())
+        self.assertEqual(11, Rcode.RESERVED11.get_code())
+        self.assertEqual(12, Rcode.RESERVED12.get_code())
+        self.assertEqual(13, Rcode.RESERVED13.get_code())
+        self.assertEqual(14, Rcode.RESERVED14.get_code())
+        self.assertEqual(15, Rcode.RESERVED15.get_code())
+        self.assertEqual(16, Rcode.BADVERS.get_code())
 
     def test_get_extended_code(self):
-        self.assertEqual(0, Rcode.NOERROR().get_extended_code())
-        self.assertEqual(0, Rcode.YXRRSET().get_extended_code())
-        self.assertEqual(1, Rcode.BADVERS().get_extended_code())
+        self.assertEqual(0, Rcode.NOERROR.get_extended_code())
+        self.assertEqual(0, Rcode.YXRRSET.get_extended_code())
+        self.assertEqual(1, Rcode.BADVERS.get_extended_code())
         self.assertEqual(0xab, Rcode(0xabf).get_extended_code())
         self.assertEqual(0xff, Rcode(0xfff).get_extended_code())
 
@@ -107,13 +107,13 @@ class RcodeTest(unittest.TestCase):
         self.assertEqual("RESERVED15", Rcode(15).to_text())
         self.assertEqual("BADVERS", Rcode(16).to_text())
         
-        self.assertEqual("17", Rcode(Rcode.BADVERS().get_code() + 1).to_text())
+        self.assertEqual("17", Rcode(Rcode.BADVERS.get_code() + 1).to_text())
         self.assertEqual("4095", Rcode(0xfff).to_text())
 
     def test_richcmp(self):
-        r1 = Rcode.NOERROR()
-        r2 = Rcode.FORMERR()
-        r3 = Rcode.FORMERR()
+        r1 = Rcode.NOERROR
+        r2 = Rcode.FORMERR
+        r3 = Rcode.FORMERR
         self.assertTrue(r2 == r3)
         self.assertTrue(r1 != r2)
         self.assertFalse(r1 == r2)
diff --git a/src/lib/dns/python/tests/rrclass_python_test.py b/src/lib/dns/python/tests/rrclass_python_test.py
index a048c4c..880e331 100644
--- a/src/lib/dns/python/tests/rrclass_python_test.py
+++ b/src/lib/dns/python/tests/rrclass_python_test.py
@@ -23,8 +23,8 @@ from pydnspp import *
 
 class RRClassTest(unittest.TestCase):
     def setUp(self):
-        self.c1 = RRClass.IN()
-        self.c2 = RRClass.CH()
+        self.c1 = RRClass.IN
+        self.c2 = RRClass.CH
 
     def test_init(self):
         self.assertRaises(InvalidRRClass, RRClass, "wrong")
@@ -81,17 +81,17 @@ class RRClassTest(unittest.TestCase):
     def test_hash(self):
         # Exploiting the knowledge that the hash value is the numeric class
         # value, we can predict the comparison result.
-        self.assertEqual(hash(RRClass.IN()), hash(RRClass("IN")))
+        self.assertEqual(hash(RRClass.IN), hash(RRClass("IN")))
         self.assertEqual(hash(RRClass("in")), hash(RRClass("IN")))
-        self.assertNotEqual(hash(RRClass.IN()), hash(RRClass.CH()))
-        self.assertNotEqual(hash(RRClass.IN()), hash(RRClass("CLASS65535")))
+        self.assertNotEqual(hash(RRClass.IN), hash(RRClass.CH))
+        self.assertNotEqual(hash(RRClass.IN), hash(RRClass("CLASS65535")))
 
     def test_statics(self):
-        self.assertEqual(RRClass.IN(), RRClass("IN"))
-        self.assertEqual(RRClass.CH(), RRClass("CH"))
-        self.assertEqual(RRClass.HS(), RRClass("HS"))
-        self.assertEqual(254, RRClass.NONE().get_code())
-        self.assertEqual(255, RRClass.ANY().get_code())
+        self.assertEqual(RRClass.IN, RRClass("IN"))
+        self.assertEqual(RRClass.CH, RRClass("CH"))
+        self.assertEqual(RRClass.HS, RRClass("HS"))
+        self.assertEqual(254, RRClass.NONE.get_code())
+        self.assertEqual(255, RRClass.ANY.get_code())
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/rrset_collection_python_test.py b/src/lib/dns/python/tests/rrset_collection_python_test.py
index 2cf286e..1bbbc80 100644
--- a/src/lib/dns/python/tests/rrset_collection_python_test.py
+++ b/src/lib/dns/python/tests/rrset_collection_python_test.py
@@ -34,64 +34,64 @@ class RRsetCollectionTest(unittest.TestCase):
         self.assertRaises(TypeError, RRsetCollection, 1)
         self.assertRaises(TypeError, RRsetCollection, # extra arg
                           b'example. 0 A 192.0.2.1',
-                          Name('example'), RRClass.IN(), 1)
+                          Name('example'), RRClass.IN, 1)
         self.assertRaises(TypeError, RRsetCollection, # incorrect order
-                          b'example. 0 A 192.0.2.1', RRClass.IN(),
+                          b'example. 0 A 192.0.2.1', RRClass.IN,
                           Name('example'))
 
         # constructor will result in C++ exception.
         self.assertRaises(IscException, RRsetCollection,
                           TESTDATA_DIR + '/no_such_file', Name('example.org'),
-                          RRClass.IN())
+                          RRClass.IN)
 
     def check_find_result(self, rrsets):
         # Commonly used check pattern
-        found = rrsets.find(Name('www.example.org'), RRClass.IN(), RRType.A())
+        found = rrsets.find(Name('www.example.org'), RRClass.IN, RRType.A)
         self.assertNotEqual(None, found)
         self.assertEqual(Name('www.example.org'), found.get_name())
-        self.assertEqual(RRClass.IN(), found.get_class())
-        self.assertEqual(RRType.A(), found.get_type())
+        self.assertEqual(RRClass.IN, found.get_class())
+        self.assertEqual(RRType.A, found.get_type())
         self.assertEqual('192.0.2.1', found.get_rdata()[0].to_text())
 
     def test_find(self):
         # Checking the underlying find() is called as intended, both for
         # success and failure cases, and with two different constructors.
         rrsets = RRsetCollection(TESTDATA_DIR + '/example.org',
-                                 Name('example.org'), RRClass.IN())
+                                 Name('example.org'), RRClass.IN)
         self.check_find_result(rrsets)
-        self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN(),
-                                           RRType.A()))
+        self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN,
+                                           RRType.A))
 
         rrsets = RRsetCollection(b'www.example.org. 3600 IN A 192.0.2.1',
-                                 Name('example.org'), RRClass.IN())
+                                 Name('example.org'), RRClass.IN)
         self.check_find_result(rrsets)
-        self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN(),
-                                           RRType.A()))
+        self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN,
+                                           RRType.A))
 
     def test_find_badargs(self):
         rrsets = RRsetCollection()
 
         # Check bad arguments: bad types
-        self.assertRaises(TypeError, rrsets.find, 1, RRClass.IN(), RRType.A())
+        self.assertRaises(TypeError, rrsets.find, 1, RRClass.IN, RRType.A)
         self.assertRaises(TypeError, rrsets.find, Name('example'), 1,
-                          RRType.A())
+                          RRType.A)
         self.assertRaises(TypeError, rrsets.find, Name('example'), 1,
-                          RRType.A())
+                          RRType.A)
         self.assertRaises(TypeError, rrsets.find, Name('example'),
-                          RRClass.IN(), 1)
-        self.assertRaises(TypeError, rrsets.find, Name('example'), RRType.A(),
-                          RRClass.IN())
+                          RRClass.IN, 1)
+        self.assertRaises(TypeError, rrsets.find, Name('example'), RRType.A,
+                          RRClass.IN)
 
         # Check bad arguments: too many/few arguments
         self.assertRaises(TypeError, rrsets.find, Name('example'),
-                          RRClass.IN(), RRType.A(), 0)
+                          RRClass.IN, RRType.A, 0)
         self.assertRaises(TypeError, rrsets.find, Name('example'),
-                          RRClass.IN())
+                          RRClass.IN)
 
     def test_add_remove_rrset(self):
         name = Name('www.example.org')
-        rrclass = RRClass.IN()
-        rrtype = RRType.A()
+        rrclass = RRClass.IN
+        rrtype = RRType.A
 
         # Create a collection with no RRsets
         rrsets = RRsetCollection()
@@ -134,7 +134,7 @@ class RRsetCollectionTest(unittest.TestCase):
                 pass
         rrsets = EmptyRRsetCollection()
         self.assertRaises(TypeError, rrsets.find, Name('www.example.org'),
-                          RRClass.IN(), RRType.A())
+                          RRClass.IN, RRType.A)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/rrset_python_test.py b/src/lib/dns/python/tests/rrset_python_test.py
index 0544872..010b60c 100644
--- a/src/lib/dns/python/tests/rrset_python_test.py
+++ b/src/lib/dns/python/tests/rrset_python_test.py
@@ -23,7 +23,7 @@ import os
 from pydnspp import *
 
 class TestModuleSpec(unittest.TestCase):
-    
+
     def setUp(self):
         self.test_name = Name("test.example.com")
         self.test_domain = Name("example.com")
@@ -78,8 +78,8 @@ class TestModuleSpec(unittest.TestCase):
     def test_add_rdata(self):
         # no iterator to read out yet (TODO: add addition test once implemented)
 
-        self.assertRaises(TypeError, self.rrset_a.add_rdata, Rdata(RRType("NS"), RRClass("IN"), "test.name"))
-        pass
+        self.assertRaises(TypeError, self.rrset_a.add_rdata,
+                          Rdata(RRType("NS"), RRClass("IN"), "test.name."))
 
     def test_to_text(self):
         self.assertEqual("test.example.com. 3600 IN A 192.0.2.1\n"
@@ -126,6 +126,6 @@ class TestModuleSpec(unittest.TestCase):
         # they would leak.
         self.assertEqual(1, sys.getrefcount(self.rrset_a.get_rdata()))
         self.assertEqual(1, sys.getrefcount(self.rrset_a.get_rdata()[0]))
-        
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/rrtype_python_test.py b/src/lib/dns/python/tests/rrtype_python_test.py
index 4548b50..7d20136 100644
--- a/src/lib/dns/python/tests/rrtype_python_test.py
+++ b/src/lib/dns/python/tests/rrtype_python_test.py
@@ -119,35 +119,35 @@ class TestModuleSpec(unittest.TestCase):
     def test_hash(self):
         # Exploiting the knowledge that the hash value is the numeric class
         # value, we can predict the comparison result.
-        self.assertEqual(hash(RRType.AAAA()), hash(RRType("AAAA")))
+        self.assertEqual(hash(RRType.AAAA), hash(RRType("AAAA")))
         self.assertEqual(hash(RRType("aaaa")), hash(RRType("AAAA")))
         self.assertEqual(hash(RRType(28)), hash(RRType("AAAA")))
-        self.assertNotEqual(hash(RRType.A()), hash(RRType.NS()))
-        self.assertNotEqual(hash(RRType.AAAA()), hash(RRType("Type65535")))
+        self.assertNotEqual(hash(RRType.A), hash(RRType.NS))
+        self.assertNotEqual(hash(RRType.AAAA), hash(RRType("Type65535")))
 
     def test_statics(self):
-        self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM())
-        self.assertEqual(RRType("DNAME"), RRType.DNAME())
-        self.assertEqual(RRType("PTR"), RRType.PTR())
-        self.assertEqual(RRType("MX"), RRType.MX())
-        self.assertEqual(RRType("DNSKEY"), RRType.DNSKEY())
-        self.assertEqual(RRType("TXT"), RRType.TXT())
-        self.assertEqual(RRType("RRSIG"), RRType.RRSIG())
-        self.assertEqual(RRType("NSEC"), RRType.NSEC())
-        self.assertEqual(RRType("AAAA"), RRType.AAAA())
-        self.assertEqual(RRType("DS"), RRType.DS())
-        self.assertEqual(RRType("OPT"), RRType.OPT())
-        self.assertEqual(RRType("A"), RRType.A())
-        self.assertEqual(RRType("NS"), RRType.NS())
-        self.assertEqual(RRType("CNAME"), RRType.CNAME())
-        self.assertEqual(RRType("SOA"), RRType.SOA())
-        self.assertEqual(RRType("NSEC3"), RRType.NSEC3())
+        self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM)
+        self.assertEqual(RRType("DNAME"), RRType.DNAME)
+        self.assertEqual(RRType("PTR"), RRType.PTR)
+        self.assertEqual(RRType("MX"), RRType.MX)
+        self.assertEqual(RRType("DNSKEY"), RRType.DNSKEY)
+        self.assertEqual(RRType("TXT"), RRType.TXT)
+        self.assertEqual(RRType("RRSIG"), RRType.RRSIG)
+        self.assertEqual(RRType("NSEC"), RRType.NSEC)
+        self.assertEqual(RRType("AAAA"), RRType.AAAA)
+        self.assertEqual(RRType("DS"), RRType.DS)
+        self.assertEqual(RRType("OPT"), RRType.OPT)
+        self.assertEqual(RRType("A"), RRType.A)
+        self.assertEqual(RRType("NS"), RRType.NS)
+        self.assertEqual(RRType("CNAME"), RRType.CNAME)
+        self.assertEqual(RRType("SOA"), RRType.SOA)
+        self.assertEqual(RRType("NSEC3"), RRType.NSEC3)
 
         # these can't be built with string input
         # (see the original cpp TODO)
-        self.assertEqual(251, RRType.IXFR().get_code())
-        self.assertEqual(252, RRType.AXFR().get_code())
-        self.assertEqual(255, RRType.ANY().get_code())
+        self.assertEqual(251, RRType.IXFR.get_code())
+        self.assertEqual(252, RRType.AXFR.get_code())
+        self.assertEqual(255, RRType.ANY.get_code())
         
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tests/tsig_python_test.py b/src/lib/dns/python/tests/tsig_python_test.py
index 4d99175..282431c 100644
--- a/src/lib/dns/python/tests/tsig_python_test.py
+++ b/src/lib/dns/python/tests/tsig_python_test.py
@@ -40,7 +40,7 @@ class TSIGContextTest(unittest.TestCase):
         self.keyring = TSIGKeyRing()
         self.message = Message(Message.RENDER)
         self.renderer = MessageRenderer()
-        self.test_class = RRClass.IN()
+        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,
@@ -59,12 +59,12 @@ class TSIGContextTest(unittest.TestCase):
     # 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,
+                             qtype=RRType.A, answer_data=None,
                              answer_type=None, add_question=True,
-                             rcode=Rcode.NOERROR()):
+                             rcode=Rcode.NOERROR):
         self.message.clear(Message.RENDER)
         self.message.set_qid(id)
-        self.message.set_opcode(Opcode.QUERY())
+        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)
@@ -120,7 +120,7 @@ class TSIGContextTest(unittest.TestCase):
         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())
+        self.assertEqual(TSIGError(Rcode.NOERROR), self.tsig_ctx.get_error())
 
         # No message signed yet
         self.assertRaises(TSIGContextError, self.tsig_ctx.last_had_signature)
@@ -249,7 +249,7 @@ class TSIGContextTest(unittest.TestCase):
         tsig = self.createMessageAndSign(self.qid, self.test_name,
                                          self.tsig_verify_ctx,
                                          QR_FLAG|AA_FLAG|RD_FLAG,
-                                         RRType.A(), "192.0.2.1")
+                                         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"
@@ -280,7 +280,7 @@ class TSIGContextTest(unittest.TestCase):
         zone_name = Name("example.com")
 
         tsig = self.createMessageAndSign(axfr_qid, zone_name, self.tsig_ctx,
-                                         0, RRType.AXFR())
+                                         0, RRType.AXFR)
 
         received_data = read_wire_data("tsig_verify1.wire")
         self.commonVerifyChecks(self.tsig_verify_ctx, tsig, received_data,
@@ -289,10 +289,10 @@ class TSIGContextTest(unittest.TestCase):
 
         tsig = self.createMessageAndSign(axfr_qid, zone_name,
                                          self.tsig_verify_ctx,
-                                         AA_FLAG|QR_FLAG, RRType.AXFR(),
+                                         AA_FLAG|QR_FLAG, RRType.AXFR,
                                          "ns.example.com. root.example.com." +\
                                          " 2011041503 7200 3600 2592000 1200",
-                                         RRType.SOA())
+                                         RRType.SOA)
 
         received_data = read_wire_data("tsig_verify2.wire")
         self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
@@ -302,8 +302,8 @@ class TSIGContextTest(unittest.TestCase):
             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(),
+                                         AA_FLAG|QR_FLAG, RRType.AXFR,
+                                         "ns.example.com.", RRType.NS,
                                          False)
         self.commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac)
 
@@ -316,7 +316,7 @@ class TSIGContextTest(unittest.TestCase):
 
         test_qid = 0x7fc4
         tsig = self.createMessageAndSign(test_qid, self.test_name,
-                                         self.tsig_ctx, 0, RRType.SOA())
+                                         self.tsig_ctx, 0, RRType.SOA)
 
         # "advance the clock" and try validating, which should fail due to
         # BADTIME
@@ -328,8 +328,8 @@ class TSIGContextTest(unittest.TestCase):
         # 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())
+                                         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" +\
@@ -344,7 +344,7 @@ class TSIGContextTest(unittest.TestCase):
         fix_current_time(0x4da8b9d6)
 
         tsig = self.createMessageAndSign(self.qid, self.test_name,
-                                         self.tsig_ctx, 0, RRType.SOA())
+                                         self.tsig_ctx, 0, RRType.SOA)
 
         # "rewind the clock" and try validating, which should fail due to
         # BADTIME
@@ -361,7 +361,7 @@ class TSIGContextTest(unittest.TestCase):
         fix_current_time(0x4da8b9d6)
 
         tsig = self.createMessageAndSign(self.qid, self.test_name,
-                                         self.tsig_ctx, 0, RRType.SOA())
+                                         self.tsig_ctx, 0, RRType.SOA)
 
         fix_current_time(0x4da8b9d6 + 301)
         self.assertEqual(TSIGError.BAD_TIME,
@@ -382,7 +382,7 @@ class TSIGContextTest(unittest.TestCase):
     def test_badtime_overflow(self):
         fix_current_time(200)
         tsig = self.createMessageAndSign(self.qid, self.test_name,
-                                         self.tsig_ctx, 0, RRType.SOA())
+                                         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
@@ -522,7 +522,7 @@ class TSIGContextTest(unittest.TestCase):
                          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(),
+                                  QR_FLAG|AA_FLAG|RD_FLAG, RRType.A,
                                   "192.0.2.1")
         self.assertEqual(TSIGContext.STATE_SENT_RESPONSE,
                          self.tsig_verify_ctx.get_state())
diff --git a/src/lib/dns/python/tests/tsigerror_python_test.py b/src/lib/dns/python/tests/tsigerror_python_test.py
index a968b6b..01860d3 100644
--- a/src/lib/dns/python/tests/tsigerror_python_test.py
+++ b/src/lib/dns/python/tests/tsigerror_python_test.py
@@ -28,7 +28,7 @@ class TSIGErrorTest(unittest.TestCase):
 
     def test_from_rcode(self):
         # We use RCODE for code values from 0-15.
-        self.assertEqual(0, TSIGError(Rcode.NOERROR()).get_code())
+        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
@@ -50,19 +50,19 @@ class TSIGErrorTest(unittest.TestCase):
         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.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)
+        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())
+        self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR).to_text())
 
         # Well known TSIG errors
         self.assertEqual("BADSIG", TSIGError.BAD_SIG.to_text())
@@ -74,21 +74,21 @@ class TSIGErrorTest(unittest.TestCase):
         self.assertEqual("65535", TSIGError(65535).to_text());
 
         # also check str() works same way
-        self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR())))
+        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())
+        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())
+        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())
+        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()))
diff --git a/src/lib/dns/python/tests/zone_checker_python_test.py b/src/lib/dns/python/tests/zone_checker_python_test.py
index 66b6c47..dc7d258 100644
--- a/src/lib/dns/python/tests/zone_checker_python_test.py
+++ b/src/lib/dns/python/tests/zone_checker_python_test.py
@@ -35,8 +35,8 @@ class ZoneCheckerTest(unittest.TestCase):
         rrsets = RRsetCollection(b'example.org. 0 SOA . . 0 0 0 0 0\n' +
                                  b'example.org. 0 NS ns.example.org.\n' +
                                  b'ns.example.org. 0 A 192.0.2.1\n',
-                                 Name('example.org'), RRClass.IN())
-        self.assertTrue(check_zone(Name('example.org'), RRClass.IN(),
+                                 Name('example.org'), RRClass.IN)
+        self.assertTrue(check_zone(Name('example.org'), RRClass.IN,
                                    rrsets,
                                    (lambda r: self.__callback(r, errors),
                                     lambda r: self.__callback(r, warns))))
@@ -45,8 +45,8 @@ class ZoneCheckerTest(unittest.TestCase):
 
         # Check fails and one additional warning.
         rrsets = RRsetCollection(b'example.org. 0 NS ns.example.org.',
-                                 Name('example.org'), RRClass.IN())
-        self.assertFalse(check_zone(Name('example.org'), RRClass.IN(), rrsets,
+                                 Name('example.org'), RRClass.IN)
+        self.assertFalse(check_zone(Name('example.org'), RRClass.IN, rrsets,
                                     (lambda r: self.__callback(r, errors),
                                      lambda r: self.__callback(r, warns))))
         self.assertEqual(['zone example.org/IN: has 0 SOA records'], errors)
@@ -56,7 +56,7 @@ class ZoneCheckerTest(unittest.TestCase):
         # Same RRset collection, suppressing callbacks
         errors = []
         warns = []
-        self.assertFalse(check_zone(Name('example.org'), RRClass.IN(), rrsets,
+        self.assertFalse(check_zone(Name('example.org'), RRClass.IN, rrsets,
                                     (None, None)))
         self.assertEqual([], errors)
         self.assertEqual([], warns)
@@ -64,29 +64,29 @@ class ZoneCheckerTest(unittest.TestCase):
     def test_check_badarg(self):
         rrsets = RRsetCollection()
         # Bad types
-        self.assertRaises(TypeError, check_zone, 1, RRClass.IN(), rrsets,
+        self.assertRaises(TypeError, check_zone, 1, RRClass.IN, rrsets,
                           (None, None))
         self.assertRaises(TypeError, check_zone, Name('example'), 1, rrsets,
                           (None, None))
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           1, (None, None))
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, 1)
 
         # Bad callbacks
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, (None, None, None))
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, (1, None))
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, (None, 1))
 
         # Extra/missing args
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, (None, None), 1)
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets)
-        check_zone(Name('example'), RRClass.IN(), rrsets, (None, None))
+        check_zone(Name('example'), RRClass.IN, rrsets, (None, None))
 
     def test_check_callback_fail(self):
         # Let the call raise a Python exception.  It should be propagated to
@@ -96,7 +96,7 @@ class ZoneCheckerTest(unittest.TestCase):
 
         # Using an empty collection, triggering an error callback.
         self.assertRaises(FakeException, check_zone, Name('example.org'),
-                          RRClass.IN(), RRsetCollection(),
+                          RRClass.IN, RRsetCollection(),
                           (__bad_callback, None))
 
         # An unusual case: the callback is expected to return None, but if it
@@ -108,7 +108,7 @@ class ZoneCheckerTest(unittest.TestCase):
 
         ref_checker = RefChecker()
         orig_refcnt = sys.getrefcount(ref_checker)
-        check_zone(Name('example.org'), RRClass.IN(), RRsetCollection(),
+        check_zone(Name('example.org'), RRClass.IN, RRsetCollection(),
                    (lambda r: __callback(r, ref_checker), None))
         self.assertEqual(orig_refcnt, sys.getrefcount(ref_checker))
 
@@ -132,48 +132,45 @@ class ZoneCheckerTest(unittest.TestCase):
                     raise FakeException('find error')
                 if self.__find_result is not 'use_default':
                     return self.__find_result
-                if rrtype == RRType.SOA():
-                    soa = RRset(Name('example'), RRClass.IN(), rrtype,
-                                RRTTL(0))
-                    soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+                if rrtype == RRType.SOA:
+                    soa = RRset(Name('example'), RRClass.IN, rrtype, RRTTL(0))
+                    soa.add_rdata(Rdata(RRType.SOA, RRClass.IN,
                                         '. . 0 0 0 0 0'))
                     return soa
-                if rrtype == RRType.NS():
-                    ns = RRset(Name('example'), RRClass.IN(), rrtype,
-                               RRTTL(0))
-                    ns.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
-                                       'example.org'))
+                if rrtype == RRType.NS:
+                    ns = RRset(Name('example'), RRClass.IN, rrtype, RRTTL(0))
+                    ns.add_rdata(Rdata(RRType.NS, RRClass.IN, 'example.org.'))
                     return ns
                 return None
 
         # A successful case.  Just checking it works in that case.
         rrsets = FakeRRsetCollection()
-        self.assertTrue(check_zone(Name('example'), RRClass.IN(), rrsets,
+        self.assertTrue(check_zone(Name('example'), RRClass.IN, rrsets,
                                    (None, None)))
 
         # Likewise, normal case but zone check fails.
         rrsets = FakeRRsetCollection(False, None)
-        self.assertFalse(check_zone(Name('example'), RRClass.IN(), rrsets,
+        self.assertFalse(check_zone(Name('example'), RRClass.IN, rrsets,
                                     (None, None)))
 
         # Our find() returns a bad type of result.
         rrsets = FakeRRsetCollection(False, 1)
-        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+        self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
                           rrsets, (None, None))
 
         # Our find() returns an empty SOA RRset.  C++ zone checker code
         # throws, which results in IscException.
         rrsets = FakeRRsetCollection(False, RRset(Name('example'),
-                                                  RRClass.IN(),
-                                                  RRType.SOA(), RRTTL(0)))
+                                                  RRClass.IN,
+                                                  RRType.SOA, RRTTL(0)))
         self.assertRaises(IscException, check_zone, Name('example'),
-                          RRClass.IN(), rrsets, (None, None))
+                          RRClass.IN, rrsets, (None, None))
 
         # Our find() raises an exception.  That exception is propagated to
         # the top level.
         rrsets = FakeRRsetCollection(True)
         self.assertRaises(FakeException, check_zone, Name('example'),
-                          RRClass.IN(), rrsets, (None, None))
+                          RRClass.IN, rrsets, (None, None))
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/src/lib/dns/python/tsigerror_python_inc.cc b/src/lib/dns/python/tsigerror_python_inc.cc
index ed3b605..a98a9b0 100644
--- a/src/lib/dns/python/tsigerror_python_inc.cc
+++ b/src/lib/dns/python/tsigerror_python_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const TSIGError_doc = "\n\
 TSIG errors.\n\
diff --git a/src/lib/dns/rdata/generic/cname_5.cc b/src/lib/dns/rdata/generic/cname_5.cc
index 5bb0aea..e87eeec 100644
--- a/src/lib/dns/rdata/generic/cname_5.cc
+++ b/src/lib/dns/rdata/generic/cname_5.cc
@@ -22,15 +22,49 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid CNAME RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The CNAME must be absolute since there's no parameter that specifies
+/// the origin name; if it is not absolute, \c MissingNameOrigin
+/// exception will be thrown.  These must not be represented as a quoted
+/// string.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 CNAME::CNAME(const std::string& namestr) :
-    cname_(namestr)
-{}
+    // Fill in dummy name and replace it soon below.
+    cname_(Name::ROOT_NAME())
+{
+    try {
+        std::istringstream ss(namestr);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        cname_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for CNAME: "
+                      << namestr);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct CNAME from '" <<
+                  namestr << "': " << ex.what());
+    }
+}
 
 CNAME::CNAME(InputBuffer& buffer, size_t) :
     Rdata(), cname_(buffer)
@@ -39,6 +73,27 @@ CNAME::CNAME(InputBuffer& buffer, size_t) :
     // check consistency.
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of a CNAME RDATA.  The CNAME field can be
+/// non-absolute if \c origin is non-NULL, in which case \c origin is
+/// used to make it absolute.  It must not be represented as a quoted
+/// string.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of CNAME when it
+/// is non-absolute.
+CNAME::CNAME(MasterLexer& lexer, const Name* origin,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    cname_(createNameFromLexer(lexer, origin))
+{}
+
 CNAME::CNAME(const CNAME& other) :
     Rdata(), cname_(other.cname_)
 {}
diff --git a/src/lib/dns/rdata/generic/dname_39.cc b/src/lib/dns/rdata/generic/dname_39.cc
index a22fcc3..d1d349e 100644
--- a/src/lib/dns/rdata/generic/dname_39.cc
+++ b/src/lib/dns/rdata/generic/dname_39.cc
@@ -22,15 +22,49 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid DNAME RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The TARGET must be absolute since there's no parameter that specifies
+/// the origin name; if it is not absolute, \c MissingNameOrigin
+/// exception will be thrown.  These must not be represented as a quoted
+/// string.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 DNAME::DNAME(const std::string& namestr) :
-    dname_(namestr)
-{}
+    // Fill in dummy name and replace it soon below.
+    dname_(Name::ROOT_NAME())
+{
+    try {
+        std::istringstream ss(namestr);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        dname_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for DNAME: "
+                      << namestr);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct DNAME from '" <<
+                  namestr << "': " << ex.what());
+    }
+}
 
 DNAME::DNAME(InputBuffer& buffer, size_t) :
     dname_(buffer)
@@ -39,6 +73,27 @@ DNAME::DNAME(InputBuffer& buffer, size_t) :
     // check consistency.
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of a DNAME RDATA.  The TARGET field can be
+/// non-absolute if \c origin is non-NULL, in which case \c origin is
+/// used to make it absolute.  It must not be represented as a quoted
+/// string.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of TARGET when it
+/// is non-absolute.
+DNAME::DNAME(MasterLexer& lexer, const Name* origin,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    dname_(createNameFromLexer(lexer, origin))
+{}
+
 DNAME::DNAME(const DNAME& other) :
     Rdata(), dname_(other.dname_)
 {}
diff --git a/src/lib/dns/rdata/generic/mx_15.cc b/src/lib/dns/rdata/generic/mx_15.cc
index b95ba05..12ada97 100644
--- a/src/lib/dns/rdata/generic/mx_15.cc
+++ b/src/lib/dns/rdata/generic/mx_15.cc
@@ -26,9 +26,12 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using boost::lexical_cast;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -40,21 +43,80 @@ MX::MX(InputBuffer& buffer, size_t) :
     // check consistency.
 }
 
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid MX RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The EXCHANGE name must be absolute since there's no parameter that
+/// specifies the origin name; if it is not absolute, \c MissingNameOrigin
+/// exception will be thrown. It must not be represented as a quoted
+/// string.
+///
+/// See the construction that takes \c MasterLexer for other fields.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 MX::MX(const std::string& mx_str) :
-    preference_(0), mxname_(".")
+    // Fill in dummy name and replace them soon below.
+    preference_(0), mxname_(Name::ROOT_NAME())
 {
-    istringstream iss(mx_str);
-    uint16_t pref;
-    string mxname;
-
-    iss >> pref >> mxname;
+    try {
+        std::istringstream ss(mx_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        const uint32_t num =
+            lexer.getNextToken(MasterToken::NUMBER).getNumber();
+        if (num > 65535) {
+            isc_throw(InvalidRdataText, "Invalid MX preference in: "
+                      << mx_str);
+        }
+        preference_ = static_cast<uint16_t>(num);
+
+        mxname_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for MX: "
+                      << mx_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct MX from '" <<
+                  mx_str << "': " << ex.what());
+    }
+}
 
-    if (iss.bad() || iss.fail() || !iss.eof()) {
-        isc_throw(InvalidRdataText, "Invalid MX text format");
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an MX RDATA.  The EXCHANGE field can be non-absolute if \c origin
+/// is non-NULL, in which case \c origin is used to make it absolute.
+/// It must not be represented as a quoted string.
+///
+/// The PREFERENCE field must be a valid decimal representation of an
+/// unsigned 16-bit integer.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of EXCHANGE when it
+/// is non-absolute.
+MX::MX(MasterLexer& lexer, const Name* origin,
+       MasterLoader::Options, MasterLoaderCallbacks&) :
+    preference_(0), mxname_(".")
+{
+    const uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (num > 65535) {
+        isc_throw(InvalidRdataText, "Invalid MX preference: " << num);
     }
+    preference_ = static_cast<uint16_t>(num);
 
-    preference_ = pref;
-    mxname_ = Name(mxname);
+    mxname_ = createNameFromLexer(lexer, origin);
 }
 
 MX::MX(uint16_t preference, const Name& mxname) :
diff --git a/src/lib/dns/rdata/generic/ns_2.cc b/src/lib/dns/rdata/generic/ns_2.cc
index 631da9d..d75ab7d 100644
--- a/src/lib/dns/rdata/generic/ns_2.cc
+++ b/src/lib/dns/rdata/generic/ns_2.cc
@@ -22,15 +22,49 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid NS RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The NSDNAME must be absolute since there's no parameter that
+/// specifies the origin name; if it is not absolute, \c
+/// MissingNameOrigin exception will be thrown.  These must not be
+/// represented as a quoted string.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 NS::NS(const std::string& namestr) :
-    nsname_(namestr)
-{}
+    // Fill in dummy name and replace them soon below.
+    nsname_(Name::ROOT_NAME())
+{
+    try {
+        std::istringstream ss(namestr);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        nsname_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for NS: "
+                      << namestr);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct NS from '" <<
+                  namestr << "': " << ex.what());
+    }
+}
 
 NS::NS(InputBuffer& buffer, size_t) :
     nsname_(buffer)
@@ -39,6 +73,27 @@ NS::NS(InputBuffer& buffer, size_t) :
     // check consistency.
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of an NS RDATA.  The NSDNAME field can be
+/// non-absolute if \c origin is non-NULL, in which case \c origin is
+/// used to make it absolute.  It must not be represented as a quoted
+/// string.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of NSDNAME when it
+/// is non-absolute.
+NS::NS(MasterLexer& lexer, const Name* origin,
+       MasterLoader::Options, MasterLoaderCallbacks&) :
+    nsname_(createNameFromLexer(lexer, origin))
+{}
+
 NS::NS(const NS& other) :
     Rdata(), nsname_(other.nsname_)
 {}
diff --git a/src/lib/dns/rdata/generic/ptr_12.cc b/src/lib/dns/rdata/generic/ptr_12.cc
index b76fc7f..080faee 100644
--- a/src/lib/dns/rdata/generic/ptr_12.cc
+++ b/src/lib/dns/rdata/generic/ptr_12.cc
@@ -22,15 +22,49 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid PTR RDATA. There can be
+/// extra space characters at the beginning or end of the text (which
+/// are simply ignored), but other extra text, including a new line,
+/// will make the construction fail with an exception.
+///
+/// The PTRDNAME must be absolute since there's no parameter that
+/// specifies the origin name; if it is not absolute, \c
+/// MissingNameOrigin exception will be thrown. These must not be
+/// represented as a quoted string.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 PTR::PTR(const std::string& type_str) :
-    ptr_name_(type_str)
-{}
+    // Fill in dummy name and replace them soon below.
+    ptr_name_(Name::ROOT_NAME())
+{
+    try {
+        std::istringstream ss(type_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        ptr_name_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for PTR: "
+                      << type_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct PTR from '" <<
+                  type_str << "': " << ex.what());
+    }
+}
 
 PTR::PTR(InputBuffer& buffer, size_t) :
     ptr_name_(buffer)
@@ -39,6 +73,27 @@ PTR::PTR(InputBuffer& buffer, size_t) :
     // check consistency.
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of a PTR RDATA.  The PTRDNAME field can be
+/// non-absolute if \c origin is non-NULL, in which case \c origin is
+/// used to make it absolute.  It must not be represented as a quoted
+/// string.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of PTRDNAME when it
+/// is non-absolute.
+PTR::PTR(MasterLexer& lexer, const Name* origin,
+         MasterLoader::Options, MasterLoaderCallbacks&) :
+    ptr_name_(createNameFromLexer(lexer, origin))
+{}
+
 PTR::PTR(const PTR& source) :
     Rdata(), ptr_name_(source.ptr_name_)
 {}
diff --git a/src/lib/dns/rdata/in_1/srv_33.cc b/src/lib/dns/rdata/in_1/srv_33.cc
index af8bbe3..ac62071 100644
--- a/src/lib/dns/rdata/in_1/srv_33.cc
+++ b/src/lib/dns/rdata/in_1/srv_33.cc
@@ -25,9 +25,12 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
 using namespace std;
 using namespace isc::util;
 using namespace isc::util::str;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -48,45 +51,57 @@ struct SRVImpl {
 
 /// \brief Constructor from string.
 ///
-/// \c srv_str must be formatted as follows:
-/// \code <Priority> <Weight> <Port> <Target>
-/// \endcode
-/// where
-/// - <Priority>, <Weight>, and <Port> are an unsigned
-///   16-bit decimal integer.
-/// - <Target> is a valid textual representation of domain name.
-///
-/// An example of valid string is:
-/// \code "1 5 1500 example.com." \endcode
-///
-/// <b>Exceptions</b>
-///
-/// If <Target> is not a valid domain name, a corresponding exception
-/// from the \c Name class will be thrown;
-/// if %any of the other bullet points above is not met, an exception of
-/// class \c InvalidRdataText will be thrown.
-/// This constructor internally involves resource allocation, and if it fails
-/// a corresponding standard exception will be thrown.
+/// The given string must represent a valid SRV RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The TARGET name must be absolute since there's no parameter that
+/// specifies the origin name; if it is not absolute, \c MissingNameOrigin
+/// exception will be thrown. It must not be represented as a quoted
+/// string.
+///
+/// See the construction that takes \c MasterLexer for other fields.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 SRV::SRV(const std::string& srv_str) :
     impl_(NULL)
 {
-    istringstream iss(srv_str);
-
     try {
-        const int32_t priority = tokenToNum<int32_t, 16>(getToken(iss));
-        const int32_t weight = tokenToNum<int32_t, 16>(getToken(iss));
-        const int32_t port = tokenToNum<int32_t, 16>(getToken(iss));
-        const Name targetname(getToken(iss));
-
-        if (!iss.eof()) {
-            isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
-                    srv_str);
+        std::istringstream ss(srv_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+        if (num > 65535) {
+            isc_throw(InvalidRdataText, "Invalid SRV priority in: " << srv_str);
+        }
+        const uint16_t priority = static_cast<uint16_t>(num);
+
+        num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+        if (num > 65535) {
+            isc_throw(InvalidRdataText, "Invalid SRV weight in: " << srv_str);
+        }
+        const uint16_t weight = static_cast<uint16_t>(num);
+
+        num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+        if (num > 65535) {
+            isc_throw(InvalidRdataText, "Invalid SRV port in: " << srv_str);
+        }
+        const uint16_t port = static_cast<uint16_t>(num);
+
+        const Name targetname = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for SRV: "
+                      << srv_str);
         }
 
         impl_ = new SRVImpl(priority, weight, port, targetname);
-    } catch (const StringTokenError& ste) {
-        isc_throw(InvalidRdataText, "Invalid SRV text: " <<
-                  ste.what() << ": " << srv_str);
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct SRV from '" <<
+                  srv_str << "': " << ex.what());
     }
 }
 
@@ -112,14 +127,58 @@ SRV::SRV(InputBuffer& buffer, size_t rdata_len) {
         isc_throw(InvalidRdataLength, "SRV too short");
     }
 
-    uint16_t priority = buffer.readUint16();
-    uint16_t weight = buffer.readUint16();
-    uint16_t port = buffer.readUint16();
+    const uint16_t priority = buffer.readUint16();
+    const uint16_t weight = buffer.readUint16();
+    const uint16_t port = buffer.readUint16();
     const Name targetname(buffer);
 
     impl_ = new SRVImpl(priority, weight, port, targetname);
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an SRV RDATA.  The TARGET field can be non-absolute if \c origin
+/// is non-NULL, in which case \c origin is used to make it absolute.
+/// It must not be represented as a quoted string.
+///
+/// The PRIORITY, WEIGHT and PORT fields must each be a valid decimal
+/// representation of an unsigned 16-bit integers respectively.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of TARGET when it
+/// is non-absolute.
+SRV::SRV(MasterLexer& lexer, const Name* origin,
+         MasterLoader::Options, MasterLoaderCallbacks&)
+{
+    uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (num > 65535) {
+        isc_throw(InvalidRdataText, "Invalid SRV priority: " << num);
+    }
+    const uint16_t priority = static_cast<uint16_t>(num);
+
+    num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (num > 65535) {
+        isc_throw(InvalidRdataText, "Invalid SRV weight: " << num);
+    }
+    const uint16_t weight = static_cast<uint16_t>(num);
+
+    num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (num > 65535) {
+        isc_throw(InvalidRdataText, "Invalid SRV port: " << num);
+    }
+    const uint16_t port = static_cast<uint16_t>(num);
+
+    const Name targetname = createNameFromLexer(lexer, origin);
+
+    impl_ = new SRVImpl(priority, weight, port, targetname);
+}
+
 /// \brief The copy constructor.
 ///
 /// It internally allocates a resource, and if it fails a corresponding
diff --git a/src/lib/dns/rdata/template.h b/src/lib/dns/rdata/template.h
index 9e84cc3..3bfeb85 100644
--- a/src/lib/dns/rdata/template.h
+++ b/src/lib/dns/rdata/template.h
@@ -39,6 +39,10 @@
 // Note: do not remove the comment lines beginning with "BEGIN_" and "END_".
 // These are markers used by a script for auto-generating build-able source
 // files.
+//
+// On completion of implementing a new type of Rdata, remove the corresponding
+// entry from the meta_types dictionary of gen-rdatacode.py.in.  Otherwise
+// it will cause build failure.
 
 class MyType : public Rdata {
 public:
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index 1ff4163..89dc49d 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -294,28 +294,14 @@ public:
 
     // BEGIN_WELL_KNOWN_CLASS_DECLARATIONS
     // END_WELL_KNOWN_CLASS_DECLARATIONS
-    
-    static const RRClass& NONE();
 
 private:
-    // \brief Meta-classes
-    enum {
-        RRCLASS_RESERVED0 = 0,
-        RRCLASS_NONE = 254
-    };
     uint16_t classcode_;
 };
 
 // BEGIN_WELL_KNOWN_CLASS_DEFINITIONS
 // END_WELL_KNOWN_CLASS_DEFINITIONS
 
-inline const RRClass&
-RRClass::NONE() {
-    static RRClass rrclass(RRCLASS_NONE);
-
-    return (rrclass);
-}
-
 ///
 /// \brief Insert the \c RRClass as a string into stream.
 ///
diff --git a/src/lib/dns/rrset_collection_base.h b/src/lib/dns/rrset_collection_base.h
index 5ae172a..f7c9b6b 100644
--- a/src/lib/dns/rrset_collection_base.h
+++ b/src/lib/dns/rrset_collection_base.h
@@ -27,7 +27,7 @@ namespace dns {
 
 /// \brief Error during RRsetCollectionBase find() operation
 ///
-/// This exception is thrown when an calling implementation of
+/// This exception is thrown when calling an implementation of
 /// \c RRsetCollectionBase::find() results in an error which is not due
 /// to unmatched data, but because of some other underlying error
 /// condition.
@@ -58,13 +58,37 @@ public:
     /// is found, \c NULL is returned.
     ///
     /// This method's implementations currently are not specified to
-    /// handle \c RRTypes such as RRSIG and NSEC3. RRSIGs are attached
-    /// to their corresponding \c RRset and it is not straightforward to
-    /// search for them. Searching for RRSIGs will return \c false
-    /// always. Support for RRSIGs may be added in the future.
+    /// handle \c RRTypes such as RRSIG and NSEC3.  This interface may be
+    /// refined to clarify this point in the future, and perhaps, provide
+    /// additional API for these RRType.
     ///
-    /// Non-concrete types such as ANY and AXFR are unsupported and will
-    /// return \c false always.
+    /// As for RRSIG, there are some fundamental open questions.  For
+    /// example, it's not clear whether we want to return all RRSIGs of
+    /// the given name covering any RR types (in which case, we need to
+    /// figure out how), or we need to extend the interface so we can
+    /// specify the covered type.  A specific derived implementation may
+    /// return something if type RRSIG is specified, but this is not
+    /// specified here at the base class level. So, for RRSIGs the
+    /// behavior should be assumed as undefined.
+    ///
+    /// As for NSEC3, it's not clear whether owner names (which included
+    /// hashed labels) are the best choice of search key, because in many
+    /// cases, what the application wants to find is an NSEC3 that has the
+    /// hash of some particular "normal" domain names.  Also, if the underlying
+    /// implementation encapsulates a single zone, NSEC3 records conceptually
+    /// belong to a separate name space, which may cause implementation
+    /// difficulty.
+    ///
+    /// Behavior with meta types such as ANY and AXFR are also
+    /// undefined. A specific implementation may return something for
+    /// these.  But, unlike the case of RRSIGs, these types of RRsets
+    /// are not expected to be added to any implementation of
+    /// collection in the first place (by the definition of "meta
+    /// types"), so querying for such types is basically an invalid
+    /// operation. The API doesn't require implementations to check
+    /// this condition and reject it, so the behavior is
+    /// undefined. This interface will not be refined in future
+    /// versions for these meta types.
     ///
     /// \throw RRsetCollectionError if find() results in some
     /// implementation-specific error.
@@ -185,6 +209,8 @@ public:
     }
 };
 
+typedef boost::shared_ptr<RRsetCollectionBase> RRsetCollectionPtr;
+
 } // end of namespace dns
 } // end of namespace isc
 
diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h
index 273a486..5541635 100644
--- a/src/lib/dns/rrtype-placeholder.h
+++ b/src/lib/dns/rrtype-placeholder.h
@@ -262,43 +262,13 @@ public:
     // BEGIN_WELL_KNOWN_TYPE_DECLARATIONS
     // END_WELL_KNOWN_TYPE_DECLARATIONS
 
-    static const RRType& IXFR();
-    static const RRType& AXFR();
-    static const RRType& ANY();
-
 private:
-    // \brief Meta-classes
-    // XXX: these should be implemented using rrparamregistry
-    enum {
-        RRTYPE_IXFR = 251,
-        RRTYPE_AXFR = 252,
-        RRTYPE_ANY = 255
-    };
-
     uint16_t typecode_;
 };
 
 // BEGIN_WELL_KNOWN_TYPE_DEFINITIONS
 // END_WELL_KNOWN_TYPE_DEFINITIONS
 
-inline const RRType&
-RRType::IXFR() {
-    static RRType rrtype(RRTYPE_IXFR);
-    return (rrtype);
-}
-
-inline const RRType&
-RRType::AXFR() {
-    static RRType rrtype(RRTYPE_AXFR);
-    return (rrtype);
-}
-
-inline const RRType&
-RRType::ANY() {
-    static RRType rrtype(RRTYPE_ANY);
-    return (rrtype);
-}
-
 ///
 /// \brief Insert the \c RRType as a string into stream.
 ///
diff --git a/src/lib/dns/tests/rdata_cname_unittest.cc b/src/lib/dns/tests/rdata_cname_unittest.cc
index 6451f72..5f602f0 100644
--- a/src/lib/dns/tests/rdata_cname_unittest.cc
+++ b/src/lib/dns/tests/rdata_cname_unittest.cc
@@ -33,11 +33,16 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_CNAME_Test : public RdataTest {
-    // there's nothing to specialize
+public:
+    Rdata_CNAME_Test() :
+        rdata_cname("cn.example.com."),
+        rdata_cname2("cn2.example.com.")
+    {}
+
+    const generic::CNAME rdata_cname;
+    const generic::CNAME rdata_cname2;
 };
 
-const generic::CNAME rdata_cname("cn.example.com");
-const generic::CNAME rdata_cname2("cn2.example.com");
 const uint8_t wiredata_cname[] = {
     0x02, 0x63, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
     0x63, 0x6f, 0x6d, 0x00 };
@@ -50,16 +55,21 @@ const uint8_t wiredata_cname2[] = {
     0x03, 0x63, 0x6e, 0x32, 0xc0, 0x03 };
 
 TEST_F(Rdata_CNAME_Test, createFromText) {
-    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com")));
+    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com.")));
     // explicitly add a trailing dot.  should be the same RDATA.
     EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com.")));
     // should be case sensitive.
-    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("CN.EXAMPLE.COM")));
+    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("CN.EXAMPLE.COM.")));
     // RDATA of a class-independent type should be recognized for any
     // "unknown" class.
     EXPECT_EQ(0, rdata_cname.compare(*createRdata(RRType("CNAME"),
                                                   RRClass(65000),
-                                                  "cn.example.com")));
+                                                  "cn.example.com.")));
+}
+
+TEST_F(Rdata_CNAME_Test, badText) {
+    // Extra text at end of line
+    EXPECT_THROW(generic::CNAME("cname.example.com. extra."), InvalidRdataText);
 }
 
 TEST_F(Rdata_CNAME_Test, createFromWire) {
@@ -79,7 +89,7 @@ TEST_F(Rdata_CNAME_Test, createFromWire) {
                                       "rdata_cname_fromWire", 71),
                  DNSMessageFORMERR);
 
-    EXPECT_EQ(0, generic::CNAME("cn2.example.com").compare(
+    EXPECT_EQ(0, generic::CNAME("cn2.example.com.").compare(
                   *rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
                                         "rdata_cname_fromWire", 55)));
     EXPECT_THROW(*rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
@@ -90,7 +100,17 @@ TEST_F(Rdata_CNAME_Test, createFromWire) {
 TEST_F(Rdata_CNAME_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_cname.compare(
         *test::createRdataUsingLexer(RRType::CNAME(), RRClass::IN(),
-                                     "cn.example.com")));
+                                     "cn.example.com.")));
+
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, generic::CNAME("cname10.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::CNAME(), RRClass::IN(),
+                                     "cname10")));
+
+    // Extra text at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::CNAME(), RRClass::IN(),
+                                             "cname.example.com. extra."));
 }
 
 TEST_F(Rdata_CNAME_Test, toWireBuffer) {
diff --git a/src/lib/dns/tests/rdata_dname_unittest.cc b/src/lib/dns/tests/rdata_dname_unittest.cc
index c4e517c..7209e36 100644
--- a/src/lib/dns/tests/rdata_dname_unittest.cc
+++ b/src/lib/dns/tests/rdata_dname_unittest.cc
@@ -33,11 +33,16 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_DNAME_Test : public RdataTest {
-    // there's nothing to specialize
+public:
+    Rdata_DNAME_Test() :
+        rdata_dname("dn.example.com."),
+        rdata_dname2("dn2.example.com.")
+    {}
+
+    const generic::DNAME rdata_dname;
+    const generic::DNAME rdata_dname2;
 };
 
-const generic::DNAME rdata_dname("dn.example.com");
-const generic::DNAME rdata_dname2("dn2.example.com");
 const uint8_t wiredata_dname[] = {
     0x02, 0x64, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
     0x63, 0x6f, 0x6d, 0x00 };
@@ -52,16 +57,21 @@ const uint8_t wiredata_dname2[] = {
     0x63, 0x6f, 0x6d, 0x00 };
 
 TEST_F(Rdata_DNAME_Test, createFromText) {
-    EXPECT_EQ(0, rdata_dname.compare(generic::DNAME("dn.example.com")));
+    EXPECT_EQ(0, rdata_dname.compare(generic::DNAME("dn.example.com.")));
     // explicitly add a trailing dot.  should be the same RDATA.
     EXPECT_EQ(0, rdata_dname.compare(generic::DNAME("dn.example.com.")));
     // should be case sensitive.
-    EXPECT_EQ(0, rdata_dname.compare(generic::DNAME("DN.EXAMPLE.COM")));
+    EXPECT_EQ(0, rdata_dname.compare(generic::DNAME("DN.EXAMPLE.COM.")));
     // RDATA of a class-independent type should be recognized for any
     // "unknown" class.
     EXPECT_EQ(0, rdata_dname.compare(*createRdata(RRType("DNAME"),
                                                   RRClass(65000),
-                                                  "dn.example.com")));
+                                                  "dn.example.com.")));
+}
+
+TEST_F(Rdata_DNAME_Test, badText) {
+    // Extra text at end of line
+    EXPECT_THROW(generic::DNAME("dname.example.com. extra."), InvalidRdataText);
 }
 
 TEST_F(Rdata_DNAME_Test, createFromWire) {
@@ -81,7 +91,7 @@ TEST_F(Rdata_DNAME_Test, createFromWire) {
                                       "rdata_dname_fromWire", 71),
                  DNSMessageFORMERR);
 
-    EXPECT_EQ(0, generic::DNAME("dn2.example.com").compare(
+    EXPECT_EQ(0, generic::DNAME("dn2.example.com.").compare(
                   *rdataFactoryFromFile(RRType("DNAME"), RRClass("IN"),
                                         "rdata_dname_fromWire", 55)));
     EXPECT_THROW(*rdataFactoryFromFile(RRType("DNAME"), RRClass("IN"),
@@ -92,7 +102,17 @@ TEST_F(Rdata_DNAME_Test, createFromWire) {
 TEST_F(Rdata_DNAME_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_dname.compare(
         *test::createRdataUsingLexer(RRType::DNAME(), RRClass::IN(),
-                                     "dn.example.com")));
+                                     "dn.example.com.")));
+
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, generic::DNAME("dname8.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::DNAME(), RRClass::IN(),
+                                     "dname8")));
+
+    // Extra text at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::DNAME(), RRClass::IN(),
+                                             "dname.example.com. extra."));
 }
 
 TEST_F(Rdata_DNAME_Test, toWireBuffer) {
diff --git a/src/lib/dns/tests/rdata_mx_unittest.cc b/src/lib/dns/tests/rdata_mx_unittest.cc
index 6c6039a..6e4eaba 100644
--- a/src/lib/dns/tests/rdata_mx_unittest.cc
+++ b/src/lib/dns/tests/rdata_mx_unittest.cc
@@ -32,13 +32,16 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_MX_Test : public RdataTest {
-    // there's nothing to specialize
-};
+public:
+    Rdata_MX_Test() :
+        rdata_mx(10, Name("mx.example.com"))
+    {}
 
-const generic::MX rdata_mx(10, Name("mx.example.com"));
+    const generic::MX rdata_mx;
+};
 
 TEST_F(Rdata_MX_Test, createFromText) {
-    const generic::MX rdata_mx2("10 mx.example.com");
+    const generic::MX rdata_mx2("10 mx.example.com.");
     EXPECT_EQ(0, rdata_mx2.compare(rdata_mx));
 }
 
@@ -48,6 +51,12 @@ TEST_F(Rdata_MX_Test, badText) {
     EXPECT_THROW(const generic::MX rdata_mx("SPOON"), InvalidRdataText);
     EXPECT_THROW(const generic::MX rdata_mx("10 mx. example.com."),
                  InvalidRdataText);
+    // No origin and relative
+    EXPECT_THROW(const generic::MX rdata_mx("10 mx.example.com"),
+                 MissingNameOrigin);
+    // Extra text at end of line
+    EXPECT_THROW(const generic::MX rdata_mx("10 mx.example.com. extra."),
+                 InvalidRdataText);
 }
 
 TEST_F(Rdata_MX_Test, copy) {
@@ -65,11 +74,25 @@ TEST_F(Rdata_MX_Test, createFromWire) {
 TEST_F(Rdata_MX_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_mx.compare(
         *test::createRdataUsingLexer(RRType::MX(), RRClass::IN(),
-                                     "10 mx.example.com")));
+                                     "10 mx.example.com.")));
+
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, generic::MX("10 mx2.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::MX(), RRClass::IN(),
+                                     "10 mx2")));
 
     // Exceptions cause NULL to be returned.
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::MX(), RRClass::IN(),
-                                             "10 mx. example.com"));
+                                             "10 mx. example.com."));
+
+    // 65536 is larger than maximum possible preference
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::MX(), RRClass::IN(),
+                                             "65536 mx.example.com."));
+
+    // Extra text at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::MX(), RRClass::IN(),
+                                             "10 mx.example.com. extra."));
 }
 
 TEST_F(Rdata_MX_Test, toWireRenderer) {
diff --git a/src/lib/dns/tests/rdata_ns_unittest.cc b/src/lib/dns/tests/rdata_ns_unittest.cc
index d536393..53eb670 100644
--- a/src/lib/dns/tests/rdata_ns_unittest.cc
+++ b/src/lib/dns/tests/rdata_ns_unittest.cc
@@ -33,11 +33,16 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_NS_Test : public RdataTest {
-    // there's nothing to specialize
+public:
+    Rdata_NS_Test() :
+        rdata_ns("ns.example.com."),
+        rdata_ns2("ns2.example.com.")
+    {}
+
+    const generic::NS rdata_ns;
+    const generic::NS rdata_ns2;
 };
 
-const generic::NS rdata_ns("ns.example.com");
-const generic::NS rdata_ns2("ns2.example.com");
 const uint8_t wiredata_ns[] = {
     0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
     0x63, 0x6f, 0x6d, 0x00 };
@@ -50,15 +55,20 @@ const uint8_t wiredata_ns2[] = {
     0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
 
 TEST_F(Rdata_NS_Test, createFromText) {
-    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com")));
+    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
     // explicitly add a trailing dot.  should be the same RDATA.
     EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
     // should be case sensitive.
-    EXPECT_EQ(0, rdata_ns.compare(generic::NS("NS.EXAMPLE.COM")));
+    EXPECT_EQ(0, rdata_ns.compare(generic::NS("NS.EXAMPLE.COM.")));
     // RDATA of a class-independent type should be recognized for any
     // "unknown" class.
     EXPECT_EQ(0, rdata_ns.compare(*createRdata(RRType("NS"), RRClass(65000),
-                                               "ns.example.com")));
+                                               "ns.example.com.")));
+}
+
+TEST_F(Rdata_NS_Test, badText) {
+    // Extra input at end of line
+    EXPECT_THROW(generic::NS("ns.example.com. extra."), InvalidRdataText);
 }
 
 TEST_F(Rdata_NS_Test, createFromWire) {
@@ -78,7 +88,7 @@ TEST_F(Rdata_NS_Test, createFromWire) {
                                       "rdata_ns_fromWire", 71),
                  DNSMessageFORMERR);
 
-    EXPECT_EQ(0, generic::NS("ns2.example.com").compare(
+    EXPECT_EQ(0, generic::NS("ns2.example.com.").compare(
                   *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
                                         "rdata_ns_fromWire", 55)));
     EXPECT_THROW(*rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
@@ -89,11 +99,21 @@ TEST_F(Rdata_NS_Test, createFromWire) {
 TEST_F(Rdata_NS_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_ns.compare(
         *test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
-                                     "ns.example.com")));
+                                     "ns.example.com.")));
+
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, generic::NS("ns8.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+                                     "ns8")));
 
     // Exceptions cause NULL to be returned.
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
                                              ""));
+
+    // Extra input at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+                                             "ns.example.com. extra."));
 }
 
 TEST_F(Rdata_NS_Test, toWireBuffer) {
@@ -119,13 +139,13 @@ TEST_F(Rdata_NS_Test, toText) {
 }
 
 TEST_F(Rdata_NS_Test, compare) {
-    generic::NS small("a.example");
-    generic::NS large("example");
+    generic::NS small("a.example.");
+    generic::NS large("example.");
     EXPECT_TRUE(Name("a.example") > Name("example"));
     EXPECT_GT(0, small.compare(large));
 }
 
 TEST_F(Rdata_NS_Test, getNSName) {
-    EXPECT_EQ(Name("ns.example.com"), rdata_ns.getNSName());
+    EXPECT_EQ(Name("ns.example.com."), rdata_ns.getNSName());
 }
 }
diff --git a/src/lib/dns/tests/rdata_ptr_unittest.cc b/src/lib/dns/tests/rdata_ptr_unittest.cc
index 44b849a..5d6d37d 100644
--- a/src/lib/dns/tests/rdata_ptr_unittest.cc
+++ b/src/lib/dns/tests/rdata_ptr_unittest.cc
@@ -37,11 +37,16 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_PTR_Test : public RdataTest {
-    // there's nothing to specialize
+public:
+     Rdata_PTR_Test() :
+         rdata_ptr("ns.example.com."),
+         rdata_ptr2("ns2.example.com.")
+     {}
+
+     const generic::PTR rdata_ptr;
+     const generic::PTR rdata_ptr2;
 };
 
-const generic::PTR rdata_ptr("ns.example.com");
-const generic::PTR rdata_ptr2("ns2.example.com");
 const uint8_t wiredata_ptr[] = {
     0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
     0x63, 0x6f, 0x6d, 0x00 };
@@ -54,15 +59,20 @@ const uint8_t wiredata_ptr2[] = {
     0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
 
 TEST_F(Rdata_PTR_Test, createFromText) {
-    EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("ns.example.com")));
+    EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("ns.example.com.")));
     // explicitly add a trailing dot.  should be the same RDATA.
     EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("ns.example.com.")));
     // should be case sensitive.
-    EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("NS.EXAMPLE.COM")));
+    EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("NS.EXAMPLE.COM.")));
     // RDATA of a class-independent type should be recognized for any
     // "unknown" class.
     EXPECT_EQ(0, rdata_ptr.compare(*createRdata(RRType("PTR"), RRClass(65000),
-                                               "ns.example.com")));
+                                               "ns.example.com.")));
+}
+
+TEST_F(Rdata_PTR_Test, badText) {
+    // Extra text at end of line
+    EXPECT_THROW(generic::PTR("foo.example.com. extra."), InvalidRdataText);
 }
 
 TEST_F(Rdata_PTR_Test, createFromWire) {
@@ -82,7 +92,7 @@ TEST_F(Rdata_PTR_Test, createFromWire) {
                                       "rdata_ns_fromWire", 71),
                  DNSMessageFORMERR);
 
-    EXPECT_EQ(0, generic::PTR("ns2.example.com").compare(
+    EXPECT_EQ(0, generic::PTR("ns2.example.com.").compare(
                   *rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
                                         "rdata_ns_fromWire", 55)));
     EXPECT_THROW(*rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
@@ -93,7 +103,17 @@ TEST_F(Rdata_PTR_Test, createFromWire) {
 TEST_F(Rdata_PTR_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_ptr.compare(
         *test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
-                                     "ns.example.com")));
+                                     "ns.example.com.")));
+
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, generic::PTR("foo0.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
+                                     "foo0")));
+
+    // Extra text at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
+                                             "foo.example.com. extra."));
 }
 
 TEST_F(Rdata_PTR_Test, toWireBuffer) {
@@ -119,8 +139,8 @@ TEST_F(Rdata_PTR_Test, toText) {
 }
 
 TEST_F(Rdata_PTR_Test, compare) {
-    generic::PTR small("a.example");
-    generic::PTR large("example");
+    generic::PTR small("a.example.");
+    generic::PTR large("example.");
     EXPECT_TRUE(Name("a.example") > Name("example"));
     EXPECT_GT(0, small.compare(large));
 }
diff --git a/src/lib/dns/tests/rdata_srv_unittest.cc b/src/lib/dns/tests/rdata_srv_unittest.cc
index 066755f..6ca0c7f 100644
--- a/src/lib/dns/tests/rdata_srv_unittest.cc
+++ b/src/lib/dns/tests/rdata_srv_unittest.cc
@@ -33,14 +33,23 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_SRV_Test : public RdataTest {
-    // there's nothing to specialize
+public:
+    Rdata_SRV_Test() :
+        srv_txt("1 5 1500 a.example.com."),
+        srv_txt2("1 5 1400 example.com."),
+        too_long_label("012345678901234567890123456789"
+                       "0123456789012345678901234567890123."),
+        rdata_srv(srv_txt),
+        rdata_srv2(srv_txt2)
+    {}
+
+    const string srv_txt;
+    const string srv_txt2;
+    const string too_long_label;
+    const in::SRV rdata_srv;
+    const in::SRV rdata_srv2;
 };
 
-string srv_txt("1 5 1500 a.example.com.");
-string srv_txt2("1 5 1400 example.com.");
-string too_long_label("012345678901234567890123456789"
-    "0123456789012345678901234567890123");
-
 // 1 5 1500 a.example.com.
 const uint8_t wiredata_srv[] = {
     0x00, 0x01, 0x00, 0x05, 0x05, 0xdc, 0x01, 0x61, 0x07, 0x65, 0x78,
@@ -50,9 +59,6 @@ const uint8_t wiredata_srv2[] = {
     0x00, 0x01, 0x00, 0x05, 0x05, 0x78, 0x07, 0x65, 0x78, 0x61, 0x6d,
     0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00};
 
-const in::SRV rdata_srv(srv_txt);
-const in::SRV rdata_srv2(srv_txt2);
-
 TEST_F(Rdata_SRV_Test, createFromText) {
     EXPECT_EQ(1, rdata_srv.getPriority());
     EXPECT_EQ(5, rdata_srv.getWeight());
@@ -78,6 +84,8 @@ TEST_F(Rdata_SRV_Test, badText) {
     // bad name
     EXPECT_THROW(in::SRV("1 5 1500 a.example.com." + too_long_label),
                  TooLongLabel);
+    // Extra text at end of line
+    EXPECT_THROW(in::SRV("1 5 1500 a.example.com. extra."), InvalidRdataText);
 }
 
 TEST_F(Rdata_SRV_Test, assignment) {
@@ -124,10 +132,29 @@ TEST_F(Rdata_SRV_Test, createFromLexer) {
         *test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
                                      "1 5 1500 a.example.com.")));
 
+    // test::createRdataUsingLexer() constructs relative to
+    // "example.org." origin.
+    EXPECT_EQ(0, in::SRV("1 5 1500 server16.example.org.").compare(
+        *test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
+                                     "1 5 1500 server16")));
+
     // Exceptions cause NULL to be returned.
+
+    // Bad priority
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
+                                             "65536 5 1500 "
+                                             "a.example.com."));
+    // Bad weight
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
+                                             "1 65536 1500 "
+                                             "a.example.com."));
+    // Bad port
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
                                              "1 5 281474976710656 "
                                              "a.example.com."));
+    // Extra text at end of line
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::SRV(), RRClass::IN(),
+                                             "1 5 1500 a.example.com. extra."));
 }
 
 TEST_F(Rdata_SRV_Test, toWireBuffer) {
diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc
index 11f1c54..17af873 100644
--- a/src/lib/dns/tests/rrclass_unittest.cc
+++ b/src/lib/dns/tests/rrclass_unittest.cc
@@ -148,4 +148,29 @@ TEST_F(RRClassTest, LeftShiftOperator) {
     oss << RRClass::IN();
     EXPECT_EQ(RRClass::IN().toText(), oss.str());
 }
+
+// Below, we'll check definitions for all well-known RR classes; whether they
+// are defined and have the correct parameter values.  Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct ClassParam {
+    const char* const txt;      // "IN", "CH", etc
+    const uint16_t code;        // 1, 3,
+    const RRClass& (*obj)();     // RRClass::IN(), etc
+} known_classes[] = {
+    {"IN", 1, RRClass::IN}, {"CH", 3, RRClass::CH}, {"HS", 4, RRClass::HS},
+    {"NONE", 254, RRClass::NONE}, {"ANY", 255, RRClass::ANY},
+    {NULL, 0, NULL}
+};
+
+TEST(RRClassConstTest, wellKnowns) {
+    for (int i = 0; known_classes[i].txt; ++i) {
+        SCOPED_TRACE("Checking well known RRClass: " +
+                     string(known_classes[i].txt));
+        EXPECT_EQ(known_classes[i].code,
+                  RRClass(known_classes[i].txt).getCode());
+        EXPECT_EQ(known_classes[i].code,
+                  (*known_classes[i].obj)().getCode());
+    }
+}
 }
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index 725eea7..d16ce3c 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -168,7 +168,7 @@ TEST_F(RRsetTest, addRdataPtr) {
     // Pointer version of addRdata() doesn't type check and does allow to
     //add a different type of Rdata as a result.
     rrset_a_empty.addRdata(createRdata(RRType::NS(), RRClass::IN(),
-                                       "ns.example.com"));
+                                       "ns.example.com."));
     EXPECT_EQ(3, rrset_a_empty.getRdataCount());
 }
 
@@ -205,7 +205,7 @@ TEST_F(RRsetTest, toText) {
     // Unless it is type ANY or NONE
     EXPECT_EQ("test.example.com. 3600 ANY A\n",
               rrset_any_a_empty.toText());
-    EXPECT_EQ("test.example.com. 3600 CLASS254 A\n",
+    EXPECT_EQ("test.example.com. 3600 NONE A\n",
               rrset_none_a_empty.toText());
 }
 
diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc
index 28ecee6..ee302a1 100644
--- a/src/lib/dns/tests/rrtype_unittest.cc
+++ b/src/lib/dns/tests/rrtype_unittest.cc
@@ -145,4 +145,57 @@ TEST_F(RRTypeTest, LeftShiftOperator) {
     oss << RRType::A();
     EXPECT_EQ(RRType::A().toText(), oss.str());
 }
+
+// Below, we'll check definitions for all well-known RR types; whether they
+// are defined and have the correct parameter values.  Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct TypeParam {
+    const char* const txt;      // "A", "AAAA", "NS", etc
+    const uint16_t code;        // 1, 28, 2, etc
+    const RRType& (*obj)();     // RRType::A(), etc
+} known_types[] = {
+    {"A", 1, RRType::A}, {"NS", 2, RRType::NS}, {"MD", 3, RRType::MD},
+    {"MF", 4, RRType::MF}, {"CNAME", 5, RRType::CNAME},
+    {"SOA", 6, RRType::SOA}, {"MB", 7, RRType::MB}, {"MG", 8, RRType::MG},
+    {"MR", 9, RRType::MR}, {"NULL", 10, RRType::Null},
+    {"WKS", 11, RRType::WKS}, {"PTR", 12, RRType::PTR},
+    {"HINFO", 13, RRType::HINFO}, {"MINFO", 14, RRType::MINFO},
+    {"MX", 15, RRType::MX}, {"TXT", 16, RRType::TXT}, {"RP", 17, RRType::RP},
+    {"AFSDB", 18, RRType::AFSDB}, {"X25", 19, RRType::X25},
+    {"ISDN", 20, RRType::ISDN}, {"RT", 21, RRType::RT},
+    {"NSAP", 22, RRType::NSAP}, {"NSAP-PTR", 23, RRType::NSAP_PTR},
+    {"SIG", 24, RRType::SIG}, {"KEY", 25, RRType::KEY},
+    {"PX", 26, RRType::PX}, {"GPOS", 27, RRType::GPOS},
+    {"AAAA", 28, RRType::AAAA}, {"LOC", 29, RRType::LOC},
+    {"NXT", 30, RRType::NXT}, {"SRV", 33, RRType::SRV},
+    {"NAPTR", 35, RRType::NAPTR}, {"KX", 36, RRType::KX},
+    {"CERT", 37, RRType::CERT}, {"A6", 38, RRType::A6},
+    {"DNAME", 39, RRType::DNAME}, {"OPT", 41, RRType::OPT},
+    {"APL", 42, RRType::APL}, {"DS", 43, RRType::DS},
+    {"SSHFP", 44, RRType::SSHFP}, {"IPSECKEY", 45, RRType::IPSECKEY},
+    {"RRSIG", 46, RRType::RRSIG}, {"NSEC", 47, RRType::NSEC},
+    {"DNSKEY", 48, RRType::DNSKEY}, {"DHCID", 49, RRType::DHCID},
+    {"NSEC3", 50, RRType::NSEC3}, {"NSEC3PARAM", 51, RRType::NSEC3PARAM},
+    {"TLSA", 52, RRType::TLSA}, {"HIP", 55, RRType::HIP},
+    {"SPF", 99, RRType::SPF}, {"UNSPEC", 103, RRType::UNSPEC},
+    {"NID", 104, RRType::NID}, {"L32", 105, RRType::L32},
+    {"L64", 106, RRType::L64}, {"LP", 107, RRType::LP},
+    {"TKEY", 249, RRType::TKEY}, {"TSIG", 250, RRType::TSIG},
+    {"IXFR", 251, RRType::IXFR}, {"AXFR", 252, RRType::AXFR},
+    {"MAILB", 253, RRType::MAILB}, {"MAILA", 254, RRType::MAILA},
+    {"ANY", 255, RRType::ANY}, {"URI", 256, RRType::URI},
+    {"CAA", 257, RRType::CAA}, {"DLV", 32769, RRType::DLV},
+    {NULL, 0, NULL}
+};
+
+TEST(RRTypeConstTest, wellKnowns) {
+    for (int i = 0; known_types[i].txt; ++i) {
+        SCOPED_TRACE("Checking well known RRType: " +
+                     string(known_types[i].txt));
+        EXPECT_EQ(known_types[i].code, RRType(known_types[i].txt).getCode());
+        EXPECT_EQ(known_types[i].code,
+                  (*known_types[i].obj)().getCode());
+    }
+}
 }
diff --git a/src/lib/dns/tests/zone_checker_unittest.cc b/src/lib/dns/tests/zone_checker_unittest.cc
index dbe204d..320cda6 100644
--- a/src/lib/dns/tests/zone_checker_unittest.cc
+++ b/src/lib/dns/tests/zone_checker_unittest.cc
@@ -160,7 +160,7 @@ TEST_F(ZoneCheckerTest, checkSOA) {
     // Likewise, if the SOA RRset contains non SOA Rdata, it should be a bug.
     rrsets_->removeRRset(zname_, zclass_, RRType::SOA());
     soa_.reset(new RRset(zname_, zclass_, RRType::SOA(), RRTTL(60)));
-    soa_->addRdata(createRdata(RRType::NS(), zclass_, "ns.example.com"));
+    soa_->addRdata(createRdata(RRType::NS(), zclass_, "ns.example.com."));
     rrsets_->addRRset(soa_);
     EXPECT_THROW(checkZone(zname_, zclass_, *rrsets_, callbacks_), Unexpected);
     checkIssues();              // no error/warning should be reported
@@ -218,7 +218,7 @@ TEST_F(ZoneCheckerTest, checkNSData) {
     // If there's a CNAME at the name instead, it's an error.
     rrsets_->removeRRset(Name("*.example.com"), zclass_, RRType::A());
     RRsetPtr cname(new RRset(ns_name, zclass_, RRType::CNAME(), RRTTL(60)));
-    cname->addRdata(generic::CNAME("cname.example.com"));
+    cname->addRdata(generic::CNAME("cname.example.com."));
     rrsets_->addRRset(cname);
     EXPECT_FALSE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     expected_errors_.push_back("zone example.com/IN: NS 'ns.example.com' is "
@@ -245,7 +245,7 @@ TEST_F(ZoneCheckerTest, checkNSData) {
     rrsets_->removeRRset(ns_name, zclass_, RRType::CNAME());
     rrsets_->removeRRset(zname_, zclass_, RRType::NS());
     ns_.reset(new RRset(zname_, zclass_, RRType::NS(), RRTTL(60)));
-    ns_->addRdata(generic::NS("ns.example.org"));
+    ns_->addRdata(generic::NS("ns.example.org."));
     rrsets_->addRRset(ns_);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     checkIssues();
@@ -274,7 +274,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDelegation) {
     rrsets_->addRRset(ns_);
     RRsetPtr child_ns(new RRset(Name("child.example.com"), zclass_,
                                 RRType::NS(), RRTTL(60)));
-    child_ns->addRdata(generic::NS("ns.example.org"));
+    child_ns->addRdata(generic::NS("ns.example.org."));
     rrsets_->addRRset(child_ns);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     checkIssues();
@@ -282,7 +282,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDelegation) {
     // Zone cut at the NS name.  Same result.
     rrsets_->removeRRset(child_ns->getName(), zclass_, RRType::NS());
     child_ns.reset(new RRset(ns_name, zclass_, RRType::NS(), RRTTL(60)));
-    child_ns->addRdata(generic::NS("ns.example.org"));
+    child_ns->addRdata(generic::NS("ns.example.org."));
     rrsets_->addRRset(child_ns);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     checkIssues();
@@ -291,7 +291,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDelegation) {
     rrsets_->removeRRset(child_ns->getName(), zclass_, RRType::NS());
     child_ns.reset(new RRset(Name("another.ns.child.example.com"), zclass_,
                              RRType::NS(), RRTTL(60)));
-    child_ns->addRdata(generic::NS("ns.example.org"));
+    child_ns->addRdata(generic::NS("ns.example.org."));
     rrsets_->addRRset(child_ns);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     expected_warns_.push_back("zone example.com/IN: NS has no address");
@@ -309,7 +309,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDNAME) {
     ns_->addRdata(generic::NS(ns_name));
     rrsets_->addRRset(ns_);
     RRsetPtr dname(new RRset(zname_, zclass_, RRType::DNAME(), RRTTL(60)));
-    dname->addRdata(generic::DNAME("example.org"));
+    dname->addRdata(generic::DNAME("example.org."));
     rrsets_->addRRset(dname);
     EXPECT_FALSE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     expected_errors_.push_back("zone example.com/IN: NS 'ns.child.example.com'"
@@ -320,7 +320,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDNAME) {
     rrsets_->removeRRset(zname_, zclass_, RRType::DNAME());
     dname.reset(new RRset(Name("child.example.com"), zclass_, RRType::DNAME(),
                           RRTTL(60)));
-    dname->addRdata(generic::DNAME("example.org"));
+    dname->addRdata(generic::DNAME("example.org."));
     rrsets_->addRRset(dname);
     EXPECT_FALSE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     expected_errors_.push_back("zone example.com/IN: NS 'ns.child.example.com'"
@@ -332,7 +332,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDNAME) {
     // this implementation prefers the NS and skips further checks.
     ns_.reset(new RRset(Name("child.example.com"), zclass_, RRType::NS(),
                         RRTTL(60)));
-    ns_->addRdata(generic::NS("ns.example.org"));
+    ns_->addRdata(generic::NS("ns.example.org."));
     rrsets_->addRRset(ns_);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     checkIssues();
@@ -342,7 +342,7 @@ TEST_F(ZoneCheckerTest, checkNSWithDNAME) {
     rrsets_->removeRRset(dname->getName(), zclass_, RRType::DNAME());
     rrsets_->removeRRset(ns_->getName(), zclass_, RRType::NS());
     dname.reset(new RRset(ns_name, zclass_, RRType::DNAME(), RRTTL(60)));
-    dname->addRdata(generic::DNAME("example.org"));
+    dname->addRdata(generic::DNAME("example.org."));
     rrsets_->addRRset(dname);
     EXPECT_TRUE(checkZone(zname_, zclass_, *rrsets_, callbacks_));
     expected_warns_.push_back("zone example.com/IN: NS has no address");
diff --git a/src/lib/nsas/tests/nameserver_address_store_unittest.cc b/src/lib/nsas/tests/nameserver_address_store_unittest.cc
index 6ddae72..ceb5775 100644
--- a/src/lib/nsas/tests/nameserver_address_store_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_store_unittest.cc
@@ -386,7 +386,7 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) {
 
     // 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"));
+    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
diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h
index d6b4d92..9f92149 100644
--- a/src/lib/nsas/tests/nsas_test.h
+++ b/src/lib/nsas/tests/nsas_test.h
@@ -264,8 +264,8 @@ protected:
         rrch_->addRdata(ConstRdataPtr(new RdataTest<A>("1324")));
 
         // NS records take a single name
-        rrns_->addRdata(rdata::generic::NS("example.fr"));
-        rrns_->addRdata(rdata::generic::NS("example.de"));
+        rrns_->addRdata(rdata::generic::NS("example.fr."));
+        rrns_->addRdata(rdata::generic::NS("example.de."));
 
         // Single NS record with 0 TTL
         rr_single_->addRdata(rdata::generic::NS(ns_name_));
diff --git a/src/lib/python/bind10_config.py.in b/src/lib/python/bind10_config.py.in
index 6db64e2..9cd8d66 100644
--- a/src/lib/python/bind10_config.py.in
+++ b/src/lib/python/bind10_config.py.in
@@ -43,8 +43,8 @@ def reload():
     #  the system.
     # PLUGIN_PATHS: configuration modules that are not associated to specific
     #  process
-    # LIBEXECPATH: Paths to programs invoked by the boss process
-    #  The boss process (directly or via a helper module) uses this as
+    # LIBEXECPATH: Paths to programs invoked by the b10-init process
+    #  The b10-init process (directly or via a helper module) uses this as
     #  the prefererred PATH before starting a child process.
     #  When "FROM_SOURCE", it lists the directories where the programs are
     #  built so that when BIND 10 is experimentally started on the source
@@ -53,7 +53,7 @@ def reload():
     # B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
     # tests where we want to use various 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)
+    # is passed from the b10-init process)
     if "B10_FROM_SOURCE" in os.environ:
         if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
             DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
diff --git a/src/lib/python/isc/Makefile.am b/src/lib/python/isc/Makefile.am
index 8f5f144..712843e 100644
--- a/src/lib/python/isc/Makefile.am
+++ b/src/lib/python/isc/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config dns log net notify util testutils acl bind10
+SUBDIRS = datasrc util cc config dns log net notify testutils acl bind10
 SUBDIRS += xfrin log_messages server_common ddns sysinfo statistics
 
 python_PYTHON = __init__.py
diff --git a/src/lib/python/isc/__init__.py b/src/lib/python/isc/__init__.py
index 029f110..37138a2 100644
--- a/src/lib/python/isc/__init__.py
+++ b/src/lib/python/isc/__init__.py
@@ -1,7 +1,3 @@
-# On some systems, it appears the dynamic linker gets
-# confused if the order is not right here
-# There is probably a solution for this, but for now:
-# order is important here!
-import isc.cc
-import isc.config
-import isc.datasrc
+"""
+This is the top directory for common BIND 10 Python modules and packages.
+"""
diff --git a/src/lib/python/isc/acl/acl_inc.cc b/src/lib/python/isc/acl/acl_inc.cc
index a9f7c9d..d9b2c6d 100644
--- a/src/lib/python/isc/acl/acl_inc.cc
+++ b/src/lib/python/isc/acl/acl_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const acl_doc = "\
 Implementation module for ACL operations\n\n\
diff --git a/src/lib/python/isc/acl/dns_requestacl_inc.cc b/src/lib/python/isc/acl/dns_requestacl_inc.cc
index 673fa23..343c2fd 100644
--- a/src/lib/python/isc/acl/dns_requestacl_inc.cc
+++ b/src/lib/python/isc/acl/dns_requestacl_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const RequestACL_doc = "\
 The DNS Request ACL.\n\
diff --git a/src/lib/python/isc/acl/dns_requestcontext_inc.cc b/src/lib/python/isc/acl/dns_requestcontext_inc.cc
index f71bc59..2e54812 100644
--- a/src/lib/python/isc/acl/dns_requestcontext_inc.cc
+++ b/src/lib/python/isc/acl/dns_requestcontext_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const RequestContext_doc = "\
 DNS request to be checked.\n\
diff --git a/src/lib/python/isc/acl/dns_requestloader_inc.cc b/src/lib/python/isc/acl/dns_requestloader_inc.cc
index a911275..4ec2fc4 100644
--- a/src/lib/python/isc/acl/dns_requestloader_inc.cc
+++ b/src/lib/python/isc/acl/dns_requestloader_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 
 // Note: this is derived from the generic Loader class of the C++
diff --git a/src/lib/python/isc/acl/dnsacl_inc.cc b/src/lib/python/isc/acl/dnsacl_inc.cc
index b2e7338..c2a6555 100644
--- a/src/lib/python/isc/acl/dnsacl_inc.cc
+++ b/src/lib/python/isc/acl/dnsacl_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const dnsacl_doc = "\
 Implementation module for DNS ACL operations\n\n\
diff --git a/src/lib/python/isc/bind10/Makefile.am b/src/lib/python/isc/bind10/Makefile.am
index aa5d0ab..8d2f179 100644
--- a/src/lib/python/isc/bind10/Makefile.am
+++ b/src/lib/python/isc/bind10/Makefile.am
@@ -3,3 +3,8 @@ SUBDIRS = . tests
 python_PYTHON = __init__.py sockcreator.py component.py special_component.py \
 		socket_cache.py
 pythondir = $(pyexecdir)/isc/bind10
+
+CLEANDIRS = __pycache__
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/lib/python/isc/bind10/component.py b/src/lib/python/isc/bind10/component.py
index febeb10..2efb376 100644
--- a/src/lib/python/isc/bind10/component.py
+++ b/src/lib/python/isc/bind10/component.py
@@ -28,12 +28,12 @@ configuration). This is yet to be designed.
 """
 
 import isc.log
-from isc.log_messages.bind10_messages import *
+from isc.log_messages.init_messages import *
 import time
 import os
 import signal
 
-logger = isc.log.Logger("boss")
+logger = isc.log.Logger("init")
 DBG_TRACE_DATA = 20
 DBG_TRACE_DETAILED = 80
 
@@ -96,13 +96,13 @@ class BaseComponent:
     that is already shutting down, impossible to stop, etc. We need to add more
     states in future to handle it properly.
     """
-    def __init__(self, boss, kind):
+    def __init__(self, b10_init, kind):
         """
         Creates the component in not running mode.
 
         The parameters are:
-        - `boss` the boss object to plug into. The component needs to plug
-          into it to know when it failed, etc.
+        - `b10_init` the b10_init object to plug into. The component needs
+           to plug into it to know when it failed, etc.
         - `kind` is the kind of component. It may be one of:
           * 'core' means the system can't run without it and it can't be
             safely restarted. If it does not start, the system is brought
@@ -127,7 +127,7 @@ class BaseComponent:
         Note that the __init__ method of child class should have these
         parameters:
 
-        __init__(self, process, boss, kind, address=None, params=None)
+        __init__(self, process, b10_init, kind, address=None, params=None)
 
         The extra parameters are:
         - `process` - which program should be started.
@@ -153,7 +153,7 @@ class BaseComponent:
             raise ValueError('Component kind can not be ' + kind)
         self.__state = STATE_STOPPED
         self._kind = kind
-        self._boss = boss
+        self._b10_init = b10_init
         self._original_start_time = None
 
     def start(self):
@@ -204,13 +204,14 @@ class BaseComponent:
 
     def failed(self, exit_code):
         """
-        Notify the component it crashed. This will be called from boss object.
+        Notify the component it crashed. This will be called from b10_init
+        object.
 
         If you try to call failed on a component that is not running,
         a ValueError is raised.
 
         If it is a core component or needed component and it was started only
-        recently, the component will become dead and will ask the boss to shut
+        recently, the component will become dead and will ask b10_init to shut
         down with error exit status. A dead component can't be started again.
 
         Otherwise the component will try to restart.
@@ -253,7 +254,7 @@ class BaseComponent:
              self._original_start_time):
             self.__state = STATE_DEAD
             logger.fatal(BIND10_COMPONENT_UNSATISFIED, self.name())
-            self._boss.component_shutdown(1)
+            self._b10_init.component_shutdown(1)
             return False
         # This means we want to restart
         else:
@@ -326,7 +327,7 @@ class BaseComponent:
         should be registered).
 
         You should register all the processes created by calling
-        self._boss.register_process.
+        self._b10_init.register_process.
         """
         pass
 
@@ -407,15 +408,15 @@ class Component(BaseComponent):
     directly. It is not recommended to override methods of this class
     on one-by-one basis.
     """
-    def __init__(self, process, boss, kind, address=None, params=None,
+    def __init__(self, process, b10_init, kind, address=None, params=None,
                  start_func=None):
         """
         Creates the component in not running mode.
 
         The parameters are:
         - `process` is the name of the process to start.
-        - `boss` the boss object to plug into. The component needs to plug
-          into it to know when it failed, etc.
+        - `b10_init` the b10-init object to plug into. The component needs to
+          plug into it to know when it failed, etc.
         - `kind` is the kind of component. Refer to the documentation of
           BaseComponent for details.
         - `address` is the address on message bus. It is used to ask it to
@@ -429,7 +430,7 @@ class Component(BaseComponent):
            There's a sensible default if not provided, which just launches
            the program without any special care.
         """
-        BaseComponent.__init__(self, boss, kind)
+        BaseComponent.__init__(self, b10_init, kind)
         self._process = process
         self._start_func = start_func
         self._address = address
@@ -443,25 +444,26 @@ class Component(BaseComponent):
         process and return the procinfo object describing the running process.
 
         If you don't provide the _start_func, the usual startup by calling
-        boss.start_simple is performed.
+        b10_init.start_simple is performed.
         """
         # This one is not tested. For one, it starts a real process
         # which is out of scope of unit tests, for another, it just
-        # delegates the starting to other function in boss (if a derived
+        # delegates the starting to other function in b10_init (if a derived
         # class does not provide an override function), which is tested
         # by use.
         if self._start_func is not None:
             procinfo = self._start_func()
         else:
             # TODO Handle params, etc
-            procinfo = self._boss.start_simple(self._process)
+            procinfo = self._b10_init.start_simple(self._process)
         self._procinfo = procinfo
-        self._boss.register_process(self.pid(), self)
+        self._b10_init.register_process(self.pid(), self)
 
     def _stop_internal(self):
-        self._boss.stop_process(self._process, self._address, self.pid())
+        self._b10_init.stop_process(self._process, self._address, self.pid())
         # TODO Some way to wait for the process that doesn't want to
-        # terminate and kill it would prove nice (or add it to boss somewhere?)
+        # terminate and kill it would prove nice (or add it to b10_init
+        # somewhere?)
 
     def name(self):
         """
@@ -498,7 +500,7 @@ class Configurator:
     b10-auth as core, it is safe to stop that one.
 
     The parameters are:
-    * `boss`: The boss we are managing for.
+    * `b10_init`: The b10-init we are managing for.
     * `specials`: Dict of specially started components. Each item is a class
       representing the component.
 
@@ -527,13 +529,14 @@ class Configurator:
       priority are started before the ones with lower priority. If it is
       not present, it defaults to 0.
     """
-    def __init__(self, boss, specials = {}):
+    def __init__(self, b10_init, specials = {}):
         """
         Initializes the configurator, but nothing is started yet.
 
-        The boss parameter is the boss object used to start and stop processes.
+        The b10_init parameter is the b10-init object used to start and stop
+        processes.
         """
-        self.__boss = boss
+        self.__b10_init = b10_init
         # These could be __private, but as we access them from within unittest,
         # it's more comfortable to have them just _protected.
 
@@ -551,7 +554,7 @@ class Configurator:
     def startup(self, configuration):
         """
         Starts the first set of processes. This configuration is expected
-        to be hardcoded from the boss itself to start the configuration
+        to be hardcoded from the b10-init itself to start the configuration
         manager and other similar things.
         """
         if self._running:
@@ -642,7 +645,7 @@ class Configurator:
                     # TODO: Better error handling
                     creator = self.__specials[component_config['special']]
                 component = creator(component_config.get('process', cname),
-                                    self.__boss, component_config['kind'],
+                                    self.__b10_init, component_config['kind'],
                                     component_config.get('address'),
                                     component_config.get('params'))
                 priority = component_config.get('priority', 0)
diff --git a/src/lib/python/isc/bind10/sockcreator.py b/src/lib/python/isc/bind10/sockcreator.py
index 593d1a6..db9e6c5 100644
--- a/src/lib/python/isc/bind10/sockcreator.py
+++ b/src/lib/python/isc/bind10/sockcreator.py
@@ -20,10 +20,10 @@ import errno
 import copy
 import subprocess
 import copy
-from isc.log_messages.bind10_messages import *
+from isc.log_messages.init_messages import *
 from libutil_io_python import recv_fd
 
-logger = isc.log.Logger("boss")
+logger = isc.log.Logger("init")
 
 """
 Module that comunicates with the privileged socket creator (b10-sockcreator).
@@ -251,7 +251,7 @@ class Creator(Parser):
         """Function used before running a program that needs to run as a
         different user."""
         # Put us into a separate process group so we don't get
-        # SIGINT signals on Ctrl-C (the boss will shut everthing down by
+        # SIGINT signals on Ctrl-C (b10-init will shut everthing down by
         # other means).
         os.setpgrp()
 
diff --git a/src/lib/python/isc/bind10/socket_cache.py b/src/lib/python/isc/bind10/socket_cache.py
index d6c1175..1c5199c 100644
--- a/src/lib/python/isc/bind10/socket_cache.py
+++ b/src/lib/python/isc/bind10/socket_cache.py
@@ -106,7 +106,8 @@ class Cache:
     This is the cache for sockets from socket creator. The purpose of cache
     is to hold the sockets that were requested, until they are no longer
     needed. One reason is, the socket is created before it is sent over the
-    unix domain socket in boss, so we need to keep it somewhere for a while.
+    unix domain socket in b10-init, so we need to keep it somewhere for a
+    while.
 
     The other reason is, a single socket might be requested multiple times.
     So we keep it here in case someone else might ask for it.
@@ -114,7 +115,7 @@ class Cache:
     Each socket kept here has a reference count and when it drops to zero,
     it is removed from cache and closed.
 
-    This is expected to be part of Boss, it is not a general utility class.
+    This is expected to be part of Init, it is not a general utility class.
 
     It is not expected to be subclassed. The methods and members are named
     as protected so tests are easier access into them.
@@ -175,7 +176,7 @@ class Cache:
           restrictions and of all copies of socket handed out are considered,
           so it can be raised even if you call it with share_mode 'ANY').
         - isc.bind10.sockcreator.CreatorError: fatal creator errors are
-          propagated. Thay should cause the boss to exit if ever encountered.
+          propagated. Thay should cause b10-init to exit if ever encountered.
 
         Note that it isn't guaranteed the tokens would be unique and they
         should be used as an opaque handle only.
@@ -220,11 +221,11 @@ class Cache:
         one returned from previous call from get_token. The token can be used
         only once to receive the socket.
 
-        The application is a token representing the application that requested
-        it. Currently, boss uses the file descriptor of connection from the
-        application, but anything which can be a key in a dict is OK from the
-        cache's point of view. You just need to use the same thing in
-        drop_application.
+        The application is a token representing the application that
+        requested it. Currently, b10-init uses the file descriptor of
+        connection from the application, but anything which can be a key in
+        a dict is OK from the cache's point of view. You just need to use
+        the same thing in drop_application.
 
         In case the token is considered invalid (it doesn't come from the
         get_token, it was already used, the socket wasn't picked up soon
diff --git a/src/lib/python/isc/bind10/special_component.py b/src/lib/python/isc/bind10/special_component.py
index dcd9b64..3196795 100644
--- a/src/lib/python/isc/bind10/special_component.py
+++ b/src/lib/python/isc/bind10/special_component.py
@@ -26,23 +26,23 @@ class SockCreator(BaseComponent):
 
     Note: _creator shouldn't be reset explicitly once created.  The
     underlying Popen object would then wait() the child process internally,
-    which breaks the assumption of the boss, who is expecting to see
+    which breaks the assumption of b10-init, who is expecting to see
     the process die in waitpid().
     """
-    def __init__(self, process, boss, kind, address=None, params=None):
-        BaseComponent.__init__(self, boss, kind)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        BaseComponent.__init__(self, b10_init, kind)
         self.__creator = None
 
     def _start_internal(self):
-        self._boss.curproc = 'b10-sockcreator'
+        self._b10_init.curproc = 'b10-sockcreator'
         self.__creator = isc.bind10.sockcreator.Creator(LIBEXECPATH + ':' +
                                                         os.environ['PATH'])
-        self._boss.register_process(self.pid(), self)
-        self._boss.set_creator(self.__creator)
-        self._boss.log_started(self.pid())
+        self._b10_init.register_process(self.pid(), self)
+        self._b10_init.set_creator(self.__creator)
+        self._b10_init.log_started(self.pid())
 
         # We are now ready for switching user.
-        self._boss.change_user()
+        self._b10_init.change_user()
 
     def _stop_internal(self):
         self.__creator.terminate()
@@ -64,12 +64,12 @@ class SockCreator(BaseComponent):
 
 class Msgq(Component):
     """
-    The message queue. Starting is passed to boss, stopping is not supported
-    and we leave the boss kill it by signal.
+    The message queue. Starting is passed to b10-init, stopping is not
+    supported and we leave b10-init kill it by signal.
     """
-    def __init__(self, process, boss, kind, address=None, params=None):
-        Component.__init__(self, process, boss, kind, None, None,
-                           boss.start_msgq)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        Component.__init__(self, process, b10_init, kind, None, None,
+                           b10_init.start_msgq)
 
     def _stop_internal(self):
         """
@@ -78,7 +78,7 @@ class Msgq(Component):
         But as it is stateless, it's OK to kill it.
 
         So we disable this method (as the only time it could be called is
-        during shutdown) and wait for the boss to kill it in the next shutdown
+        during shutdown) and wait for b10-init to kill it in the next shutdown
         step.
 
         This actually breaks the recommendation at Component we shouldn't
@@ -89,24 +89,24 @@ class Msgq(Component):
         pass
 
 class CfgMgr(Component):
-    def __init__(self, process, boss, kind, address=None, params=None):
-        Component.__init__(self, process, boss, kind, 'ConfigManager',
-                           None, boss.start_cfgmgr)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        Component.__init__(self, process, b10_init, kind, 'ConfigManager',
+                           None, b10_init.start_cfgmgr)
 
 class Auth(Component):
-    def __init__(self, process, boss, kind, address=None, params=None):
-        Component.__init__(self, process, boss, kind, 'Auth', None,
-                           boss.start_auth)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        Component.__init__(self, process, b10_init, kind, 'Auth', None,
+                           b10_init.start_auth)
 
 class Resolver(Component):
-    def __init__(self, process, boss, kind, address=None, params=None):
-        Component.__init__(self, process, boss, kind, 'Resolver', None,
-                           boss.start_resolver)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        Component.__init__(self, process, b10_init, kind, 'Resolver', None,
+                           b10_init.start_resolver)
 
 class CmdCtl(Component):
-    def __init__(self, process, boss, kind, address=None, params=None):
-        Component.__init__(self, process, boss, kind, 'Cmdctl', None,
-                           boss.start_cmdctl)
+    def __init__(self, process, b10_init, kind, address=None, params=None):
+        Component.__init__(self, process, b10_init, kind, 'Cmdctl', None,
+                           b10_init.start_cmdctl)
 def get_specials():
     """
     List of specially started components. Each one should be the class than can
diff --git a/src/lib/python/isc/bind10/tests/component_test.py b/src/lib/python/isc/bind10/tests/component_test.py
index 8603201..adc035e 100644
--- a/src/lib/python/isc/bind10/tests/component_test.py
+++ b/src/lib/python/isc/bind10/tests/component_test.py
@@ -31,9 +31,9 @@ class TestError(Exception):
     """
     pass
 
-class BossUtils:
+class InitUtils:
     """
-    A class that brings some utilities for pretending we're Boss.
+    A class that brings some utilities for pretending we're Init.
     This is expected to be inherited by the testcases themselves.
     """
     def setUp(self):
@@ -70,7 +70,7 @@ class BossUtils:
         isc.bind10.component.time.time = lambda: tm + 30
 
     # Few functions that pretend to start something. Part of pretending of
-    # being boss.
+    # being b10-init.
     def start_msgq(self):
         pass
 
@@ -86,7 +86,7 @@ class BossUtils:
     def start_cmdctl(self):
         pass
 
-class ComponentTests(BossUtils, unittest.TestCase):
+class ComponentTests(InitUtils, unittest.TestCase):
     """
     Tests for the bind10.component.Component class
     """
@@ -94,7 +94,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
         """
         Pretend a newly started system.
         """
-        BossUtils.setUp(self)
+        InitUtils.setUp(self)
         self._shutdown = False
         self._exitcode = None
         self.__start_called = False
@@ -103,7 +103,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
         self.__registered_processes = {}
         self.__stop_process_params = None
         self.__start_simple_params = None
-        # Pretending to be boss
+        # Pretending to be b10-init
         self.__change_user_called = False
 
     def change_user(self):
@@ -149,7 +149,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
         its behaviour.
 
         The process used is some nonsense, as this isn't used in this
-        kind of tests and we pretend to be the boss.
+        kind of tests and we pretend to be the b10-init.
         """
         component = Component('No process', self, kind, 'homeless', [])
         component._start_internal = self.__start
@@ -176,7 +176,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
         Test the correct data are stored inside the component.
         """
         component = self.__create_component('core')
-        self.assertEqual(self, component._boss)
+        self.assertEqual(self, component._b10_init)
         self.assertEqual("No process", component._process)
         self.assertEqual(None, component._start_func)
         self.assertEqual("homeless", component._address)
@@ -539,7 +539,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
 
     def register_process(self, pid, process):
         """
-        Part of pretending to be a boss
+        Part of pretending to be a b10-init
         """
         self.__registered_processes[pid] = process
 
@@ -570,13 +570,13 @@ class ComponentTests(BossUtils, unittest.TestCase):
 
     def stop_process(self, process, address, pid):
         """
-        Part of pretending to be boss.
+        Part of pretending to be b10-init.
         """
         self.__stop_process_params = (process, address, pid)
 
     def start_simple(self, process):
         """
-        Part of pretending to be boss.
+        Part of pretending to be b10-init.
         """
         self.__start_simple_params = process
 
@@ -632,14 +632,14 @@ class ComponentTests(BossUtils, unittest.TestCase):
 
     def set_creator(self, creator):
         """
-        Part of faking being the boss. Check the creator (faked as well)
+        Part of faking being the b10-init. Check the creator (faked as well)
         is passed here.
         """
         self.assertTrue(isinstance(creator, self.FakeCreator))
 
     def log_started(self, pid):
         """
-        Part of faking the boss. Check the pid is the one of the fake creator.
+        Part of faking the b10-init. Check the pid is the one of the fake creator.
         """
         self.assertEqual(42, pid)
 
@@ -706,13 +706,13 @@ class FailComponent(BaseComponent):
     """
     A mock component that fails whenever it is started.
     """
-    def __init__(self, name, boss, kind, address=None, params=None):
-        BaseComponent.__init__(self, boss, kind)
+    def __init__(self, name, b10_init, kind, address=None, params=None):
+        BaseComponent.__init__(self, b10_init, kind)
 
     def _start_internal(self):
         raise TestError("test error")
 
-class ConfiguratorTest(BossUtils, unittest.TestCase):
+class ConfiguratorTest(InitUtils, unittest.TestCase):
     """
     Tests for the configurator.
     """
@@ -720,7 +720,7 @@ class ConfiguratorTest(BossUtils, unittest.TestCase):
         """
         Prepare some test data for the tests.
         """
-        BossUtils.setUp(self)
+        InitUtils.setUp(self)
         self.log = []
         # The core "hardcoded" configuration
         self.__core = {
@@ -755,11 +755,12 @@ class ConfiguratorTest(BossUtils, unittest.TestCase):
         self.__core_log = self.__core_log_create + self.__core_log_start
         self.__specials = { 'test': self.__component_test }
 
-    def __component_test(self, process, boss, kind, address=None, params=None):
+    def __component_test(self, process, b10_init, kind, address=None,
+                         params=None):
         """
         Create a test component. It will log events to us.
         """
-        self.assertEqual(self, boss)
+        self.assertEqual(self, b10_init)
         return TestComponent(self, process, kind, address, params)
 
     def test_init(self):
diff --git a/src/lib/python/isc/cc/Makefile.am b/src/lib/python/isc/cc/Makefile.am
index b0ba3b2..f7c5b00 100644
--- a/src/lib/python/isc/cc/Makefile.am
+++ b/src/lib/python/isc/cc/Makefile.am
@@ -1,6 +1,19 @@
-SUBDIRS = . tests
+SUBDIRS = . cc_generated tests
 
-python_PYTHON =	__init__.py data.py session.py message.py
+python_PYTHON =	__init__.py data.py session.py message.py logger.py
+BUILT_SOURCES = $(PYTHON_LOGMSGPKG_DIR)/work/pycc_messages.py
+nodist_pylogmessage_PYTHON = $(PYTHON_LOGMSGPKG_DIR)/work/pycc_messages.py
+pylogmessagedir = $(pyexecdir)/isc/log_messages/
+
+CLEANFILES = $(PYTHON_LOGMSGPKG_DIR)/work/pycc_messages.py
+CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/pycc_messages.pyc
+
+EXTRA_DIST = pycc_messages.mes proto_defs.py
+
+# Define rule to build logging source files from message file
+$(PYTHON_LOGMSGPKG_DIR)/work/pycc_messages.py: pycc_messages.mes
+	$(top_builddir)/src/lib/log/compiler/message \
+		-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/pycc_messages.mes
 
 pythondir = $(pyexecdir)/isc/cc
 
diff --git a/src/lib/python/isc/cc/cc_generated/.gitignore b/src/lib/python/isc/cc/cc_generated/.gitignore
new file mode 100644
index 0000000..5755493
--- /dev/null
+++ b/src/lib/python/isc/cc/cc_generated/.gitignore
@@ -0,0 +1,2 @@
+/__init__.py
+/proto_defs.py
diff --git a/src/lib/python/isc/cc/cc_generated/Makefile.am b/src/lib/python/isc/cc/cc_generated/Makefile.am
new file mode 100644
index 0000000..87e49c1
--- /dev/null
+++ b/src/lib/python/isc/cc/cc_generated/Makefile.am
@@ -0,0 +1,31 @@
+# This makefile is a hack to enable tests to run with one module generated
+# while the rest is just used. The generated file is created under build dir,
+# not the src dir, which means it is not found when these are different.
+#
+# We have a forwarder module in the src dir and build the real one in different
+# location. This is similar to what happens in log_messages/work. We can't
+# reuse the name `work`, since it would collide, so we use less generic name.
+
+nodist_python_PYTHON = proto_defs.py
+BUILT_SOURCES = proto_defs.py __init__.py
+noinst_SCRIPTS = __init__.py
+
+proto_defs.py: $(top_srcdir)/src/lib/cc/proto_defs.cc \
+	$(top_srcdir)/src/lib/util/python/pythonize_constants.py
+	$(PYTHON) $(top_srcdir)/src/lib/util/python/pythonize_constants.py \
+		$(top_srcdir)/src/lib/cc/proto_defs.cc $@
+
+# We need to create an __init__.py, so it is recognized as module.
+# But it may be empty.
+__init__.py:
+	touch $@
+
+pythondir = $(pyexecdir)/isc/cc
+
+CLEANDIRS = __pycache__
+
+CLEANFILES = proto_defs.py __init__.py
+CLEANFILES += proto_defs.pyc __init__.pyc
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/lib/python/isc/cc/logger.py b/src/lib/python/isc/cc/logger.py
new file mode 100644
index 0000000..5fd440f
--- /dev/null
+++ b/src/lib/python/isc/cc/logger.py
@@ -0,0 +1,26 @@
+# Copyright (C) 2013  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 a logging utility module for other modules of the cc library
+package.
+
+"""
+
+import isc.log
+
+# C++ version of the CC module uses 'cc'; using the same name does not
+# necessarily cause disruption, but we use a different name to minimize
+# possible confusion.
+logger = isc.log.Logger('pycc')
diff --git a/src/lib/python/isc/cc/proto_defs.py b/src/lib/python/isc/cc/proto_defs.py
new file mode 100644
index 0000000..6044a36
--- /dev/null
+++ b/src/lib/python/isc/cc/proto_defs.py
@@ -0,0 +1,2 @@
+# Forwarder module. Look into cc_generated/Makefile.am for details.
+from cc_generated.proto_defs import *
diff --git a/src/lib/python/isc/cc/pycc_messages.mes b/src/lib/python/isc/cc/pycc_messages.mes
new file mode 100644
index 0000000..997b899
--- /dev/null
+++ b/src/lib/python/isc/cc/pycc_messages.mes
@@ -0,0 +1,20 @@
+# Copyright (C) 2013  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.
+
+# No namespace declaration - these constants go in the global namespace
+# of the libddns_messages python module.
+
+% PYCC_LNAME_RECEIVED received local name: %1
+Debug message: the local module received its unique identifier (name)
+from msgq on completion of establishing the session with msgq.
diff --git a/src/lib/python/isc/cc/session.py b/src/lib/python/isc/cc/session.py
index 33a47bd..036c078 100644
--- a/src/lib/python/isc/cc/session.py
+++ b/src/lib/python/isc/cc/session.py
@@ -22,6 +22,10 @@ import threading
 import bind10_config
 
 import isc.cc.message
+import isc.log
+from isc.cc.logger import logger
+from isc.log_messages.pycc_messages import *
+from isc.cc.proto_defs import *
 
 class ProtocolError(Exception): pass
 class NetworkError(Exception): pass
@@ -30,7 +34,7 @@ class SessionTimeout(Exception): pass
 
 class Session:
     MSGQ_DEFAULT_TIMEOUT = 4000
-    
+
     def __init__(self, socket_file=None):
         self._socket = None
         self._lname = None
@@ -60,6 +64,8 @@ class Session:
             self._lname = msg["lname"]
             if not self._lname:
                 raise ProtocolError("Could not get local name")
+            logger.debug(logger.DBGLVL_TRACE_BASIC, PYCC_LNAME_RECEIVED,
+                         self._lname)
         except socket.error as se:
                 raise SessionError(se)
 
@@ -159,7 +165,7 @@ class Session:
         if len(data) == 0: # server closed connection
             raise ProtocolError("Read of 0 bytes: connection closed")
         return data
-        
+
     def _receive_len_data(self):
         """Reads self._recv_len_size bytes of data from the socket into
            self._recv_len_data
@@ -203,7 +209,7 @@ class Session:
             # they may never both be non-zero (we are either starting
             # a full read, or continuing one of the reads
             assert self._recv_size == 0 or self._recv_len_size == 0
-            
+
             if self._recv_size == 0:
                 if self._recv_len_size == 0:
                     # both zero, start a new full read
@@ -256,15 +262,35 @@ class Session:
             "instance": instance,
         })
 
-    def group_sendmsg(self, msg, group, instance = "*", to = "*"):
+    def group_sendmsg(self, msg, group, instance=CC_INSTANCE_WILDCARD,
+                      to=CC_TO_WILDCARD, want_answer=False):
+        '''
+        Send a message over the CC session.
+
+        Parameters:
+        - msg The message to send, encoded as python structures (dicts,
+          lists, etc).
+        - group The recipient group to send to.
+        - instance Instance in the group.
+        - to Direct recipient (overrides the above, should contain the
+          lname of the recipient).
+        - want_answer If an answer is requested. If there's no recipient
+          and this is true, the message queue would send an error message
+          instead of the answer.
+
+        Return:
+          A sequence number that can be used to wait for an answer
+          (see group_recvmsg).
+        '''
         seq = self._next_sequence()
         self.sendmsg({
-            "type": "send",
-            "from": self._lname,
-            "to": to,
-            "group": group,
-            "instance": instance,
-            "seq": seq,
+            CC_HEADER_TYPE: CC_COMMAND_SEND,
+            CC_HEADER_FROM: self._lname,
+            CC_HEADER_TO: to,
+            CC_HEADER_GROUP: group,
+            CC_HEADER_INSTANCE: instance,
+            CC_HEADER_SEQ: seq,
+            CC_HEADER_WANT_ANSWER: want_answer
         }, isc.cc.message.to_wire(msg))
         return seq
 
diff --git a/src/lib/python/isc/cc/tests/message_test.py b/src/lib/python/isc/cc/tests/message_test.py
index c417068..17f034d 100644
--- a/src/lib/python/isc/cc/tests/message_test.py
+++ b/src/lib/python/isc/cc/tests/message_test.py
@@ -27,20 +27,27 @@ class MessageTest(unittest.TestCase):
         self.msg1_str = "{\"just\": [\"an\", \"arbitrary\", \"structure\"]}";
         self.msg1_wire = self.msg1_str.encode()
 
-        self.msg2 = { "aaa": [ 1, 1.1, True, False, None ] }
-        self.msg2_str = "{\"aaa\": [1, 1.1, true, false, null]}";
+        self.msg2 = { "aaa": [ 1, True, False, None ] }
+        self.msg2_str = "{\"aaa\": [1, true, false, null]}";
         self.msg2_wire = self.msg2_str.encode()
 
         self.msg3 = { "aaa": [ 1, 1.1, True, False, "string\n" ] }
         self.msg3_str = "{\"aaa\": [1, 1.1, true, false, \"string\n\" ]}";
         self.msg3_wire = self.msg3_str.encode()
 
+        # Due to the inherent impreciseness of floating point values,
+        # we test this one separately (with AlmostEqual)
+        self.msg_float = 1.1
+        self.msg_float_str = "1.1";
+        self.msg_float_wire = self.msg_float_str.encode()
+
     def test_encode_json(self):
         self.assertEqual(self.msg1_wire, isc.cc.message.to_wire(self.msg1))
         self.assertEqual(self.msg2_wire, isc.cc.message.to_wire(self.msg2))
-
+        self.assertAlmostEqual(float(self.msg_float_wire),
+                               float(isc.cc.message.to_wire(self.msg_float)))
         self.assertRaises(TypeError, isc.cc.message.to_wire, NotImplemented)
-        
+
     def test_decode_json(self):
         self.assertEqual(self.msg1, isc.cc.message.from_wire(self.msg1_wire))
         self.assertEqual(self.msg2, isc.cc.message.from_wire(self.msg2_wire))
diff --git a/src/lib/python/isc/cc/tests/sendcmd.py b/src/lib/python/isc/cc/tests/sendcmd.py
index 753a649..fa5fa3c 100755
--- a/src/lib/python/isc/cc/tests/sendcmd.py
+++ b/src/lib/python/isc/cc/tests/sendcmd.py
@@ -1,4 +1,20 @@
 #!/usr/bin/python3
+
+# 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.
+
 import isc, sys
 
 cc = isc.cc.Session()
diff --git a/src/lib/python/isc/cc/tests/session_test.py b/src/lib/python/isc/cc/tests/session_test.py
index e589085..8de1e96 100644
--- a/src/lib/python/isc/cc/tests/session_test.py
+++ b/src/lib/python/isc/cc/tests/session_test.py
@@ -19,6 +19,7 @@
 
 import unittest
 import os
+import json
 from isc.cc.session import *
 
 # our fake socket, where we can read and insert messages
@@ -73,8 +74,23 @@ class MySocket():
 
         result.extend(self.readsent(header_length))
         result.extend(self.readsent(data_length))
+
         return result
 
+    def readsentmsg_parsed(self):
+        length_buf = self.readsent(4)
+        length = struct.unpack('>I', length_buf)[0]
+        header_length_buf = self.readsent(2)
+        header_length = struct.unpack('>H', header_length_buf)[0]
+        data_length = length - 2 - header_length
+
+        env = json.loads(self.readsent(header_length).decode('utf-8'), strict=False)
+        if (data_length > 0):
+            msg = json.loads(self.readsent(data_length).decode('utf-8'), strict=False)
+        else:
+            msg = {}
+        return (env, msg)
+
     def recv(self, length):
         if len(self.recvqueue) == 0:
             if self._blocking:
@@ -208,25 +224,25 @@ class testSession(unittest.TestCase):
 
         # 'malformed' messages
         # shouldn't some of these raise exceptions?
-        #self.recv_and_compare(sess, 
+        #self.recv_and_compare(sess,
         #                      b'\x00',
         #                      None, None)
-        #self.recv_and_compare(sess, 
+        #self.recv_and_compare(sess,
         #                      b'\x00\x00\x00\x10',
         #                      None, None)
-        #self.recv_and_compare(sess, 
+        #self.recv_and_compare(sess,
         #                      b'\x00\x00\x00\x02\x00\x00',
         #                      None, None)
-        #self.recv_and_compare(sess, 
+        #self.recv_and_compare(sess,
         #                      b'\x00\x00\x00\x02\x00\x02',
         #                      None, None)
-        #self.recv_and_compare(sess, 
+        #self.recv_and_compare(sess,
         #                      b'',
         #                      None, None)
 
         # need to clear
         sess._socket.recvqueue = bytearray()
-        
+
         # 'queueing' system
         # sending message {'to': 'someone', 'reply': 1}, {"hello": "a"}
         #print("sending message {'to': 'someone', 'reply': 1}, {'hello': 'a'}")
@@ -240,7 +256,7 @@ class testSession(unittest.TestCase):
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
-        
+
         # ask for a differe sequence number reply (that doesn't exist)
         # then ask for the one that is there
         self.assertFalse(sess.has_queued_msgs())
@@ -253,7 +269,7 @@ class testSession(unittest.TestCase):
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
-        
+
         # ask for a differe sequence number reply (that doesn't exist)
         # then ask for any message
         self.assertFalse(sess.has_queued_msgs())
@@ -266,7 +282,7 @@ class testSession(unittest.TestCase):
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
-        
+
         #print("sending message {'to': 'someone', 'reply': 1}, {'hello': 'a'}")
 
         # ask for a differe sequence number reply (that doesn't exist)
@@ -287,7 +303,7 @@ class testSession(unittest.TestCase):
         self.assertEqual({'to': 'someone'}, env)
         self.assertEqual({"hello": "b"}, msg)
         self.assertFalse(sess.has_queued_msgs())
-        
+
         # send a message, then one with specific reply value
         # ask for that specific message (get the second)
         # then ask for any message (get the first)
@@ -326,49 +342,73 @@ class testSession(unittest.TestCase):
     def test_group_subscribe(self):
         sess = MySession()
         sess.group_subscribe("mygroup")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00<\x00:{"group": "mygroup", "type": "subscribe", "instance": "*"}')
-        
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "subscribe",
+                                 "instance": "*"}, {}))
+
         sess.group_subscribe("mygroup")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00<\x00:{"group": "mygroup", "type": "subscribe", "instance": "*"}')
-        
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "subscribe",
+                                 "instance": "*"}, {}))
+
         sess.group_subscribe("mygroup", "my_instance")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00F\x00D{"group": "mygroup", "type": "subscribe", "instance": "my_instance"}')
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "subscribe",
+                                 "instance": "my_instance"}, {}))
 
     def test_group_unsubscribe(self):
         sess = MySession()
         sess.group_unsubscribe("mygroup")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00>\x00<{"group": "mygroup", "type": "unsubscribe", "instance": "*"}')
-        
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "unsubscribe",
+                                 "instance": "*"}, {}))
+
         sess.group_unsubscribe("mygroup")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00>\x00<{"group": "mygroup", "type": "unsubscribe", "instance": "*"}')
-        
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "unsubscribe",
+                                 "instance": "*"}, {}))
+
         sess.group_unsubscribe("mygroup", "my_instance")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00H\x00F{"group": "mygroup", "type": "unsubscribe", "instance": "my_instance"}')
+        sent = sess._socket.readsentmsg_parsed()
+        self.assertEqual(sent, ({"group": "mygroup", "type": "unsubscribe",
+                                 "instance": "my_instance"}, {}))
 
     def test_group_sendmsg(self):
         sess = MySession()
         self.assertEqual(sess._sequence, 1)
 
-        sess.group_sendmsg({ 'hello': 'a' }, "my_group")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00p\x00`{"from": "test_name", "seq": 2, "to": "*", "instance": "*", "group": "my_group", "type": "send"}{"hello": "a"}')
-        self.assertEqual(sess._sequence, 2)
+        msg = { "hello": "a" }
 
-        sess.group_sendmsg({ 'hello': 'a' }, "my_group", "my_instance")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00z\x00j{"from": "test_name", "seq": 3, "to": "*", "instance": "my_instance", "group": "my_group", "type": "send"}{"hello": "a"}')
-        self.assertEqual(sess._sequence, 3)
-        
-        sess.group_sendmsg({ 'hello': 'a' }, "your_group", "your_instance")
-        sent = sess._socket.readsentmsg()
-        self.assertEqual(sent, b'\x00\x00\x00~\x00n{"from": "test_name", "seq": 4, "to": "*", "instance": "your_instance", "group": "your_group", "type": "send"}{"hello": "a"}')
-        self.assertEqual(sess._sequence, 4)
+        def check_sent(additional_headers, sequence):
+            sent = sess._socket.readsentmsg_parsed()
+            headers = dict({"from": "test_name",
+                            "seq": sequence,
+                            "to": "*",
+                            "type": "send"},
+                           **additional_headers)
+            self.assertEqual(sent, (headers, msg))
+            self.assertEqual(sess._sequence, sequence)
+
+        sess.group_sendmsg(msg, "my_group")
+        check_sent({"instance": "*", "group": "my_group",
+                    "want_answer": False}, 2)
+
+        sess.group_sendmsg(msg, "my_group", "my_instance")
+        check_sent({"instance": "my_instance", "group": "my_group",
+                    "want_answer": False}, 3)
+
+        sess.group_sendmsg(msg, "your_group", "your_instance")
+        check_sent({"instance": "your_instance", "group": "your_group",
+                    "want_answer": False}, 4)
+
+        # Test the optional want_answer parameter
+        sess.group_sendmsg(msg, "group", want_answer=True)
+        check_sent({"instance": "*", "group": "group", "want_answer": True}, 5)
+
+
+        sess.group_sendmsg(msg, "group", want_answer=False)
+        check_sent({"instance": "*", "group": "group", "want_answer": False},
+                   6)
 
     def test_group_recvmsg(self):
         # must this one do anything except not return messages with
@@ -377,13 +417,25 @@ class testSession(unittest.TestCase):
 
     def test_group_reply(self):
         sess = MySession()
-        sess.group_reply({ 'from': 'me', 'group': 'our_group', 'instance': 'other_instance', 'seq': 4}, {"hello": "a"})
-        sent = sess._socket.readsentmsg();
-        self.assertEqual(sent, b'\x00\x00\x00\x8b\x00{{"from": "test_name", "seq": 2, "to": "me", "instance": "other_instance", "reply": 4, "group": "our_group", "type": "send"}{"hello": "a"}')
-        
-        sess.group_reply({ 'from': 'me', 'group': 'our_group', 'instance': 'other_instance', 'seq': 9}, {"hello": "a"})
-        sent = sess._socket.readsentmsg();
-        self.assertEqual(sent, b'\x00\x00\x00\x8b\x00{{"from": "test_name", "seq": 3, "to": "me", "instance": "other_instance", "reply": 9, "group": "our_group", "type": "send"}{"hello": "a"}')
+        sess.group_reply({ 'from': 'me', 'group': 'our_group',
+                           'instance': 'other_instance', 'seq': 4},
+                         {"hello": "a"})
+        sent = sess._socket.readsentmsg_parsed();
+        self.assertEqual(sent, ({"from": "test_name", "seq": 2,
+                                 "to": "me", "instance": "other_instance",
+                                 "reply": 4, "group": "our_group",
+                                 "type": "send"},
+                                {"hello": "a"}))
+
+        sess.group_reply({ 'from': 'me', 'group': 'our_group',
+                           'instance': 'other_instance', 'seq': 9},
+                         {"hello": "a"})
+        sent = sess._socket.readsentmsg_parsed();
+        self.assertEqual(sent, ({"from": "test_name", "seq": 3,
+                                 "to": "me", "instance": "other_instance",
+                                 "reply": 9, "group": "our_group",
+                                 "type": "send"},
+                                {"hello": "a"}))
 
     def test_timeout(self):
         if "BIND10_TEST_SOCKET_FILE" not in os.environ:
diff --git a/src/lib/python/isc/cc/tests/test_session.py b/src/lib/python/isc/cc/tests/test_session.py
index 3c4960f..b73e5bf 100644
--- a/src/lib/python/isc/cc/tests/test_session.py
+++ b/src/lib/python/isc/cc/tests/test_session.py
@@ -1,3 +1,18 @@
+# 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.
+
 import isc
 
 import time
diff --git a/src/lib/python/isc/config/ccsession.py b/src/lib/python/isc/config/ccsession.py
index 8464a01..a5858a7 100644
--- a/src/lib/python/isc/config/ccsession.py
+++ b/src/lib/python/isc/config/ccsession.py
@@ -37,6 +37,7 @@
 """
 
 from isc.cc import Session
+from isc.cc.proto_defs import *
 from isc.config.config_data import ConfigData, MultiConfigData, BIND10_CONFIG_DATA_VERSION
 import isc.config.module_spec
 import isc
@@ -50,6 +51,31 @@ logger = isc.log.Logger("config")
 
 class ModuleCCSessionError(Exception): pass
 
+class RPCError(ModuleCCSessionError):
+    """
+    An exception raised by rpc_call in case the remote side reports
+    an error. It can be used to distinguish remote errors from protocol errors.
+    Also, it holds the code as well as the error message.
+    """
+    def __init__(self, code, message):
+        ModuleCCSessionError.__init__(self, message)
+        self.__code = code
+
+    def code(self):
+        """
+        The code as sent over the CC.
+        """
+        return self.__code
+
+class RPCRecipientMissing(RPCError):
+    """
+    Special version of the RPCError, for cases the recipient of the call
+    isn't connected to the bus. The code is always
+    isc.cc.proto_defs.CC_REPLY_NO_RECPT.
+    """
+    def __init__(self, message):
+        RPCError.__init__(self, CC_REPLY_NO_RECPT, message)
+
 def parse_answer(msg):
     """Returns a tuple (rcode, value), where value depends on the
        command that was called. If rcode != 0, value is a string
@@ -66,7 +92,8 @@ def parse_answer(msg):
         raise ModuleCCSessionError("wrong rcode type in answer message")
     else:
         if len(msg['result']) > 1:
-            if (msg['result'][0] != 0 and type(msg['result'][1]) != str):
+            if (msg['result'][0] != CC_REPLY_SUCCESS and
+                type(msg['result'][1]) != str):
                 raise ModuleCCSessionError("rcode in answer message is non-zero, value is not a string")
             return msg['result'][0], msg['result'][1]
         else:
@@ -79,7 +106,7 @@ def create_answer(rcode, arg = None):
        a string containing an error message"""
     if type(rcode) != int:
         raise ModuleCCSessionError("rcode in create_answer() must be an integer")
-    if rcode != 0 and type(arg) != str:
+    if rcode != CC_REPLY_SUCCESS and type(arg) != str:
         raise ModuleCCSessionError("arg in create_answer for rcode != 0 must be a string describing the error")
     if arg != None:
         return { 'result': [ rcode, arg ] }
@@ -299,7 +326,7 @@ class ModuleCCSession(ConfigData):
                         isc.cc.data.remove_identical(new_config, self.get_local_config())
                         answer = self._config_handler(new_config)
                         rcode, val = parse_answer(answer)
-                        if rcode == 0:
+                        if rcode == CC_REPLY_SUCCESS:
                             newc = self.get_local_config()
                             isc.cc.data.merge(newc, new_config)
                             self.set_local_config(newc)
@@ -474,6 +501,42 @@ class ModuleCCSession(ConfigData):
         except isc.cc.SessionTimeout:
             raise ModuleCCSessionError("CC Session timeout waiting for configuration manager")
 
+    def rpc_call(self, command, group, instance=CC_INSTANCE_WILDCARD,
+                 to=CC_TO_WILDCARD, params=None):
+        """
+        Create a command with the given name and parameters. Send it to a
+        recipient, wait for the answer and parse it.
+
+        This is a wrapper around the group_sendmsg and group_recvmsg on the CC
+        session. It exists mostly for convenience.
+
+        Params:
+        - command: Name of the command to call on the remote side.
+        - group, instance, to: Address specification of the recipient.
+        - params: Parameters to pass to the command (as keyword arguments).
+
+        Return: The return value of the remote call (just the value, no status
+          code or anything). May be None.
+
+        Raise:
+        - RPCRecipientMissing if the given recipient doesn't exist.
+        - RPCError if the other side sent an error response. The error string
+          is in the exception.
+        - ModuleCCSessionError in case of protocol errors, like malformed
+          answer.
+        """
+        cmd = create_command(command, params)
+        seq = self._session.group_sendmsg(cmd, group, instance=instance,
+                                          to=to, want_answer=True)
+        # For non-blocking, we'll have rpc_call_async (once the nonblock
+        # actualy works)
+        reply, rheaders = self._session.group_recvmsg(nonblock=False, seq=seq)
+        code, value = parse_answer(reply)
+        if code == CC_REPLY_NO_RECPT:
+            raise RPCRecipientMissing(value)
+        elif code != CC_REPLY_SUCCESS:
+            raise RPCError(code, value)
+        return value
 
 class UIModuleCCSession(MultiConfigData):
     """This class is used in a configuration user interface. It contains
diff --git a/src/lib/python/isc/config/cfgmgr.py b/src/lib/python/isc/config/cfgmgr.py
index 9563cab..bc24cbb 100644
--- a/src/lib/python/isc/config/cfgmgr.py
+++ b/src/lib/python/isc/config/cfgmgr.py
@@ -68,6 +68,62 @@ class ConfigManagerData:
             self.db_filename = data_path + os.sep + file_name
             self.data_path = data_path
 
+    def check_for_updates(file_config):
+        """
+        Given the parsed JSON data from the config file,
+        check whether it needs updating due to version changes.
+        Return the data with updates (or the original data if no
+        updates were necessary).
+        Even though it is at this moment not technically necessary, this
+        function makes and returns a copy of the given data.
+        """
+        config = copy.deepcopy(file_config)
+        if 'version' in config:
+            data_version = config['version']
+        else:
+            # If it is not present, assume latest or earliest?
+            data_version = 1
+
+        # For efficiency, if up-to-date, return now
+        if data_version == config_data.BIND10_CONFIG_DATA_VERSION:
+            return config
+
+        # Don't know what to do if it is more recent
+        if data_version > config_data.BIND10_CONFIG_DATA_VERSION:
+            raise ConfigManagerDataReadError(
+                      "Cannot load configuration file: version "
+                      "%d not yet supported" % config['version'])
+
+        # At some point we might give up supporting older versions
+        if data_version < 1:
+            raise ConfigManagerDataReadError(
+                      "Cannot load configuration file: version "
+                      "%d no longer supported" % config['version'])
+
+        # Ok, so we have a still-supported older version. Apply all
+        # updates
+        new_data_version = data_version
+        if new_data_version == 1:
+            # only format change, no other changes necessary
+            new_data_version = 2
+        if new_data_version == 2:
+            # 'Boss' got changed to 'Init'; If for some reason both are
+            # present, simply ignore the old one
+            if 'Boss' in config:
+                if not 'Init' in config:
+                    config['Init'] = config['Boss']
+                    del config['Boss']
+                else:
+                    # This should not happen, but we don't want to overwrite
+                    # any config in this case, so warn about it
+                    logger.warn(CFGMGR_CONFIG_UPDATE_BOSS_AND_INIT_FOUND)
+            new_data_version = 3
+
+        config['version'] = new_data_version
+        logger.info(CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE, data_version,
+                    new_data_version)
+        return config
+
     def read_from_file(data_path, file_name):
         """Read the current configuration found in the file file_name.
            If file_name is absolute, data_path is ignored. Otherwise
@@ -90,21 +146,7 @@ class ConfigManagerData:
             # If possible, we automatically convert to the new
             # scheme and update the configuration
             # If not, we raise an exception
-            if 'version' in file_config:
-                if file_config['version'] == config_data.BIND10_CONFIG_DATA_VERSION:
-                    config.data = file_config
-                elif file_config['version'] == 1:
-                    # only format change, no other changes necessary
-                    file_config['version'] = 2
-                    logger.info(CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE, 1, 2)
-                    config.data = file_config
-                else:
-                    if config_data.BIND10_CONFIG_DATA_VERSION > file_config['version']:
-                        raise ConfigManagerDataReadError("Cannot load configuration file: version %d no longer supported" % file_config['version'])
-                    else:
-                        raise ConfigManagerDataReadError("Cannot load configuration file: version %d not yet supported" % file_config['version'])
-            else:
-                raise ConfigManagerDataReadError("No version information in configuration file " + config.db_filename)
+            config.data = ConfigManagerData.check_for_updates(file_config)
         except IOError as ioe:
             # if IOError is 'no such file or directory', then continue
             # (raise empty), otherwise fail (raise error)
@@ -210,7 +252,7 @@ class ConfigManager:
         else:
             self.cc = isc.cc.Session()
         self.cc.group_subscribe("ConfigManager")
-        self.cc.group_subscribe("Boss", "ConfigManager")
+        self.cc.group_subscribe("Init", "ConfigManager")
         self.running = False
         # As a core module, CfgMgr is different than other modules,
         # as it does not use a ModuleCCSession, and hence needs
@@ -232,10 +274,10 @@ class ConfigManager:
             # handler, so make it use defaults (and flush any buffered logs)
             ccsession.default_logconfig_handler({}, self.log_config_data)
 
-    def notify_boss(self):
-        """Notifies the Boss module that the Config Manager is running"""
+    def notify_b10_init(self):
+        """Notifies the Init module that the Config Manager is running"""
         # TODO: Use a real, broadcast notification here.
-        self.cc.group_sendmsg({"running": "ConfigManager"}, "Boss")
+        self.cc.group_sendmsg({"running": "ConfigManager"}, "Init")
 
     def set_module_spec(self, spec):
         """Adds a ModuleSpec"""
@@ -551,7 +593,7 @@ class ConfigManager:
     def run(self):
         """Runs the configuration manager."""
         self.running = True
-        while (self.running):
+        while self.running:
             # we just wait eternally for any command here, so disable
             # timeouts for this specific recv
             self.cc.set_timeout(0)
@@ -566,3 +608,4 @@ class ConfigManager:
                 # Only respond if there actually is something to respond with
                 if answer is not None:
                     self.cc.group_reply(env, answer)
+        logger.info(CFGMGR_STOPPED_BY_COMMAND)
diff --git a/src/lib/python/isc/config/cfgmgr_messages.mes b/src/lib/python/isc/config/cfgmgr_messages.mes
index 8701db3..73b6cef 100644
--- a/src/lib/python/isc/config/cfgmgr_messages.mes
+++ b/src/lib/python/isc/config/cfgmgr_messages.mes
@@ -41,6 +41,16 @@ system. The most likely cause is that msgq is not running.
 The configuration manager is starting, reading and saving the configuration
 settings to the shown file.
 
+% CFGMGR_CONFIG_UPDATE_BOSS_AND_INIT_FOUND Configuration found for both 'Boss' and 'Init', ignoring 'Boss'
+In the process of updating the configuration from version 2 to version 3,
+the configuration manager has found that there are existing configurations
+for both the old value 'Boss' and the new value 'Init'. This should in
+theory not happen, as in older versions 'Init' does not exist, and in newer
+versions 'Boss' does not exist. The configuration manager will continue
+with the update process, leaving the values for both as they are, so as not
+to overwrite any settings. However, the values for 'Boss' are ignored by
+BIND 10, and it is probably wise to check the configuration file manually.
+
 % CFGMGR_DATA_READ_ERROR error reading configuration database from disk: %1
 There was a problem reading the persistent configuration data as stored
 on disk. The file may be corrupted, or it is of a version from where
@@ -61,6 +71,9 @@ error is given. The most likely cause is that the system does not have
 write access to the configuration database file. The updated
 configuration is not stored.
 
+% CFGMGR_STOPPED_BY_COMMAND received shutdown command, shutting down
+The configuration manager received a shutdown command, and is exiting.
+
 % CFGMGR_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down
 There was a keyboard interrupt signal to stop the cfgmgr daemon. The
 daemon will now shut down.
diff --git a/src/lib/python/isc/config/config_data.py b/src/lib/python/isc/config/config_data.py
index ae61e2a..495d20b 100644
--- a/src/lib/python/isc/config/config_data.py
+++ b/src/lib/python/isc/config/config_data.py
@@ -27,7 +27,7 @@ import copy
 
 class ConfigDataError(Exception): pass
 
-BIND10_CONFIG_DATA_VERSION = 2
+BIND10_CONFIG_DATA_VERSION = 3
 
 # Helper functions
 def spec_part_is_list(spec_part):
diff --git a/src/lib/python/isc/config/tests/ccsession_test.py b/src/lib/python/isc/config/tests/ccsession_test.py
index ad364ac..3c1c57e 100644
--- a/src/lib/python/isc/config/tests/ccsession_test.py
+++ b/src/lib/python/isc/config/tests/ccsession_test.py
@@ -289,6 +289,67 @@ class TestModuleCCSession(unittest.TestCase):
         fake_session.close()
         mccs.__del__() # with closed fake_session
 
+    def rpc_check(self, reply):
+        fake_session = FakeModuleCCSession()
+        mccs = self.create_session("spec1.spec", None, None, fake_session)
+        fake_session.message_queue = [
+            ["Spec1", None, reply, False]
+        ]
+        exception = None
+        try:
+            result = mccs.rpc_call("test", "Spec2", params={
+                                       "param1": "Param 1",
+                                       "param2": "Param 2"
+                                   })
+        except Exception as e:
+            # We first want to check the value sent, raise the exception
+            # afterwards. So store it for a short while.
+            exception = e
+        self.assertEqual([
+                ["Spec2", "*", {"command": ["test", {
+                    "param1": "Param 1",
+                    "param2": "Param 2"
+                }]}, True]
+            ], fake_session.message_queue)
+        if exception is not None:
+            raise exception
+        return result
+
+    def test_rpc_call_success(self):
+        """
+        Test we can send an RPC (command) and get an answer. The answer is
+        success in this case.
+        """
+        result = self.rpc_check({"result": [0, {"Hello": "a"}]})
+        self.assertEqual({"Hello": "a"}, result)
+
+    def test_rpc_call_success_none(self):
+        """
+        Test the success case of RPC command, but the answer is empty
+        (eg. a "void" function on the remote side).
+        """
+        self.assertIsNone(self.rpc_check({"result": [0]}))
+
+    def test_rpc_call_malformed_answer(self):
+        """
+        Test it successfully raises ModuleCCSessionError when a malformed
+        reply is sent.
+        """
+        self.assertRaises(ModuleCCSessionError, self.rpc_check, ["Nonsense"])
+
+    def test_rpc_call_error(self):
+        """
+        Test it raises an exception when the remote side reports an error.
+        """
+        self.assertRaises(RPCError, self.rpc_check, {"result": [1, "Error"]})
+
+    def test_rpc_call_no_recpt(self):
+        """
+        Test RPC raises an error when the recipient is not there.
+        """
+        self.assertRaises(RPCRecipientMissing, self.rpc_check,
+                          {"result": [-1, "Error"]})
+
     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 891a7d7..d99fb86 100644
--- a/src/lib/python/isc/config/tests/cfgmgr_test.py
+++ b/src/lib/python/isc/config/tests/cfgmgr_test.py
@@ -29,7 +29,7 @@ class TestConfigManagerData(unittest.TestCase):
         self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
         self.config_manager_data = ConfigManagerData(self.writable_data_path,
                                                      file_name="b10-config.db")
-        self.assert_(self.config_manager_data)
+        self.assertTrue(self.config_manager_data)
 
     def test_abs_file(self):
         """
@@ -49,6 +49,49 @@ class TestConfigManagerData(unittest.TestCase):
         self.assertEqual(self.config_manager_data.db_filename,
                          self.writable_data_path + os.sep + "b10-config.db")
 
+    def test_check_for_updates_up_to_date(self):
+        # This should automatically give an up-to-date version
+        file_config = ConfigManagerData.read_from_file(
+                        self.writable_data_path, "b10-config.db").data
+        updated_config = ConfigManagerData.check_for_updates(file_config)
+        self.assertEqual(file_config, updated_config)
+
+    def test_check_for_updates_from_1(self):
+        config = { "version": 1,
+                   "foo": "bar",
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
+    def test_check_for_updates_from_2(self):
+        # No 'Boss' present, no change (except version)
+        config = { "version": 2,
+                   "foo": "bar",
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
+        # With Boss, should be changed to 'Init'
+        config = { "version": 2,
+                   "Boss": { "some config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config = { "version": config_data.BIND10_CONFIG_DATA_VERSION,
+                   "Init": { "some config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        self.assertEqual(config, updated)
+
+        # With Boss AND Init, no change
+        config = { "version": 2,
+                   "Boss": { "some config": 1 },
+                   "Init": { "some other config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
     def test_read_from_file(self):
         ConfigManagerData.read_from_file(self.writable_data_path, "b10-config.db")
         self.assertRaises(ConfigManagerDataEmpty,
@@ -170,65 +213,61 @@ class TestConfigManager(unittest.TestCase):
                          cm.config.db_filename)
 
     def test_init(self):
-        self.assert_(self.cm.module_specs == {})
-        self.assert_(self.cm.data_path == self.writable_data_path)
-        self.assert_(self.cm.config != None)
-        self.assert_(self.fake_session.has_subscription("ConfigManager"))
-        self.assert_(self.fake_session.has_subscription("Boss", "ConfigManager"))
+        self.assertEqual(self.cm.module_specs, {})
+        self.assertEqual(self.cm.data_path, self.writable_data_path)
+        self.assertIsNotNone(self.cm.config)
+        self.assertTrue(self.fake_session.has_subscription("ConfigManager"))
+        self.assertTrue(self.fake_session.has_subscription("Init", "ConfigManager"))
         self.assertFalse(self.cm.running)
 
-    def test_notify_boss(self):
-        self.cm.notify_boss()
-        msg = self.fake_session.get_message("Boss", None)
-        self.assert_(msg)
+    def test_notify_b10_init(self):
+        self.cm.notify_b10_init()
+        msg = self.fake_session.get_message("Init", None)
+        self.assertTrue(msg)
         # this one is actually wrong, but 'current status quo'
         self.assertEqual(msg, {"running": "ConfigManager"})
 
     def test_set_module_spec(self):
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), 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)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), 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")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), 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)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), 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)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), 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.assertIn(module_spec.get_module_name(), 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)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), 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")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         module_spec2 = self.cm.get_module_spec(module_spec.get_module_name())
         self.assertEqual(module_spec.get_full_spec(), module_spec2)
 
@@ -238,16 +277,16 @@ class TestConfigManager(unittest.TestCase):
         config_spec = self.cm.get_config_spec()
         self.assertEqual(config_spec, {})
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         config_spec = self.cm.get_config_spec()
         self.assertEqual(config_spec, { 'Spec1': None })
         self.cm.remove_module_spec('Spec1')
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         config_spec = self.cm.get_config_spec()
         self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
         config_spec = self.cm.get_config_spec('Spec2')
@@ -258,16 +297,16 @@ class TestConfigManager(unittest.TestCase):
         commands_spec = self.cm.get_commands_spec()
         self.assertEqual(commands_spec, {})
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         commands_spec = self.cm.get_commands_spec()
         self.assertEqual(commands_spec, { 'Spec1': None })
         self.cm.remove_module_spec('Spec1')
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         commands_spec = self.cm.get_commands_spec()
         self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
         commands_spec = self.cm.get_commands_spec('Spec2')
@@ -277,16 +316,16 @@ class TestConfigManager(unittest.TestCase):
         statistics_spec = self.cm.get_statistics_spec()
         self.assertEqual(statistics_spec, {})
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         statistics_spec = self.cm.get_statistics_spec()
         self.assertEqual(statistics_spec, { 'Spec1': None })
         self.cm.remove_module_spec('Spec1')
         module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
-        self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+        self.assertNotIn(module_spec.get_module_name(), self.cm.module_specs)
         self.cm.set_module_spec(module_spec)
-        self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+        self.assertIn(module_spec.get_module_name(), self.cm.module_specs)
         statistics_spec = self.cm.get_statistics_spec()
         self.assertEqual(statistics_spec['Spec2'], module_spec.get_statistics_spec())
         statistics_spec = self.cm.get_statistics_spec('Spec2')
@@ -543,7 +582,8 @@ class TestConfigManager(unittest.TestCase):
     def test_set_config_all(self):
         my_ok_answer = { 'result': [ 0 ] }
 
-        self.assertEqual({"version": 2}, self.cm.config.data)
+        self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION},
+                         self.cm.config.data)
 
         self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
         self.cm.handle_msg(ccsession.create_command(
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 45feb35..ddeabb6 100644
--- a/src/lib/python/isc/config/tests/config_data_test.py
+++ b/src/lib/python/isc/config/tests/config_data_test.py
@@ -360,8 +360,8 @@ class TestMultiConfigData(unittest.TestCase):
         self.assertFalse(self.mcd.have_specification(module_spec.get_module_name()))
         self.mcd.set_specification(module_spec)
         self.assertTrue(self.mcd.have_specification(module_spec.get_module_name()))
-        self.assert_(module_spec.get_module_name() in self.mcd._specifications)
-        self.assertEquals(module_spec, self.mcd._specifications[module_spec.get_module_name()])
+        self.assertIn(module_spec.get_module_name(), self.mcd._specifications)
+        self.assertEqual(module_spec, self.mcd._specifications[module_spec.get_module_name()])
         self.assertRaises(ConfigDataError, self.mcd.set_specification, "asdf")
         self.mcd.remove_specification(module_spec.get_module_name())
         self.assertFalse(self.mcd.have_specification(module_spec.get_module_name()))
@@ -693,12 +693,15 @@ class TestMultiConfigData(unittest.TestCase):
                            'name': 'Spec32', 'value': None,
                            'modified': False}], maps)
         maps = self.mcd.get_value_maps("/Spec32/named_set_item")
-        self.assertEqual([{'default': True, 'type': 'integer',
-                           'name': 'Spec32/named_set_item/a',
-                           'value': 1, 'modified': False},
-                          {'default': True, 'type': 'integer',
-                           'name': 'Spec32/named_set_item/b',
-                           'value': 2, 'modified': False}], maps)
+        self.assertEqual(len(maps), 2)
+        self.assertIn({'default': True, 'type': 'integer',
+                       'name': 'Spec32/named_set_item/a',
+                       'value': 1, 'modified': False},
+                      maps)
+        self.assertIn({'default': True, 'type': 'integer',
+                       'name': 'Spec32/named_set_item/b',
+                       'value': 2, 'modified': False},
+                      maps)
         maps = self.mcd.get_value_maps("/Spec32/named_set_item/a")
         self.assertEqual([{'default': True, 'type': 'integer',
                            'name': 'Spec32/named_set_item/a',
@@ -829,10 +832,10 @@ class TestMultiConfigData(unittest.TestCase):
                                                       "bbbb": 6})
         config_items = self.mcd.get_config_item_list("/Spec32/named_set_item",
                                                      True)
-        self.assertEqual(['Spec32/named_set_item/aaaa',
-                          'Spec32/named_set_item/aabb',
-                          'Spec32/named_set_item/bbbb',
-                         ], config_items)
+        self.assertEqual(len(config_items), 3)
+        self.assertIn('Spec32/named_set_item/aaaa', config_items)
+        self.assertIn('Spec32/named_set_item/aabb', config_items)
+        self.assertIn('Spec32/named_set_item/bbbb', config_items)
 
         self.mcd.set_value('Spec32/named_set_item', {})
         config_items = self.mcd.get_config_item_list("/Spec32/named_set_item",
diff --git a/src/lib/python/isc/config/tests/module_spec_test.py b/src/lib/python/isc/config/tests/module_spec_test.py
index a2a2daf..4767860 100644
--- a/src/lib/python/isc/config/tests/module_spec_test.py
+++ b/src/lib/python/isc/config/tests/module_spec_test.py
@@ -38,7 +38,7 @@ class TestModuleSpec(unittest.TestCase):
 
     def spec1(self, dd):
         module_spec = dd.get_full_spec()
-        self.assert_('module_name' in module_spec)
+        self.assertIn('module_name', module_spec)
         self.assertEqual(module_spec['module_name'], "Spec1")
         
     def test_open_file_name(self):
diff --git a/src/lib/python/isc/config/tests/unittest_fakesession.py b/src/lib/python/isc/config/tests/unittest_fakesession.py
index 1641ec0..7043683 100644
--- a/src/lib/python/isc/config/tests/unittest_fakesession.py
+++ b/src/lib/python/isc/config/tests/unittest_fakesession.py
@@ -28,7 +28,7 @@ class WouldBlockForever(Exception):
 class FakeModuleCCSession:
     def __init__(self):
         self.subscriptions = {}
-        # each entry is of the form [ channel, instance, message ]
+        # each entry is of the form [ channel, instance, message, want_answer ]
         self.message_queue = []
         self._socket = "ok we just need something not-None here atm"
         # if self.timeout is set to anything other than 0, and
@@ -68,12 +68,14 @@ class FakeModuleCCSession:
         else:
             return False
 
-    def group_sendmsg(self, msg, channel, target = None):
-        self.message_queue.append([ channel, target, msg ])
+    def group_sendmsg(self, msg, group, instance=None, to=None,
+                      want_answer=False):
+        self.message_queue.append([ group, instance, msg, want_answer ])
+        return 42
 
     def group_reply(self, env, msg):
         if 'group' in env:
-            self.message_queue.append([ env['group'], None, msg])
+            self.message_queue.append([ env['group'], None, msg, False])
 
     def group_recvmsg(self, nonblock=True, seq = None):
         for qm in self.message_queue:
diff --git a/src/lib/python/isc/datasrc/client_inc.cc b/src/lib/python/isc/datasrc/client_inc.cc
index 9e66016..7b6fac5 100644
--- a/src/lib/python/isc/datasrc/client_inc.cc
+++ b/src/lib/python/isc/datasrc/client_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2011-2013  Internet Systems Consortium.
+//
+// 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.
+
 namespace {
 
 const char* const DataSourceClient_doc = "\
diff --git a/src/lib/python/isc/datasrc/client_python.cc b/src/lib/python/isc/datasrc/client_python.cc
index 9e4bd42..a30ae38 100644
--- a/src/lib/python/isc/datasrc/client_python.cc
+++ b/src/lib/python/isc/datasrc/client_python.cc
@@ -27,7 +27,7 @@
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/client_list.h>
 
 #include <dns/python/name_python.h>
diff --git a/src/lib/python/isc/datasrc/datasrc.cc b/src/lib/python/isc/datasrc/datasrc.cc
index cfacc64..c183af9 100644
--- a/src/lib/python/isc/datasrc/datasrc.cc
+++ b/src/lib/python/isc/datasrc/datasrc.cc
@@ -218,23 +218,6 @@ initModulePart_ZoneLoader(PyObject* mod) {
 }
 
 bool
-initModulePart_ZoneUpdater(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(&zoneupdater_type) < 0) {
-        return (false);
-    }
-    void* zip = &zoneupdater_type;
-    if (PyModule_AddObject(mod, "ZoneUpdater", static_cast<PyObject*>(zip)) < 0) {
-        return (false);
-    }
-    Py_INCREF(&zoneupdater_type);
-
-    return (true);
-}
-
-bool
 initModulePart_ZoneJournalReader(PyObject* mod) {
     if (PyType_Ready(&journal_reader_type) < 0) {
         return (false);
diff --git a/src/lib/python/isc/datasrc/finder_inc.cc b/src/lib/python/isc/datasrc/finder_inc.cc
index 467c6ad..b2b3c43 100644
--- a/src/lib/python/isc/datasrc/finder_inc.cc
+++ b/src/lib/python/isc/datasrc/finder_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2011-2012  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.
+
 namespace {
 const char* const ZoneFinder_doc = "\
 The base class to search a zone for RRsets.\n\
diff --git a/src/lib/python/isc/datasrc/finder_python.cc b/src/lib/python/isc/datasrc/finder_python.cc
index 1b0e3d1..05c44c9 100644
--- a/src/lib/python/isc/datasrc/finder_python.cc
+++ b/src/lib/python/isc/datasrc/finder_python.cc
@@ -26,7 +26,7 @@
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
 
 #include <dns/python/name_python.h>
diff --git a/src/lib/python/isc/datasrc/iterator_inc.cc b/src/lib/python/isc/datasrc/iterator_inc.cc
index 087200a..9a3da7d 100644
--- a/src/lib/python/isc/datasrc/iterator_inc.cc
+++ b/src/lib/python/isc/datasrc/iterator_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 
 const char* const ZoneIterator_doc = "\
diff --git a/src/lib/python/isc/datasrc/iterator_python.cc b/src/lib/python/isc/datasrc/iterator_python.cc
index 9e6900c..9757a3b 100644
--- a/src/lib/python/isc/datasrc/iterator_python.cc
+++ b/src/lib/python/isc/datasrc/iterator_python.cc
@@ -25,7 +25,7 @@
 #include <datasrc/client.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 
 #include <dns/python/name_python.h>
 #include <dns/python/rrset_python.h>
diff --git a/src/lib/python/isc/datasrc/journal_reader_inc.cc b/src/lib/python/isc/datasrc/journal_reader_inc.cc
index 35ba70e..3200fb5 100644
--- a/src/lib/python/isc/datasrc/journal_reader_inc.cc
+++ b/src/lib/python/isc/datasrc/journal_reader_inc.cc
@@ -1,3 +1,17 @@
+// 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.
+
 namespace {
 const char* const ZoneJournalReader_doc = "\
 The base class for retrieving differences between two versions of a\n\
diff --git a/src/lib/python/isc/datasrc/sqlite3_ds.py b/src/lib/python/isc/datasrc/sqlite3_ds.py
index dc80afd..19d8581 100644
--- a/src/lib/python/isc/datasrc/sqlite3_ds.py
+++ b/src/lib/python/isc/datasrc/sqlite3_ds.py
@@ -25,7 +25,7 @@ RR_RDATA_INDEX = 7
 
 # Current major and minor versions of schema
 SCHEMA_MAJOR_VERSION = 2
-SCHEMA_MINOR_VERSION = 1
+SCHEMA_MINOR_VERSION = 2
 
 class Sqlite3DSError(Exception):
     """ Define exceptions."""
@@ -73,6 +73,8 @@ def create(cur):
         cur.execute("CREATE INDEX records_byrname ON records (rname)")
         cur.execute("""CREATE INDEX records_bytype_and_rname ON records
                        (rdtype, rname)""")
+        cur.execute("""CREATE INDEX records_byrname_and_rdtype ON records
+                       (rname, rdtype)""")
         cur.execute("""CREATE TABLE nsec3 (id INTEGER PRIMARY KEY,
                     zone_id INTEGER NOT NULL,
                     hash TEXT NOT NULL COLLATE NOCASE,
diff --git a/src/lib/python/isc/datasrc/tests/Makefile.am b/src/lib/python/isc/datasrc/tests/Makefile.am
index c16d295..eb82972 100644
--- a/src/lib/python/isc/datasrc/tests/Makefile.am
+++ b/src/lib/python/isc/datasrc/tests/Makefile.am
@@ -11,6 +11,7 @@ EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/new_minor_schema.sqlite3
 EXTRA_DIST += testdata/example.com
 EXTRA_DIST += testdata/example.com.ch
+EXTRA_DIST += testdata/static.zone
 CLEANFILES = $(abs_builddir)/rwtest.sqlite3.copied
 CLEANFILES += $(abs_builddir)/zoneloadertest.sqlite3
 
diff --git a/src/lib/python/isc/datasrc/tests/clientlist_test.py b/src/lib/python/isc/datasrc/tests/clientlist_test.py
index ea39d4e..bdac69c 100644
--- a/src/lib/python/isc/datasrc/tests/clientlist_test.py
+++ b/src/lib/python/isc/datasrc/tests/clientlist_test.py
@@ -43,8 +43,8 @@ class ClientListTest(unittest.TestCase):
         Test the constructor. It should accept an RRClass. Check it
         reject invalid inputs.
         """
-        isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
-        isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH())
+        isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
+        isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH)
         # Not enough arguments
         self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList)
         # Bad types of arguments
@@ -52,7 +52,7 @@ class ClientListTest(unittest.TestCase):
         self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList, "IN")
         # Too many arguments
         self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList,
-                         isc.dns.RRClass.IN(), isc.dns.RRClass.IN())
+                         isc.dns.RRClass.IN, isc.dns.RRClass.IN)
 
     def test_configure(self):
         """
@@ -60,7 +60,7 @@ class ClientListTest(unittest.TestCase):
         ones are acceptend and invalid rejected. We check the changes
         have effect.
         """
-        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
         # This should be NOP now
         self.clist.configure("[]", True)
         # Check the zone is not there yet
@@ -102,7 +102,7 @@ class ClientListTest(unittest.TestCase):
         Test the find accepts the right arguments, some of them can be omitted,
         etc.
         """
-        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
         self.clist.configure('''[{
             "type": "MasterFiles",
             "params": {
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index 659e7a8..abc9739 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -34,6 +34,8 @@ WRITE_ZONE_DB_FILE = TESTDATA_WRITE_PATH + "rwtest.sqlite3.copied"
 READ_ZONE_DB_CONFIG = "{ \"database_file\": \"" + READ_ZONE_DB_FILE + "\" }"
 WRITE_ZONE_DB_CONFIG = "{ \"database_file\": \"" + WRITE_ZONE_DB_FILE + "\"}"
 
+STATIC_ZONE_CONFIG = '"' + TESTDATA_PATH + "static.zone" + '"'
+
 def add_rrset(rrset_list, name, rrclass, rrtype, ttl, rdatas):
     rrset_to_add = isc.dns.RRset(name, rrclass, rrtype, ttl)
     if rdatas is not None:
@@ -51,8 +53,8 @@ def check_for_rrset(expected_rrsets, rrset):
     return False
 
 def create_soa(serial):
-    soa = RRset(Name('example.org'), RRClass.IN(), RRType.SOA(), RRTTL(3600))
-    soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+    soa = RRset(Name('example.org'), RRClass.IN, RRType.SOA, RRTTL(3600))
+    soa.add_rdata(Rdata(RRType.SOA, RRClass.IN,
                         'ns1.example.org. admin.example.org. ' +
                         str(serial) + ' 3600 1800 2419200 7200'))
     return soa
@@ -66,13 +68,13 @@ def test_findall_common(self, tested):
     result, rrset, _ = tested.find_all(isc.dns.Name("www.sql1.example.com"),
                                        ZoneFinder.FIND_DEFAULT)
     self.assertEqual(ZoneFinder.DELEGATION, result)
-    expected = RRset(Name('sql1.example.com.'), RRClass.IN(), RRType.NS(),
+    expected = RRset(Name('sql1.example.com.'), RRClass.IN, RRType.NS,
                      RRTTL(3600))
-    expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+    expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
                              'dns01.example.com.'))
-    expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+    expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
                              'dns02.example.com.'))
-    expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+    expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
                              'dns03.example.com.'))
     self.assertTrue(rrsets_equal(expected, rrset))
 
@@ -88,16 +90,16 @@ def test_findall_common(self, tested):
     self.assertEqual(2, len(rrsets))
     rrsets.sort(key=lambda rrset: rrset.get_type().to_text())
     expected = [
-        RRset(Name('mix.example.com.'), RRClass.IN(), RRType.A(),
+        RRset(Name('mix.example.com.'), RRClass.IN, RRType.A,
               RRTTL(3600)),
-        RRset(Name('mix.example.com.'), RRClass.IN(), RRType.AAAA(),
+        RRset(Name('mix.example.com.'), RRClass.IN, RRType.AAAA,
               RRTTL(3600))
     ]
-    expected[0].add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
-    expected[0].add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.2"))
-    expected[1].add_rdata(Rdata(RRType.AAAA(), RRClass.IN(),
+    expected[0].add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
+    expected[0].add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.2"))
+    expected[1].add_rdata(Rdata(RRType.AAAA, RRClass.IN,
                                 "2001:db8::1"))
-    expected[1].add_rdata(Rdata(RRType.AAAA(), RRClass.IN(),
+    expected[1].add_rdata(Rdata(RRType.AAAA, RRClass.IN,
                                 "2001:db8::2"))
     for (rrset, exp) in zip(rrsets, expected):
         self.assertTrue(rrsets_equal(exp, rrset))
@@ -129,9 +131,6 @@ class DataSrcClient(unittest.TestCase):
         self.assertRaises(isc.datasrc.Error,
                           isc.datasrc.DataSourceClient, "sqlite3",
                           "{ \"foo\": 1 }")
-        self.assertRaises(isc.datasrc.Error,
-                          isc.datasrc.DataSourceClient, "memory",
-                          "{ \"foo\": 1 }")
 
     def test_iterate(self):
         dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
@@ -158,9 +157,9 @@ class DataSrcClient(unittest.TestCase):
         expected_rrset_list = []
 
         name = isc.dns.Name("sql1.example.com")
-        rrclass = isc.dns.RRClass.IN()
+        rrclass = isc.dns.RRClass.IN
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.DNSKEY(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.DNSKEY, isc.dns.RRTTL(3600),
                   [
                      "256 3 5 AwEAAdYdRhBAEY67R/8G1N5AjGF6asIiNh/pNGeQ8xDQP13J"+
                      "N2lo+sNqWcmpYNhuVqRbLB+mamsU1XcCICSBvAlSmfz/ZUdafX23knAr"+
@@ -168,7 +167,7 @@ class DataSrcClient(unittest.TestCase):
                      "5fs0dE/xLztL/CzZ"
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.DNSKEY(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.DNSKEY, isc.dns.RRTTL(3600),
                   [
                      "257 3 5 AwEAAbaKDSa9XEFTsjSYpUTHRotTS9Tz3krfDucugW5UokGQ"+
                      "KC26QlyHXlPTZkC+aRFUs/dicJX2kopndLcnlNAPWiKnKtrsFSCnIJDB"+
@@ -179,22 +178,22 @@ class DataSrcClient(unittest.TestCase):
                      "jRWAzGsxJiJyjd6w2k0="
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.NS, isc.dns.RRTTL(3600),
                   [
                     "dns01.example.com."
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.NS, isc.dns.RRTTL(3600),
                   [
                     "dns02.example.com."
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.NS, isc.dns.RRTTL(3600),
                   [
                     "dns03.example.com."
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.NSEC(), isc.dns.RRTTL(7200),
+                  isc.dns.RRType.NSEC, isc.dns.RRTTL(7200),
                   [
                      "www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"
                   ])
@@ -204,36 +203,36 @@ class DataSrcClient(unittest.TestCase):
         # Since we passed separate_rrs = True to get_iterator, we get several
         # sets of RRSIGs, one for each TTL
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(7200), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(7200), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.SOA(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.SOA, isc.dns.RRTTL(3600),
                   [
                      "master.example.com. admin.example.com. 678 3600 1800 2419200 7200"
                   ])
         name = isc.dns.Name("www.sql1.example.com.")
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.A(), isc.dns.RRTTL(3600),
+                  isc.dns.RRType.A, isc.dns.RRTTL(3600),
                   [
                      "192.0.2.100"
                   ])
         name = isc.dns.Name("www.sql1.example.com.")
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.NSEC(), isc.dns.RRTTL(7200),
+                  isc.dns.RRType.NSEC, isc.dns.RRTTL(7200),
                   [
                      "sql1.example.com. A RRSIG NSEC"
                   ])
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
         add_rrset(expected_rrset_list, name, rrclass,
-                  isc.dns.RRType.RRSIG(), isc.dns.RRTTL(7200), None)
+                  isc.dns.RRType.RRSIG, isc.dns.RRTTL(7200), None)
 
         # rrs is an iterator, but also has direct get_next_rrset(), use
         # the latter one here
@@ -287,11 +286,11 @@ class DataSrcClient(unittest.TestCase):
         dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
         iterator = dsc.get_iterator(isc.dns.Name("sql1.example.com."))
         expected_soa = isc.dns.RRset(isc.dns.Name("sql1.example.com."),
-                                     isc.dns.RRClass.IN(),
-                                     isc.dns.RRType.SOA(),
+                                     isc.dns.RRClass.IN,
+                                     isc.dns.RRType.SOA,
                                      isc.dns.RRTTL(3600))
-        expected_soa.add_rdata(isc.dns.Rdata(isc.dns.RRType.SOA(),
-                                             isc.dns.RRClass.IN(),
+        expected_soa.add_rdata(isc.dns.Rdata(isc.dns.RRType.SOA,
+                                             isc.dns.RRClass.IN,
                                              "master.example.com. " +
                                              "admin.example.com. 678 " +
                                              "3600 1800 2419200 7200"))
@@ -337,7 +336,7 @@ class DataSrcClient(unittest.TestCase):
         result, finder = dsc.find_zone(isc.dns.Name("example.com"))
 
         self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+        self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
         self.assertEqual("example.com.", finder.get_origin().to_text())
 
         test_findall_common(self, finder)
@@ -347,11 +346,11 @@ class DataSrcClient(unittest.TestCase):
 
         result, finder = dsc.find_zone(isc.dns.Name("example.com"))
         self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+        self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
         self.assertEqual("example.com.", finder.get_origin().to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -359,13 +358,13 @@ class DataSrcClient(unittest.TestCase):
 
         # Check the optional parameters are optional
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A())
+                                       isc.dns.RRType.A)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
                          rrset.to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("www.sql1.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.DELEGATION, result)
         self.assertEqual("sql1.example.com. 3600 IN NS dns01.example.com.\n" +
@@ -374,7 +373,7 @@ class DataSrcClient(unittest.TestCase):
                          rrset.to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("doesnotexist.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
@@ -382,16 +381,16 @@ class DataSrcClient(unittest.TestCase):
 
         self.assertRaises(isc.datasrc.OutOfZone, finder.find,
                           isc.dns.Name("www.some.other.domain"),
-                          isc.dns.RRType.A())
+                          isc.dns.RRType.A)
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.TXT(),
+                                       isc.dns.RRType.TXT,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.NXRRSET, result)
         self.assertEqual(None, rrset)
 
         result, rrset, _ = finder.find(isc.dns.Name("cname-ext.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.CNAME, result)
         self.assertEqual(
@@ -400,14 +399,14 @@ class DataSrcClient(unittest.TestCase):
 
         result, rrset, flags = \
             finder.find(isc.dns.Name("foo.wild.example.com"),
-                        isc.dns.RRType.A(), finder.FIND_DEFAULT)
+                        isc.dns.RRType.A, finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual(finder.RESULT_WILDCARD, flags)
         self.assertEqual("foo.wild.example.com. 3600 IN A 192.0.2.255\n",
                          rrset.to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("foo.wild.example.com"),
-                                       isc.dns.RRType.TXT(),
+                                       isc.dns.RRType.TXT,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.NXRRSET, result)
         self.assertTrue(finder.RESULT_WILDCARD, flags)
@@ -415,7 +414,7 @@ class DataSrcClient(unittest.TestCase):
 
         self.assertRaises(TypeError, finder.find,
                           "foo",
-                          isc.dns.RRType.A(),
+                          isc.dns.RRType.A,
                           finder.FIND_DEFAULT)
         self.assertRaises(TypeError, finder.find,
                           isc.dns.Name("cname-ext.example.com"),
@@ -423,7 +422,7 @@ class DataSrcClient(unittest.TestCase):
                           finder.FIND_DEFAULT)
         self.assertRaises(TypeError, finder.find,
                           isc.dns.Name("cname-ext.example.com"),
-                          isc.dns.RRType.A(),
+                          isc.dns.RRType.A,
                           "foo")
 
 class DataSrcUpdater(unittest.TestCase):
@@ -451,7 +450,7 @@ class DataSrcUpdater(unittest.TestCase):
         dsc = isc.datasrc.DataSourceClient("sqlite3", WRITE_ZONE_DB_CONFIG)
         updater = dsc.get_updater(isc.dns.Name("example.com"), False)
         result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
-                                        isc.dns.RRType.A(),
+                                        isc.dns.RRType.A,
                                         ZoneFinder.FIND_DEFAULT)
         self.assertEqual(ZoneFinder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -459,7 +458,7 @@ class DataSrcUpdater(unittest.TestCase):
 
         # Omit optional parameters
         result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
-                                        isc.dns.RRType.A())
+                                        isc.dns.RRType.A)
         self.assertEqual(ZoneFinder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
                          rrset.to_text())
@@ -471,11 +470,11 @@ class DataSrcUpdater(unittest.TestCase):
         # first make sure, through a separate finder, that some record exists
         result, finder = dsc.find_zone(isc.dns.Name("example.com"))
         self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+        self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
         self.assertEqual("example.com.", finder.get_origin().to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -490,13 +489,13 @@ class DataSrcUpdater(unittest.TestCase):
         # The record should be gone in the updater, but not in the original
         # finder (since we have not committed)
         result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
-                                        isc.dns.RRType.A(),
+                                        isc.dns.RRType.A,
                                         finder.FIND_DEFAULT)
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -508,7 +507,7 @@ class DataSrcUpdater(unittest.TestCase):
 
         # the record should be gone now in the 'real' finder as well
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
@@ -522,41 +521,77 @@ class DataSrcUpdater(unittest.TestCase):
         self.assertRaises(isc.datasrc.Error, updater.commit)
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
                          rrset.to_text())
 
+    def test_updater_rrset_collection(self):
+        dsc = isc.datasrc.DataSourceClient("sqlite3", WRITE_ZONE_DB_CONFIG)
+        updater = dsc.get_updater(isc.dns.Name("example.com"), False)
+        updater_refs = sys.getrefcount(updater)
+
+        # Get (internally create) updater's RRset collection
+        rrsets = updater.get_rrset_collection()
+
+        # From this point we cannot make further updates
+        rrset = RRset(isc.dns.Name('www.example.com'), isc.dns.RRClass.IN,
+                      isc.dns.RRType.AAAA, isc.dns.RRTTL(10))
+        rrset.add_rdata(isc.dns.Rdata(isc.dns.RRType.AAAA,
+                                      isc.dns.RRClass.IN, '2001:db8::1'))
+        self.assertRaises(isc.datasrc.Error, updater.add_rrset, rrset)
+
+        # Checks basic API
+        found = rrsets.find(isc.dns.Name("www.example.com"),
+                            isc.dns.RRClass.IN, isc.dns.RRType.A)
+        self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
+                         found.to_text())
+        self.assertEqual(None, rrsets.find(isc.dns.Name("www.example.com"),
+                                           isc.dns.RRClass.IN,
+                                           isc.dns.RRType.AAAA))
+
+        # Once committed collection cannot be used any more.
+        updater.commit()
+        self.assertRaises(isc.dns.RRsetCollectionError,
+                          rrsets.find, isc.dns.Name("www.example.com"),
+                          isc.dns.RRClass.IN, isc.dns.RRType.A)
+
+        # When we destroy the RRsetCollection it should release the refcount
+        # to the updater.
+        rrsets = None
+        self.assertEqual(updater_refs, sys.getrefcount(updater))
+
     def test_two_modules(self):
-        # load two modules, and check if they don't interfere
-        mem_cfg = { "type": "memory", "class": "IN", "zones": [] };
-        dsc_mem = isc.datasrc.DataSourceClient("memory", json.dumps(mem_cfg))
+        # load two modules, and check if they don't interfere; as the
+        # memory datasource module no longer exists, we check the static
+        # datasource instead (as that uses the memory datasource
+        # anyway).
+        dsc_static = isc.datasrc.DataSourceClient("static", STATIC_ZONE_CONFIG)
         dsc_sql = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
 
         # check if exceptions are working
         self.assertRaises(isc.datasrc.Error, isc.datasrc.DataSourceClient,
-                          "memory", "{}")
+                          "static", "\"\"")
         self.assertRaises(isc.datasrc.Error, isc.datasrc.DataSourceClient,
                           "sqlite3", "{}")
 
         # see if a lookup succeeds in sqlite3 ds
         result, finder = dsc_sql.find_zone(isc.dns.Name("example.com"))
         self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+        self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
         self.assertEqual("example.com.", finder.get_origin().to_text())
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
                          rrset.to_text())
 
-        # see if a lookup fails in mem ds
-        result, finder = dsc_mem.find_zone(isc.dns.Name("example.com"))
+        # see if a lookup fails in static ds
+        result, finder = dsc_static.find_zone(isc.dns.Name("example"))
         self.assertEqual(finder.NXDOMAIN, result)
 
-
     def test_update_delete_abort(self):
         # we don't do enything with this one, just making sure loading two
         # datasources
@@ -565,11 +600,11 @@ class DataSrcUpdater(unittest.TestCase):
         # first make sure, through a separate finder, that some record exists
         result, finder = dsc.find_zone(isc.dns.Name("example.com"))
         self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+        self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
         self.assertEqual("example.com.", finder.get_origin().to_text())
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -584,7 +619,7 @@ class DataSrcUpdater(unittest.TestCase):
         # The record should be gone in the updater, but not in the original
         # finder (since we have not committed)
         result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
-                                        isc.dns.RRType.A(),
+                                        isc.dns.RRType.A,
                                         finder.FIND_DEFAULT)
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
@@ -594,7 +629,7 @@ class DataSrcUpdater(unittest.TestCase):
 
         # the record should still be available in the 'real' finder as well
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
-                                       isc.dns.RRType.A(),
+                                       isc.dns.RRType.A,
                                        finder.FIND_DEFAULT)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -689,8 +724,10 @@ class DataSrcUpdater(unittest.TestCase):
         self.assertTrue(dsc.delete_zone(zone_name))
 
     def test_create_zone_not_implemented(self):
-        mem_cfg = '{ "type": "memory", "class": "IN", "zones": [] }';
-        dsc = isc.datasrc.DataSourceClient("memory", mem_cfg)
+        # As the memory datasource module no longer exists, we check the
+        # static datasource instead (as that uses the memory datasource
+        # anyway).
+        dsc = isc.datasrc.DataSourceClient("static", STATIC_ZONE_CONFIG)
         self.assertRaises(isc.datasrc.NotImplemented, dsc.create_zone,
                           isc.dns.Name("example.com"))
 
@@ -720,9 +757,9 @@ class JournalWrite(unittest.TestCase):
         conn.close()
 
     def create_a(self, address):
-        a_rr = RRset(Name('www.example.org'), RRClass.IN(), RRType.A(),
+        a_rr = RRset(Name('www.example.org'), RRClass.IN, RRType.A,
                      RRTTL(3600))
-        a_rr.add_rdata(Rdata(RRType.A(), RRClass.IN(), address))
+        a_rr.add_rdata(Rdata(RRType.A, RRClass.IN, address))
         return (a_rr)
 
     def test_journal_write(self):
diff --git a/src/lib/python/isc/datasrc/tests/testdata/static.zone b/src/lib/python/isc/datasrc/tests/testdata/static.zone
new file mode 100644
index 0000000..51525db
--- /dev/null
+++ b/src/lib/python/isc/datasrc/tests/testdata/static.zone
@@ -0,0 +1,3 @@
+BIND.           3600    CH  SOA BIND. BIND. 3 3600 300 36000 3600
+BIND.           3600    CH  NS  BIND.
+VERSION.BIND.   3600    CH  TXT "10"
diff --git a/src/lib/python/isc/datasrc/tests/zone_loader_test.py b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
index 62f67cd..e437e36 100644
--- a/src/lib/python/isc/datasrc/tests/zone_loader_test.py
+++ b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
@@ -13,6 +13,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import isc.log
 import isc.datasrc
 import isc.dns
 
@@ -33,6 +34,7 @@ ORIG_DB_FILE = TESTDATA_PATH + '/example.com.sqlite3'
 DB_FILE = TESTDATA_WRITE_PATH + '/zoneloadertest.sqlite3'
 DB_CLIENT_CONFIG = '{ "database_file": "' + DB_FILE + '" }'
 DB_SOURCE_CLIENT_CONFIG = '{ "database_file": "' + SOURCE_DB_FILE + '" }'
+STATIC_ZONE_CONFIG = '"' + TESTDATA_PATH + "/static.zone" + '"'
 
 ORIG_SOA_TXT = 'example.com. 3600 IN SOA master.example.com. ' +\
                'admin.example.com. 1234 3600 1800 2419200 7200\n'
@@ -96,7 +98,7 @@ class ZoneLoaderTests(unittest.TestCase):
         """
         result, finder = self.client.find_zone(self.test_name)
         self.assertEqual(self.client.SUCCESS, result)
-        result, rrset, _ = finder.find(self.test_name, isc.dns.RRType.SOA())
+        result, rrset, _ = finder.find(self.test_name, isc.dns.RRType.SOA)
         self.assertEqual(finder.SUCCESS, result)
         self.assertEqual(soa_txt, rrset.to_text())
 
@@ -214,10 +216,15 @@ class ZoneLoaderTests(unittest.TestCase):
                           self.client, zone_name, self.source_client)
 
     def test_no_ds_load_support(self):
-        # This may change in the future, but atm, the in-mem ds does
-        # not support the API the zone loader uses (it has direct load calls)
-        inmem_client = isc.datasrc.DataSourceClient('memory',
-                                                    '{ "type": "memory" }');
+        # As the memory datasource module no longer exists, we check the
+        # static datasource instead (as that uses the memory datasource
+        # anyway).
+        #
+        # This may change in the future, but ATM, the static ds does not
+        # support the API the zone loader uses (it has direct load
+        # calls).
+        inmem_client = isc.datasrc.DataSourceClient('static',
+                                                    STATIC_ZONE_CONFIG);
         self.assertRaises(isc.datasrc.NotImplemented,
                           isc.datasrc.ZoneLoader,
                           inmem_client, self.test_name, self.test_file)
@@ -231,7 +238,7 @@ class ZoneLoaderTests(unittest.TestCase):
     def test_wrong_class_from_client(self):
         # For ds->ds loading, wrong class is detected upon construction
         # Need a bit of the extended setup for CH source client
-        clientlist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH())
+        clientlist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH)
         clientlist.configure('[ { "type": "static", "params": "' +
                              STATIC_ZONE_FILE +'" } ]', False)
         self.source_client, _, _ = clientlist.find(isc.dns.Name("bind."),
diff --git a/src/lib/python/isc/datasrc/updater_inc.cc b/src/lib/python/isc/datasrc/updater_inc.cc
index 32715ec..6a17587 100644
--- a/src/lib/python/isc/datasrc/updater_inc.cc
+++ b/src/lib/python/isc/datasrc/updater_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2011,2013  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.
+
 namespace {
 
 const char* const ZoneUpdater_doc = "\
@@ -76,6 +90,10 @@ This method must not be called once commit() is performed. If it calls\n\
 after commit() the implementation must throw a isc.datasrc.Error\n\
 exception.\n\
 \n\
+Implementations of ZoneUpdater may not allow adding or deleting RRsets\n\
+after get_rrset_collection() is called. In this case, implementations\n\
+throw an InvalidOperation exception.\n\
+\n\
 Todo As noted above we may have to revisit the design details as we\n\
 gain experiences:\n\
 \n\
@@ -133,6 +151,10 @@ This method must not be called once commit() is performed. If it calls\n\
 after commit() the implementation must throw a isc.datasrc.Error\n\
 exception.\n\
 \n\
+Implementations of ZoneUpdater may not allow adding or deleting RRsets\n\
+after get_rrset_collection() is called. In this case, implementations\n\
+throw an InvalidOperation exception.\n\
+\n\
 Todo: As noted above we may have to revisit the design details as we\n\
 gain experiences:\n\
 \n\
@@ -178,4 +200,67 @@ Exceptions:\n\
              error, or wrapper error\n\\n\
 \n\
 ";
+
+// Modifications:
+// -  remove reference to isc.datasrc.RRsetCollectionBase (hidden for Python
+//    wrapper)
+const char* const ZoneUpdater_getRRsetCollection_doc = "\
+get_rrset_collection() -> isc.dns.RRsetCollectionBase \n\
+\n\
+Return an RRsetCollection for the updater.\n\
+\n\
+This method returns an RRsetCollection for the updater, implementing\n\
+the isc.dns.RRsetCollectionBase interface. Typically, the returned\n\
+RRsetCollection is a singleton for its ZoneUpdater. The returned\n\
+RRsetCollection object must not be used after its corresponding\n\
+ZoneUpdater has been destroyed. The returned RRsetCollection object\n\
+may be used to search RRsets from the ZoneUpdater. The actual\n\
+RRsetCollection returned has a behavior dependent on the ZoneUpdater\n\
+implementation.\n\
+\n\
+The behavior of the RRsetCollection is similar to the behavior of the\n\
+Zonefinder returned by get_finder(). In fact, it's redundant in a\n\
+sense because one can implement the dns.RRsetCollectionBase interface\n\
+using an updater and get_finder() interface (unless it's expected to\n\
+support zone iteration, and the initial implementation of the\n\
+RRsetCollection returned by this method doesn't support it). We\n\
+still provide it as an updater's method so it will be easier for an\n\
+updater implementation to customize the RRsetCollection\n\
+implementation, and also for making it easy to impose restrictions\n\
+described below.\n\
+\n\
+Specific data sources may have special restrictions. That's especially\n\
+the case for database-based data sources. Such restrictions may also\n\
+result in limiting the usage of the RRsetCollection as described in\n\
+the following paragraphs. A specific updater implementation may\n\
+provide more flexible behavior, but applications using this interface\n\
+must assume the most restricted case unless it knows it uses a\n\
+particular specialized updater implementation that loosens specific\n\
+restrictions.\n\
+\n\
+- An application must not add or delete RRsets after\n\
+  get_rrset_collection() is called.\n\
+- An application must not use the returned collection from\n\
+  get_rrset_collection() once commit() is called on the updater that\n\
+  generates the collection.\n\
+\n\
+Implementations of ZoneUpdater may not allow adding or deleting RRsets\n\
+after get_rrset_collection() is called. This is because if an\n\
+iterator of the collection is being used at that time the modification\n\
+to the zone may break an internal assumption of the iterator and may\n\
+result in unexpected behavior. Also, the iterator may conceptually\n\
+hold a \"reader lock\" of the zone (in an implementation dependent\n\
+manner), which would prevent the addition or deletion, surprising the\n\
+caller (who would normally expect it to succeed).\n\
+\n\
+Implementations of ZoneUpdater may disable a previously returned\n\
+RRsetCollection after commit() is called. This is because the returned\n\
+RRsetCollection may internally rely on the conceptual transaction of\n\
+the updater that generates the collection (which would be literally\n\
+the case for database-based data sources), and once the transaction is\n\
+committed anything that relies on it won't be valid. If an\n\
+RRsetCollection is disabled, using methods such as find() and using\n\
+its iterator would cause an exception to be thrown.\n\
+\n\
+";
 } // unnamed namespace
diff --git a/src/lib/python/isc/datasrc/updater_python.cc b/src/lib/python/isc/datasrc/updater_python.cc
index 97ffa00..e61db75 100644
--- a/src/lib/python/isc/datasrc/updater_python.cc
+++ b/src/lib/python/isc/datasrc/updater_python.cc
@@ -32,6 +32,7 @@
 #include <dns/python/rrset_python.h>
 #include <dns/python/rrclass_python.h>
 #include <dns/python/rrtype_python.h>
+#include <dns/python/rrset_collection_python.h>
 
 #include "datasrc.h"
 #include "updater_python.h"
@@ -195,6 +196,107 @@ ZoneUpdater_find_all(PyObject* po_self, PyObject* args) {
         &self->cppobj->getFinder(), args));
 }
 
+namespace {
+// Below we define Python RRsetCollection class generated by the updater.
+// It's never expected to be instantiated directly from Python code, so
+// everything is hidden here, and tp_init always fails.
+
+class s_UpdaterRRsetCollection : public s_RRsetCollection {
+public:
+    s_UpdaterRRsetCollection() : s_RRsetCollection(), base_obj_(NULL) {}
+    PyObject* base_obj_;
+};
+
+int
+RRsetCollection_init(PyObject*, PyObject*, PyObject*) {
+    // can't be called directly; actually, the constructor shouldn't even be
+    // called, but we catch the case just in case.
+    PyErr_SetString(PyExc_TypeError,
+                    "datasrc.RRsetCollection cannot be constructed directly");
+
+    return (-1);
+}
+
+void
+RRsetCollection_destroy(PyObject* po_self) {
+    s_UpdaterRRsetCollection* const self =
+        static_cast<s_UpdaterRRsetCollection*>(po_self);
+
+    // We don't own the C++ collection object; we shouldn't delete it here.
+
+    // Note: we need to check if this is NULL; it remains NULL in case of
+    // direct instantiation (which fails).
+    if (self->base_obj_ != NULL) {
+        Py_DECREF(self->base_obj_);
+    }
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyTypeObject updater_rrset_collection_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "datasrc.UpdaterRRsetCollection",
+    sizeof(s_UpdaterRRsetCollection),   // tp_basicsize
+    0,                                  // tp_itemsize
+    RRsetCollection_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
+    NULL,
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    NULL,                               // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,   // tp_base (rrset_collection_base_type, set at run time)
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    RRsetCollection_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
+};
+} // unnamed namespace
+
+PyObject*
+ZoneUpdater_getRRsetCollection(PyObject* po_self, PyObject*) {
+    s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
+
+    s_UpdaterRRsetCollection* collection =
+        static_cast<s_UpdaterRRsetCollection*>(
+            PyObject_New(s_RRsetCollection, &updater_rrset_collection_type));
+    collection->cppobj = &self->cppobj->getRRsetCollection();
+    collection->base_obj_ = po_self;;
+    Py_INCREF(collection->base_obj_);
+
+    return (collection);
+}
+
 // This list contains the actual set of functions we have in
 // python. Each entry has
 // 1. Python method name
@@ -207,6 +309,8 @@ PyMethodDef ZoneUpdater_methods[] = {
     { "delete_rrset", ZoneUpdater_deleteRRset,
       METH_VARARGS, ZoneUpdater_deleteRRset_doc },
     { "commit", ZoneUpdater_commit, METH_NOARGS, ZoneUpdater_commit_doc },
+    { "get_rrset_collection", ZoneUpdater_getRRsetCollection,
+      METH_NOARGS, ZoneUpdater_getRRsetCollection_doc },
     // Instead of a getFinder, we implement the finder functionality directly
     // This is because ZoneFinder is non-copyable, and we should not create
     // a ZoneFinder object from a reference only (which is what is returned
@@ -292,6 +396,56 @@ createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source,
     return (py_zu);
 }
 
+bool
+initModulePart_ZoneUpdater(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(&zoneupdater_type) < 0) {
+        return (false);
+    }
+    void* zip = &zoneupdater_type;
+    if (PyModule_AddObject(mod, "ZoneUpdater",
+                           static_cast<PyObject*>(zip)) < 0)
+    {
+        return (false);
+    }
+    Py_INCREF(&zoneupdater_type);
+
+    // get_rrset_collection() needs the base class type information.  Since
+    // it's defined in a separate loadable module, we retrieve its C object
+    // via the Python interpreter.  Directly referring to
+    // isc::dns::python::rrset_collection_base_type might work depending on
+    // the runtime environment (and in fact it does for some), but that would
+    // be less portable.
+    try {
+        if (updater_rrset_collection_type.tp_base == NULL) {
+            PyObjectContainer dns_module(PyImport_ImportModule("isc.dns"));
+            PyObjectContainer dns_dict(PyModule_GetDict(dns_module.get()));
+            // GetDict doesn't acquire a reference, so we need to get it to
+            // meet the container's requirement.
+            Py_INCREF(dns_dict.get());
+            PyObjectContainer base(
+                PyDict_GetItemString(dns_dict.get(), "RRsetCollectionBase"));
+            PyTypeObject* pt_rrset_collection_base =
+                static_cast<PyTypeObject*>(static_cast<void*>(base.get()));
+            updater_rrset_collection_type.tp_base = pt_rrset_collection_base;
+            if (PyType_Ready(&updater_rrset_collection_type) < 0) {
+                isc_throw(Unexpected, "failed to import isc.dns module");
+            }
+
+            // Make sure the base type won't suddenly disappear.  Note that we
+            // are effectively leaking it; it's intentional.
+            Py_INCREF(base.get());
+        }
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in ZoneUpdater initialization");
+        return (false);
+    }
+
+    return (true);
+}
 } // namespace python
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/python/isc/datasrc/updater_python.h b/src/lib/python/isc/datasrc/updater_python.h
index b09c524..b7f1452 100644
--- a/src/lib/python/isc/datasrc/updater_python.h
+++ b/src/lib/python/isc/datasrc/updater_python.h
@@ -36,7 +36,7 @@ extern PyTypeObject zoneupdater_type;
 PyObject* createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source,
                                   PyObject* base_obj = NULL);
 
-
+bool initModulePart_ZoneUpdater(PyObject* mod);
 } // namespace python
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/python/isc/datasrc/zone_loader_inc.cc b/src/lib/python/isc/datasrc/zone_loader_inc.cc
index ae6fa3c..aed3192 100644
--- a/src/lib/python/isc/datasrc/zone_loader_inc.cc
+++ b/src/lib/python/isc/datasrc/zone_loader_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2012-2013  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.
+
 namespace {
 const char* const ZoneLoader_doc = "\
 Class to load data into a data source client.\n\
diff --git a/src/lib/python/isc/ddns/libddns_messages.mes b/src/lib/python/isc/ddns/libddns_messages.mes
index 406151c..ab982ad 100644
--- a/src/lib/python/isc/ddns/libddns_messages.mes
+++ b/src/lib/python/isc/ddns/libddns_messages.mes
@@ -121,7 +121,7 @@ a bad class. The class of the update RRset must be either the same
 as the class in the Zone Section, ANY, or NONE.
 A FORMERR response is sent back to the client.
 
-% LIBDDNS_UPDATE_DATASRC_ERROR error in datasource during DDNS update: %1
+% LIBDDNS_UPDATE_DATASRC_COMMIT_FAILED error in datasource during DDNS update: %1
 An error occurred while committing the DDNS update changes to the
 datasource. The specific error is printed. A SERVFAIL response is sent
 back to the client.
@@ -167,14 +167,6 @@ rejected by the zone's update ACL.  When this library is used by
 b10-ddns, the server will then completely ignore the request; no
 response will be sent.
 
-% LIBDDNS_UPDATE_ERROR update client %1 for zone %2: %3
-Debug message.  An error is found in processing a dynamic update
-request.  This log message is used for general errors that are not
-normally expected to happen.  So, in general, it would mean some
-problem in the client implementation or an interoperability issue
-with this implementation.  The client's address, the zone name and
-class, and description of the error are logged.
-
 % LIBDDNS_UPDATE_FORWARD_FAIL update client %1 for zone %2: update forwarding not supported
 Debug message.  An update request is sent to a secondary server.  This
 is not necessarily invalid, but this implementation does not yet
@@ -205,6 +197,14 @@ should give more information on what prerequisite type failed.
 If the result code is FORMERR, the prerequisite section was not well-formed.
 An error response with the given result code is sent back to the client.
 
+% LIBDDNS_UPDATE_PROCESSING_FAILED update client %1 for zone %2: %3
+Debug message.  An error is found in processing a dynamic update
+request.  This log message is used for general errors that are not
+normally expected to happen.  So, in general, it would mean some
+problem in the client implementation or an interoperability issue
+with this implementation.  The client's address, the zone name and
+class, and description of the error are logged.
+
 % LIBDDNS_UPDATE_UNCAUGHT_EXCEPTION update client %1 for zone %2: uncaught exception while processing update section: %3
 An uncaught exception was encountered while processing the Update
 section of a DDNS message. The specific exception is shown in the log message.
diff --git a/src/lib/python/isc/ddns/session.py b/src/lib/python/isc/ddns/session.py
index 60834fb..3368523 100644
--- a/src/lib/python/isc/ddns/session.py
+++ b/src/lib/python/isc/ddns/session.py
@@ -135,7 +135,7 @@ class DDNS_SOA:
     def __write_soa_internal(self, origin_soa, soa_num):
         '''Write back serial number to soa'''
         new_soa = RRset(origin_soa.get_name(), origin_soa.get_class(),
-                        RRType.SOA(), origin_soa.get_ttl())
+                        RRType.SOA, origin_soa.get_ttl())
         soa_rdata_parts = origin_soa.get_rdata()[0].to_text().split()
         soa_rdata_parts[2] = str(soa_num.get_value())
         new_soa.add_rdata(Rdata(origin_soa.get_type(), origin_soa.get_class(),
@@ -248,18 +248,18 @@ class UpdateSession:
             self.__check_update_acl(self.__zname, self.__zclass)
             self._create_diff()
             prereq_result = self.__check_prerequisites()
-            if prereq_result != Rcode.NOERROR():
+            if prereq_result != Rcode.NOERROR:
                 self.__make_response(prereq_result)
                 return UPDATE_ERROR, self.__zname, self.__zclass
             update_result = self.__do_update()
-            if update_result != Rcode.NOERROR():
+            if update_result != Rcode.NOERROR:
                 self.__make_response(update_result)
                 return UPDATE_ERROR, self.__zname, self.__zclass
-            self.__make_response(Rcode.NOERROR())
+            self.__make_response(Rcode.NOERROR)
             return UPDATE_SUCCESS, self.__zname, self.__zclass
         except UpdateError as e:
             if not e.nolog:
-                logger.debug(logger.DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_ERROR,
+                logger.debug(logger.DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_PROCESSING_FAILED,
                              ClientFormatter(self.__client_addr, self.__tsig),
                              ZoneFormatter(e.zname, e.zclass), e)
             # If RCODE is specified, create a corresponding resonse and return
@@ -272,7 +272,7 @@ class UpdateSession:
         except isc.datasrc.Error as e:
             logger.error(LIBDDNS_DATASRC_ERROR,
                          ClientFormatter(self.__client_addr, self.__tsig), e)
-            self.__make_response(Rcode.SERVFAIL())
+            self.__make_response(Rcode.SERVFAIL)
             return UPDATE_ERROR, None, None
 
     def _get_update_zone(self):
@@ -295,11 +295,11 @@ class UpdateSession:
         n_zones = self.__message.get_rr_count(SECTION_ZONE)
         if n_zones != 1:
             raise UpdateError('Invalid number of records in zone section: ' +
-                              str(n_zones), None, None, Rcode.FORMERR())
+                              str(n_zones), None, None, Rcode.FORMERR)
         zrecord = self.__message.get_question()[0]
-        if zrecord.get_type() != RRType.SOA():
+        if zrecord.get_type() != RRType.SOA:
             raise UpdateError('update zone section contains non-SOA',
-                              None, None, Rcode.FORMERR())
+                              None, None, Rcode.FORMERR)
 
         # See if we're serving a primary zone specified in the zone section.
         zname = zrecord.get_name()
@@ -316,12 +316,12 @@ class UpdateSession:
             logger.debug(DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_FORWARD_FAIL,
                          ClientFormatter(self.__client_addr, self.__tsig),
                          ZoneFormatter(zname, zclass))
-            raise UpdateError('forward', zname, zclass, Rcode.NOTIMP(), True)
+            raise UpdateError('forward', zname, zclass, Rcode.NOTIMP, True)
         # zone wasn't found
         logger.debug(DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_NOTAUTH,
                      ClientFormatter(self.__client_addr, self.__tsig),
                      ZoneFormatter(zname, zclass))
-        raise UpdateError('notauth', zname, zclass, Rcode.NOTAUTH(), True)
+        raise UpdateError('notauth', zname, zclass, Rcode.NOTAUTH, True)
 
     def _create_diff(self):
         '''
@@ -352,7 +352,7 @@ class UpdateSession:
             logger.info(LIBDDNS_UPDATE_DENIED,
                         ClientFormatter(self.__client_addr, self.__tsig),
                         ZoneFormatter(zname, zclass))
-            raise UpdateError('rejected', zname, zclass, Rcode.REFUSED(), True)
+            raise UpdateError('rejected', zname, zclass, Rcode.REFUSED, True)
         if action == DROP:
             logger.info(LIBDDNS_UPDATE_DROPPED,
                         ClientFormatter(self.__client_addr, self.__tsig),
@@ -459,7 +459,7 @@ class UpdateSession:
     def __check_prerequisites(self):
         '''Check the prerequisites section of the UPDATE Message.
            RFC2136 Section 2.4.
-           Returns a dns Rcode signaling either no error (Rcode.NOERROR())
+           Returns a dns Rcode signaling either no error (Rcode.NOERROR)
            or that one of the prerequisites failed (any other Rcode).
         '''
 
@@ -473,20 +473,20 @@ class UpdateSession:
                             ClientFormatter(self.__client_addr),
                             ZoneFormatter(self.__zname, self.__zclass),
                             RRsetFormatter(rrset))
-                return Rcode.NOTZONE()
+                return Rcode.NOTZONE
 
             # Algorithm taken from RFC2136 Section 3.2
-            if rrset.get_class() == RRClass.ANY():
+            if rrset.get_class() == RRClass.ANY:
                 if rrset.get_ttl().get_value() != 0 or\
                    rrset.get_rdata_count() != 0:
                     logger.info(LIBDDNS_PREREQ_FORMERR_ANY,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
-                elif rrset.get_type() == RRType.ANY():
+                    return Rcode.FORMERR
+                elif rrset.get_type() == RRType.ANY:
                     if not self.__prereq_name_in_use(rrset):
-                        rcode = Rcode.NXDOMAIN()
+                        rcode = Rcode.NXDOMAIN
                         logger.info(LIBDDNS_PREREQ_NAME_IN_USE_FAILED,
                                     ClientFormatter(self.__client_addr),
                                     ZoneFormatter(self.__zname, self.__zclass),
@@ -494,23 +494,23 @@ class UpdateSession:
                         return rcode
                 else:
                     if not self.__prereq_rrset_exists(rrset):
-                        rcode = Rcode.NXRRSET()
+                        rcode = Rcode.NXRRSET
                         logger.info(LIBDDNS_PREREQ_RRSET_EXISTS_FAILED,
                                     ClientFormatter(self.__client_addr),
                                     ZoneFormatter(self.__zname, self.__zclass),
                                     RRsetFormatter(rrset), rcode)
                         return rcode
-            elif rrset.get_class() == RRClass.NONE():
+            elif rrset.get_class() == RRClass.NONE:
                 if rrset.get_ttl().get_value() != 0 or\
                    rrset.get_rdata_count() != 0:
                     logger.info(LIBDDNS_PREREQ_FORMERR_NONE,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
-                elif rrset.get_type() == RRType.ANY():
+                    return Rcode.FORMERR
+                elif rrset.get_type() == RRType.ANY:
                     if not self.__prereq_name_not_in_use(rrset):
-                        rcode = Rcode.YXDOMAIN()
+                        rcode = Rcode.YXDOMAIN
                         logger.info(LIBDDNS_PREREQ_NAME_NOT_IN_USE_FAILED,
                                     ClientFormatter(self.__client_addr),
                                     ZoneFormatter(self.__zname, self.__zclass),
@@ -518,7 +518,7 @@ class UpdateSession:
                         return rcode
                 else:
                     if not self.__prereq_rrset_does_not_exist(rrset):
-                        rcode = Rcode.YXRRSET()
+                        rcode = Rcode.YXRRSET
                         logger.info(LIBDDNS_PREREQ_RRSET_DOES_NOT_EXIST_FAILED,
                                     ClientFormatter(self.__client_addr),
                                     ZoneFormatter(self.__zname, self.__zclass),
@@ -530,7 +530,7 @@ class UpdateSession:
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
+                    return Rcode.FORMERR
                 else:
                     collect_rrsets(exact_match_rrsets, rrset)
             else:
@@ -538,11 +538,11 @@ class UpdateSession:
                             ClientFormatter(self.__client_addr),
                             ZoneFormatter(self.__zname, self.__zclass),
                             RRsetFormatter(rrset))
-                return Rcode.FORMERR()
+                return Rcode.FORMERR
 
         for collected_rrset in exact_match_rrsets:
             if not self.__prereq_rrset_exists_value(collected_rrset):
-                rcode = Rcode.NXRRSET()
+                rcode = Rcode.NXRRSET
                 logger.info(LIBDDNS_PREREQ_RRSET_EXISTS_VAL_FAILED,
                             ClientFormatter(self.__client_addr),
                             ZoneFormatter(self.__zname, self.__zclass),
@@ -550,7 +550,7 @@ class UpdateSession:
                 return rcode
 
         # All prerequisites are satisfied
-        return Rcode.NOERROR()
+        return Rcode.NOERROR
 
     def __set_soa_rrset(self, rrset):
         '''Sets the given rrset to the member __added_soa (which
@@ -570,7 +570,7 @@ class UpdateSession:
                             ClientFormatter(self.__client_addr),
                             ZoneFormatter(self.__zname, self.__zclass),
                             RRsetFormatter(rrset))
-                return Rcode.NOTZONE()
+                return Rcode.NOTZONE
             if rrset.get_class() == self.__zclass:
                 # In fact, all metatypes are in a specific range,
                 # so one check can test TKEY to ANY
@@ -581,52 +581,52 @@ class UpdateSession:
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
-                if rrset.get_type() == RRType.SOA():
+                    return Rcode.FORMERR
+                if rrset.get_type() == RRType.SOA:
                     # In case there's multiple soa records in the update
                     # somehow, just take the last
                     for rr in foreach_rr(rrset):
                         self.__set_soa_rrset(rr)
-            elif rrset.get_class() == RRClass.ANY():
+            elif rrset.get_class() == RRClass.ANY:
                 if rrset.get_ttl().get_value() != 0:
                     logger.info(LIBDDNS_UPDATE_DELETE_NONZERO_TTL,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
+                    return Rcode.FORMERR
                 if rrset.get_rdata_count() > 0:
                     logger.info(LIBDDNS_UPDATE_DELETE_RRSET_NOT_EMPTY,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
+                    return Rcode.FORMERR
                 if rrset.get_type().get_code() >= 249 and\
                    rrset.get_type().get_code() <= 254:
                     logger.info(LIBDDNS_UPDATE_DELETE_BAD_TYPE,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
-            elif rrset.get_class() == RRClass.NONE():
+                    return Rcode.FORMERR
+            elif rrset.get_class() == RRClass.NONE:
                 if rrset.get_ttl().get_value() != 0:
                     logger.info(LIBDDNS_UPDATE_DELETE_RR_NONZERO_TTL,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
+                    return Rcode.FORMERR
                 if rrset.get_type().get_code() >= 249:
                     logger.info(LIBDDNS_UPDATE_DELETE_RR_BAD_TYPE,
                                 ClientFormatter(self.__client_addr),
                                 ZoneFormatter(self.__zname, self.__zclass),
                                 RRsetFormatter(rrset))
-                    return Rcode.FORMERR()
+                    return Rcode.FORMERR
             else:
                 logger.info(LIBDDNS_UPDATE_BAD_CLASS,
                             ClientFormatter(self.__client_addr),
                             ZoneFormatter(self.__zname, self.__zclass),
                             RRsetFormatter(rrset))
-                return Rcode.FORMERR()
-        return Rcode.NOERROR()
+                return Rcode.FORMERR
+        return Rcode.NOERROR
 
     def __do_update_add_single_rr(self, rr, existing_rrset):
         '''Helper for __do_update_add_rrs_to_rrset: only add the
@@ -657,7 +657,7 @@ class UpdateSession:
         # For a number of cases, we may need to remove data in the zone
         # (note; SOA is handled separately by __do_update, so that one
         # is explicitely ignored here)
-        if rrset.get_type() == RRType.SOA():
+        if rrset.get_type() == RRType.SOA:
             return
         result, orig_rrset, _ = self.__diff.find(rrset.get_name(),
                                                  rrset.get_type())
@@ -668,7 +668,7 @@ class UpdateSession:
             return
         elif result == ZoneFinder.SUCCESS:
             # if update is cname, and zone rr is not, ignore
-            if rrset.get_type() == RRType.CNAME():
+            if rrset.get_type() == RRType.CNAME:
                 # Remove original CNAME record (the new one
                 # is added below)
                 self.__diff.delete_data(orig_rrset)
@@ -679,7 +679,7 @@ class UpdateSession:
         elif result == ZoneFinder.NXRRSET:
             # There is data present, but not for this type.
             # If this type is CNAME, ignore the update
-            if rrset.get_type() == RRType.CNAME():
+            if rrset.get_type() == RRType.CNAME:
                 return
         for rr in foreach_rr(rrset):
             self.__do_update_add_single_rr(rr, orig_rrset)
@@ -696,8 +696,8 @@ class UpdateSession:
                                                         rrset.get_type())
         if result == ZoneFinder.SUCCESS:
             if to_delete.get_name() == self.__zname and\
-               (to_delete.get_type() == RRType.SOA() or\
-                to_delete.get_type() == RRType.NS()):
+               (to_delete.get_type() == RRType.SOA or\
+                to_delete.get_type() == RRType.NS):
                 # ignore
                 return
             for rr in foreach_rr(to_delete):
@@ -749,8 +749,8 @@ class UpdateSession:
             for to_delete in rrsets:
                 # if name == self.__zname and type is soa or ns, don't delete!
                 if to_delete.get_name() == self.__zname and\
-                   (to_delete.get_type() == RRType.SOA() or
-                    to_delete.get_type() == RRType.NS()):
+                   (to_delete.get_type() == RRType.SOA or
+                    to_delete.get_type() == RRType.NS):
                     continue
                 else:
                     for rr in foreach_rr(to_delete):
@@ -771,10 +771,10 @@ class UpdateSession:
         to_delete = convert_rrset_class(rrset, self.__zclass)
 
         if rrset.get_name() == self.__zname:
-            if rrset.get_type() == RRType.SOA():
+            if rrset.get_type() == RRType.SOA:
                 # ignore
                 return
-            elif rrset.get_type() == RRType.NS():
+            elif rrset.get_type() == RRType.NS:
                 # hmm. okay. annoying. There must be at least one left,
                 # delegate to helper method
                 self.__ns_deleter_helper(to_delete)
@@ -793,14 +793,14 @@ class UpdateSession:
         # serial magic and add the newly created one
 
         # get it from DS and to increment and stuff
-        result, old_soa, _ = self.__diff.find(self.__zname, RRType.SOA(),
+        result, old_soa, _ = self.__diff.find(self.__zname, RRType.SOA,
                                               ZoneFinder.NO_WILDCARD |
                                               ZoneFinder.FIND_GLUE_OK)
         # We may implement recovering from missing SOA data at some point, but
         # for now servfail on such a broken state
         if result != ZoneFinder.SUCCESS:
             raise UpdateError("Error finding SOA record in datasource.",
-                    self.__zname, self.__zclass, Rcode.SERVFAIL())
+                    self.__zname, self.__zclass, Rcode.SERVFAIL)
         serial_operation = DDNS_SOA()
         if self.__added_soa is not None and\
         serial_operation.soa_update_check(old_soa, self.__added_soa):
@@ -820,7 +820,7 @@ class UpdateSession:
         '''
         # prescan
         prescan_result = self.__do_prescan()
-        if prescan_result != Rcode.NOERROR():
+        if prescan_result != Rcode.NOERROR:
             return prescan_result
 
         # update
@@ -841,22 +841,22 @@ class UpdateSession:
             for rrset in self.__message.get_section(SECTION_UPDATE):
                 if rrset.get_class() == self.__zclass:
                     self.__do_update_add_rrs_to_rrset(rrset)
-                elif rrset.get_class() == RRClass.ANY():
-                    if rrset.get_type() == RRType.ANY():
+                elif rrset.get_class() == RRClass.ANY:
+                    if rrset.get_type() == RRType.ANY:
                         self.__do_update_delete_name(rrset)
                     else:
                         self.__do_update_delete_rrset(rrset)
-                elif rrset.get_class() == RRClass.NONE():
+                elif rrset.get_class() == RRClass.NONE:
                     self.__do_update_delete_rrs_from_rrset(rrset)
 
             self.__diff.commit()
-            return Rcode.NOERROR()
+            return Rcode.NOERROR
         except isc.datasrc.Error as dse:
-            logger.info(LIBDDNS_UPDATE_DATASRC_ERROR, dse)
-            return Rcode.SERVFAIL()
+            logger.info(LIBDDNS_UPDATE_DATASRC_COMMIT_FAILED, dse)
+            return Rcode.SERVFAIL
         except Exception as uce:
             logger.error(LIBDDNS_UPDATE_UNCAUGHT_EXCEPTION,
                          ClientFormatter(self.__client_addr),
                          ZoneFormatter(self.__zname, self.__zclass),
                          uce)
-            return Rcode.SERVFAIL()
+            return Rcode.SERVFAIL
diff --git a/src/lib/python/isc/ddns/tests/session_tests.py b/src/lib/python/isc/ddns/tests/session_tests.py
index f7c2d3c..bc25310 100644
--- a/src/lib/python/isc/ddns/tests/session_tests.py
+++ b/src/lib/python/isc/ddns/tests/session_tests.py
@@ -30,8 +30,8 @@ WRITE_ZONE_DB_FILE = TESTDATA_WRITE_PATH + "rwtest.sqlite3.copied"
 WRITE_ZONE_DB_CONFIG = "{ \"database_file\": \"" + WRITE_ZONE_DB_FILE + "\"}"
 
 TEST_ZONE_NAME = Name('example.org')
-UPDATE_RRTYPE = RRType.SOA()
-TEST_RRCLASS = RRClass.IN()
+UPDATE_RRTYPE = RRType.SOA
+TEST_RRCLASS = RRClass.IN
 TEST_ZONE_RECORD = Question(TEST_ZONE_NAME, TEST_RRCLASS, UPDATE_RRTYPE)
 TEST_CLIENT6 = ('2001:db8::1', 53, 0, 0)
 TEST_CLIENT4 = ('192.0.2.1', 53)
@@ -42,8 +42,8 @@ def create_update_msg(zones=[TEST_ZONE_RECORD], prerequisites=[],
                       updates=[], tsig_key=None):
     msg = Message(Message.RENDER)
     msg.set_qid(5353)           # arbitrary chosen
-    msg.set_opcode(Opcode.UPDATE())
-    msg.set_rcode(Rcode.NOERROR())
+    msg.set_opcode(Opcode.UPDATE)
+    msg.set_rcode(Rcode.NOERROR)
     for z in zones:
         msg.add_question(z)
     for p in prerequisites:
@@ -99,7 +99,7 @@ class SessionModuleTests(unittest.TestCase):
 
     def test_foreach_rr_in_rrset(self):
         rrset = create_rrset("www.example.org", TEST_RRCLASS,
-                             RRType.A(), 3600, [ "192.0.2.1" ])
+                             RRType.A, 3600, [ "192.0.2.1" ])
 
         l = []
         for rr in foreach_rr(rrset):
@@ -121,17 +121,17 @@ class SessionModuleTests(unittest.TestCase):
     def test_convert_rrset_class(self):
         # Converting an RRSET to a different class should work
         # if the rdata types can be converted
-        rrset = create_rrset("www.example.org", RRClass.NONE(), RRType.A(),
+        rrset = create_rrset("www.example.org", RRClass.NONE, RRType.A,
                              3600, [ b'\xc0\x00\x02\x01', b'\xc0\x00\x02\x02'])
 
-        rrset2 = convert_rrset_class(rrset, RRClass.IN())
+        rrset2 = convert_rrset_class(rrset, RRClass.IN)
         self.assertEqual("www.example.org. 3600 IN A 192.0.2.1\n" +
                          "www.example.org. 3600 IN A 192.0.2.2\n",
                          str(rrset2))
 
-        rrset3 = convert_rrset_class(rrset2, RRClass.NONE())
-        self.assertEqual("www.example.org. 3600 CLASS254 A \\# 4 " +
-                         "c0000201\nwww.example.org. 3600 CLASS254 " +
+        rrset3 = convert_rrset_class(rrset2, RRClass.NONE)
+        self.assertEqual("www.example.org. 3600 NONE A \\# 4 " +
+                         "c0000201\nwww.example.org. 3600 NONE " +
                          "A \\# 4 c0000202\n",
                          str(rrset3))
 
@@ -140,10 +140,10 @@ class SessionModuleTests(unittest.TestCase):
         # there was a ticket about making a better hierarchy for
         # dns/parsing related exceptions)
         self.assertRaises(InvalidRdataLength, convert_rrset_class,
-                          rrset, RRClass.CH())
+                          rrset, RRClass.CH)
         add_rdata(rrset, b'\xc0\x00')
         self.assertRaises(DNSMessageFORMERR, convert_rrset_class,
-                          rrset, RRClass.IN())
+                          rrset, RRClass.IN)
 
     def test_collect_rrsets(self):
         '''
@@ -152,25 +152,25 @@ class SessionModuleTests(unittest.TestCase):
         '''
         collected = []
 
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.1" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.1" ]))
         # Same name and class, different type
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.TXT(), 0, [ "one" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.2" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.TXT(), 0, [ "two" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.TXT, 0, [ "one" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.2" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.TXT, 0, [ "two" ]))
         # Same class and type as an existing one, different name
-        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.3" ]))
+        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.3" ]))
         # Same name and type as an existing one, different class
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
-                                               RRType.TXT(), 0, [ "one" ]))
-        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.4" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
-                                               RRType.TXT(), 0, [ "two" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+                                               RRType.TXT, 0, [ "one" ]))
+        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.4" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+                                               RRType.TXT, 0, [ "two" ]))
 
         strings = [ rrset.to_text() for rrset in collected ]
         # note + vs , in this list
@@ -216,7 +216,7 @@ class SessionTestBase(unittest.TestCase):
         '''Perform common checks on update resposne message.'''
         self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_QR))
         # note: we convert opcode to text it'd be more helpful on failure.
-        self.assertEqual(Opcode.UPDATE().to_text(), msg.get_opcode().to_text())
+        self.assertEqual(Opcode.UPDATE.to_text(), msg.get_opcode().to_text())
         self.assertEqual(expected_rcode.to_text(), msg.get_rcode().to_text())
         # All sections should be cleared
         self.assertEqual(0, msg.get_rr_count(SECTION_ZONE))
@@ -230,22 +230,22 @@ class TestDDNSSOA(unittest.TestCase):
         '''unittest for update_soa function'''
         soa_update = DDNS_SOA()
         soa_rr = create_rrset("example.org", TEST_RRCLASS,
-                              RRType.SOA(), 3600, ["ns1.example.org. " +
+                              RRType.SOA, 3600, ["ns1.example.org. " +
                               "admin.example.org. " +
                               "1233 3600 1800 2419200 7200"])
         expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
-                                       RRType.SOA(), 3600, ["ns1.example.org. "
+                                       RRType.SOA, 3600, ["ns1.example.org. "
                                        + "admin.example.org. " +
                                        "1234 3600 1800 2419200 7200"])
         self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
                          expected_soa_rr.get_rdata()[0].to_text())
         max_serial = 2 ** 32 - 1
         soa_rdata = "%d %s"%(max_serial,"3600 1800 2419200 7200")
-        soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(), 3600,
+        soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA, 3600,
                               ["ns1.example.org. " + "admin.example.org. " +
                               soa_rdata])
         expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
-                                       RRType.SOA(), 3600, ["ns1.example.org. "
+                                       RRType.SOA, 3600, ["ns1.example.org. "
                                        + "admin.example.org. " +
                                        "1 3600 1800 2419200 7200"])
         self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
@@ -253,11 +253,11 @@ class TestDDNSSOA(unittest.TestCase):
 
     def test_soa_update_check(self):
         '''unittest for soa_update_check function'''
-        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
                                     3600, ["ns1.example.org. " +
                                     "admin.example.org. " +
                                     "1233 3600 1800 2419200 7200"])
-        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
                                     3600, ["ns1.example.org. " +
                                     "admin.example.org. " +
                                     "1234 3600 1800 2419200 7200"])
@@ -269,11 +269,11 @@ class TestDDNSSOA(unittest.TestCase):
                                                      small_soa_rr))
         small_serial = 1235 + 2 ** 31
         soa_rdata = "%d %s"%(small_serial,"3600 1800 2419200 7200")
-        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
                                     3600, ["ns1.example.org. " +
                                            "admin.example.org. " +
                                            soa_rdata])
-        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
                                     3600, ["ns1.example.org. " +
                                     "admin.example.org. " +
                                     "1234 3600 1800 2419200 7200"])
@@ -305,41 +305,41 @@ class SessionTest(SessionTestBase):
         self.assertEqual(UPDATE_ERROR, result)
         self.assertEqual(None, zname)
         self.assertEqual(None, zclass)
-        self.check_response(session.get_message(), Rcode.FORMERR())
+        self.check_response(session.get_message(), Rcode.FORMERR)
 
         # Zone section contains multiple records
         msg = create_update_msg(zones=[TEST_ZONE_RECORD, TEST_ZONE_RECORD])
         session = UpdateSession(msg, TEST_CLIENT4, None)
         self.assertEqual(UPDATE_ERROR, session.handle()[0])
-        self.check_response(session.get_message(), Rcode.FORMERR())
+        self.check_response(session.get_message(), Rcode.FORMERR)
 
         # Zone section's type is not SOA
         msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                                RRType.A())])
+                                                RRType.A)])
         session = UpdateSession(msg, TEST_CLIENT4, None)
         self.assertEqual(UPDATE_ERROR, session.handle()[0])
-        self.check_response(session.get_message(), Rcode.FORMERR())
+        self.check_response(session.get_message(), Rcode.FORMERR)
 
     def test_update_secondary(self):
         # specified zone is configured as a secondary.  Since this
         # implementation doesn't support update forwarding, the result
         # should be NOTIMP.
         msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                                RRType.SOA())])
+                                                RRType.SOA)])
         session = UpdateSession(msg, TEST_CLIENT4,
                                 ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
                                            TEST_RRCLASS, self._datasrc_client))
         self.assertEqual(UPDATE_ERROR, session.handle()[0])
-        self.check_response(session.get_message(), Rcode.NOTIMP())
+        self.check_response(session.get_message(), Rcode.NOTIMP)
 
     def check_notauth(self, zname, zclass=TEST_RRCLASS):
         '''Common test sequence for the 'notauth' test'''
-        msg = create_update_msg(zones=[Question(zname, zclass, RRType.SOA())])
+        msg = create_update_msg(zones=[Question(zname, zclass, RRType.SOA)])
         session = UpdateSession(msg, TEST_CLIENT4,
                                 ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
                                            TEST_RRCLASS, self._datasrc_client))
         self.assertEqual(UPDATE_ERROR, session.handle()[0])
-        self.check_response(session.get_message(), Rcode.NOTAUTH())
+        self.check_response(session.get_message(), Rcode.NOTAUTH)
 
     def test_update_notauth(self):
         '''Update attempt for non authoritative zones'''
@@ -349,7 +349,7 @@ class SessionTest(SessionTestBase):
         # (match must be exact)
         self.check_notauth(Name('sub.example.org'))
         # zone class doesn't match
-        self.check_notauth(Name('example.org'), RRClass.CH())
+        self.check_notauth(Name('example.org'), RRClass.CH)
 
     def test_update_datasrc_error(self):
         # if the data source client raises an exception, it should result in
@@ -358,17 +358,17 @@ class SessionTest(SessionTestBase):
             def find_zone(self, name):
                 raise isc.datasrc.Error('faked exception')
         msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
-                                                RRType.SOA())])
+                                                RRType.SOA)])
         session = UpdateSession(msg, TEST_CLIENT4,
                                 ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
                                            TEST_RRCLASS,
                                            BadDataSourceClient()))
         self.assertEqual(UPDATE_ERROR, session.handle()[0])
-        self.check_response(session.get_message(), Rcode.SERVFAIL())
+        self.check_response(session.get_message(), Rcode.SERVFAIL)
 
     def test_foreach_rr_in_rrset(self):
         rrset = create_rrset("www.example.org", TEST_RRCLASS,
-                             RRType.A(), 3600, [ "192.0.2.1" ])
+                             RRType.A, 3600, [ "192.0.2.1" ])
 
         l = []
         for rr in foreach_rr(rrset):
@@ -390,17 +390,17 @@ class SessionTest(SessionTestBase):
     def test_convert_rrset_class(self):
         # Converting an RRSET to a different class should work
         # if the rdata types can be converted
-        rrset = create_rrset("www.example.org", RRClass.NONE(), RRType.A(),
+        rrset = create_rrset("www.example.org", RRClass.NONE, RRType.A,
                              3600, [ b'\xc0\x00\x02\x01', b'\xc0\x00\x02\x02'])
 
-        rrset2 = convert_rrset_class(rrset, RRClass.IN())
+        rrset2 = convert_rrset_class(rrset, RRClass.IN)
         self.assertEqual("www.example.org. 3600 IN A 192.0.2.1\n" +
                          "www.example.org. 3600 IN A 192.0.2.2\n",
                          str(rrset2))
 
-        rrset3 = convert_rrset_class(rrset2, RRClass.NONE())
-        self.assertEqual("www.example.org. 3600 CLASS254 A \\# 4 " +
-                         "c0000201\nwww.example.org. 3600 CLASS254 " +
+        rrset3 = convert_rrset_class(rrset2, RRClass.NONE)
+        self.assertEqual("www.example.org. 3600 NONE A \\# 4 " +
+                         "c0000201\nwww.example.org. 3600 NONE " +
                          "A \\# 4 c0000202\n",
                          str(rrset3))
 
@@ -409,10 +409,10 @@ class SessionTest(SessionTestBase):
         # there was a ticket about making a better hierarchy for
         # dns/parsing related exceptions)
         self.assertRaises(InvalidRdataLength, convert_rrset_class,
-                          rrset, RRClass.CH())
+                          rrset, RRClass.CH)
         add_rdata(rrset, b'\xc0\x00')
         self.assertRaises(DNSMessageFORMERR, convert_rrset_class,
-                          rrset, RRClass.IN())
+                          rrset, RRClass.IN)
 
     def test_collect_rrsets(self):
         '''
@@ -421,25 +421,25 @@ class SessionTest(SessionTestBase):
         '''
         collected = []
 
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.1" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.1" ]))
         # Same name and class, different type
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.TXT(), 0, [ "one" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.2" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
-                                               RRType.TXT(), 0, [ "two" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.TXT, 0, [ "one" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.2" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+                                               RRType.TXT, 0, [ "two" ]))
         # Same class and type as an existing one, different name
-        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.3" ]))
+        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.3" ]))
         # Same name and type as an existing one, different class
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
-                                               RRType.TXT(), 0, [ "one" ]))
-        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
-                                               RRType.A(), 0, [ "192.0.2.4" ]))
-        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
-                                               RRType.TXT(), 0, [ "two" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+                                               RRType.TXT, 0, [ "one" ]))
+        collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+                                               RRType.A, 0, [ "192.0.2.4" ]))
+        collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+                                               RRType.TXT, 0, [ "two" ]))
 
         strings = [ rrset.to_text() for rrset in collected ]
         # note + vs , in this list
@@ -469,64 +469,64 @@ class SessionTest(SessionTestBase):
         '''
         # Basic existence checks
         # www.example.org should have an A, but not an MX
-        rrset = create_rrset("www.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("www.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, expected, rrset)
-        rrset = create_rrset("www.example.org", rrclass, RRType.MX(), 0)
+        rrset = create_rrset("www.example.org", rrclass, RRType.MX, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         # example.org should have an MX, but not an A
-        rrset = create_rrset("example.org", rrclass, RRType.MX(), 0)
+        rrset = create_rrset("example.org", rrclass, RRType.MX, 0)
         self.__prereq_helper(method, expected, rrset)
-        rrset = create_rrset("example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         # Also check the case where the name does not even exist
-        rrset = create_rrset("doesnotexist.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("doesnotexist.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         # Wildcard expansion should not be applied, but literal matches
         # should work
-        rrset = create_rrset("foo.wildcard.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("foo.wildcard.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, not expected, rrset)
 
-        rrset = create_rrset("*.wildcard.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("*.wildcard.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, expected, rrset)
 
         # Likewise, CNAME directly should match, but what it points to should
         # not
-        rrset = create_rrset("cname.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("cname.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, not expected, rrset)
 
-        rrset = create_rrset("cname.example.org", rrclass, RRType.CNAME(), 0)
+        rrset = create_rrset("cname.example.org", rrclass, RRType.CNAME, 0)
         self.__prereq_helper(method, expected, rrset)
 
         # And also make sure a delegation (itself) is not treated as existing
         # data
-        rrset = create_rrset("foo.sub.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("foo.sub.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, not expected, rrset)
         # But the delegation data itself should match
-        rrset = create_rrset("sub.example.org", rrclass, RRType.NS(), 0)
+        rrset = create_rrset("sub.example.org", rrclass, RRType.NS, 0)
         self.__prereq_helper(method, expected, rrset)
         # As should glue
-        rrset = create_rrset("ns.sub.example.org", rrclass, RRType.A(), 0)
+        rrset = create_rrset("ns.sub.example.org", rrclass, RRType.A, 0)
         self.__prereq_helper(method, expected, rrset)
 
     def test_check_prerequisite_exists(self):
         method = self._session._UpdateSession__prereq_rrset_exists
         self.__check_prerequisite_exists_combined(method,
-                                                  RRClass.ANY(),
+                                                  RRClass.ANY,
                                                   True)
 
     def test_check_prerequisite_does_not_exist(self):
         method = self._session._UpdateSession__prereq_rrset_does_not_exist
         self.__check_prerequisite_exists_combined(method,
-                                                  RRClass.NONE(),
+                                                  RRClass.NONE,
                                                   False)
 
     def test_check_prerequisite_exists_value(self):
         method = self._session._UpdateSession__prereq_rrset_exists_value
 
-        rrset = create_rrset("www.example.org", RRClass.IN(), RRType.A(), 0)
+        rrset = create_rrset("www.example.org", RRClass.IN, RRType.A, 0)
         # empty one should not match
         self.__prereq_helper(method, False, rrset)
 
@@ -539,11 +539,11 @@ class SessionTest(SessionTestBase):
         self.__prereq_helper(method, False, rrset)
 
         # Also test one with more than one RR
-        rrset = create_rrset("example.org", RRClass.IN(), RRType.NS(), 0)
+        rrset = create_rrset("example.org", RRClass.IN, RRType.NS, 0)
         self.__prereq_helper(method, False, rrset)
         add_rdata(rrset, "ns1.example.org.")
         self.__prereq_helper(method, False, rrset)
-        add_rdata(rrset, "ns2.example.org")
+        add_rdata(rrset, "ns2.example.org.")
         self.__prereq_helper(method, False, rrset)
         add_rdata(rrset, "ns3.example.org.")
         self.__prereq_helper(method, True, rrset)
@@ -551,7 +551,7 @@ class SessionTest(SessionTestBase):
         self.__prereq_helper(method, False, rrset)
 
         # Repeat that, but try a different order of Rdata addition
-        rrset = create_rrset("example.org", RRClass.IN(), RRType.NS(), 0)
+        rrset = create_rrset("example.org", RRClass.IN, RRType.NS, 0)
         self.__prereq_helper(method, False, rrset)
         add_rdata(rrset, "ns3.example.org.")
         self.__prereq_helper(method, False, rrset)
@@ -563,8 +563,8 @@ class SessionTest(SessionTestBase):
         self.__prereq_helper(method, False, rrset)
 
         # and test one where the name does not even exist
-        rrset = create_rrset("doesnotexist.example.org", RRClass.IN(),
-                             RRType.A(), 0, [ "192.0.2.1" ])
+        rrset = create_rrset("doesnotexist.example.org", RRClass.IN,
+                             RRType.A, 0, [ "192.0.2.1" ])
         self.__prereq_helper(method, False, rrset)
 
     def __check_prerequisite_name_in_use_combined(self, method, rrclass,
@@ -573,42 +573,42 @@ class SessionTest(SessionTestBase):
            in behaviour) methods __prereq_name_in_use and
            __prereq_name_not_in_use
         '''
-        rrset = create_rrset("example.org", rrclass, RRType.ANY(), 0)
+        rrset = create_rrset("example.org", rrclass, RRType.ANY, 0)
         self.__prereq_helper(method, expected, rrset)
 
-        rrset = create_rrset("www.example.org", rrclass, RRType.ANY(), 0)
+        rrset = create_rrset("www.example.org", rrclass, RRType.ANY, 0)
         self.__prereq_helper(method, expected, rrset)
 
         rrset = create_rrset("doesnotexist.example.org", rrclass,
-                             RRType.ANY(), 0)
+                             RRType.ANY, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         rrset = create_rrset("belowdelegation.sub.example.org", rrclass,
-                             RRType.ANY(), 0)
+                             RRType.ANY, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         rrset = create_rrset("foo.wildcard.example.org", rrclass,
-                             RRType.ANY(), 0)
+                             RRType.ANY, 0)
         self.__prereq_helper(method, not expected, rrset)
 
         # empty nonterminal should not match
         rrset = create_rrset("nonterminal.example.org", rrclass,
-                             RRType.ANY(), 0)
+                             RRType.ANY, 0)
         self.__prereq_helper(method, not expected, rrset)
         rrset = create_rrset("empty.nonterminal.example.org", rrclass,
-                             RRType.ANY(), 0)
+                             RRType.ANY, 0)
         self.__prereq_helper(method, expected, rrset)
 
     def test_check_prerequisite_name_in_use(self):
         method = self._session._UpdateSession__prereq_name_in_use
         self.__check_prerequisite_name_in_use_combined(method,
-                                                       RRClass.ANY(),
+                                                       RRClass.ANY,
                                                        True)
 
     def test_check_prerequisite_name_not_in_use(self):
         method = self._session._UpdateSession__prereq_name_not_in_use
         self.__check_prerequisite_name_in_use_combined(method,
-                                                       RRClass.NONE(),
+                                                       RRClass.NONE,
                                                        False)
 
     def check_prerequisite_result(self, expected, prerequisites):
@@ -632,7 +632,7 @@ class SessionTest(SessionTestBase):
         self.assertEqual(expected.to_text(),
                          session._UpdateSession__message.get_rcode().to_text())
         # And that the result looks right
-        if expected == Rcode.NOERROR():
+        if expected == Rcode.NOERROR:
             self.assertEqual(UPDATE_SUCCESS, result)
         else:
             self.assertEqual(UPDATE_ERROR, result)
@@ -672,7 +672,7 @@ class SessionTest(SessionTestBase):
         self.assertEqual(expected.to_text(),
                          session._UpdateSession__message.get_rcode().to_text())
         # And that the result looks right
-        if expected == Rcode.NOERROR():
+        if expected == Rcode.NOERROR:
             self.assertEqual(UPDATE_SUCCESS, result)
         else:
             self.assertEqual(UPDATE_ERROR, result)
@@ -685,78 +685,75 @@ class SessionTest(SessionTestBase):
         # in the specific prerequisite type tests)
 
         # Let's first define a number of prereq's that should succeed
-        rrset_exists_yes = create_rrset("example.org", RRClass.ANY(),
-                                        RRType.SOA(), 0)
+        rrset_exists_yes = create_rrset("example.org", RRClass.ANY,
+                                        RRType.SOA, 0)
 
-        rrset_exists_value_yes = create_rrset("www.example.org", RRClass.IN(),
-                                              RRType.A(), 0, [ "192.0.2.1" ])
+        rrset_exists_value_yes = create_rrset("www.example.org", RRClass.IN,
+                                              RRType.A, 0, [ "192.0.2.1" ])
 
         rrset_does_not_exist_yes = create_rrset("foo.example.org",
-                                                RRClass.NONE(), RRType.SOA(),
+                                                RRClass.NONE, RRType.SOA,
                                                 0)
 
-        name_in_use_yes = create_rrset("www.example.org", RRClass.ANY(),
-                                       RRType.ANY(), 0)
+        name_in_use_yes = create_rrset("www.example.org", RRClass.ANY,
+                                       RRType.ANY, 0)
 
-        name_not_in_use_yes = create_rrset("foo.example.org", RRClass.NONE(),
-                                           RRType.ANY(), 0)
+        name_not_in_use_yes = create_rrset("foo.example.org", RRClass.NONE,
+                                           RRType.ANY, 0)
 
-        rrset_exists_value_1 = create_rrset("example.org", RRClass.IN(),
-                                            RRType.NS(), 0,
-                                            [ "ns1.example.org" ])
-        rrset_exists_value_2 = create_rrset("example.org", RRClass.IN(),
-                                            RRType.NS(), 0,
-                                            [ "ns2.example.org" ])
-        rrset_exists_value_3 = create_rrset("example.org", RRClass.IN(),
-                                            RRType.NS(), 0,
-                                            [ "ns3.example.org" ])
+        rrset_exists_value_1 = create_rrset("example.org", RRClass.IN,
+                                            RRType.NS, 0, ["ns1.example.org."])
+        rrset_exists_value_2 = create_rrset("example.org", RRClass.IN,
+                                            RRType.NS, 0, ["ns2.example.org."])
+        rrset_exists_value_3 = create_rrset("example.org", RRClass.IN,
+                                            RRType.NS, 0, ["ns3.example.org."])
 
         # and a number that should not
-        rrset_exists_no = create_rrset("foo.example.org", RRClass.ANY(),
-                                       RRType.SOA(), 0)
+        rrset_exists_no = create_rrset("foo.example.org", RRClass.ANY,
+                                       RRType.SOA, 0)
 
-        rrset_exists_value_no = create_rrset("www.example.org", RRClass.IN(),
-                                             RRType.A(), 0, [ "192.0.2.2" ])
+        rrset_exists_value_no = create_rrset("www.example.org", RRClass.IN,
+                                             RRType.A, 0, [ "192.0.2.2" ])
 
-        rrset_does_not_exist_no = create_rrset("example.org", RRClass.NONE(),
-                                               RRType.SOA(), 0)
+        rrset_does_not_exist_no = create_rrset("example.org", RRClass.NONE,
+                                               RRType.SOA, 0)
 
-        name_in_use_no = create_rrset("foo.example.org", RRClass.ANY(),
-                                      RRType.ANY(), 0)
+        name_in_use_no = create_rrset("foo.example.org", RRClass.ANY,
+                                      RRType.ANY, 0)
 
-        name_not_in_use_no = create_rrset("www.example.org", RRClass.NONE(),
-                                          RRType.ANY(), 0)
+        name_not_in_use_no = create_rrset("www.example.org", RRClass.NONE,
+                                          RRType.ANY, 0)
         # check 'no' result codes
-        self.check_prerequisite_result(Rcode.NXRRSET(),
+        self.check_prerequisite_result(Rcode.NXRRSET,
                                        [ rrset_exists_no ])
-        self.check_prerequisite_result(Rcode.NXRRSET(),
+        self.check_prerequisite_result(Rcode.NXRRSET,
                                        [ rrset_exists_value_no ])
-        self.check_prerequisite_result(Rcode.YXRRSET(),
+        self.check_prerequisite_result(Rcode.YXRRSET,
                                        [ rrset_does_not_exist_no ])
-        self.check_prerequisite_result(Rcode.NXDOMAIN(),
+        self.check_prerequisite_result(Rcode.NXDOMAIN,
                                        [ name_in_use_no ])
-        self.check_prerequisite_result(Rcode.YXDOMAIN(),
+        self.check_prerequisite_result(Rcode.YXDOMAIN,
                                        [ name_not_in_use_no ])
 
         # the 'yes' codes should result in ok
         # individually
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_exists_yes ] )
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_exists_value_yes ])
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_does_not_exist_yes ])
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ name_in_use_yes ])
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ name_not_in_use_yes ])
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_exists_value_1,
                                          rrset_exists_value_2,
                                          rrset_exists_value_3])
 
         # and together
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_exists_yes,
                                          rrset_exists_value_yes,
                                          rrset_does_not_exist_yes,
@@ -768,7 +765,7 @@ class SessionTest(SessionTestBase):
 
         # try out a permutation, note that one rrset is split up,
         # and the order of the RRs should not matter
-        self.check_prerequisite_result(Rcode.NOERROR(),
+        self.check_prerequisite_result(Rcode.NOERROR,
                                        [ rrset_exists_value_3,
                                          rrset_exists_yes,
                                          rrset_exists_value_2,
@@ -777,7 +774,7 @@ class SessionTest(SessionTestBase):
 
         # Should fail on the first error, even if most of the
         # prerequisites are ok
-        self.check_prerequisite_result(Rcode.NXDOMAIN(),
+        self.check_prerequisite_result(Rcode.NXDOMAIN,
                                        [ rrset_exists_value_3,
                                          rrset_exists_yes,
                                          rrset_exists_value_2,
@@ -786,39 +783,39 @@ class SessionTest(SessionTestBase):
                                          rrset_exists_value_1])
 
     def test_prerequisite_notzone(self):
-        rrset = create_rrset("some.other.zone.", RRClass.ANY(), RRType.SOA(), 0)
-        self.check_prerequisite_result(Rcode.NOTZONE(), [ rrset ])
+        rrset = create_rrset("some.other.zone.", RRClass.ANY, RRType.SOA, 0)
+        self.check_prerequisite_result(Rcode.NOTZONE, [ rrset ])
 
     def test_prerequisites_formerr(self):
         # test for form errors in the prerequisite section
 
         # Class ANY, non-zero TTL
-        rrset = create_rrset("example.org", RRClass.ANY(), RRType.SOA(), 1)
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        rrset = create_rrset("example.org", RRClass.ANY, RRType.SOA, 1)
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
         # Class ANY, but with rdata
-        rrset = create_rrset("example.org", RRClass.ANY(), RRType.A(), 0,
+        rrset = create_rrset("example.org", RRClass.ANY, RRType.A, 0,
                              [ b'\x00\x00\x00\x00' ])
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
         # Class NONE, non-zero TTL
-        rrset = create_rrset("example.org", RRClass.NONE(), RRType.SOA(), 1)
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        rrset = create_rrset("example.org", RRClass.NONE, RRType.SOA, 1)
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
         # Class NONE, but with rdata
-        rrset = create_rrset("example.org", RRClass.NONE(), RRType.A(), 0,
+        rrset = create_rrset("example.org", RRClass.NONE, RRType.A, 0,
                              [ b'\x00\x00\x00\x00' ])
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
         # Matching class and type, but non-zero TTL
-        rrset = create_rrset("www.example.org", RRClass.IN(), RRType.A(), 1,
+        rrset = create_rrset("www.example.org", RRClass.IN, RRType.A, 1,
                              [ "192.0.2.1" ])
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
         # Completely different class
-        rrset = create_rrset("example.org", RRClass.CH(), RRType.TXT(), 0,
+        rrset = create_rrset("example.org", RRClass.CH, RRType.TXT, 0,
                              [ "foo" ])
-        self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
 
     def __prereq_helper(self, method, expected, rrset):
         '''Calls the given method with self._datasrc_client
@@ -830,84 +827,84 @@ class SessionTest(SessionTestBase):
         '''Prepare a number of RRsets to be used in several update tests
            The rrsets are stored in self'''
         orig_a_rrset = create_rrset("www.example.org", TEST_RRCLASS,
-                                    RRType.A(), 3600, [ "192.0.2.1" ])
+                                    RRType.A, 3600, [ "192.0.2.1" ])
         self.orig_a_rrset = orig_a_rrset
 
         rrset_update_a = create_rrset("www.example.org", TEST_RRCLASS,
-                                      RRType.A(), 3600,
+                                      RRType.A, 3600,
                                       [ "192.0.2.2", "192.0.2.3" ])
         self.rrset_update_a = rrset_update_a
 
         rrset_update_soa = create_rrset("example.org", TEST_RRCLASS,
-                                        RRType.SOA(), 3600,
+                                        RRType.SOA, 3600,
                                         [ "ns1.example.org. " +
                                           "admin.example.org. " +
                                           "1233 3600 1800 2419200 7200" ])
         self.rrset_update_soa = rrset_update_soa
 
-        rrset_update_soa_del = create_rrset("example.org", RRClass.NONE(),
-                                            RRType.SOA(), 0,
+        rrset_update_soa_del = create_rrset("example.org", RRClass.NONE,
+                                            RRType.SOA, 0,
                                             [ "ns1.example.org. " +
                                               "admin.example.org. " +
                                               "1233 3600 1800 2419200 7200" ])
         self.rrset_update_soa_del = rrset_update_soa_del
 
         rrset_update_soa2 = create_rrset("example.org", TEST_RRCLASS,
-                                         RRType.SOA(), 3600,
+                                         RRType.SOA, 3600,
                                          [ "ns1.example.org. " +
                                            "admin.example.org. " +
                                            "4000 3600 1800 2419200 7200" ])
         self.rrset_update_soa2 = rrset_update_soa2
 
-        rrset_update_del_name = create_rrset("www.example.org", RRClass.ANY(),
-                                             RRType.ANY(), 0)
+        rrset_update_del_name = create_rrset("www.example.org", RRClass.ANY,
+                                             RRType.ANY, 0)
         self.rrset_update_del_name = rrset_update_del_name
 
-        rrset_update_del_name_apex = create_rrset("example.org", RRClass.ANY(),
-                                                  RRType.ANY(), 0)
+        rrset_update_del_name_apex = create_rrset("example.org", RRClass.ANY,
+                                                  RRType.ANY, 0)
         self.rrset_update_del_name_apex = rrset_update_del_name_apex
 
-        rrset_update_del_rrset = create_rrset("www.example.org", RRClass.ANY(),
-                                              RRType.A(), 0)
+        rrset_update_del_rrset = create_rrset("www.example.org", RRClass.ANY,
+                                              RRType.A, 0)
         self.rrset_update_del_rrset = rrset_update_del_rrset
 
-        rrset_update_del_mx_apex = create_rrset("example.org", RRClass.ANY(),
-                                                RRType.MX(), 0)
+        rrset_update_del_mx_apex = create_rrset("example.org", RRClass.ANY,
+                                                RRType.MX, 0)
         self.rrset_update_del_mx_apex = rrset_update_del_mx_apex
 
-        rrset_update_del_soa_apex = create_rrset("example.org", RRClass.ANY(),
-                                                 RRType.SOA(), 0)
+        rrset_update_del_soa_apex = create_rrset("example.org", RRClass.ANY,
+                                                 RRType.SOA, 0)
         self.rrset_update_del_soa_apex = rrset_update_del_soa_apex
 
-        rrset_update_del_ns_apex = create_rrset("example.org", RRClass.ANY(),
-                                                RRType.NS(), 0)
+        rrset_update_del_ns_apex = create_rrset("example.org", RRClass.ANY,
+                                                RRType.NS, 0)
         self.rrset_update_del_ns_apex = rrset_update_del_ns_apex
 
         rrset_update_del_rrset_part = create_rrset("www.example.org",
-                                                   RRClass.NONE(), RRType.A(),
+                                                   RRClass.NONE, RRType.A,
                                                    0,
                                                    [ b'\xc0\x00\x02\x02',
                                                      b'\xc0\x00\x02\x03' ])
         self.rrset_update_del_rrset_part = rrset_update_del_rrset_part
 
-        rrset_update_del_rrset_ns = create_rrset("example.org", RRClass.NONE(),
-                                        RRType.NS(), 0,
+        rrset_update_del_rrset_ns = create_rrset("example.org", RRClass.NONE,
+                                        RRType.NS, 0,
                                         [ b'\x03ns1\x07example\x03org\x00',
                                           b'\x03ns2\x07example\x03org\x00',
                                           b'\x03ns3\x07example\x03org\x00' ])
         self.rrset_update_del_rrset_ns = rrset_update_del_rrset_ns
 
-        rrset_update_del_rrset_mx = create_rrset("example.org", RRClass.NONE(),
-                                RRType.MX(), 0,
+        rrset_update_del_rrset_mx = create_rrset("example.org", RRClass.NONE,
+                                RRType.MX, 0,
                                 [ b'\x00\x0a\x04mail\x07example\x03org\x00' ])
         self.rrset_update_del_rrset_mx = rrset_update_del_rrset_mx
 
     def test_acl_before_prereq(self):
-        name_in_use_no = create_rrset("foo.example.org", RRClass.ANY(),
-                                      RRType.ANY(), 0)
+        name_in_use_no = create_rrset("foo.example.org", RRClass.ANY,
+                                      RRType.ANY, 0)
 
         # Test a prerequisite that would fail
-        self.check_full_handle_result(Rcode.NXDOMAIN(), [], [ name_in_use_no ])
+        self.check_full_handle_result(Rcode.NXDOMAIN, [], [ name_in_use_no ])
 
         # Change ACL so that it would be denied
         self._acl_map = {(TEST_ZONE_NAME, TEST_RRCLASS):
@@ -915,7 +912,7 @@ class SessionTest(SessionTestBase):
 
         # The prerequisite should now not be reached; it should fail on the
         # ACL
-        self.check_full_handle_result(Rcode.REFUSED(), [], [ name_in_use_no ])
+        self.check_full_handle_result(Rcode.REFUSED, [], [ name_in_use_no ])
 
     def test_prescan(self):
         '''Test whether the prescan succeeds on data that is ok, and whether
@@ -923,29 +920,29 @@ class SessionTest(SessionTestBase):
         # prepare a set of correct update statements
         self.__initialize_update_rrsets()
 
-        self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+        self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_a ])
 
         # check if soa is noticed
-        self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_soa ],
+        self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_soa ],
                                   self.rrset_update_soa)
 
         # Other types of succesful prechecks
-        self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_soa2 ],
+        self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_soa2 ],
                                   self.rrset_update_soa2)
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_del_name ])
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_del_name_apex ])
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_del_rrset ])
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_del_mx_apex ])
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_del_rrset_part ])
 
         # and check a few permutations of the above
         # all of them (with one of the soas)
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [
                                     self.rrset_update_a,
                                     self.rrset_update_soa,
@@ -960,16 +957,16 @@ class SessionTest(SessionTestBase):
         # Two soas. Should we reject or simply use the last?
         # (RFC is not really explicit on this, but between the lines I read
         # use the last)
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_soa,
                                     self.rrset_update_soa2 ],
                                     self.rrset_update_soa2)
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [ self.rrset_update_soa2,
                                     self.rrset_update_soa ],
                                   self.rrset_update_soa)
 
-        self.check_prescan_result(Rcode.NOERROR(),
+        self.check_prescan_result(Rcode.NOERROR,
                                   [
                                     self.rrset_update_del_mx_apex,
                                     self.rrset_update_del_name,
@@ -984,36 +981,36 @@ class SessionTest(SessionTestBase):
     def test_prescan_failures(self):
         '''Test whether prescan fails on bad data'''
         # out of zone data
-        rrset = create_rrset("different.zone", RRClass.ANY(), RRType.TXT(), 0)
-        self.check_prescan_result(Rcode.NOTZONE(), [ rrset ])
+        rrset = create_rrset("different.zone", RRClass.ANY, RRType.TXT, 0)
+        self.check_prescan_result(Rcode.NOTZONE, [ rrset ])
 
         # forbidden type, zone class
-        rrset = create_rrset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.ANY(), 0,
+        rrset = create_rrset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.ANY, 0,
                              [ b'\x00' ])
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
         # non-zero TTL, class ANY
-        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.TXT(), 1)
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.TXT, 1)
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
         # non-zero Rdata, class ANY
-        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.TXT(), 0,
+        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.TXT, 0,
                              [ "foo" ])
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
         # forbidden type, class ANY
-        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.AXFR(), 0,
+        rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.AXFR, 0,
                              [ b'\x00' ])
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
         # non-zero TTL, class NONE
-        rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE(), RRType.TXT(), 1)
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE, RRType.TXT, 1)
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
         # forbidden type, class NONE
-        rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE(), RRType.AXFR(), 0,
+        rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE, RRType.AXFR, 0,
                              [ b'\x00' ])
-        self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+        self.check_prescan_result(Rcode.FORMERR, [ rrset ])
 
     def __check_inzone_data(self, expected_result, name, rrtype,
                             expected_rrset = None):
@@ -1054,7 +1051,7 @@ class SessionTest(SessionTestBase):
 
         # during this test, we will extend it at some point
         extended_a_rrset = create_rrset("www.example.org", TEST_RRCLASS,
-                                        RRType.A(), 3600,
+                                        RRType.A, 3600,
                                         [ "192.0.2.1",
                                           "192.0.2.2",
                                           "192.0.2.3" ])
@@ -1062,90 +1059,90 @@ class SessionTest(SessionTestBase):
         # Sanity check, make sure original data is really there before updates
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.orig_a_rrset)
 
         # Add two rrs
-        self.check_full_handle_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+        self.check_full_handle_result(Rcode.NOERROR, [ self.rrset_update_a ])
 
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  extended_a_rrset)
 
         # Adding the same RRsets should not make a difference.
-        self.check_full_handle_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+        self.check_full_handle_result(Rcode.NOERROR, [ self.rrset_update_a ])
 
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  extended_a_rrset)
 
         # Now delete those two, and we should end up with the original RRset
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset_part ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.orig_a_rrset)
 
         # 'Deleting' them again should make no difference
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset_part ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.orig_a_rrset)
 
         # But deleting the entire rrset, independent of its contents, should
         # work
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
         # Check that if we update the SOA, it is updated to our value
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_soa2 ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.SOA(),
+                                 RRType.SOA,
                                  self.rrset_update_soa2)
 
     def test_glue_deletions(self):
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("sub.example.org."),
-                                 RRType.NS())
+                                 RRType.NS)
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("ns.sub.example.org."),
-                                 RRType.A())
+                                 RRType.A)
 
         # See that we can delete glue
         rrset_delete_glue = create_rrset("ns.sub.example.org.",
-                                         RRClass.ANY(),
-                                         RRType.A(),
+                                         RRClass.ANY,
+                                         RRType.A,
                                          0)
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ rrset_delete_glue ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("sub.example.org."),
-                                 RRType.NS())
+                                 RRType.NS)
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("ns.sub.example.org."),
-                                 RRType.A())
+                                 RRType.A)
 
         # Check that we don't accidentally delete a delegation if we
         # try to delete non-existent glue
         rrset_delete_nonexistent_glue = create_rrset("foo.sub.example.org.",
-                                                     RRClass.ANY(),
-                                                     RRType.A(),
+                                                     RRClass.ANY,
+                                                     RRType.A,
                                                      0)
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ rrset_delete_nonexistent_glue ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("sub.example.org."),
-                                 RRType.NS())
+                                 RRType.NS)
 
     def test_update_add_new_data(self):
         '''
@@ -1154,26 +1151,26 @@ class SessionTest(SessionTestBase):
         # Add data at a completely new name
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("new.example.org"),
-                                 RRType.A())
-        rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.A(),
+                                 RRType.A)
+        rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.A,
                              3600, [ "192.0.2.1", "192.0.2.2" ])
-        self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+        self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("new.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  rrset)
 
         # Also try a name where data is present, but none of this
         # specific type
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
                                  isc.dns.Name("new.example.org"),
-                                 RRType.TXT())
-        rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.TXT(),
+                                 RRType.TXT)
+        rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.TXT,
                              3600, [ "foo" ])
-        self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+        self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("new.example.org"),
-                                 RRType.TXT(),
+                                 RRType.TXT,
                                  rrset)
 
     def test_update_add_new_data_interspersed(self):
@@ -1186,36 +1183,36 @@ class SessionTest(SessionTestBase):
         # Add data at a completely new name
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("new_a.example.org"),
-                                 RRType.A())
+                                 RRType.A)
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("new_txt.example.org"),
-                                 RRType.TXT())
+                                 RRType.TXT)
 
-        rrset1 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A(),
+        rrset1 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A,
                               3600, [ "192.0.2.1" ])
 
-        rrset2 = create_rrset("new_txt.example.org", TEST_RRCLASS, RRType.TXT(),
+        rrset2 = create_rrset("new_txt.example.org", TEST_RRCLASS, RRType.TXT,
                               3600, [ "foo" ])
 
-        rrset3 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A(),
+        rrset3 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A,
                               3600, [ "192.0.2.2" ])
 
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ rrset1, rrset2, rrset3 ])
 
         # The update should have merged rrset1 and rrset3
         rrset_merged = create_rrset("new_a.example.org", TEST_RRCLASS,
-                                    RRType.A(), 3600,
+                                    RRType.A, 3600,
                                     [ "192.0.2.1", "192.0.2.2" ])
 
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("new_a.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  rrset_merged)
 
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("new_txt.example.org"),
-                                 RRType.TXT(),
+                                 RRType.TXT,
                                  rrset2)
 
     def test_update_delete_name(self):
@@ -1227,21 +1224,21 @@ class SessionTest(SessionTestBase):
         # First check it is there
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
         # Delete the entire name
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_name ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
         # Should still be gone after pointless second delete
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_name ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
     def test_update_apex_special_cases(self):
         '''
@@ -1251,23 +1248,23 @@ class SessionTest(SessionTestBase):
 
         # the original SOA
         orig_soa_rrset = create_rrset("example.org", TEST_RRCLASS,
-                                      RRType.SOA(), 3600,
+                                      RRType.SOA, 3600,
                                       [ "ns1.example.org. " +
                                         "admin.example.org. " +
                                         "1234 3600 1800 2419200 7200" ])
         # At some point, the SOA SERIAL will be auto-incremented
         incremented_soa_rrset_01 = create_rrset("example.org", TEST_RRCLASS,
-                RRType.SOA(), 3600, ["ns1.example.org. " +
+                RRType.SOA, 3600, ["ns1.example.org. " +
                                      "admin.example.org. " +
                                      "1235 3600 1800 2419200 7200" ])
         incremented_soa_rrset_02 = create_rrset("example.org", TEST_RRCLASS,
-                RRType.SOA(), 3600, ["ns1.example.org. " +
+                RRType.SOA, 3600, ["ns1.example.org. " +
                                      "admin.example.org. " +
                                      "1236 3600 1800 2419200 7200" ])
 
         # We will delete some of the NS records
         orig_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
-                                      RRType.NS(), 3600,
+                                      RRType.NS, 3600,
                                       [ "ns1.example.org.",
                                         "ns2.example.org.",
                                         "ns3.example.org." ])
@@ -1275,48 +1272,48 @@ class SessionTest(SessionTestBase):
         # Sanity check, make sure original data is really there before updates
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.NS(),
+                                 RRType.NS,
                                  orig_ns_rrset)
         # We will delete the MX record later in this test, so let's make
         # sure that it exists (we do not care about its value)
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.MX())
+                                 RRType.MX)
 
         # Check that we cannot delete the SOA record by direct deletion
         # both by name+type and by full rrset
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_soa_apex,
                                         self.rrset_update_soa_del ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.SOA(),
+                                 RRType.SOA,
                                  incremented_soa_rrset_01)
 
         # If we delete everything at the apex, the SOA and NS rrsets should be
         # untouched (but serial will be incremented)
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_name_apex ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.SOA(),
+                                 RRType.SOA,
                                  incremented_soa_rrset_02)
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.NS(),
+                                 RRType.NS,
                                  orig_ns_rrset)
         # but the MX should be gone
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
                                  isc.dns.Name("example.org"),
-                                 RRType.MX())
+                                 RRType.MX)
 
         # Deleting the NS rrset by name and type only, it should also be left
         # untouched
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_ns_apex ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.NS(),
+                                 RRType.NS,
                                  orig_ns_rrset)
 
     def test_update_apex_special_case_ns_rrset(self):
@@ -1325,28 +1322,28 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         # When we are done, we should have a reduced NS rrset
         short_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
-                                      RRType.NS(), 3600,
+                                      RRType.NS, 3600,
                                       [ "ns3.example.org." ])
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset_ns ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.NS(),
+                                 RRType.NS,
                                  short_ns_rrset)
 
     def test_update_apex_special_case_ns_rrset2(self):
         # If we add new NS records, then delete all existing ones, it
         # should not keep any
         self.__initialize_update_rrsets()
-        new_ns = create_rrset("example.org", TEST_RRCLASS, RRType.NS(), 3600,
-                              [ "newns1.example.org", "newns2.example.org" ])
+        new_ns = create_rrset("example.org", TEST_RRCLASS, RRType.NS, 3600,
+                              [ "newns1.example.org.", "newns2.example.org." ])
 
-        self.check_full_handle_result(Rcode.NOERROR(),
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ new_ns,
                                         self.rrset_update_del_rrset_ns ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.NS(),
+                                 RRType.NS,
                                  new_ns)
 
     def test_update_delete_normal_rrset_at_apex(self):
@@ -1358,12 +1355,12 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("example.org"),
-                                 RRType.MX())
-        self.check_full_handle_result(Rcode.NOERROR(),
+                                 RRType.MX)
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset_mx ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
                                  isc.dns.Name("example.org"),
-                                 RRType.MX())
+                                 RRType.MX)
 
     def test_update_add_then_delete_rrset(self):
         # If we add data, then delete the whole rrset, added data should
@@ -1371,13 +1368,13 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
-        self.check_full_handle_result(Rcode.NOERROR(),
+                                 RRType.A)
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_a,
                                         self.rrset_update_del_rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
     def test_update_add_then_delete_name(self):
         # If we add data, then delete the entire name, added data should
@@ -1385,13 +1382,13 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
-        self.check_full_handle_result(Rcode.NOERROR(),
+                                 RRType.A)
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_a,
                                         self.rrset_update_del_name ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
+                                 RRType.A)
 
     def test_update_delete_then_add_rrset(self):
         # If we delete an entire rrset, then add something there again,
@@ -1399,13 +1396,13 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
-        self.check_full_handle_result(Rcode.NOERROR(),
+                                 RRType.A)
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_rrset,
                                         self.rrset_update_a ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.rrset_update_a)
 
     def test_update_delete_then_add_rrset(self):
@@ -1414,13 +1411,13 @@ class SessionTest(SessionTestBase):
         self.__initialize_update_rrsets()
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A())
-        self.check_full_handle_result(Rcode.NOERROR(),
+                                 RRType.A)
+        self.check_full_handle_result(Rcode.NOERROR,
                                       [ self.rrset_update_del_name,
                                         self.rrset_update_a ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.rrset_update_a)
 
     def test_update_cname_special_cases(self):
@@ -1428,31 +1425,31 @@ class SessionTest(SessionTestBase):
 
         # Sanity check
         orig_cname_rrset = create_rrset("cname.example.org", TEST_RRCLASS,
-                                        RRType.CNAME(), 3600,
+                                        RRType.CNAME, 3600,
                                         [ "www.example.org." ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
                                  isc.dns.Name("cname.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  orig_cname_rrset)
 
         # If we try to add data where a cname is preset
-        rrset = create_rrset("cname.example.org", TEST_RRCLASS, RRType.A(),
+        rrset = create_rrset("cname.example.org", TEST_RRCLASS, RRType.A,
                              3600, [ "192.0.2.1" ])
 
-        self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+        self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
                                  isc.dns.Name("cname.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  orig_cname_rrset)
 
         # But updating the cname itself should work
         new_cname_rrset = create_rrset("cname.example.org", TEST_RRCLASS,
-                                       RRType.CNAME(), 3600,
+                                       RRType.CNAME, 3600,
                                        [ "mail.example.org." ])
-        self.check_full_handle_result(Rcode.NOERROR(), [ new_cname_rrset ])
+        self.check_full_handle_result(Rcode.NOERROR, [ new_cname_rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
                                  isc.dns.Name("cname.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  new_cname_rrset)
 
         self.__initialize_update_rrsets()
@@ -1461,27 +1458,27 @@ class SessionTest(SessionTestBase):
         # present should do nothing either
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.orig_a_rrset)
         new_cname_rrset = create_rrset("www.example.org", TEST_RRCLASS,
-                                       RRType.CNAME(), 3600,
+                                       RRType.CNAME, 3600,
                                        [ "mail.example.org." ])
-        self.check_full_handle_result(Rcode.NOERROR(), [ new_cname_rrset ])
+        self.check_full_handle_result(Rcode.NOERROR, [ new_cname_rrset ])
         self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                  isc.dns.Name("www.example.org"),
-                                 RRType.A(),
+                                 RRType.A,
                                  self.orig_a_rrset)
 
     def test_update_bad_class(self):
-        rrset = create_rrset("example.org.", RRClass.CH(), RRType.TXT(), 0,
+        rrset = create_rrset("example.org.", RRClass.CH, RRType.TXT, 0,
                              [ "foo" ])
-        self.check_full_handle_result(Rcode.FORMERR(), [ rrset ])
+        self.check_full_handle_result(Rcode.FORMERR, [ rrset ])
 
     def test_uncaught_exception(self):
         def my_exc():
             raise Exception("foo")
         self._session._UpdateSession__update_soa = my_exc
-        self.assertEqual(Rcode.SERVFAIL().to_text(),
+        self.assertEqual(Rcode.SERVFAIL.to_text(),
                          self._session._UpdateSession__do_update().to_text())
 
 class SessionACLTest(SessionTestBase):
@@ -1527,7 +1524,7 @@ class SessionACLTest(SessionTestBase):
                                                          self._datasrc_client,
                                                          acl_map))
         self.assertEqual((UPDATE_ERROR, None, None), session.handle())
-        self.check_response(session.get_message(), Rcode.REFUSED())
+        self.check_response(session.get_message(), Rcode.REFUSED)
 
         # If the message contains TSIG, it should match the ACCEPT
         # ACL entry, and the request should be granted.
diff --git a/src/lib/python/isc/ddns/tests/zone_config_tests.py b/src/lib/python/isc/ddns/tests/zone_config_tests.py
index 7facb48..0ada906 100644
--- a/src/lib/python/isc/ddns/tests/zone_config_tests.py
+++ b/src/lib/python/isc/ddns/tests/zone_config_tests.py
@@ -26,7 +26,7 @@ import socket
 # Some common test parameters
 TEST_ZONE_NAME = Name('example.org')
 TEST_SECONDARY_ZONE_NAME = Name('example.com')
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
 TEST_TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
 TEST_ACL_CONTEXT = isc.acl.dns.RequestContext(
     socket.getaddrinfo("192.0.2.1", 1234, 0, socket.SOCK_DGRAM,
@@ -88,12 +88,12 @@ class ZoneConfigTest(unittest.TestCase):
         # zone class doesn't match (but zone name matches)
         self.__datasrc_client.set_find_result(DataSourceClient.SUCCESS)
         zconfig = ZoneConfig({(TEST_SECONDARY_ZONE_NAME, TEST_RRCLASS)},
-                             RRClass.CH(), self.__datasrc_client)
+                             RRClass.CH, self.__datasrc_client)
         self.assertEqual((ZONE_NOTFOUND, None),
                          (zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS)))
         # similar to the previous case, but also in the secondary list
         zconfig = ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
-                             RRClass.CH(), self.__datasrc_client)
+                             RRClass.CH, self.__datasrc_client)
         self.assertEqual((ZONE_NOTFOUND, None),
                          (zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS)))
 
@@ -107,7 +107,7 @@ class ZoneConfigTest(unittest.TestCase):
         zconfig = ZoneConfig({(TEST_SECONDARY_ZONE_NAME, TEST_RRCLASS),
                               (Name('example'), TEST_RRCLASS),
                               (Name('sub.example.org'), TEST_RRCLASS),
-                              (TEST_ZONE_NAME, RRClass.CH())},
+                              (TEST_ZONE_NAME, RRClass.CH)},
                              TEST_RRCLASS, self.__datasrc_client)
         self.assertEqual((ZONE_PRIMARY, self.__datasrc_client),
                          self.zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS))
@@ -134,7 +134,7 @@ class ACLConfigTest(unittest.TestCase):
         # 'All reject' ACL will still apply for any other zones
         acl = self.__zconfig.get_update_acl(Name('example.com'), TEST_RRCLASS)
         self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
-        acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH())
+        acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH)
         self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
 
         # Test with a map with a few more ACL entries.  Should be nothing
@@ -143,14 +143,14 @@ class ACLConfigTest(unittest.TestCase):
                        REQUEST_LOADER.load([{"action": "REJECT"}]),
                    (TEST_ZONE_NAME, TEST_RRCLASS):
                        REQUEST_LOADER.load([{"action": "ACCEPT"}]),
-                   (TEST_ZONE_NAME, RRClass.CH()):
+                   (TEST_ZONE_NAME, RRClass.CH):
                        REQUEST_LOADER.load([{"action": "DROP"}])}
         self.__zconfig.set_update_acl_map(acl_map)
         acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, TEST_RRCLASS)
         self.assertEqual(ACCEPT, acl.execute(TEST_ACL_CONTEXT))
         acl = self.__zconfig.get_update_acl(Name('example.com'), TEST_RRCLASS)
         self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
-        acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH())
+        acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH)
         self.assertEqual(DROP, acl.execute(TEST_ACL_CONTEXT))
 
 if __name__ == "__main__":
diff --git a/src/lib/python/isc/log_messages/Makefile.am b/src/lib/python/isc/log_messages/Makefile.am
index 97ff6e6..c8b9c7a 100644
--- a/src/lib/python/isc/log_messages/Makefile.am
+++ b/src/lib/python/isc/log_messages/Makefile.am
@@ -1,7 +1,7 @@
 SUBDIRS = work
 
 EXTRA_DIST = __init__.py
-EXTRA_DIST += bind10_messages.py
+EXTRA_DIST += init_messages.py
 EXTRA_DIST += cmdctl_messages.py
 EXTRA_DIST += ddns_messages.py
 EXTRA_DIST += stats_messages.py
@@ -18,9 +18,10 @@ EXTRA_DIST += loadzone_messages.py
 EXTRA_DIST += server_common_messages.py
 EXTRA_DIST += dbutil_messages.py
 EXTRA_DIST += msgq_messages.py
+EXTRA_DIST += pycc_messages.py
 
 CLEANFILES = __init__.pyc
-CLEANFILES += bind10_messages.pyc
+CLEANFILES += init_messages.pyc
 CLEANFILES += cmdctl_messages.pyc
 CLEANFILES += ddns_messages.pyc
 CLEANFILES += stats_messages.pyc
@@ -37,6 +38,7 @@ CLEANFILES += loadzone_messages.pyc
 CLEANFILES += server_common_messages.pyc
 CLEANFILES += dbutil_messages.pyc
 CLEANFILES += msgq_messages.pyc
+CLEANFILES += pycc_messages.pyc
 
 CLEANDIRS = __pycache__
 
diff --git a/src/lib/python/isc/log_messages/bind10_messages.py b/src/lib/python/isc/log_messages/bind10_messages.py
deleted file mode 100644
index 68ce94c..0000000
--- a/src/lib/python/isc/log_messages/bind10_messages.py
+++ /dev/null
@@ -1 +0,0 @@
-from work.bind10_messages import *
diff --git a/src/lib/python/isc/log_messages/gen-forwarder.sh b/src/lib/python/isc/log_messages/gen-forwarder.sh
index 84c2450..e9fec4b 100755
--- a/src/lib/python/isc/log_messages/gen-forwarder.sh
+++ b/src/lib/python/isc/log_messages/gen-forwarder.sh
@@ -1,5 +1,20 @@
 #!/bin/sh
 
+# 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.
+
 MODULE_NAME=$1
 if test -z $MODULE_NAME; then
 	echo 'Usage: gen-forwarder.sh module_name'
diff --git a/src/lib/python/isc/log_messages/init_messages.py b/src/lib/python/isc/log_messages/init_messages.py
new file mode 100644
index 0000000..15288bf
--- /dev/null
+++ b/src/lib/python/isc/log_messages/init_messages.py
@@ -0,0 +1 @@
+from work.init_messages import *
diff --git a/src/lib/python/isc/log_messages/pycc_messages.py b/src/lib/python/isc/log_messages/pycc_messages.py
new file mode 100644
index 0000000..77b3804
--- /dev/null
+++ b/src/lib/python/isc/log_messages/pycc_messages.py
@@ -0,0 +1 @@
+from work.pycc_messages import *
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index fdd9bb9..d1ec2e9 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -299,12 +299,12 @@ class NotifyOut:
                          format_zone_str(zone_name, zone_class))
             return []
 
-        result, ns_rrset, _ = finder.find(zone_name, RRType.NS())
+        result, ns_rrset, _ = finder.find(zone_name, RRType.NS)
         if result is not finder.SUCCESS or ns_rrset is None:
             logger.warn(NOTIFY_OUT_ZONE_NO_NS,
                         format_zone_str(zone_name, zone_class))
             return []
-        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
         if result is not finder.SUCCESS or soa_rrset is None or \
                 soa_rrset.get_rdata_count() != 1:
             logger.warn(NOTIFY_OUT_ZONE_BAD_SOA,
@@ -320,11 +320,11 @@ class NotifyOut:
             ns_result, ns_finder = ds_client.find_zone(ns_name)
             if ns_result is DataSourceClient.SUCCESS or \
                ns_result is DataSourceClient.PARTIALMATCH:
-                result, rrset, _ = ns_finder.find(ns_name, RRType.A())
+                result, rrset, _ = ns_finder.find(ns_name, RRType.A)
                 if result is ns_finder.SUCCESS and rrset is not None:
                     addrs.extend([a.to_text() for a in rrset.get_rdata()])
 
-                result, rrset, _ = ns_finder.find(ns_name, RRType.AAAA())
+                result, rrset, _ = ns_finder.find(ns_name, RRType.AAAA)
                 if result is ns_finder.SUCCESS and rrset is not None:
                     addrs.extend([aaaa.to_text()
                                     for aaaa in rrset.get_rdata()])
@@ -504,10 +504,10 @@ class NotifyOut:
         msg = Message(Message.RENDER)
         qid = random.randint(0, 0xFFFF)
         msg.set_qid(qid)
-        msg.set_opcode(Opcode.NOTIFY())
-        msg.set_rcode(Rcode.NOERROR())
+        msg.set_opcode(Opcode.NOTIFY)
+        msg.set_rcode(Rcode.NOERROR)
         msg.set_header_flag(Message.HEADERFLAG_AA)
-        msg.add_question(Question(zone_name, zone_class, RRType.SOA()))
+        msg.add_question(Question(zone_name, zone_class, RRType.SOA))
         msg.add_rrset(Message.SECTION_ANSWER, self._get_zone_soa(zone_name,
                                                                  zone_class))
         return msg, qid
@@ -526,7 +526,7 @@ class NotifyOut:
                                            zone_name.to_text() + '/' +
                                            zone_class.to_text() + ' not found')
 
-        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+        result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
         if result is not finder.SUCCESS or soa_rrset is None or \
                 soa_rrset.get_rdata_count() != 1:
             raise NotifyOutDataSourceError('_get_zone_soa: Zone ' +
@@ -561,7 +561,7 @@ class NotifyOut:
                             Name(zone_notify_info.zone_name).to_text())
                 return _BAD_QUERY_NAME
 
-            if msg.get_opcode() != Opcode.NOTIFY():
+            if msg.get_opcode() != Opcode.NOTIFY:
                 logger.warn(NOTIFY_OUT_REPLY_BAD_OPCODE, from_addr[0],
                             from_addr[1], msg.get_opcode().to_text())
                 return _BAD_OPCODE
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 08663d4..3b2324d 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -364,7 +364,7 @@ class TestNotifyOut(unittest.TestCase):
 
     def test_get_notify_slaves_from_ns(self):
         records = self._notify._get_notify_slaves_from_ns(Name('example.net.'),
-                                                          RRClass.IN())
+                                                          RRClass.IN)
         self.assertEqual(6, len(records))
         self.assertEqual('8:8::8:8', records[5])
         self.assertEqual('7.7.7.7', records[4])
@@ -374,7 +374,7 @@ class TestNotifyOut(unittest.TestCase):
         self.assertEqual('3.3.3.3', records[0])
 
         records = self._notify._get_notify_slaves_from_ns(Name('example.com.'),
-                                                          RRClass.IN())
+                                                          RRClass.IN)
         self.assertEqual(3, len(records))
         self.assertEqual('5:5::5:5', records[2])
         self.assertEqual('4:4::4:4', records[1])
@@ -383,19 +383,19 @@ class TestNotifyOut(unittest.TestCase):
     def test_get_notify_slaves_from_ns_unusual(self):
         self._notify._db_file = TESTDATA_SRCDIR + '/brokentest.sqlite3'
         self.assertEqual([], self._notify._get_notify_slaves_from_ns(
-                Name('nons.example'), RRClass.IN()))
+                Name('nons.example'), RRClass.IN))
         self.assertEqual([], self._notify._get_notify_slaves_from_ns(
-                Name('nosoa.example'), RRClass.IN()))
+                Name('nosoa.example'), RRClass.IN))
         self.assertEqual([], self._notify._get_notify_slaves_from_ns(
-                Name('multisoa.example'), RRClass.IN()))
+                Name('multisoa.example'), RRClass.IN))
 
         self.assertEqual([], self._notify._get_notify_slaves_from_ns(
-                Name('nosuchzone.example'), RRClass.IN()))
+                Name('nosuchzone.example'), RRClass.IN))
 
         # This will cause failure in getting access to the data source.
         self._notify._db_file = TESTDATA_SRCDIR + '/nodir/error.sqlite3'
         self.assertEqual([], self._notify._get_notify_slaves_from_ns(
-                Name('example.com'), RRClass.IN()))
+                Name('example.com'), RRClass.IN))
 
     def test_init_notify_out(self):
         self._notify._init_notify_out(self._db_file)
@@ -423,7 +423,9 @@ class TestNotifyOut(unittest.TestCase):
         self._notify._notify_infos[('example.com.', 'IN')].notify_timeout = time.time() + 5
         timeout, valid_fds, notifying_zones = self._notify._prepare_select_info()
         self.assertEqual(timeout, 0)
-        self.assertListEqual([2, 1], valid_fds)
+        self.assertEqual(len(valid_fds), 2)
+        self.assertIn(1, valid_fds)
+        self.assertIn(2, valid_fds)
 
     def test_shutdown(self):
         thread = self._notify.dispatcher()
diff --git a/src/lib/python/isc/server_common/auth_command.py b/src/lib/python/isc/server_common/auth_command.py
index 493d5fb..5b7635a 100644
--- a/src/lib/python/isc/server_common/auth_command.py
+++ b/src/lib/python/isc/server_common/auth_command.py
@@ -22,6 +22,13 @@ from isc.log_messages.server_common_messages import *
 from isc.server_common.logger import logger
 
 AUTH_MODULE_NAME = 'Auth'
+AUTH_LOADZONE_COMMAND = 'loadzone'
+
+def auth_loadzone_params(zone_name, zone_class):
+    return {
+        "origin": zone_name.to_text(),
+        "class": zone_class.to_text()
+    }
 
 def auth_loadzone_command(module_cc, zone_name, zone_class):
     '''Create a 'loadzone' command with a given zone for Auth server.
@@ -50,8 +57,5 @@ def auth_loadzone_command(module_cc, zone_name, zone_class):
     # to notification-driven approach, at which point the function would
     # be changed a lot.
 
-    param = {
-        "origin": zone_name.to_text(),
-        "class": zone_class.to_text()
-    }
-    return create_command("loadzone", param)
+    return create_command(AUTH_LOADZONE_COMMAND,
+                          auth_loadzone_params(zone_name, zone_class))
diff --git a/src/lib/python/isc/server_common/dns_tcp.py b/src/lib/python/isc/server_common/dns_tcp.py
index 3b78d0d..9ce94fe 100644
--- a/src/lib/python/isc/server_common/dns_tcp.py
+++ b/src/lib/python/isc/server_common/dns_tcp.py
@@ -248,7 +248,7 @@ class DNSTCPContext:
                                  ClientFormatter(self.__remote_addr),
                                  self.__send_marker, total_len)
                     return self.SENDING
-                logger.warn(PYSERVER_COMMON_DNS_TCP_SEND_ERROR,
+                logger.warn(PYSERVER_COMMON_DNS_TCP_SEND_FAILED,
                             ClientFormatter(self.__remote_addr),
                             self.__send_marker, total_len, ex)
                 self.__sock.close()
diff --git a/src/lib/python/isc/server_common/server_common_messages.mes b/src/lib/python/isc/server_common/server_common_messages.mes
index bd4e3cc..f22ce65 100644
--- a/src/lib/python/isc/server_common/server_common_messages.mes
+++ b/src/lib/python/isc/server_common/server_common_messages.mes
@@ -27,7 +27,7 @@ transmitted over a TCP connection, possibly after multiple send
 operations.  The destination address and the total size of the message
 (including the 2-byte length field) are shown in the log message.
 
-% PYSERVER_COMMON_DNS_TCP_SEND_ERROR failed to send TCP message to %1 (%2/%3 bytes sent): %4
+% PYSERVER_COMMON_DNS_TCP_SEND_FAILED failed to send TCP message to %1 (%2/%3 bytes sent): %4
 A DNS message has been attempted to be sent out over a TCP connection,
 but it failed due to some network error.  Although it's not expected
 to happen too often, it can still happen for various reasons.  The
diff --git a/src/lib/python/isc/statistics/counters.py b/src/lib/python/isc/statistics/counters.py
index 99b989d..8138ab6 100644
--- a/src/lib/python/isc/statistics/counters.py
+++ b/src/lib/python/isc/statistics/counters.py
@@ -393,9 +393,7 @@ class Counters():
             for name in zones:
                 if attr in zones[name]:
                     sum_ += zones[name][attr]
-            if  sum_ > 0:
-                _set_counter(zones_data, zones_spec,
-                             id_str, sum_)
+            _set_counter(zones_data, zones_spec, id_str, sum_)
         # insert entire-server counts
         statistics_data[self._perzone_prefix] = dict(
             statistics_data[self._perzone_prefix],
diff --git a/src/lib/python/isc/statistics/tests/counters_test.py b/src/lib/python/isc/statistics/tests/counters_test.py
index ff15efc..395a959 100644
--- a/src/lib/python/isc/statistics/tests/counters_test.py
+++ b/src/lib/python/isc/statistics/tests/counters_test.py
@@ -120,7 +120,7 @@ class TestBasicMethods(unittest.TestCase):
                   'item_type': 'real',
                   'item_default': 0.0 }]
         counters._stop_timer(t2, elem, spec, 'time')
-        self.assertGreater(counters._get_counter(elem,'time'), 1)
+        self.assertGreaterEqual(counters._get_counter(elem,'time'), 1.0)
 
     def test_rasing_incrementers(self):
         """ use Thread"""
@@ -139,9 +139,9 @@ class TestBasicMethods(unittest.TestCase):
             counters._get_counter(self.counters._statistics._data,
                                  counter_name),
             concurrency * number)
-        self.assertGreater(
+        self.assertGreaterEqual(
             counters._get_counter(self.counters._statistics._data,
-                                 timer_name), 0)
+                                 timer_name), 0.0)
 
     def test_concat(self):
         # only strings
@@ -200,7 +200,7 @@ class BaseTestCounters():
             if name.find('time_to_') == 0:
                 self.counters.start_timer(*args)
                 self.counters.stop_timer(*args)
-                self.assertGreater(self.counters.get(*args), 0)
+                self.assertGreaterEqual(self.counters.get(*args), 0.0)
                 sec = self.counters.get(*args)
                 for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                     isc.cc.data.set(self._statistics_data,
@@ -274,6 +274,21 @@ class BaseTestCounters():
                 self._statistics_data, '/'.join(args), 2)
         self.check_get_statistics()
 
+    def test_perzone_zero_counters(self):
+        # setting all counters to zero
+        for name in self.counters._zones_item_list:
+            args = (self._perzone_prefix, TEST_ZONE_NAME_STR, name)
+            if name.find('time_to_') == 0:
+                zero = 0.0
+            else:
+                zero = 0
+            # set zero
+            self.counters._incdec(*args, step=zero)
+            for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
+                isc.cc.data.set(self._statistics_data,
+                                '%s/%s/%s' % (args[0], zone_str, name), zero)
+        self.check_get_statistics()
+
     def test_undefined_item(self):
         # test DataNotFoundError raising when specifying item defined
         # in the specfile
diff --git a/src/lib/python/isc/sysinfo/sysinfo.py b/src/lib/python/isc/sysinfo/sysinfo.py
index 8e4610c..099ac89 100644
--- a/src/lib/python/isc/sysinfo/sysinfo.py
+++ b/src/lib/python/isc/sysinfo/sysinfo.py
@@ -44,7 +44,7 @@ class SysInfo:
         self._net_stats = 'Unknown\n'
         self._net_connections = 'Unknown\n'
 
-        # The following are Linux speicific, and should eventually be removed
+        # The following are Linux specific, and should eventually be removed
         # from this level; for now we simply default to None (so they won't
         # be printed)
         self._platform_distro = None
@@ -162,9 +162,12 @@ class SysInfoPOSIX(SysInfo):
 
         u = os.uname()
         self._platform_name = u[0]
+        self._hostname = u[1]
         self._platform_version = u[2]
         self._platform_machine = u[4]
 
+        self._loadavg = os.getloadavg()
+
 class SysInfoLinux(SysInfoPOSIX):
     """Linux implementation of the SysInfo class.
     See the SysInfo class documentation for more information.
@@ -322,8 +325,8 @@ class SysInfoBSD(SysInfoPOSIX):
         except (subprocess.CalledProcessError, OSError):
             self._net_connections = 'Warning: "netstat -nr" command failed.\n'
 
-class SysInfoOpenBSD(SysInfoBSD):
-    """OpenBSD implementation of the SysInfo class.
+class SysInfoNetBSD(SysInfoBSD):
+    """NetBSD and OpenBSD implementation of the SysInfo class.
     See the SysInfo class documentation for more information.
     """
     def __init__(self):
@@ -499,8 +502,8 @@ def SysInfoFromFactory():
     osname = platform.system()
     if osname == 'Linux':
         return SysInfoLinux()
-    elif osname == 'OpenBSD':
-        return SysInfoOpenBSD()
+    elif (osname == 'NetBSD') or (osname == 'OpenBSD'):
+        return SysInfoNetBSD()
     elif osname == 'FreeBSD':
         return SysInfoFreeBSD()
     elif osname == 'Darwin':
@@ -508,4 +511,4 @@ def SysInfoFromFactory():
     elif osname == 'BIND10Testcase':
         return SysInfoTestcase()
     else:
-        return SysInfo()
+        return SysInfoPOSIX()
diff --git a/src/lib/python/isc/testutils/rrset_utils.py b/src/lib/python/isc/testutils/rrset_utils.py
index 7eac772..eb3da28 100644
--- a/src/lib/python/isc/testutils/rrset_utils.py
+++ b/src/lib/python/isc/testutils/rrset_utils.py
@@ -30,7 +30,7 @@ def rrsets_equal(a, b):
            a.get_class() == b.get_class() and \
            a.get_type() == b.get_type() and \
            a.get_ttl() == b.get_ttl() and \
-           (a.get_type() == RRType.RRSIG() or
+           (a.get_type() == RRType.RRSIG or
             sorted(a.get_rdata()) == sorted(b.get_rdata()))
 
 # The following are short cut utilities to create an RRset of a specific
@@ -38,25 +38,25 @@ def rrsets_equal(a, b):
 # tests, so we define default values for them for convenience.
 
 def create_a(name, address, ttl=3600):
-    rrset = RRset(name, RRClass.IN(), RRType.A(), RRTTL(ttl))
-    rrset.add_rdata(Rdata(RRType.A(), RRClass.IN(), address))
+    rrset = RRset(name, RRClass.IN, RRType.A, RRTTL(ttl))
+    rrset.add_rdata(Rdata(RRType.A, RRClass.IN, address))
     return rrset
 
 def create_aaaa(name, address, ttl=3600):
-    rrset = RRset(name, RRClass.IN(), RRType.AAAA(), RRTTL(ttl))
-    rrset.add_rdata(Rdata(RRType.AAAA(), RRClass.IN(), address))
+    rrset = RRset(name, RRClass.IN, RRType.AAAA, RRTTL(ttl))
+    rrset.add_rdata(Rdata(RRType.AAAA, RRClass.IN, address))
     return rrset
 
 def create_ns(nsname, name=Name('example.com'), ttl=3600):
     '''For convenience we use a default name often used as a zone name'''
-    rrset = RRset(name, RRClass.IN(), RRType.NS(), RRTTL(ttl))
-    rrset.add_rdata(Rdata(RRType.NS(), RRClass.IN(), nsname))
+    rrset = RRset(name, RRClass.IN, RRType.NS, RRTTL(ttl))
+    rrset.add_rdata(Rdata(RRType.NS, RRClass.IN, nsname))
     return rrset
 
-def create_cname(target='target.example.com', name=Name('example.com'),
+def create_cname(target='target.example.com.', name=Name('example.com'),
                  ttl=3600):
-    rrset = RRset(name, RRClass.IN(), RRType.CNAME(), RRTTL(ttl))
-    rrset.add_rdata(Rdata(RRType.CNAME(), RRClass.IN(), target))
+    rrset = RRset(name, RRClass.IN, RRType.CNAME, RRTTL(ttl))
+    rrset.add_rdata(Rdata(RRType.CNAME, RRClass.IN, target))
     return rrset
 
 def create_generic(name, rdlen, type=RRType('TYPE65300'), ttl=3600):
@@ -67,16 +67,16 @@ def create_generic(name, rdlen, type=RRType('TYPE65300'), ttl=3600):
     The RDATA will be filled with specified length of all-0 data.
 
     '''
-    rrset = RRset(name, RRClass.IN(), type, RRTTL(ttl))
-    rrset.add_rdata(Rdata(type, RRClass.IN(), '\\# ' +
+    rrset = RRset(name, RRClass.IN, type, RRTTL(ttl))
+    rrset.add_rdata(Rdata(type, RRClass.IN, '\\# ' +
                           str(rdlen) + ' ' + '00' * rdlen))
     return rrset
 
 def create_soa(serial, name=Name('example.com'), ttl=3600):
     '''For convenience we use a default name often used as a zone name'''
 
-    rrset = RRset(name, RRClass.IN(), RRType.SOA(), RRTTL(ttl))
+    rrset = RRset(name, RRClass.IN, RRType.SOA, RRTTL(ttl))
     rdata_str = 'master.example.com. admin.example.com. ' + \
         str(serial) + ' 3600 1800 2419200 7200'
-    rrset.add_rdata(Rdata(RRType.SOA(), RRClass.IN(), rdata_str))
+    rrset.add_rdata(Rdata(RRType.SOA, RRClass.IN, rdata_str))
     return rrset
diff --git a/src/lib/python/isc/util/cio/socketsession_inc.cc b/src/lib/python/isc/util/cio/socketsession_inc.cc
index e200063..beee66c 100644
--- a/src/lib/python/isc/util/cio/socketsession_inc.cc
+++ b/src/lib/python/isc/util/cio/socketsession_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 namespace {
 const char* const socketsession_doc = "\
 This module defines a set of classes that support forwarding a\n\
diff --git a/src/lib/python/isc/util/cio/socketsessionforwarder_inc.cc b/src/lib/python/isc/util/cio/socketsessionforwarder_inc.cc
index 6b9de01..47b162f 100644
--- a/src/lib/python/isc/util/cio/socketsessionforwarder_inc.cc
+++ b/src/lib/python/isc/util/cio/socketsessionforwarder_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 namespace {
 // Modifications:
 //  reference to the module description (instead of "utility")
diff --git a/src/lib/python/isc/util/cio/socketsessionreceiver_inc.cc b/src/lib/python/isc/util/cio/socketsessionreceiver_inc.cc
index ed29d3e..bb0374e 100644
--- a/src/lib/python/isc/util/cio/socketsessionreceiver_inc.cc
+++ b/src/lib/python/isc/util/cio/socketsessionreceiver_inc.cc
@@ -1,3 +1,17 @@
+// Copyright (C) 2012  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.
+
 namespace {
 // Modifications
 //   - about return value
diff --git a/src/lib/python/isc/xfrin/diff.py b/src/lib/python/isc/xfrin/diff.py
index ea51967..4e06eea 100644
--- a/src/lib/python/isc/xfrin/diff.py
+++ b/src/lib/python/isc/xfrin/diff.py
@@ -146,12 +146,12 @@ class Diff:
         """
         # first add or delete must be of type SOA
         if len(buf) == 0 and\
-           rr.get_type() != isc.dns.RRType.SOA():
+           rr.get_type() != isc.dns.RRType.SOA:
             raise ValueError("First " + operation +
                              " in single update mode must be of type SOA")
         # And later adds or deletes may not
         elif len(buf) != 0 and\
-           rr.get_type() == isc.dns.RRType.SOA():
+           rr.get_type() == isc.dns.RRType.SOA:
             raise ValueError("Multiple SOA records in single " +
                              "update mode " + operation)
         buf.append((operation, rr))
@@ -238,8 +238,8 @@ class Diff:
             '''A helper routine to identify whether two RRsets are of the
             same 'type'.  For RRSIGs we should consider type covered, too.
             '''
-            if rrset1.get_type() != isc.dns.RRType.RRSIG() or \
-                    rrset2.get_type != isc.dns.RRType.RRSIG():
+            if rrset1.get_type() != isc.dns.RRType.RRSIG or \
+                    rrset2.get_type != isc.dns.RRType.RRSIG:
                 return rrset1.get_type() == rrset2.get_type()
             # RR type of the both RRsets is RRSIG.  Compare type covered.
             # We know they have exactly one RDATA.
@@ -425,7 +425,7 @@ class Diff:
             return a.get_name() == b.get_name() and\
                    a.get_type() == b.get_type() and\
                    a.get_rdata()[0] == b.get_rdata()[0]
-        if rr.get_type() == isc.dns.RRType.SOA():
+        if rr.get_type() == isc.dns.RRType.SOA:
             return buf
         else:
             return [ op for op in buf if not same_rr(op[1], rr)]
@@ -584,3 +584,16 @@ class Diff:
             if rr.get_name() == name:
                 new_rrsets.append(rr)
         return result, new_rrsets, flags
+
+    def get_rrset_collection(self):
+        '''
+        This first applies all changes to the data source. Then it creates
+        and returns an RRsetCollection on top of the corresponding zone
+        updater. Notice it might be impossible to apply more changes after
+        that.
+
+        This must not be called after a commit, or it'd throw ValueError.
+        '''
+        # Apply itself will check it is not yet commited.
+        self.apply()
+        return self.__updater.get_rrset_collection()
diff --git a/src/lib/python/isc/xfrin/tests/diff_tests.py b/src/lib/python/isc/xfrin/tests/diff_tests.py
index 906406f..bb83340 100644
--- a/src/lib/python/isc/xfrin/tests/diff_tests.py
+++ b/src/lib/python/isc/xfrin/tests/diff_tests.py
@@ -16,7 +16,8 @@
 import isc.log
 import unittest
 from isc.datasrc import ZoneFinder
-from isc.dns import Name, RRset, RRClass, RRType, RRTTL, Rdata
+from isc.dns import Name, RRset, RRClass, RRType, RRTTL, Rdata, \
+    RRsetCollectionBase
 from isc.xfrin.diff import Diff, NoSuchZone
 
 class TestError(Exception):
@@ -56,8 +57,8 @@ class DiffTest(unittest.TestCase):
         self.__find_all_name = None
         self.__find_all_options = None
         # Some common values
-        self.__rrclass = RRClass.IN()
-        self.__type = RRType.A()
+        self.__rrclass = RRClass.IN
+        self.__type = RRType.A
         self.__ttl = RRTTL(3600)
         # And RRsets
         # Create two valid rrsets
@@ -80,27 +81,27 @@ class DiffTest(unittest.TestCase):
         # Also create a few other (valid) rrsets
         # A SOA record
         self.__rrset_soa = RRset(Name('example.org.'), self.__rrclass,
-                                 RRType.SOA(), RRTTL(3600))
-        self.__rrset_soa.add_rdata(Rdata(RRType.SOA(), self.__rrclass,
+                                 RRType.SOA, RRTTL(3600))
+        self.__rrset_soa.add_rdata(Rdata(RRType.SOA, self.__rrclass,
                                          "ns1.example.org. " +
                                          "admin.example.org. " +
                                          "1233 3600 1800 2419200 7200"))
         # A few single-rr rrsets that together would for a multi-rr rrset
         self.__rrset3 = RRset(Name('c.example.org.'), self.__rrclass,
-                              RRType.TXT(), self.__ttl)
-        self.__rrset3.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "one"))
+                              RRType.TXT, self.__ttl)
+        self.__rrset3.add_rdata(Rdata(RRType.TXT, self.__rrclass, "one"))
         self.__rrset4 = RRset(Name('c.example.org.'), self.__rrclass,
-                              RRType.TXT(), self.__ttl)
-        self.__rrset4.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "two"))
+                              RRType.TXT, self.__ttl)
+        self.__rrset4.add_rdata(Rdata(RRType.TXT, self.__rrclass, "two"))
         self.__rrset5 = RRset(Name('c.example.org.'), self.__rrclass,
-                              RRType.TXT(), self.__ttl)
-        self.__rrset5.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "three"))
+                              RRType.TXT, self.__ttl)
+        self.__rrset5.add_rdata(Rdata(RRType.TXT, self.__rrclass, "three"))
         self.__rrset6 = RRset(Name('d.example.org.'), self.__rrclass,
-                              RRType.A(), self.__ttl)
-        self.__rrset6.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.1"))
+                              RRType.A, self.__ttl)
+        self.__rrset6.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.1"))
         self.__rrset7 = RRset(Name('d.example.org.'), self.__rrclass,
-                              RRType.A(), self.__ttl)
-        self.__rrset7.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.2"))
+                              RRType.A, self.__ttl)
+        self.__rrset7.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.2"))
 
     def __mock_compact(self):
         """
@@ -315,7 +316,7 @@ class DiffTest(unittest.TestCase):
         self.assertRaises(ValueError, diff.add_data, self.__rrset2)
         self.assertRaises(ValueError, diff.delete_data, self.__rrset1)
         self.assertRaises(ValueError, diff.find, Name('foo.example.org.'),
-                          RRType.A())
+                          RRType.A)
         self.assertRaises(ValueError, diff.find_all, Name('foo.example.org.'))
         diff.apply = orig_apply
         self.assertRaises(ValueError, diff.apply)
@@ -434,9 +435,9 @@ class DiffTest(unittest.TestCase):
         Test a wrong class of rrset is rejected.
         """
         diff = Diff(self, Name('example.org.'))
-        rrset = RRset(Name('a.example.org.'), RRClass.CH(), RRType.NS(),
+        rrset = RRset(Name('a.example.org.'), RRClass.CH, RRType.NS,
                       self.__ttl)
-        rrset.add_rdata(Rdata(RRType.NS(), RRClass.CH(), 'ns.example.org.'))
+        rrset.add_rdata(Rdata(RRType.NS, RRClass.CH, 'ns.example.org.'))
         self.assertRaises(ValueError, diff.add_data, rrset)
         self.assertRaises(ValueError, diff.delete_data, rrset)
 
@@ -516,14 +517,14 @@ class DiffTest(unittest.TestCase):
         '''
         diff = Diff(self, Name('example.org.'))
         rrsig1 = RRset(Name('example.org'), self.__rrclass,
-                       RRType.RRSIG(), RRTTL(3600))
-        rrsig1.add_rdata(Rdata(RRType.RRSIG(), self.__rrclass,
+                       RRType.RRSIG, RRTTL(3600))
+        rrsig1.add_rdata(Rdata(RRType.RRSIG, self.__rrclass,
                                'A 5 3 3600 20000101000000 20000201000000 ' +
                                '0 example.org. FAKEFAKEFAKE'))
         diff.add_data(rrsig1)
         rrsig2 = RRset(Name('example.org'), self.__rrclass,
-                       RRType.RRSIG(), RRTTL(1800))
-        rrsig2.add_rdata(Rdata(RRType.RRSIG(), self.__rrclass,
+                       RRType.RRSIG, RRTTL(1800))
+        rrsig2.add_rdata(Rdata(RRType.RRSIG, self.__rrclass,
                                'AAAA 5 3 3600 20000101000000 20000201000000 ' +
                                '1 example.org. FAKEFAKEFAKE'))
         diff.add_data(rrsig2)
@@ -557,7 +558,7 @@ class DiffTest(unittest.TestCase):
         '''
         diff_multi = Diff(self, Name('example.org.'), single_update_mode=False)
         self.assertRaises(ValueError, diff_multi.find_updated,
-                          Name('example.org.'), RRType.A())
+                          Name('example.org.'), RRType.A)
         self.assertRaises(ValueError, diff_multi.find_all_updated,
                           Name('example.org.'))
 
@@ -570,12 +571,12 @@ class DiffTest(unittest.TestCase):
         '''
 
         # full rrset for A (to check compact())
-        txt = RRset(Name('c.example.org.'), self.__rrclass, RRType.TXT(),
+        txt = RRset(Name('c.example.org.'), self.__rrclass, RRType.TXT,
                     RRTTL(3600))
         txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "one"))
         txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "two"))
         txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "three"))
-        a = RRset(Name('d.example.org.'), self.__rrclass, RRType.A(),
+        a = RRset(Name('d.example.org.'), self.__rrclass, RRType.A,
                   RRTTL(3600))
         a.add_rdata(Rdata(a.get_type(), a.get_class(), "192.0.2.1"))
         a.add_rdata(Rdata(a.get_type(), a.get_class(), "192.0.2.2"))
@@ -679,7 +680,7 @@ class DiffTest(unittest.TestCase):
     def test_find(self):
         diff = Diff(self, Name('example.org.'))
         name = Name('www.example.org.')
-        rrtype = RRType.A()
+        rrtype = RRType.A
 
         self.assertFalse(self.__find_called)
         self.assertEqual(None, self.__find_name)
@@ -697,7 +698,7 @@ class DiffTest(unittest.TestCase):
     def test_find_options(self):
         diff = Diff(self, Name('example.org.'))
         name = Name('foo.example.org.')
-        rrtype = RRType.TXT()
+        rrtype = RRType.TXT
         options = ZoneFinder.NO_WILDCARD
 
         self.assertEqual("find_return", diff.find(name, rrtype, options))
@@ -997,8 +998,8 @@ class DiffTest(unittest.TestCase):
 
         # Add a second rr with different type at same name
         add_rrset = RRset(self.__rrset3.get_name(), self.__rrclass,
-                          RRType.A(), self.__ttl)
-        add_rrset.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.2"))
+                          RRType.A, self.__ttl)
+        add_rrset.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.2"))
         diff.add_data(add_rrset)
 
         self.__check_find_all_call(diff.find_all_updated, self.__rrset3,
@@ -1087,6 +1088,52 @@ class DiffTest(unittest.TestCase):
             self.__check_find_all_call(diff.find_all, self.__rrset3,
                                        rcode)
 
+    class Collection(isc.dns.RRsetCollectionBase):
+        '''
+        Our own mock RRsetCollection. We only pass it through, but we
+        still define an (mostly empty) find method to satisfy the
+        expectations.
+        '''
+        def __init__(self):
+            '''
+            Empty init. The base class's __init__ can't be called,
+            so we need to provide our own to shadow it -- and make sure
+            not to call the super().__init__().
+            '''
+            pass
+
+        def find(self, name, rrclass, rrtype):
+            '''
+            Empty find method. Returns None to each query (pretends
+            the collection is empty. Present mostly for completeness.
+            '''
+            return None
+
+    def get_rrset_collection(self):
+        '''
+        Part of pretending to be the zone updater. This returns the rrset
+        collection (a mock one, unuseable) for the updater.
+        '''
+        return self.Collection()
+
+    def test_get_rrset_collection(self):
+        '''
+        Test the diff can return corresponding rrset collection. Test
+        it applies the data first.
+        '''
+        diff = Diff(self, Name('example.org'), single_update_mode=True)
+        diff.add_data(self.__rrset_soa)
+        collection = diff.get_rrset_collection()
+        # Check it is applied
+        self.assertEqual(1, len(self.__data_operations))
+        self.assertEqual('add', self.__data_operations[0][0])
+        # Check the returned one is actually RRsetCollection
+        self.assertTrue(isinstance(collection, self.Collection))
+        # The collection is just the mock from above, so this doesn't do much
+        # testing, but we check that the mock got through and didn't get hurt.
+        self.assertIsNone(collection.find(Name('example.org'), RRClass.IN,
+                                          RRType.SOA))
+
 if __name__ == "__main__":
     isc.log.init("bind10")
     isc.log.resetUnitTestRootLogger()
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index 7eae6fe..8d4ae58 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -609,7 +609,7 @@ SERVFAIL:
         if (category == ResponseClassifier::RCODE) {
 
             // Special case as this message takes two arguments.
-            LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERROR).
+            LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_RETURNED).
                       arg(questionText(question_)).arg(rcode);
 
         } else {
diff --git a/src/lib/resolve/resolve_messages.mes b/src/lib/resolve/resolve_messages.mes
index 6447082..c89dedb 100644
--- a/src/lib/resolve/resolve_messages.mes
+++ b/src/lib/resolve/resolve_messages.mes
@@ -133,7 +133,7 @@ A debug message indicating that a protocol error was received and that
 the resolver is repeating the query to the same nameserver.  After this
 repeated query, there will be the indicated number of retries left.
 
-% RESLIB_RCODE_ERROR response to query for <%1> returns RCODE of %2
+% RESLIB_RCODE_RETURNED response to query for <%1> returns RCODE of %2
 A debug message, the response to the specified query indicated an error
 that is not covered by a specific code path.  A SERVFAIL will be returned.
 
diff --git a/src/lib/resolve/tests/response_classifier_unittest.cc b/src/lib/resolve/tests/response_classifier_unittest.cc
index 23c8666..30aeabb 100644
--- a/src/lib/resolve/tests/response_classifier_unittest.cc
+++ b/src/lib/resolve/tests/response_classifier_unittest.cc
@@ -131,9 +131,9 @@ public:
 
         // ... the CNAME records
         rrs_in_cname_www1->addRdata(ConstRdataPtr(
-            new CNAME("www.example.com")));
+            new CNAME("www.example.com.")));
         rrs_in_cname_www2->addRdata(ConstRdataPtr(
-            new CNAME("www1.example.com")));
+            new CNAME("www1.example.com.")));
     }
 
     Message     msg_a;              // Pointer to message in RENDER state
diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc
index 530c919..b214ef5 100644
--- a/src/lib/server_common/portconfig.cc
+++ b/src/lib/server_common/portconfig.cc
@@ -152,7 +152,7 @@ installListenAddresses(const AddressList& new_addresses,
         throw;
     } catch (const exception& e) {
         // Any other kind of exception is fatal. It might mean we are in
-        // inconsistent state with the boss/socket creator, so we abort
+        // inconsistent state with the b10-init/socket creator, so we abort
         // to make sure it doesn't last.
         LOG_FATAL(logger, SRVCOMM_EXCEPTION_ALLOC).arg(e.what());
         abort();
diff --git a/src/lib/server_common/portconfig.h b/src/lib/server_common/portconfig.h
index 0795728..7213e09 100644
--- a/src/lib/server_common/portconfig.h
+++ b/src/lib/server_common/portconfig.h
@@ -92,8 +92,9 @@ parseAddresses(isc::data::ConstElementPtr addresses,
 /// but removes all the sockets it listened on. One of the exceptions is
 /// propagated.
 ///
-/// The ports are requested from the socket creator through boss. Therefore
-/// you need to initialize the SocketRequestor before using this function.
+/// The ports are requested from the socket creator through b10-init.
+/// Therefore you need to initialize the SocketRequestor before using this
+/// function.
 ///
 /// \param new_addresses are the addresses you want to listen on.
 /// \param address_store is the place you store your current addresses. It is
@@ -107,7 +108,7 @@ parseAddresses(isc::data::ConstElementPtr addresses,
 ///
 /// \throw asiolink::IOError when initialization or closing of socket fails.
 /// \throw isc::server_common::SocketRequestor::Socket error when the
-///     boss/socket creator doesn't want to give us the socket.
+///     b10-init/socket creator doesn't want to give us the socket.
 /// \throw std::bad_alloc when allocation fails.
 /// \throw isc::InvalidOperation when the function is called and the
 ///     SocketRequestor isn't initialized yet.
diff --git a/src/lib/server_common/socket_request.cc b/src/lib/server_common/socket_request.cc
index e471ad0..981930d 100644
--- a/src/lib/server_common/socket_request.cc
+++ b/src/lib/server_common/socket_request.cc
@@ -34,21 +34,21 @@ namespace server_common {
 namespace {
 SocketRequestor* requestor(NULL);
 
-// Before the boss process calls send_fd, it first sends this
+// Before the b10-init process calls send_fd, it first sends this
 // string to indicate success, followed by the file descriptor
 const std::string& CREATOR_SOCKET_OK() {
     static const std::string str("1\n");
     return (str);
 }
 
-// Before the boss process calls send_fd, it sends this
+// Before the b10-init process calls send_fd, it sends this
 // string to indicate failure. It will not send a file descriptor.
 const std::string& CREATOR_SOCKET_UNAVAILABLE() {
     static const std::string str("0\n");
     return (str);
 }
 
-// The name of the ccsession command to request a socket from boss
+// The name of the ccsession command to request a socket from b10-init
 // (the actual format of command and response are hardcoded in their
 // respective methods)
 const std::string& REQUEST_SOCKET_COMMAND() {
@@ -56,7 +56,7 @@ const std::string& REQUEST_SOCKET_COMMAND() {
     return (str);
 }
 
-// The name of the ccsession command to tell boss we no longer need
+// The name of the ccsession command to tell b10-init we no longer need
 // a socket (the actual format of command and response are hardcoded
 // in their respective methods)
 const std::string& RELEASE_SOCKET_COMMAND() {
@@ -69,7 +69,7 @@ const size_t SOCKET_ERROR_CODE = 2;
 const size_t SHARE_ERROR_CODE = 3;
 
 // A helper converter from numeric protocol ID to the corresponding string.
-// used both for generating a message for the boss process and for logging.
+// used both for generating a message for the b10-init process and for logging.
 inline const char*
 protocolString(SocketRequestor::Protocol protocol) {
     switch (protocol) {
@@ -84,7 +84,7 @@ protocolString(SocketRequestor::Protocol protocol) {
 
 // Creates the cc session message to request a socket.
 // The actual command format is hardcoded, and should match
-// the format as read in bind10_src.py.in
+// the format as read in b10-init.py.in
 isc::data::ConstElementPtr
 createRequestSocketMessage(SocketRequestor::Protocol protocol,
                            const std::string& address, uint16_t port,
@@ -125,7 +125,7 @@ createReleaseSocketMessage(const std::string& token) {
     return (isc::config::createCommand(RELEASE_SOCKET_COMMAND(), release));
 }
 
-// Checks and parses the response receive from Boss
+// Checks and parses the response receive from Init
 // If successful, token and path will be set to the values found in the
 // answer.
 // If the response was an error response, or does not contain the
@@ -158,7 +158,7 @@ readRequestSocketAnswer(isc::data::ConstElementPtr recv_msg,
     path = answer->get("path")->stringValue();
 }
 
-// Connect to the domain socket that has been received from Boss.
+// Connect to the domain socket that has been received from Init.
 // (i.e. the one that is used to pass created sockets over).
 //
 // This should only be called if the socket had not been connected to
@@ -211,14 +211,14 @@ createFdShareSocket(const std::string& path) {
 // \return the socket fd that has been read
 int
 getSocketFd(const std::string& token, int sock_pass_fd) {
-    // Tell the boss the socket token.
+    // Tell b10-init the socket token.
     const std::string token_data = token + "\n";
     if (!isc::util::io::write_data(sock_pass_fd, token_data.c_str(),
                                    token_data.size())) {
         isc_throw(SocketRequestor::SocketError, "Error writing socket token");
     }
 
-    // Boss first sends some data to signal that getting the socket
+    // Init first sends some data to signal that getting the socket
     // from its cache succeeded
     char status[3];        // We need a space for trailing \0, hence 3
     memset(status, 0, 3);
@@ -226,7 +226,7 @@ getSocketFd(const std::string& token, int sock_pass_fd) {
         isc_throw(SocketRequestor::SocketError,
                   "Error reading status code while requesting socket");
     }
-    // Actual status value hardcoded by boss atm.
+    // Actual status value hardcoded by b10-init atm.
     if (CREATOR_SOCKET_UNAVAILABLE() == status) {
         isc_throw(SocketRequestor::SocketError,
                   "CREATOR_SOCKET_UNAVAILABLE returned");
@@ -258,7 +258,7 @@ getSocketFd(const std::string& token, int sock_pass_fd) {
 }
 
 // This implementation class for SocketRequestor uses
-// a CC session for communication with the boss process,
+// a CC session for communication with the b10-init process,
 // and fd_share to read out the socket(s).
 // Since we only use a reference to the session, it must never
 // be closed during the lifetime of this class
@@ -300,10 +300,10 @@ public:
                                        share_name.empty() ? app_name_ :
                                        share_name);
 
-        // Send it to boss
-        const int seq = session_.group_sendmsg(request_msg, "Boss");
+        // Send it to b10-init
+        const int seq = session_.group_sendmsg(request_msg, "Init");
 
-        // Get the answer from the boss.
+        // Get the answer from b10-init.
         // Just do a blocking read, we can't really do much anyway
         isc::data::ConstElementPtr env, recv_msg;
         if (!session_.group_recvmsg(env, recv_msg, false, seq)) {
@@ -330,12 +330,12 @@ public:
         const isc::data::ConstElementPtr release_msg =
             createReleaseSocketMessage(token);
 
-        // Send it to boss
-        const int seq = session_.group_sendmsg(release_msg, "Boss");
+        // Send it to b10-init
+        const int seq = session_.group_sendmsg(release_msg, "Init");
         LOG_DEBUG(logger, DBGLVL_TRACE_DETAIL, SOCKETREQUESTOR_RELEASESOCKET).
             arg(token);
 
-        // Get the answer from the boss.
+        // Get the answer from b10-init.
         // Just do a blocking read, we can't really do much anyway
         isc::data::ConstElementPtr env, recv_msg;
         if (!session_.group_recvmsg(env, recv_msg, false, seq)) {
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
index 0c971ee..48d69ba 100644
--- a/src/lib/server_common/tests/portconfig_unittest.cc
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -330,8 +330,8 @@ TEST_F(InstallListenAddressesDeathTest, inconsistent) {
     }
 }
 
-// If we are unable to tell the boss we closed a socket, we abort, as we are
-// not consistent with the boss most probably.
+// If we are unable to tell the b10-init we closed a socket, we abort, as we
+// are not consistent with b10-init most probably.
 TEST_F(InstallListenAddressesDeathTest, cantClose) {
     if (!isc::util::unittests::runningOnValgrind()) {
         installListenAddresses(valid_, store_, dnss_);
diff --git a/src/lib/server_common/tests/socket_requestor_test.cc b/src/lib/server_common/tests/socket_requestor_test.cc
index ac1731f..8da545e 100644
--- a/src/lib/server_common/tests/socket_requestor_test.cc
+++ b/src/lib/server_common/tests/socket_requestor_test.cc
@@ -35,6 +35,7 @@
 
 #include <util/io/fd.h>
 #include <util/io/fd_share.h>
+#include <util/unittests/check_valgrind.h>
 
 using namespace isc::data;
 using namespace isc::config;
@@ -76,7 +77,7 @@ TEST(SocketRequestorAccess, initialized) {
     initTestSocketRequestor(NULL);
 }
 
-// This class contains a fake (module)ccsession to emulate answers from Boss
+// This class contains a fake (module)ccsession to emulate answers from Init
 class SocketRequestorTest : public ::testing::Test {
 public:
     SocketRequestorTest() : session(ElementPtr(new ListElement),
@@ -100,7 +101,7 @@ public:
     }
 
     // Creates a valid socket request answer, as it would be sent by
-    // Boss. 'valid' in terms of format, not values
+    // Init. 'valid' in terms of format, not values
     void
     addAnswer(const std::string& token, const std::string& path) {
         ElementPtr answer_part = Element::createMap();
@@ -141,7 +142,7 @@ createExpectedRequest(const std::string& address,
 
     // create the envelope
     const ElementPtr packet = Element::createList();
-    packet->add(Element::create("Boss"));
+    packet->add(Element::create("Init"));
     packet->add(Element::create("*"));
     packet->add(createCommand("get_socket", command_args));
     packet->add(Element::create(-1));
@@ -282,7 +283,7 @@ createExpectedRelease(const std::string& token) {
 
     // create the envelope
     const ElementPtr packet = Element::createList();
-    packet->add(Element::create("Boss"));
+    packet->add(Element::create("Init"));
     packet->add(Element::create("*"));
     packet->add(createCommand("drop_socket", command_args));
     packet->add(Element::create(-1));
@@ -509,81 +510,83 @@ private:
 };
 
 TEST_F(SocketRequestorTest, testSocketPassing) {
-    TestSocket ts;
-    std::vector<std::pair<std::string, int> > data;
-    data.push_back(std::pair<std::string, int>("foo\n", 1));
-    data.push_back(std::pair<std::string, int>("bar\n", 2));
-    data.push_back(std::pair<std::string, int>("foo\n", 3));
-    data.push_back(std::pair<std::string, int>("foo\n", 1));
-    data.push_back(std::pair<std::string, int>("foo\n", -1));
-    data.push_back(std::pair<std::string, int>("foo\n", -2));
-
-    // run() returns true iff we can specify read timeout so we avoid a
-    // deadlock.  Unless there's a bug the test should succeed even without the
-    // timeout, but we don't want to make the test hang up in case with an
-    // unexpected bug, so we'd rather skip most of the tests in that case.
-    const bool timo_ok = ts.run(data);
-    SocketRequestor::SocketID socket_id;
-    if (timo_ok) {
-        // 1 should be ok
-        addAnswer("foo", ts.getPath());
-        socket_id = doRequest();
-        EXPECT_EQ("foo", socket_id.second);
-        EXPECT_EQ(0, close(socket_id.first));
-
-        // 2 should be ok too
-        addAnswer("bar", ts.getPath());
-        socket_id = doRequest();
-        EXPECT_EQ("bar", socket_id.second);
-        EXPECT_EQ(0, close(socket_id.first));
-
-        // 3 should be ok too (reuse earlier token)
-        addAnswer("foo", ts.getPath());
-        socket_id = doRequest();
-        EXPECT_EQ("foo", socket_id.second);
-        EXPECT_EQ(0, close(socket_id.first));
-    }
-    // Create a second socket server, to test that multiple different
-    // domains sockets would work as well (even though we don't actually
-    // use that feature)
-    TestSocket ts2;
-    std::vector<std::pair<std::string, int> > data2;
-    data2.push_back(std::pair<std::string, int>("foo\n", 1));
-    const bool timo_ok2 = ts2.run(data2);
-
-    if (timo_ok2) {
-        // 1 should be ok
-        addAnswer("foo", ts2.getPath());
-        socket_id = doRequest();
-        EXPECT_EQ("foo", socket_id.second);
-        EXPECT_EQ(0, close(socket_id.first));
-    }
+    if (!isc::util::unittests::runningOnValgrind()) {
+        TestSocket ts;
+        std::vector<std::pair<std::string, int> > data;
+        data.push_back(std::pair<std::string, int>("foo\n", 1));
+        data.push_back(std::pair<std::string, int>("bar\n", 2));
+        data.push_back(std::pair<std::string, int>("foo\n", 3));
+        data.push_back(std::pair<std::string, int>("foo\n", 1));
+        data.push_back(std::pair<std::string, int>("foo\n", -1));
+        data.push_back(std::pair<std::string, int>("foo\n", -2));
+
+        // run() returns true iff we can specify read timeout so we avoid a
+        // deadlock.  Unless there's a bug the test should succeed even without the
+        // timeout, but we don't want to make the test hang up in case with an
+        // unexpected bug, so we'd rather skip most of the tests in that case.
+        const bool timo_ok = ts.run(data);
+        SocketRequestor::SocketID socket_id;
+        if (timo_ok) {
+            // 1 should be ok
+            addAnswer("foo", ts.getPath());
+            socket_id = doRequest();
+            EXPECT_EQ("foo", socket_id.second);
+            EXPECT_EQ(0, close(socket_id.first));
+
+            // 2 should be ok too
+            addAnswer("bar", ts.getPath());
+            socket_id = doRequest();
+            EXPECT_EQ("bar", socket_id.second);
+            EXPECT_EQ(0, close(socket_id.first));
+
+            // 3 should be ok too (reuse earlier token)
+            addAnswer("foo", ts.getPath());
+            socket_id = doRequest();
+            EXPECT_EQ("foo", socket_id.second);
+            EXPECT_EQ(0, close(socket_id.first));
+        }
+        // Create a second socket server, to test that multiple different
+        // domains sockets would work as well (even though we don't actually
+        // use that feature)
+        TestSocket ts2;
+        std::vector<std::pair<std::string, int> > data2;
+        data2.push_back(std::pair<std::string, int>("foo\n", 1));
+        const bool timo_ok2 = ts2.run(data2);
+
+        if (timo_ok2) {
+            // 1 should be ok
+            addAnswer("foo", ts2.getPath());
+            socket_id = doRequest();
+            EXPECT_EQ("foo", socket_id.second);
+            EXPECT_EQ(0, close(socket_id.first));
+        }
 
-    if (timo_ok) {
-        // Now use first socket again
-        addAnswer("foo", ts.getPath());
-        socket_id = doRequest();
-        EXPECT_EQ("foo", socket_id.second);
-        EXPECT_EQ(0, close(socket_id.first));
+        if (timo_ok) {
+            // Now use first socket again
+            addAnswer("foo", ts.getPath());
+            socket_id = doRequest();
+            EXPECT_EQ("foo", socket_id.second);
+            EXPECT_EQ(0, close(socket_id.first));
+
+            // -1 is a "normal" error
+            addAnswer("foo", ts.getPath());
+            EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
+
+            // -2 is an unexpected error.  After this point it's not guaranteed the
+            // connection works as intended.
+            addAnswer("foo", ts.getPath());
+            EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
+        }
 
-        // -1 is a "normal" error
+        // Vector is of first socket is now empty, so the socket should be gone
         addAnswer("foo", ts.getPath());
         EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
 
-        // -2 is an unexpected error.  After this point it's not guaranteed the
-        // connection works as intended.
-        addAnswer("foo", ts.getPath());
+        // Vector is of second socket is now empty too, so the socket should be
+        // gone
+        addAnswer("foo", ts2.getPath());
         EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
     }
-
-    // Vector is of first socket is now empty, so the socket should be gone
-    addAnswer("foo", ts.getPath());
-    EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
-
-    // Vector is of second socket is now empty too, so the socket should be
-    // gone
-    addAnswer("foo", ts2.getPath());
-    EXPECT_THROW(doRequest(), SocketRequestor::SocketError);
 }
 
 }
diff --git a/src/lib/statistics/counter.h b/src/lib/statistics/counter.h
index af52da4..b0d31e9 100644
--- a/src/lib/statistics/counter.h
+++ b/src/lib/statistics/counter.h
@@ -22,10 +22,6 @@
 
 #include <vector>
 
-namespace {
-const unsigned int InitialValue = 0;
-} // anonymous namespace
-
 namespace isc {
 namespace statistics {
 
@@ -40,24 +36,19 @@ private:
 public:
     /// The constructor.
     ///
-    /// This constructor is mostly exception free. But it may still throw
-    /// a standard exception if memory allocation fails inside the method.
+    /// This constructor prepares a set of counters which has \a items
+    /// elements. The counters will be initialized with 0.
     ///
     /// \param items A number of counter items to hold (greater than 0)
     ///
     /// \throw isc::InvalidParameter \a items is 0
     explicit Counter(const size_t items) :
-        counters_(items, InitialValue)
+        counters_(items, 0)
     {
         if (items == 0) {
             isc_throw(isc::InvalidParameter, "Items must not be 0");
         }
-    };
-
-    /// The destructor.
-    ///
-    /// This method never throws an exception.
-    ~Counter() {};
+    }
 
     /// \brief Increment a counter item specified with \a type.
     ///
@@ -70,7 +61,7 @@ public:
         }
         ++counters_.at(type);
         return;
-    };
+    }
 
     /// \brief Get the value of a counter item specified with \a type.
     ///
@@ -82,7 +73,7 @@ public:
             isc_throw(isc::OutOfRange, "Counter type is out of range");
         }
         return (counters_.at(type));
-    };
+    }
 };
 
 }   // namespace statistics
diff --git a/src/lib/statistics/counter_dict.h b/src/lib/statistics/counter_dict.h
index e288dfe..6c87bec 100644
--- a/src/lib/statistics/counter_dict.h
+++ b/src/lib/statistics/counter_dict.h
@@ -26,28 +26,34 @@
 #include <cassert>
 #include <stdexcept>
 #include <string>
-#include <vector>
 #include <map>
 #include <iterator>
 #include <utility>
 
-namespace {
-typedef boost::shared_ptr<isc::statistics::Counter> CounterPtr;
-typedef std::map<std::string, CounterPtr> DictionaryMap;
-}
 
 namespace isc {
 namespace statistics {
 
 class CounterDictionary : boost::noncopyable {
 private:
+    typedef boost::shared_ptr<isc::statistics::Counter> CounterPtr;
+    typedef std::map<std::string, CounterPtr> DictionaryMap;
     DictionaryMap dictionary_;
-    std::vector<std::string> elements_;
     const size_t items_;
     // Default constructor is forbidden; number of counter items must be
     // specified at the construction of this class.
     CounterDictionary();
 public:
+    /// The constructor.
+    ///
+    /// This constructor prepares a dictionary of set of counters.
+    /// Initially the dictionary is empty.
+    /// Each counter has \a items elements. The counters will be initialized
+    /// with 0.
+    ///
+    /// \param items A number of counter items to hold (greater than 0)
+    ///
+    /// \throw isc::InvalidParameter \a items is 0
     explicit CounterDictionary(const size_t items) :
         items_(items)
     {
@@ -55,11 +61,17 @@ public:
         if (items == 0) {
             isc_throw(isc::InvalidParameter, "Items must not be 0");
         }
-    };
-    ~CounterDictionary() {};
+    }
+
+    /// \brief Add an element which has a key \a name to the dictionary.
+    ///
+    /// \param name A key of the element to add
+    ///
+    /// \throw isc::InvalidParameter an element which has \a name as key
+    ///                              already exists
     void addElement(const std::string& name) {
         // throw if the element already exists
-        if (dictionary_.count(name) != 0) {
+        if (dictionary_.find(name) != dictionary_.end()) {
             isc_throw(isc::InvalidParameter,
                       "Element " << name << " already exists");
         }
@@ -67,16 +79,30 @@ public:
         // Create a new Counter and add to the map
         dictionary_.insert(
             DictionaryMap::value_type(name, CounterPtr(new Counter(items_))));
-    };
+    }
+
+    /// \brief Delete the element which has a key \a name from the dictionary.
+    ///
+    /// \param name A key of the element to delete
+    ///
+    /// \throw isc::OutOfRange an element which has \a name as key does not
+    ///                        exist
     void deleteElement(const std::string& name) {
-        size_t result = dictionary_.erase(name);
+        const size_t result = dictionary_.erase(name);
         if (result != 1) {
             // If an element with specified name does not exist, throw
             // isc::OutOfRange.
             isc_throw(isc::OutOfRange,
                       "Element " << name << " does not exist");
         }
-    };
+    }
+
+    /// \brief Get a reference to a %Counter which has \a name as key
+    ///
+    /// \param name A key of the element
+    ///
+    /// \throw isc::OutOfRange an element which has \a name as key does not
+    ///                        exist
     Counter& getElement(const std::string& name) {
         DictionaryMap::const_iterator i = dictionary_.find(name);
         if (i != dictionary_.end()) {
@@ -88,10 +114,13 @@ public:
             isc_throw(isc::OutOfRange,
                       "Element " << name << " does not exist");
         }
-    };
+    }
+
+    /// \brief Same as \c getElement()
     Counter& operator[](const std::string& name) {
         return (getElement(name));
-    };
+    }
+
     /// \brief \c ConstIterator is a constant iterator that provides an
     /// interface for enumerating name of zones stored in CounterDictionary.
     ///
@@ -107,35 +136,28 @@ public:
                                 boost::forward_traversal_tag>
     {
         public:
-            /// The constructor.
-            ///
-            /// This constructor is mostly exception free. But it may still
-            /// throw a standard exception if memory allocation fails
-            /// inside the method.
+            /// \brief The constructor.
             ConstIterator() {}
-            /// The destructor.
-            ///
-            /// This method never throws an exception.
-            ~ConstIterator() {}
-            /// Constructor from implementation detail DictionaryMap::const_iterator
-            ConstIterator(
-                DictionaryMap::const_iterator iterator) :
+
+            /// \brief Constructor from implementation detail
+            /// DictionaryMap::const_iterator
+            ConstIterator(DictionaryMap::const_iterator iterator) :
                 iterator_(iterator)
             {}
 
         private:
-            /// \brief An internal method to increment this iterator.
+            // An internal method to increment this iterator.
             void increment() {
                 ++iterator_;
                 return;
             }
 
-            /// \brief An internal method to check equality.
+            // An internal method to check equality.
             bool equal(const ConstIterator& other) const {
                 return (iterator_ == other.iterator_);
             }
 
-            /// \brief An internal method to dereference this iterator.
+            // An internal method to dereference this iterator.
             const value_type& dereference() const {
                 return (iterator_->first);
             }
@@ -145,12 +167,15 @@ public:
             DictionaryMap::const_iterator iterator_;
     };
 
+    /// \brief Get an iterator for the beginning of the dictionary.
     ConstIterator begin() const {
         return (CounterDictionary::ConstIterator(dictionary_.begin()));
-    };
+    }
+
+    /// \brief Get an iterator for the end of the dictionary.
     ConstIterator end() const {
         return (CounterDictionary::ConstIterator(dictionary_.end()));
-    };
+    }
 
     typedef ConstIterator const_iterator;
 };
diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h
index fc8a2e0..8ba2287 100644
--- a/src/lib/testutils/mockups.h
+++ b/src/lib/testutils/mockups.h
@@ -48,7 +48,7 @@ public:
     virtual void disconnect() {}
 
     virtual int group_sendmsg(isc::data::ConstElementPtr msg, std::string group,
-                              std::string, std::string)
+                              std::string, std::string, bool)
     {
         if (!send_ok_) {
             isc_throw(isc::cc::SessionError,
diff --git a/src/lib/testutils/testdata/example.com b/src/lib/testutils/testdata/example.com
index 5e0e079..24ce218 100644
--- a/src/lib/testutils/testdata/example.com
+++ b/src/lib/testutils/testdata/example.com
@@ -6,3 +6,11 @@ ns.example.com.	A 192.0.2.1
 ;; bogus RDATA for CNAME RR, but the loadzone tool accepts it.  looking up this
 ;; record will trigger an exception.
 broken.example.com. CNAME 0123456789012345678901234567890123456789012345678901234567890123456789.example.com.
+
+;; very large RDATA. it exceeds 512 octets.
+large-rdata.example.com. TXT "0-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "1-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "2-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "3-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "4-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "5-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
diff --git a/src/lib/testutils/testdata/example.sqlite3 b/src/lib/testutils/testdata/example.sqlite3
index 0f6ee02..032e7c7 100644
Binary files a/src/lib/testutils/testdata/example.sqlite3 and b/src/lib/testutils/testdata/example.sqlite3 differ
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index 13f8f7b..3960a8b 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -30,7 +30,6 @@ libb10_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
 libb10_util_la_SOURCES += random/random_number_generator.h
 
 EXTRA_DIST = python/pycppwrapper_util.h
-
 libb10_util_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 CLEANFILES = *.gcno *.gcda
 
diff --git a/src/lib/util/io/socketsession.cc b/src/lib/util/io/socketsession.cc
index ba4e6c7..1885b1c 100644
--- a/src/lib/util/io/socketsession.cc
+++ b/src/lib/util/io/socketsession.cc
@@ -14,6 +14,8 @@
 
 #include <config.h>
 
+#include <unistd.h>
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
@@ -82,7 +84,7 @@ const size_t INITIAL_BUFSIZE = 512;
 const int SOCKSESSION_BUFSIZE = (DEFAULT_HEADER_BUFLEN + MAX_DATASIZE) * 2;
 
 struct SocketSessionForwarder::ForwarderImpl {
-    ForwarderImpl() : buf_(DEFAULT_HEADER_BUFLEN) {}
+    ForwarderImpl() : fd_(-1), buf_(DEFAULT_HEADER_BUFLEN) {}
     struct sockaddr_un sock_un_;
     socklen_t sock_un_len_;
     int fd_;
diff --git a/src/lib/util/python/Makefile.am b/src/lib/util/python/Makefile.am
index 81d528c..1e05688 100644
--- a/src/lib/util/python/Makefile.am
+++ b/src/lib/util/python/Makefile.am
@@ -1 +1,3 @@
-noinst_SCRIPTS = gen_wiredata.py mkpywrapper.py
+noinst_SCRIPTS = gen_wiredata.py mkpywrapper.py const2hdr.py \
+	pythonize_constants.py
+EXTRA_DIST = const2hdr.py pythonize_constants.py
diff --git a/src/lib/util/python/const2hdr.py b/src/lib/util/python/const2hdr.py
new file mode 100644
index 0000000..b8c56ea
--- /dev/null
+++ b/src/lib/util/python/const2hdr.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2013  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.
+
+'''
+The script takes a C++ file with constant definitions and creates a
+header file for the constants. It, however, does not understand C++
+syntax, it only does some heuristics to guess what looks like
+a constant and strips the values.
+
+The purpose is just to save some work with keeping both the source and
+header. The source syntax must be limited already, because it's used to
+generate the python module (by the
+lib/python/isc/util/pythonize_constants.py script).
+'''
+
+import sys
+import re
+
+if len(sys.argv) != 3:
+    sys.stderr.write("Usage: python3 ./const2hdr.py input.cc output.h\n")
+    sys.exit(1)
+
+[filename_in, filename_out] = sys.argv[1:3]
+
+preproc = re.compile('^#')
+constant = re.compile('^([a-zA-Z].*?[a-zA-Z_0-9]+)\\s*=.*;')
+
+with open(filename_in) as file_in, open(filename_out, "w") as file_out:
+    file_out.write("// This file is generated from " + filename_in + "\n" +
+                   "// by the const2hdr.py script.\n" +
+                   "// Do not edit, all changes will be lost.\n\n")
+    for line in file_in:
+        if preproc.match(line):
+            # There's only one preprocessor line in the .cc file. We abuse
+            # that to position the top part of the header.
+            file_out.write("#ifndef BIND10_COMMON_DEFS_H\n" +
+                           "#define BIND10_COMMON_DEFS_H\n" +
+                           "\n" +
+                           "// \\file " + filename_out + "\n" +
+'''// \\brief Common shared constants\n
+// This file contains common definitions of constasts used across the sources.
+// It includes, but is not limited to the definitions of messages sent from
+// one process to another. Since the names should be self-explanatory and
+// the variables here are used mostly to synchronize the same values across
+// multiple programs, separate documentation for each variable is not provided.
+''')
+            continue
+        # Extract the constant. Remove the values and add "extern"
+        line = constant.sub('extern \\1;', line)
+
+        file_out.write(line)
+
+    file_out.write("#endif\n")
diff --git a/src/lib/util/python/pythonize_constants.py b/src/lib/util/python/pythonize_constants.py
new file mode 100644
index 0000000..cc6d9b2
--- /dev/null
+++ b/src/lib/util/python/pythonize_constants.py
@@ -0,0 +1,57 @@
+# Copyright (C) 2013  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 script takes a C++ file with constants and converts it to a python
+module. However, the syntax it parses is very limited (it doesn't understand
+C++ at all, it just looks for lines containing the equal sign and strips
+what it thinks might be type).
+
+The purpose is to keep the same values of constants in C++ and python. This
+saves the work of keeping the constants in sync manually and is less error
+prone.
+'''
+
+import sys
+import re
+
+if len(sys.argv) != 3:
+    sys.stderr.write("Usage: python3 ./pythonize_constants.py input.cc output.py\n")
+    sys.exit(1)
+
+[filename_in, filename_out] = sys.argv[1:3]
+
+# Ignore preprocessor, namespaces and the ends of namespaces.
+ignore = re.compile('^(#|namespace|})')
+comment = re.compile('^//(.*)')
+constant = re.compile('^[a-zA-Z].*?([a-zA-Z_0-9]+\\s*=.*);')
+
+with open(filename_in) as file_in, open(filename_out, "w") as file_out:
+    file_out.write("# This file is generated from " + filename_in + "\n" +
+                   "# by the pythonize_constants.py script.\n" +
+                   "# Do not edit, all changes will be lost.\n\n")
+    for line in file_in:
+        if ignore.match(line):
+            continue
+        # Mangle comments to be python-like
+        line = comment.sub('#\\1', line)
+        # Extract the constant.
+
+        # TODO: We may want to do something with the true vs. True and
+        # NULL vs. None and such. Left out for now, since none are in
+        # the input file currently.
+        line = constant.sub('\\1', line)
+
+        file_out.write(line)
diff --git a/src/lib/util/tests/fd_share_tests.cc b/src/lib/util/tests/fd_share_tests.cc
index cc92e47..b8000e1 100644
--- a/src/lib/util/tests/fd_share_tests.cc
+++ b/src/lib/util/tests/fd_share_tests.cc
@@ -15,6 +15,7 @@
 #include <util/io/fd.h>
 #include <util/io/fd_share.h>
 
+#include <util/unittests/check_valgrind.h>
 #include <util/unittests/fork.h>
 
 #include <gtest/gtest.h>
@@ -30,44 +31,47 @@ 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);
+
+    if (!isc::util::unittests::runningOnValgrind()) {
+        // Get a pipe and fork
+        int pipes[2];
+        ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 0, pipes));
+        const 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);
+            const 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
+            const 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);
         }
-        exit(0);
     }
 }
 
diff --git a/src/lib/util/tests/fd_tests.cc b/src/lib/util/tests/fd_tests.cc
index b709405..1a1d3ee 100644
--- a/src/lib/util/tests/fd_tests.cc
+++ b/src/lib/util/tests/fd_tests.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/unittests/check_valgrind.h>
+
 #include <util/io/fd.h>
 
 #include <util/unittests/fork.h>
@@ -45,24 +47,28 @@ class FDTest : public ::testing::Test {
 
 // 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));
+    if (!isc::util::unittests::runningOnValgrind()) {
+        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));
+    if (!isc::util::unittests::runningOnValgrind()) {
+        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/tests/interprocess_sync_file_unittest.cc b/src/lib/util/tests/interprocess_sync_file_unittest.cc
index 9a1b025..6f23558 100644
--- a/src/lib/util/tests/interprocess_sync_file_unittest.cc
+++ b/src/lib/util/tests/interprocess_sync_file_unittest.cc
@@ -13,6 +13,8 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include "util/interprocess_sync_file.h"
+
+#include <util/unittests/check_valgrind.h>
 #include <gtest/gtest.h>
 #include <unistd.h>
 
@@ -53,59 +55,62 @@ parentReadLockedState (int fd) {
 }
 
 TEST(InterprocessSyncFileTest, TestLock) {
-  InterprocessSyncFile sync("test");
-  InterprocessSyncLocker locker(sync);
+    InterprocessSyncFile sync("test");
+    InterprocessSyncLocker locker(sync);
 
-  EXPECT_FALSE(locker.isLocked());
-  EXPECT_TRUE(locker.lock());
-  EXPECT_TRUE(locker.isLocked());
+    EXPECT_FALSE(locker.isLocked());
+    EXPECT_TRUE(locker.lock());
+    EXPECT_TRUE(locker.isLocked());
 
-  int fds[2];
+    if (!isc::util::unittests::runningOnValgrind()) {
 
-  // Here, we check that a lock has been taken by forking and
-  // checking from the child that a lock exists. This has to be
-  // done from a separate process as we test by trying to lock the
-  // range again on the lock file. The lock attempt would pass if
-  // done from the same process for the granted range. The lock
-  // attempt must fail to pass our check.
+        int fds[2];
 
-  EXPECT_EQ(0, pipe(fds));
+        // Here, we check that a lock has been taken by forking and
+        // checking from the child that a lock exists. This has to be
+        // done from a separate process as we test by trying to lock the
+        // range again on the lock file. The lock attempt would pass if
+        // done from the same process for the granted range. The lock
+        // attempt must fail to pass our check.
 
-  if (fork() == 0) {
-      unsigned char locked = 0;
-      // Child writes to pipe
-      close(fds[0]);
+        EXPECT_EQ(0, pipe(fds));
 
-      InterprocessSyncFile sync2("test");
-      InterprocessSyncLocker locker2(sync2);
+        if (fork() == 0) {
+            unsigned char locked = 0;
+            // Child writes to pipe
+            close(fds[0]);
 
-      if (!locker2.tryLock()) {
-          EXPECT_FALSE(locker2.isLocked());
-          locked = 1;
-      } else {
-          EXPECT_TRUE(locker2.isLocked());
-      }
+            InterprocessSyncFile sync2("test");
+            InterprocessSyncLocker locker2(sync2);
 
-      ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
-      EXPECT_EQ(sizeof(locked), bytes_written);
+            if (!locker2.tryLock()) {
+                EXPECT_FALSE(locker2.isLocked());
+                locked = 1;
+            } else {
+                EXPECT_TRUE(locker2.isLocked());
+            }
 
-      close(fds[1]);
-      exit(0);
-  } else {
-      // Parent reads from pipe
-      close(fds[1]);
+            ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
+            EXPECT_EQ(sizeof(locked), bytes_written);
 
-      const unsigned char locked = parentReadLockedState(fds[0]);
+            close(fds[1]);
+            exit(0);
+        } else {
+            // Parent reads from pipe
+            close(fds[1]);
 
-      close(fds[0]);
+            const unsigned char locked = parentReadLockedState(fds[0]);
 
-      EXPECT_EQ(1, locked);
-  }
+            close(fds[0]);
 
-  EXPECT_TRUE(locker.unlock());
-  EXPECT_FALSE(locker.isLocked());
+            EXPECT_EQ(1, locked);
+        }
+    }
+
+    EXPECT_TRUE(locker.unlock());
+    EXPECT_FALSE(locker.isLocked());
 
-  EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test_lockfile"));
+    EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test_lockfile"));
 }
 
 TEST(InterprocessSyncFileTest, TestMultipleFilesDirect) {
@@ -126,49 +131,53 @@ TEST(InterprocessSyncFileTest, TestMultipleFilesDirect) {
 }
 
 TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
-  InterprocessSyncFile sync("test1");
-  InterprocessSyncLocker locker(sync);
+    InterprocessSyncFile sync("test1");
+    InterprocessSyncLocker locker(sync);
 
-  EXPECT_TRUE(locker.lock());
+    EXPECT_TRUE(locker.lock());
 
-  int fds[2];
+    if (!isc::util::unittests::runningOnValgrind()) {
 
-  EXPECT_EQ(0, pipe(fds));
+        int fds[2];
 
-  if (fork() == 0) {
-      unsigned char locked = 0xff;
-      // Child writes to pipe
-      close(fds[0]);
+        EXPECT_EQ(0, pipe(fds));
 
-      InterprocessSyncFile sync2("test2");
-      InterprocessSyncLocker locker2(sync2);
+        if (fork() == 0) {
+            unsigned char locked = 0xff;
+            // Child writes to pipe
+            close(fds[0]);
 
-      if (locker2.tryLock()) {
-          locked = 0;
-      }
+            InterprocessSyncFile sync2("test2");
+            InterprocessSyncLocker locker2(sync2);
 
-      ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
-      EXPECT_EQ(sizeof(locked), bytes_written);
+            if (locker2.tryLock()) {
+                locked = 0;
+            }
 
-      close(fds[1]);
-      exit(0);
-  } else {
-      // Parent reads from pipe
-      close(fds[1]);
+            ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
+            EXPECT_EQ(sizeof(locked), bytes_written);
 
-      const unsigned char locked = parentReadLockedState(fds[0]);
+            close(fds[1]);
+            exit(0);
+        } else {
+            // Parent reads from pipe
+            close(fds[1]);
 
-      close(fds[0]);
+            const unsigned char locked = parentReadLockedState(fds[0]);
 
-      EXPECT_EQ(0, locked);
-  }
+            close(fds[0]);
 
-  EXPECT_TRUE(locker.unlock());
+            EXPECT_EQ(0, locked);
+        }
 
-  EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test1_lockfile"));
-  EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
-}
+        EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
+    }
+
+    EXPECT_TRUE(locker.unlock());
+
+    EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test1_lockfile"));
 }
 
+} // anonymous namespace
 } // namespace util
 } // namespace isc
diff --git a/src/lib/util/threads/tests/condvar_unittest.cc b/src/lib/util/threads/tests/condvar_unittest.cc
index 1e04efa..3bb7230 100644
--- a/src/lib/util/threads/tests/condvar_unittest.cc
+++ b/src/lib/util/threads/tests/condvar_unittest.cc
@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include <exceptions/exceptions.h>
+#include <util/unittests/check_valgrind.h>
 
 #include <util/threads/sync.h>
 #include <util/threads/thread.h>
@@ -84,12 +85,14 @@ ringSignal(CondVar* condvar, Mutex* mutex, int* arg) {
 
 // A simple wait-signal operation on a condition variable.
 TEST_F(CondVarTest, waitAndSignal) {
-    Mutex::Locker locker(mutex_);
-    int shared_var = 0; // let the other thread increment this
-    Thread t(boost::bind(&ringSignal, &condvar_, &mutex_, &shared_var));
-    condvar_.wait(mutex_);
-    t.wait();
-    EXPECT_EQ(1, shared_var);
+    if (!isc::util::unittests::runningOnValgrind()) {
+        Mutex::Locker locker(mutex_);
+        int shared_var = 0; // let the other thread increment this
+        Thread t(boost::bind(&ringSignal, &condvar_, &mutex_, &shared_var));
+        condvar_.wait(mutex_);
+        t.wait();
+        EXPECT_EQ(1, shared_var);
+    }
 }
 
 // Thread's main code for the next test
@@ -143,12 +146,14 @@ signalAndWait(CondVar* condvar, Mutex* mutex) {
 TEST_F(CondVarTest, destroyWhileWait) {
     // We'll destroy a CondVar object while the thread is still waiting
     // on it.  This will trigger an assertion failure.
-    EXPECT_DEATH_IF_SUPPORTED({
-            CondVar cond;
-            Mutex::Locker locker(mutex_);
-            Thread t(boost::bind(&signalAndWait, &cond, &mutex_));
-            cond.wait(mutex_);
-        }, "");
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH_IF_SUPPORTED({
+                CondVar cond;
+                Mutex::Locker locker(mutex_);
+                Thread t(boost::bind(&signalAndWait, &cond, &mutex_));
+                cond.wait(mutex_);
+            }, "");
+    }
 }
 #endif // !HAS_UNDEFINED_PTHREAD_BEHAVIOR
 
diff --git a/src/lib/util/threads/tests/lock_unittest.cc b/src/lib/util/threads/tests/lock_unittest.cc
index 1abc3fa..4c4f831 100644
--- a/src/lib/util/threads/tests/lock_unittest.cc
+++ b/src/lib/util/threads/tests/lock_unittest.cc
@@ -94,33 +94,35 @@ void
 noHandler(int) {}
 
 TEST(MutexTest, swarm) {
-    // Create a timeout in case something got stuck here
-    struct sigaction ignored, original;
-    memset(&ignored, 0, sizeof(ignored));
-    ignored.sa_handler = noHandler;
-    if (sigaction(SIGALRM, &ignored, &original)) {
-        FAIL() << "Couldn't set alarm";
-    }
-    alarm(10);
-    // This type has a low chance of being atomic itself, further raising
-    // the chance of problems appearing.
-    double canary = 0;
-    Mutex mutex;
-    // Run two parallel threads
-    bool ready1 = false;
-    bool ready2 = false;
-    Thread t1(boost::bind(&performIncrement, &canary, &ready1, &ready2,
-                          &mutex));
-    Thread t2(boost::bind(&performIncrement, &canary, &ready2, &ready1,
-                          &mutex));
-    t1.wait();
-    t2.wait();
-    // Check it the sum is the expected value.
-    EXPECT_EQ(iterations * 2, canary) << "Threads are badly synchronized";
-    // Cancel the alarm and return the original handler
-    alarm(0);
-    if (sigaction(SIGALRM, &original, NULL)) {
-        FAIL() << "Couldn't restore alarm";
+    if (!isc::util::unittests::runningOnValgrind()) {
+        // Create a timeout in case something got stuck here
+        struct sigaction ignored, original;
+        memset(&ignored, 0, sizeof(ignored));
+        ignored.sa_handler = noHandler;
+        if (sigaction(SIGALRM, &ignored, &original)) {
+            FAIL() << "Couldn't set alarm";
+        }
+        alarm(10);
+        // This type has a low chance of being atomic itself, further raising
+        // the chance of problems appearing.
+        double canary = 0;
+        Mutex mutex;
+        // Run two parallel threads
+        bool ready1 = false;
+        bool ready2 = false;
+        Thread t1(boost::bind(&performIncrement, &canary, &ready1, &ready2,
+                              &mutex));
+        Thread t2(boost::bind(&performIncrement, &canary, &ready2, &ready1,
+                              &mutex));
+        t1.wait();
+        t2.wait();
+        // Check it the sum is the expected value.
+        EXPECT_EQ(iterations * 2, canary) << "Threads are badly synchronized";
+        // Cancel the alarm and return the original handler
+        alarm(0);
+        if (sigaction(SIGALRM, &original, NULL)) {
+            FAIL() << "Couldn't restore alarm";
+        }
     }
 }
 
diff --git a/src/lib/util/threads/tests/thread_unittest.cc b/src/lib/util/threads/tests/thread_unittest.cc
index 5afdf3f..0a8df41 100644
--- a/src/lib/util/threads/tests/thread_unittest.cc
+++ b/src/lib/util/threads/tests/thread_unittest.cc
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <util/threads/thread.h>
+#include <util/unittests/check_valgrind.h>
 
 #include <boost/bind.hpp>
 
@@ -41,9 +42,11 @@ doSomething(int*) { }
 // We just test that we can forget about the thread and nothing
 // bad will happen on our side.
 TEST(ThreadTest, detached) {
-    int x;
-    for (size_t i = 0; i < detached_iterations; ++i) {
-        Thread thread(boost::bind(&doSomething, &x));
+    if (!isc::util::unittests::runningOnValgrind()) {
+        int x;
+        for (size_t i = 0; i < detached_iterations; ++i) {
+            Thread thread(boost::bind(&doSomething, &x));
+        }
     }
 }
 
@@ -55,13 +58,15 @@ markRun(bool* mark) {
 
 // Wait for a thread to end first. The variable must be set at the time.
 TEST(ThreadTest, wait) {
-    for (size_t i = 0; i < iterations; ++i) {
-        bool mark = false;
-        Thread thread(boost::bind(markRun, &mark));
-        thread.wait();
-        ASSERT_TRUE(mark) << "Not finished yet in " << i << "th iteration";
-        // Can't wait second time
-        ASSERT_THROW(thread.wait(), isc::InvalidOperation);
+    if (!isc::util::unittests::runningOnValgrind()) {
+        for (size_t i = 0; i < iterations; ++i) {
+            bool mark = false;
+            Thread thread(boost::bind(markRun, &mark));
+            thread.wait();
+            ASSERT_TRUE(mark) << "Not finished yet in " << i << "th iteration";
+            // Can't wait second time
+            ASSERT_THROW(thread.wait(), isc::InvalidOperation);
+        }
     }
 }
 
@@ -77,21 +82,25 @@ throwException() {
 
 // Exception in the thread we forget about should not do anything to us
 TEST(ThreadTest, detachedException) {
-    for (size_t i = 0; i < detached_iterations; ++i) {
-        Thread thread(throwSomething);
-    }
-    for (size_t i = 0; i < detached_iterations; ++i) {
-        Thread thread(throwException);
+    if (!isc::util::unittests::runningOnValgrind()) {
+        for (size_t i = 0; i < detached_iterations; ++i) {
+            Thread thread(throwSomething);
+        }
+        for (size_t i = 0; i < detached_iterations; ++i) {
+            Thread thread(throwException);
+        }
     }
 }
 
 // An uncaught exception in the thread should propagate through wait
 TEST(ThreadTest, exception) {
-    for (size_t i = 0; i < iterations; ++i) {
-        Thread thread(throwSomething);
-        Thread thread2(throwException);
-        ASSERT_THROW(thread.wait(), Thread::UncaughtException);
-        ASSERT_THROW(thread2.wait(), Thread::UncaughtException);
+    if (!isc::util::unittests::runningOnValgrind()) {
+        for (size_t i = 0; i < iterations; ++i) {
+            Thread thread(throwSomething);
+            Thread thread2(throwException);
+            ASSERT_THROW(thread.wait(), Thread::UncaughtException);
+            ASSERT_THROW(thread2.wait(), Thread::UncaughtException);
+        }
     }
 }
 
diff --git a/src/lib/util/unittests/check_valgrind.h b/src/lib/util/unittests/check_valgrind.h
index 80f1f85..3837b10 100644
--- a/src/lib/util/unittests/check_valgrind.h
+++ b/src/lib/util/unittests/check_valgrind.h
@@ -38,6 +38,11 @@ namespace unittests {
 
 /// \brief Check if the program is run in valgrind
 ///
+/// This is used to check for valgrind and skip (parts of) tests that fork,
+/// such as death tests, and general forking tests, and some threading tests;
+/// These tend to cause valgrind to report errors, which would hide other
+/// potential valgrind reports.
+///
 /// \return true if valgrind headers are available, and valgrind is running,
 ///         false if the headers are not available, or if valgrind is not
 ///         running
diff --git a/src/lib/util/unittests/fork.cc b/src/lib/util/unittests/fork.cc
index 3414a3c..2d5efb0 100644
--- a/src/lib/util/unittests/fork.cc
+++ b/src/lib/util/unittests/fork.cc
@@ -77,6 +77,7 @@ provide_input(int *read_pipe, const void *input, const size_t length)
         return -1;
     }
     *read_pipe = pipes[0];
+
     pid_t pid(fork());
     if (pid) { // We are in the parent
         return pid;
@@ -91,12 +92,13 @@ provide_input(int *read_pipe, const void *input, const size_t length)
     }
 }
 
+
 /*
  * This creates a pipe, forks and reads the pipe and compares it
- * with given data. Used to check output of run in asynchronous way.
+ * with given data. Used to check output of run in an asynchronous way.
  */
 pid_t
-check_output(int *write_pipe, const void *output, const size_t length)
+check_output(int *write_pipe, const void* const output, const size_t length)
 {
     int pipes[2];
     if (pipe(pipes)) {
@@ -109,9 +111,7 @@ check_output(int *write_pipe, const void *output, const size_t length)
         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];
+        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);
@@ -133,8 +133,10 @@ check_output(int *write_pipe, const void *output, const size_t length)
                 fprintf(stderr, "%02hhx", output_c[i]);
             }
             fprintf(stderr, "\n");
+            delete [] buffer;
             exit(1);
         } else {
+            delete [] buffer;
             exit(0);
         }
     }
diff --git a/src/lib/util/unittests/fork.h b/src/lib/util/unittests/fork.h
index d5623a7..6b9e749 100644
--- a/src/lib/util/unittests/fork.h
+++ b/src/lib/util/unittests/fork.h
@@ -40,10 +40,10 @@ bool
 process_ok(pid_t process);
 
 pid_t
-provide_input(int *read_pipe, const void *input, const size_t length);
+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);
+check_output(int* write_pipe, const void* const output, const size_t length);
 
 } // End of the namespace
 }
diff --git a/tests/lettuce/configurations/auth/auth_badzone.config.orig b/tests/lettuce/configurations/auth/auth_badzone.config.orig
index ab11bc9..f86882a 100644
--- a/tests/lettuce/configurations/auth/auth_badzone.config.orig
+++ b/tests/lettuce/configurations/auth/auth_badzone.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [{
             "severity": "DEBUG",
@@ -29,7 +29,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
diff --git a/tests/lettuce/configurations/auth/auth_basic.config.orig b/tests/lettuce/configurations/auth/auth_basic.config.orig
index 4067fb1..24f615c 100644
--- a/tests/lettuce/configurations/auth/auth_basic.config.orig
+++ b/tests/lettuce/configurations/auth/auth_basic.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -13,7 +13,7 @@
             "address": "127.0.0.1"
         } ]
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
diff --git a/tests/lettuce/configurations/bindctl/bindctl.config.orig b/tests/lettuce/configurations/bindctl/bindctl.config.orig
index 3530b3e..ef0e8e2 100644
--- a/tests/lettuce/configurations/bindctl/bindctl.config.orig
+++ b/tests/lettuce/configurations/bindctl/bindctl.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -17,7 +17,7 @@
     "data_sources": {
         "classes": {}
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
         }
diff --git a/tests/lettuce/configurations/bindctl_commands.config.orig b/tests/lettuce/configurations/bindctl_commands.config.orig
index b60201d..980262b 100644
--- a/tests/lettuce/configurations/bindctl_commands.config.orig
+++ b/tests/lettuce/configurations/bindctl_commands.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -23,7 +23,7 @@
             "address": "127.0.0.1"
         } ]
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "dispensable", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/ddns/ddns.config.orig b/tests/lettuce/configurations/ddns/ddns.config.orig
index 93e7c1c..02978be 100644
--- a/tests/lettuce/configurations/ddns/ddns.config.orig
+++ b/tests/lettuce/configurations/ddns/ddns.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [
             {
@@ -39,7 +39,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-xfrout": {
                 "kind": "dispensable",
diff --git a/tests/lettuce/configurations/ddns/noddns.config.orig b/tests/lettuce/configurations/ddns/noddns.config.orig
index 7a9a947..d075924 100644
--- a/tests/lettuce/configurations/ddns/noddns.config.orig
+++ b/tests/lettuce/configurations/ddns/noddns.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [
             {
@@ -35,7 +35,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-xfrout": {"kind": "dispensable"},
             "b10-auth": {"kind": "needed", "special": "auth"},
diff --git a/tests/lettuce/configurations/default.config b/tests/lettuce/configurations/default.config
index 9e1d3d1..2713def 100644
--- a/tests/lettuce/configurations/default.config
+++ b/tests/lettuce/configurations/default.config
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
diff --git a/tests/lettuce/configurations/example.org.config.orig b/tests/lettuce/configurations/example.org.config.orig
index c5545ed..7da6304 100644
--- a/tests/lettuce/configurations/example.org.config.orig
+++ b/tests/lettuce/configurations/example.org.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -26,7 +26,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
diff --git a/tests/lettuce/configurations/example.org.inmem.config b/tests/lettuce/configurations/example.org.inmem.config
index 7ea34b3..2e9ca41 100644
--- a/tests/lettuce/configurations/example.org.inmem.config
+++ b/tests/lettuce/configurations/example.org.inmem.config
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [{
             "severity": "DEBUG",
@@ -26,9 +26,13 @@
             ]
         }
     },
-    "Boss": {
+    "Stats": {
+        "poll-interval": 1
+    },
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
+            "b10-stats": { "address": "Stats", "kind": "dispensable" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
         }
     }
diff --git a/tests/lettuce/configurations/example2.org.config b/tests/lettuce/configurations/example2.org.config
index eeb9733..3bb3330 100644
--- a/tests/lettuce/configurations/example2.org.config
+++ b/tests/lettuce/configurations/example2.org.config
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "severity": "DEBUG",
@@ -27,7 +27,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
diff --git a/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
index 107c53f..d93a8c6 100644
--- a/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
+++ b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -29,7 +29,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/ixfr-out/testset1-config.db b/tests/lettuce/configurations/ixfr-out/testset1-config.db
index e78c84a..d5eaf83 100644
--- a/tests/lettuce/configurations/ixfr-out/testset1-config.db
+++ b/tests/lettuce/configurations/ixfr-out/testset1-config.db
@@ -9,7 +9,7 @@
             }
         ]
     },
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers":
             [
@@ -51,7 +51,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
index fe482f9..96e25d8 100644
--- a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
+++ b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -24,7 +24,7 @@
             }]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth-2": {"kind": "dispensable", "special": "auth"},
             "b10-auth": {"kind": "dispensable", "special": "auth"},
diff --git a/tests/lettuce/configurations/no_db_file.config b/tests/lettuce/configurations/no_db_file.config
index bc4ff5f..9e6c168 100644
--- a/tests/lettuce/configurations/no_db_file.config
+++ b/tests/lettuce/configurations/no_db_file.config
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "severity": "DEBUG",
@@ -27,7 +27,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
diff --git a/tests/lettuce/configurations/nsec3/nsec3_auth.config b/tests/lettuce/configurations/nsec3/nsec3_auth.config
index 618c5ef..5dfffa1 100644
--- a/tests/lettuce/configurations/nsec3/nsec3_auth.config
+++ b/tests/lettuce/configurations/nsec3/nsec3_auth.config
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [
             {
@@ -27,7 +27,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": {"kind": "needed", "special": "auth"},
             "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}
diff --git a/tests/lettuce/configurations/resolver/resolver_basic.config.orig b/tests/lettuce/configurations/resolver/resolver_basic.config.orig
index 0adca9f..fe5ddd0 100644
--- a/tests/lettuce/configurations/resolver/resolver_basic.config.orig
+++ b/tests/lettuce/configurations/resolver/resolver_basic.config.orig
@@ -1 +1,31 @@
-{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Resolver": {"query_acl": [{"action": "REJECT", "from": "127.0.0.1"}], "listen_on": [{"port": 47806, "address": "127.0.0.1"}]}, "Boss": {"components": {"b10-resolver": {"kind": "needed"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
+{
+    "version": 3,
+    "Logging": {
+        "loggers": [ {
+            "severity": "DEBUG",
+            "name": "*",
+            "debuglevel": 99
+        } ]
+    },
+    "Resolver": {
+        "query_acl": [ {
+            "action": "REJECT",
+            "from": "127.0.0.1"
+        } ],
+        "listen_on": [ {
+            "port": 47806,
+            "address": "127.0.0.1"
+        } ]
+    },
+    "Init": {
+        "components": {
+            "b10-resolver": {
+                "kind": "needed"
+            },
+            "b10-cmdctl": {
+                "kind": "needed",
+                "special": "cmdctl"
+            }
+        }
+    }
+}
diff --git a/tests/lettuce/configurations/xfrin/inmem_slave.conf b/tests/lettuce/configurations/xfrin/inmem_slave.conf
index cc1c997..fedf372 100644
--- a/tests/lettuce/configurations/xfrin/inmem_slave.conf
+++ b/tests/lettuce/configurations/xfrin/inmem_slave.conf
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -30,7 +30,7 @@
             ]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig b/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
index c04d917..1b2953d 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
+++ b/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -36,7 +36,7 @@
     "Stats": {
         "poll-interval": 1
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master_nons.conf.orig b/tests/lettuce/configurations/xfrin/retransfer_master_nons.conf.orig
new file mode 100644
index 0000000..bccadf7
--- /dev/null
+++ b/tests/lettuce/configurations/xfrin/retransfer_master_nons.conf.orig
@@ -0,0 +1,48 @@
+{
+    "version": 3,
+    "Logging": {
+        "loggers": [ {
+            "debuglevel": 99,
+            "severity": "DEBUG",
+            "name": "*"
+        } ]
+    },
+    "Auth": {
+        "database_file": "data/example.org-nons.sqlite3",
+        "listen_on": [ {
+            "address": "::1",
+            "port": 47807
+        } ]
+    },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "data/example.org-nons.sqlite3"
+                }
+            }]
+        }
+    },
+    "Xfrout": {
+        "zone_config": [ {
+            "origin": "example.org"
+        } ],
+        "also_notify": [ {
+            "address": "::1",
+            "port": 47806
+        } ]
+    },
+    "Stats": {
+        "poll-interval": 1
+    },
+    "Init": {
+        "components": {
+            "b10-auth": { "kind": "needed", "special": "auth" },
+            "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+            "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+            "b10-stats": { "address": "Stats", "kind": "dispensable" },
+            "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+        }
+    }
+}
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave.conf.orig b/tests/lettuce/configurations/xfrin/retransfer_slave.conf.orig
index cef04cf..2e6b17f 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave.conf.orig
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave.conf.orig
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -24,7 +24,7 @@
             }]
         }
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
index d977c58..a5c22b1 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "Logging": {
         "loggers": [ {
             "debuglevel": 99,
@@ -37,7 +37,7 @@
             "class": "IN"
         } ]
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/lettuce/data/commands/bad_command b/tests/lettuce/data/commands/bad_command
index 95d1694..2daa7cb 100644
--- a/tests/lettuce/data/commands/bad_command
+++ b/tests/lettuce/data/commands/bad_command
@@ -1,8 +1,8 @@
 !echo shouldshow
 # just add something so the test can verify it's reverted
-config add /Boss/components b10-auth
-config set /Boss/components/b10-auth/kind needed
-config set /Boss/components/b10-auth/special auth
+config add /Init/components b10-auth
+config set /Init/components/b10-auth/kind needed
+config set /Init/components/b10-auth/special auth
 bad command
 # this should not be reached
 !echo shouldnotshow
diff --git a/tests/lettuce/data/example.org-nons.sqlite3 b/tests/lettuce/data/example.org-nons.sqlite3
new file mode 100644
index 0000000..40ddbf6
Binary files /dev/null and b/tests/lettuce/data/example.org-nons.sqlite3 differ
diff --git a/tests/lettuce/features/bindctl_commands.feature b/tests/lettuce/features/bindctl_commands.feature
index 20a28fc..b9fef82 100644
--- a/tests/lettuce/features/bindctl_commands.feature
+++ b/tests/lettuce/features/bindctl_commands.feature
@@ -7,7 +7,7 @@ Feature: control with bindctl
         # a number of modules. It then removes all non-essential modules,
         # and checks whether they do disappear from the list of running
         # modules (note that it 'misuses' the help command for this,
-        # there is a Boss command 'show_processes' but it's output is
+        # there is a Init command 'show_processes' but it's output is
         # currently less standardized than 'help')
         Given I have bind10 running with configuration bindctl_commands.config
         And wait for bind10 stderr message BIND10_STARTED_CC
@@ -17,9 +17,9 @@ Feature: control with bindctl
         And wait for bind10 stderr message XFRIN_STARTED
         And wait for bind10 stderr message XFROUT_STARTED
         And wait for bind10 stderr message STATS_STARTING
-        And wait for bind10 stderr message STATHTTPD_STARTED
+        And wait for bind10 stderr message STATSHTTPD_STARTED
 
-        Then remove bind10 configuration Boss/components/NOSUCHMODULE
+        Then remove bind10 configuration Init/components/NOSUCHMODULE
         last bindctl output should contain Error
 
         bind10 module Xfrout should be running
@@ -30,29 +30,29 @@ Feature: control with bindctl
         bind10 module StatsHttpd should be running
         bind10 module Resolver should not be running
 
-        Then remove bind10 configuration Boss/components value b10-xfrout
+        Then remove bind10 configuration Init/components value b10-xfrout
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
         # assuming it won't error for further modules (if it does, the final
         # 'should not be running' tests would fail anyway)
-        Then remove bind10 configuration Boss/components value b10-stats-httpd
+        Then remove bind10 configuration Init/components value b10-stats-httpd
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
-        Then remove bind10 configuration Boss/components value b10-stats
+        Then remove bind10 configuration Init/components value b10-stats
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
-        Then remove bind10 configuration Boss/components value b10-zonemgr
+        Then remove bind10 configuration Init/components value b10-zonemgr
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
-        Then remove bind10 configuration Boss/components value b10-xfrin
+        Then remove bind10 configuration Init/components value b10-xfrin
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
-        Then remove bind10 configuration Boss/components value b10-auth
+        Then remove bind10 configuration Init/components value b10-auth
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         last bindctl output should not contain Error
 
@@ -103,7 +103,7 @@ Feature: control with bindctl
         last bindctl output should not contain shouldnotshow
         # This would fail if the entire list was passed, or the configuration
         # was committed
-        send bind10 the command config show Boss/components
+        send bind10 the command config show Init/components
         last bindctl output should not contain b10-auth
 
         # nested_command contains another execute script
@@ -124,8 +124,8 @@ Feature: control with bindctl
 
         When I send bind10 the command execute init_authoritative_server show
         # just test some parts of the output
-        last bindctl output should contain /Boss/components/b10-auth/special
-        last bindctl output should contain /Boss/components/b10-zonemgr/kind
+        last bindctl output should contain /Init/components/b10-auth/special
+        last bindctl output should contain /Init/components/b10-zonemgr/kind
         last bindctl output should contain Please
 
         # nothing should have been changed
diff --git a/tests/lettuce/features/ddns_system.feature b/tests/lettuce/features/ddns_system.feature
index 8e279a7..184c8ae 100644
--- a/tests/lettuce/features/ddns_system.feature
+++ b/tests/lettuce/features/ddns_system.feature
@@ -48,7 +48,7 @@ Feature: DDNS System
         And wait for new bind10 stderr message DDNS_STOPPED
 
         # Test 7
-        # BoB should restart it
+        # Init should restart it
         And wait for new bind10 stderr message DDNS_STARTED
 
         # Test 8
@@ -65,7 +65,7 @@ Feature: DDNS System
         # Test 9
         When I send bind10 the command Auth shutdown
         And wait for new bind10 stderr message AUTH_SHUTDOWN
-        # BoB should restart it automatically
+        # Init should restart it automatically
         And wait for new bind10 stderr message AUTH_SERVER_STARTED
 
         # Test 10
diff --git a/tests/lettuce/features/default.feature b/tests/lettuce/features/default.feature
index ce7ee1e..bd81f12 100644
--- a/tests/lettuce/features/default.feature
+++ b/tests/lettuce/features/default.feature
@@ -8,7 +8,7 @@ Feature: default bind10 config
     And wait for bind10 stderr message STATS_STARTING
 
     # These should be running
-    bind10 module Boss should be running
+    bind10 module Init should be running
     And bind10 module Logging should be running
     And bind10 module Stats should be running
 
diff --git a/tests/lettuce/features/multi_instance.feature b/tests/lettuce/features/multi_instance.feature
index 4ce135a..3ab06eb 100644
--- a/tests/lettuce/features/multi_instance.feature
+++ b/tests/lettuce/features/multi_instance.feature
@@ -34,7 +34,7 @@ Feature: Multiple instances
         If I remember the pid of process b10-auth
         And remember the pid of process b10-auth-2
 
-        When I remove bind10 configuration Boss/components value b10-auth-2
+        When I remove bind10 configuration Init/components value b10-auth-2
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
 
         Then the pid of process b10-auth should not have changed
@@ -42,9 +42,9 @@ Feature: Multiple instances
 
         When I send bind10 the following commands
         """
-        config add Boss/components b10-auth-2
-        config set Boss/components/b10-auth-2/special auth
-        config set Boss/components/b10-auth-2/kind needed
+        config add Init/components b10-auth-2
+        config set Init/components/b10-auth-2/special auth
+        config set Init/components/b10-auth-2/kind needed
         config commit
         """
         And wait for new bind10 stderr message AUTH_SERVER_STARTED
@@ -53,7 +53,7 @@ Feature: Multiple instances
         Then the pid of process b10-auth should not have changed
         A query for example.com should have rcode REFUSED
 
-        When I remove bind10 configuration Boss/components value b10-auth
+        When I remove bind10 configuration Init/components value b10-auth
         And wait for new bind10 stderr message BIND10_PROCESS_ENDED
         Then the pid of process b10-auth-2 should not have changed
         A query for example.com should have rcode REFUSED
diff --git a/tests/lettuce/features/queries.feature b/tests/lettuce/features/queries.feature
index 7ae2284..8a66d1c 100644
--- a/tests/lettuce/features/queries.feature
+++ b/tests/lettuce/features/queries.feature
@@ -8,15 +8,27 @@ Feature: Querying feature
         And wait for bind10 stderr message BIND10_STARTED_CC
         And wait for bind10 stderr message CMDCTL_STARTED
         And wait for bind10 stderr message AUTH_SERVER_STARTED
+        And wait for bind10 stderr message STATS_STARTING
 
         bind10 module Auth should be running
+        And bind10 module Stats should be running
         And bind10 module Resolver should not be running
         And bind10 module Xfrout should not be running
         And bind10 module Zonemgr should not be running
         And bind10 module Xfrin should not be running
-        And bind10 module Stats should not be running
         And bind10 module StatsHttpd should not be running
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_
+
         A query for www.example.org should have rcode NOERROR
         The last query response should have flags qr aa rd
         The last query response should have ancount 1
@@ -38,6 +50,26 @@ Feature: Querying feature
         ns2.example.org.        3600    IN      A       192.0.2.4
         """
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name     | item_value |
+          | request.v4    |          1 |
+          | request.udp   |          1 |
+          | opcode.query  |          1 |
+          | responses     |          1 |
+          | qrysuccess    |          1 |
+          | qryauthans    |          1 |
+          | rcode.noerror |          1 |
+
+
         # Repeat of the above
         A query for www.example.org should have rcode NOERROR
         The last query response should have flags qr aa rd
@@ -60,6 +92,25 @@ Feature: Querying feature
         ns2.example.org.        3600    IN      A       192.0.2.4
         """
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name     | item_value |
+          | request.v4    |          2 |
+          | request.udp   |          2 |
+          | opcode.query  |          2 |
+          | responses     |          2 |
+          | qrysuccess    |          2 |
+          | qryauthans    |          2 |
+          | rcode.noerror |          2 |
+
         # And now query something completely different
         A query for nosuchname.example.org should have rcode NXDOMAIN
         The last query response should have flags qr aa rd
@@ -71,6 +122,26 @@ Feature: Querying feature
         example.org.            3600    IN      SOA     ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
         """
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name      | item_value |
+          | request.v4     |          3 |
+          | request.udp    |          3 |
+          | opcode.query   |          3 |
+          | responses      |          3 |
+          | qrysuccess     |          2 |
+          | qryauthans     |          3 |
+          | rcode.noerror  |          2 |
+          | rcode.nxdomain |          1 |
+
     Scenario: ANY query
         Given I have bind10 running with configuration example.org.inmem.config
         And wait for bind10 stderr message BIND10_STARTED_CC
@@ -78,13 +149,24 @@ Feature: Querying feature
         And wait for bind10 stderr message AUTH_SERVER_STARTED
 
         bind10 module Auth should be running
+        And bind10 module Stats should be running
         And bind10 module Resolver should not be running
         And bind10 module Xfrout should not be running
         And bind10 module Zonemgr should not be running
         And bind10 module Xfrin should not be running
-        And bind10 module Stats should not be running
         And bind10 module StatsHttpd should not be running
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_
+
         A query for example.org type ANY should have rcode NOERROR
         The last query response should have flags qr aa rd
         The last query response should have ancount 4
@@ -104,11 +186,42 @@ Feature: Querying feature
         mail.example.org.       3600    IN      A       192.0.2.10
         """
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name     | item_value |
+          | request.v4    |          1 |
+          | request.udp   |          1 |
+          | opcode.query  |          1 |
+          | responses     |          1 |
+          | qrysuccess    |          1 |
+          | qryauthans    |          1 |
+          | rcode.noerror |          1 |
+
     Scenario: Delegation query for unsigned child zone
         Given I have bind10 running with configuration example.org.inmem.config
         And wait for bind10 stderr message BIND10_STARTED_CC
         And wait for bind10 stderr message CMDCTL_STARTED
         And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_
+
         A dnssec query for www.sub.example.org type AAAA should have rcode NOERROR
         The last query response should have flags qr rd
         The last query response should have edns_flags do
@@ -124,6 +237,28 @@ Feature: Querying feature
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         """
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name         | item_value |
+          | request.v4        |          1 |
+          | request.udp       |          1 |
+          | request.edns0     |          1 |
+          | request.dnssec_ok |          1 |
+          | opcode.query      |          1 |
+          | responses         |          1 |
+          | response.edns0    |          1 |
+          | qrynoauthans      |          1 |
+          | qryreferral       |          1 |
+          | rcode.noerror     |          1 |
+
     Scenario: SSHFP query
         # We are testing one more RR type for a normal successful case
         Given I have bind10 running with configuration example.org.inmem.config
@@ -132,18 +267,69 @@ Feature: Querying feature
         And wait for bind10 stderr message AUTH_SERVER_STARTED
 
         bind10 module Auth should be running
+        And bind10 module Stats should be running
         And bind10 module Resolver should not be running
         And bind10 module Xfrout should not be running
         And bind10 module Zonemgr should not be running
         And bind10 module Xfrin should not be running
-        And bind10 module Stats should not be running
         And bind10 module StatsHttpd should not be running
 
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_
+
         A query for example.org type SSHFP should have rcode NOERROR
         The last query response should have ancount 0
+
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name     | item_value |
+          | request.v4    |          1 |
+          | request.udp   |          1 |
+          | opcode.query  |          1 |
+          | responses     |          1 |
+          | qryauthans    |          1 |
+          | qrynxrrset    |          1 |
+          | rcode.noerror |          1 |
+
         A query for shell.example.org type SSHFP should have rcode NOERROR
         The last query response should have ancount 1
         The answer section of the last query response should be
         """
         shell.example.org.      3600    IN      SSHFP   2 1 123456789abcdef67890123456789abcdef67890
         """
+
+        When I wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+        # make sure Auth module receives a command
+        And wait for new bind10 stderr message AUTH_RECEIVED_COMMAND
+        # make sure Auth module replied to the command
+        And wait for new bind10 stderr message CC_REPLY
+        # make sure the response is for 'getstats'
+        And wait for new bind10 stderr message v4
+        Then I query statistics zones of bind10 module Auth
+        And last bindctl output should not contain "error"
+        The statistics counters are 0 in category .Auth.zones._SERVER_ except for the following items
+          | item_name     | item_value |
+          | request.v4    |          2 |
+          | request.udp   |          2 |
+          | opcode.query  |          2 |
+          | responses     |          2 |
+          | qrysuccess    |          1 |
+          | qryauthans    |          2 |
+          | qrynxrrset    |          1 |
+          | rcode.noerror |          2 |
diff --git a/tests/lettuce/features/stats_httpd.feature b/tests/lettuce/features/stats_httpd.feature
new file mode 100644
index 0000000..50d5efa
--- /dev/null
+++ b/tests/lettuce/features/stats_httpd.feature
@@ -0,0 +1,16 @@
+Feature: b10-stats-httpd module
+    Tests the stats httpd module
+
+    Scenario: Check that the module logs and responds to requests
+    Given I have bind10 running with configuration bindctl_commands.config
+    And wait for bind10 stderr message STATSHTTPD_STARTED
+
+    When I request the URL http://127.0.0.1:47811/
+    # Should result in redirect, so two query logs
+    And wait for new bind10 stderr message "GET / HTTP/1.0" 302 -
+    And wait for new bind10 stderr message "GET /bind10/statistics/xml/ HTTP/1.0" 200 -
+    The last http response status code should be 200
+
+    When I request the URL http://127.0.0.1:47811/no_such_url
+    And wait for new bind10 stderr message "GET /no_such_url HTTP/1.0" 404 -
+    The last http response status code should be 404
diff --git a/tests/lettuce/features/terrain/bind10_control.py b/tests/lettuce/features/terrain/bind10_control.py
index 142a78e..9426d8c 100644
--- a/tests/lettuce/features/terrain/bind10_control.py
+++ b/tests/lettuce/features/terrain/bind10_control.py
@@ -202,28 +202,28 @@ def parse_bindctl_output_as_data_structure():
                       "parseable data structure: '" + output + "': " + str(ve)
 
 def find_process_pid(step, process_name):
-    """Helper function to request the running processes from Boss, and
+    """Helper function to request the running processes from Init, and
        return the pid of the process with the given process_name.
-       Fails with an assert if the response from boss is not valid JSON,
+       Fails with an assert if the response from b10-init is not valid JSON,
        or if the process with the given name is not found.
     """
     # show_processes output is a list of lists, where the inner lists
     # are of the form [ pid, "name" ]
     # Not checking data form; errors will show anyway (if these turn
     # out to be too vague, we can change this)
-    step.given('send bind10 the command Boss show_processes')
+    step.given('send bind10 the command Init show_processes')
     running_processes = parse_bindctl_output_as_data_structure()
 
     for process in running_processes:
         if process[1] == process_name:
             return process[0]
     assert False, "Process named " + process_name +\
-                  " not found in output of Boss show_processes";
+                  " not found in output of Init show_processes";
 
 @step("remember the pid of process ([\S]+)")
 def remember_pid(step, process_name):
     """Stores the PID of the process with the given name as returned by
-       Boss show_processes command.
+       Init show_processes command.
        Fails if the process with the given name does not appear to exist.
        Stores the component_name->pid value in the dict world.process_pids.
        This should only be used by the related step
@@ -239,7 +239,7 @@ def remember_pid(step, process_name):
 @step('pid of process ([\S]+) should not have changed')
 def check_pid(step, process_name):
     """Checks the PID of the process with the given name as returned by
-       Boss show_processes command.
+       Init show_processes command.
        Fails if the process with the given name does not appear to exist.
        Fails if the process with the given name exists, but has a different
        pid than it had when the step 'remember the pid of process' was
@@ -343,9 +343,9 @@ def configure_ddns_on(step):
     step.behave_as("""
     When I send bind10 the following commands
         \"\"\"
-        config add Boss/components b10-ddns
-        config set Boss/components/b10-ddns/kind dispensable
-        config set Boss/components/b10-ddns/address DDNS
+        config add Init/components b10-ddns
+        config set Init/components/b10-ddns/kind dispensable
+        config set Init/components/b10-ddns/address DDNS
         config commit
         \"\"\"
     """)
@@ -358,7 +358,7 @@ def configure_ddns_off(step):
     step.behave_as("""
     When I send bind10 the following commands
         \"\"\"
-        config remove Boss/components b10-ddns
+        config remove Init/components b10-ddns
         config commit
         \"\"\"
     """)
@@ -391,14 +391,16 @@ def find_value(dictionary, key):
         for v in dictionary.values():
             return find_value(v, key)
 
- at step('the statistics counter (\S+)(?: for the zone (\S+))? should be' + \
+ at step('the statistics counter (\S+)(?: in the category (\S+))?'+ \
+          '(?: for the zone (\S+))? should be' + \
           '(?:( greater than| less than| between))? (\-?\d+)(?: and (\-?\d+))?')
-def check_statistics(step, counter, zone, gtltbt, number, upper):
+def check_statistics(step, counter, category, zone, gtltbt, number, upper):
     """
     check the output of bindctl for statistics of specified counter
     and zone.
     Parameters:
     counter ('counter <counter>'): The counter name of statistics.
+    category ('category <category>', optional): The category of counter.
     zone ('zone <zone>', optional): The zone name.
     gtltbt (' greater than'|' less than'|' between', optional): greater than
           <number> or less than <number> or between <number> and <upper>.
@@ -409,14 +411,21 @@ def check_statistics(step, counter, zone, gtltbt, number, upper):
     """
     output = parse_bindctl_output_as_data_structure()
     found = None
+    category_str = ""
     zone_str = ""
+    depth = []
+    if category:
+        depth.insert(0, category)
+        category_str = " for category %s" % category
     if zone:
-        found = find_value(find_value(output, zone), counter)
+        depth.insert(0, zone)
         zone_str = " for zone %s" % zone
-    else:
-        found = find_value(output, counter)
+    for level in depth:
+        output = find_value(output, level)
+    found = find_value(output, counter)
     assert found is not None, \
-        'Not found statistics counter %s%s' % (counter, zone_str)
+        'Not found statistics counter %s%s%s' % \
+            (counter, category_str, zone_str)
     msg = "Got %s, expected%s %s as counter %s%s" % \
         (found, gtltbt, number, counter, zone_str)
     if gtltbt and 'between' in gtltbt and upper:
@@ -430,3 +439,46 @@ def check_statistics(step, counter, zone, gtltbt, number, upper):
         assert int(found) < int(number), msg
     else:
         assert int(found) == int(number), msg
+
+ at step('statistics counters are 0 in category (\S+)( except for the' + \
+          ' following items)?')
+def check_statistics_items(step, category, has_except_for):
+    """
+    check the output of bindctl for statistics of specified counter.
+    Parameters:
+    category ('category <category>'): The category of counter.
+    has_except_for ('except for the following items'): checks values of items
+        with the multiline part.
+
+    Expected values of items are taken from the multiline part of the step in
+    the scenario. The multiline part has two columns: item_name and item_value.
+    item_name is a relative name to category. item_value is an expected value
+    for item_name.
+    """
+
+    def flatten(dictionary, prefix=''):
+        h = {}
+        for k, v in dictionary.items():
+            if type(v) is dict:
+                h.update(flatten(v, prefix+'.'+k))
+            else:
+                h[prefix+'.'+k] = v
+        return h
+
+    stats = flatten(parse_bindctl_output_as_data_structure())
+    if has_except_for:
+        # fetch step tables in the scnario as hashes
+        for item in step.hashes:
+            name = category+'.'+item['item_name']
+            value = item['item_value']
+            assert stats.has_key(name), \
+                'Statistics item %s was not found' % (name)
+            found = stats[name]
+            assert int(found) == int(value), \
+                'Statistics item %s has unexpected value %s (expect %s)' % \
+                    (name, found, value)
+            del(stats[name])
+    for name, found in stats.items():
+        assert int(found) == 0, \
+            'Statistics item %s has unexpected value %s (expect %s)' % \
+                (name, found, 0)
diff --git a/tests/lettuce/features/terrain/http.py b/tests/lettuce/features/terrain/http.py
new file mode 100644
index 0000000..f1f72f5
--- /dev/null
+++ b/tests/lettuce/features/terrain/http.py
@@ -0,0 +1,41 @@
+# Copyright (C) 2013  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 lettuce import *
+import urllib
+
+# Basic request
+ at step('request the URL (.*)')
+def request_url(step, url):
+    """
+    Performs one basic HTTP GET request. The resulting HTTPResponse object
+    will we placed in world.last_http_response
+    Parameters:
+    url: the full URL to query
+    """
+    world.last_http_response = urllib.urlopen(url)
+
+ at step('last http response status code should be ([0-9]+)')
+def check_last_response_code(step, code):
+    """
+    Checks whether the last call to request_url resulted in a response
+    with the given (numeric) status code
+    Fails if it does not, or if there never was a complete request_url
+    operation
+    """
+    assert world.last_http_response != None, "No HTTP request made yet"
+    assert int(code) == world.last_http_response.getcode(),\
+                        code + " != " +\
+                        str(world.last_http_response.getcode())
diff --git a/tests/lettuce/features/terrain/steps.py b/tests/lettuce/features/terrain/steps.py
index 8df0bae..e470acf 100644
--- a/tests/lettuce/features/terrain/steps.py
+++ b/tests/lettuce/features/terrain/steps.py
@@ -30,7 +30,7 @@ def stop_a_named_process(step, process_name):
     """
     world.processes.stop_process(process_name)
 
- at step('wait (?:(\d+) times )?for (new )?(\w+) stderr message (\w+)(?: not (\w+))?')
+ at step('wait (?:(\d+) times )?for (new )?(\w+) stderr message (\S+)(?: not (\S+))?')
 def wait_for_stderr_message(step, times, new, process_name, message, not_message):
     """
     Block until the given message is printed to the given process's stderr
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index bc05341..ce7426b 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -1,3 +1,4 @@
+
 # Copyright (C) 2011  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
@@ -63,6 +64,8 @@ copylist = [
      "configurations/ddns/noddns.config"],
     ["configurations/xfrin/retransfer_master.conf.orig",
      "configurations/xfrin/retransfer_master.conf"],
+    ["configurations/xfrin/retransfer_master_nons.conf.orig",
+     "configurations/xfrin/retransfer_master_nons.conf"],
     ["configurations/xfrin/retransfer_slave.conf.orig",
      "configurations/xfrin/retransfer_slave.conf"],
     ["data/inmem-xfrin.sqlite3.orig",
@@ -83,7 +86,7 @@ removelist = [
 # If we have waited OUTPUT_WAIT_MAX_INTERVALS times, we will abort with an
 # error (so as not to hang indefinitely)
 OUTPUT_WAIT_INTERVAL = 0.5
-OUTPUT_WAIT_MAX_INTERVALS = 20
+OUTPUT_WAIT_MAX_INTERVALS = 120
 
 # class that keeps track of one running process and the files
 # we created for it.
@@ -380,6 +383,9 @@ def initialize(scenario):
     # Convenience variable to access the last query result from querying.py
     world.last_query_result = None
 
+    # Convenience variable to access the last HTTP response from http.py
+    world.last_http_response = None
+
     # For slightly better errors, initialize a process_pids for the relevant
     # steps
     world.process_pids = None
diff --git a/tests/lettuce/features/xfrin_bind10.feature b/tests/lettuce/features/xfrin_bind10.feature
index 34674ca..7ba1ca0 100644
--- a/tests/lettuce/features/xfrin_bind10.feature
+++ b/tests/lettuce/features/xfrin_bind10.feature
@@ -25,6 +25,13 @@ Feature: Xfrin
 
     A query for www.example.org to [::1]:47806 should have rcode REFUSED
     When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
+    # The data we receive contain a NS RRset that refers to three names in the
+    # example.org. zone. All these three are nonexistent in the data, producing
+    # 3 separate warning messages in the log.
+    And wait for new bind10 stderr message XFRIN_ZONE_WARN
+    And wait for new bind10 stderr message XFRIN_ZONE_WARN
+    And wait for new bind10 stderr message XFRIN_ZONE_WARN
+    # But after complaining, the zone data should be accepted.
     Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
     A query for www.example.org to [::1]:47806 should have rcode NOERROR
@@ -38,7 +45,20 @@ Feature: Xfrin
     When I do an AXFR transfer of example.org
     Then transfer result should have 13 rrs
 
-
+    # Now try to offer another update. However, the validation of
+    # data should fail. The old version shoud still be available.
+    When I send bind10 the following commands with cmdctl port 47804:
+    """
+    config set data_sources/classes/IN[0]/params/database_file data/example.org-nons.sqlite3
+    config set Auth/database_file data/example.org-nons.sqlite3
+    config commit
+    """
+    Then I send bind10 the command Xfrin retransfer example.org IN ::1 47807
+    And wait for new bind10 stderr message XFRIN_ZONE_INVALID
+    And wait for new bind10 stderr message XFRIN_INVALID_ZONE_DATA
+    Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_FAILED
+    A query for example.org type NS to [::1]:47806 should have rcode NOERROR
+    And transfer result should have 13 rrs
 
     Scenario: Transfer with TSIG
     # Similar setup to the test above, but this time, we add TSIG configuration
@@ -74,7 +94,7 @@ Feature: Xfrin
 
     # Transfer should fail
     When I send bind10 the command Xfrin retransfer example.org
-    Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_PROTOCOL_ERROR not XFRIN_TRANSFER_SUCCESS
+    Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_PROTOCOL_VIOLATION not XFRIN_TRANSFER_SUCCESS
     # Set client to use TSIG as well
     When I send bind10 the following commands:
     """
@@ -86,3 +106,41 @@ Feature: Xfrin
     # Transwer should succeed now
     When I send bind10 the command Xfrin retransfer example.org
     Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
+
+    Scenario: Validation fails
+    # In this test, the source data of the XFR is invalid (missing NS record
+    # at the origin). We check it is rejected after the transfer.
+    #
+    # We use abuse the fact that we do not check data when we read it from
+    # the sqlite3 database (unless we load into in-memory, which we don't
+    # do here).
+    The file data/test_nonexistent_db.sqlite3 should not exist
+
+    Given I have bind10 running with configuration xfrin/retransfer_master_nons.conf with cmdctl port 47804 as master
+    And wait for master stderr message BIND10_STARTED_CC
+    And wait for master stderr message CMDCTL_STARTED
+    And wait for master stderr message AUTH_SERVER_STARTED
+    And wait for master stderr message XFROUT_STARTED
+    And wait for master stderr message ZONEMGR_STARTED
+
+    And I have bind10 running with configuration xfrin/retransfer_slave.conf
+    And wait for bind10 stderr message BIND10_STARTED_CC
+    And wait for bind10 stderr message CMDCTL_STARTED
+    And wait for bind10 stderr message AUTH_SERVER_STARTED
+    And wait for bind10 stderr message XFRIN_STARTED
+    And wait for bind10 stderr message ZONEMGR_STARTED
+
+    # Now we use the first step again to see if the file has been created
+    The file data/test_nonexistent_db.sqlite3 should exist
+
+    A query for www.example.org to [::1]:47806 should have rcode REFUSED
+    When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
+    # It should complain once about invalid data, then again that the whole
+    # zone is invalid and then reject it.
+    And wait for new bind10 stderr message XFRIN_ZONE_INVALID
+    And wait for new bind10 stderr message XFRIN_INVALID_ZONE_DATA
+    Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_FAILED
+    # The zone still doesn't exist as it is rejected.
+    # FIXME: This step fails. Probably an empty zone is created in the data
+    # source :-|. This should be REFUSED, not SERVFAIL.
+    A query for www.example.org to [::1]:47806 should have rcode SERVFAIL
diff --git a/tests/lettuce/features/xfrin_notify_handling.feature b/tests/lettuce/features/xfrin_notify_handling.feature
index b65c784..e3f2642 100644
--- a/tests/lettuce/features/xfrin_notify_handling.feature
+++ b/tests/lettuce/features/xfrin_notify_handling.feature
@@ -157,7 +157,7 @@ Feature: Xfrin incoming notify handling
     Then wait for new bind10 stderr message AUTH_RECEIVED_NOTIFY
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_NOTIFY
     Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_STARTED
-    Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_PROTOCOL_ERROR not XFRIN_XFR_TRANSFER_STARTED
+    Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_PROTOCOL_VIOLATION not XFRIN_XFR_TRANSFER_STARTED
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_FAILED not ZONEMGR_RECEIVE_XFRIN_SUCCESS
     Then wait 5 times for new master stderr message NOTIFY_OUT_SENDING_NOTIFY
     Then wait for new master stderr message NOTIFY_OUT_RETRY_EXCEEDED
diff --git a/tests/lettuce/setup_intree_bind10.sh.in b/tests/lettuce/setup_intree_bind10.sh.in
index 4ccf6ca..63b90ff 100644
--- a/tests/lettuce/setup_intree_bind10.sh.in
+++ b/tests/lettuce/setup_intree_bind10.sh.in
@@ -23,7 +23,7 @@ BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 PATH=@abs_top_builddir@/src/bin/bind10:@abs_top_builddir@/src/bin/bindctl:@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:@abs_top_builddir@/src/bin/ddns:@abs_top_builddir@/src/bin/dhcp6:@abs_top_builddir@/src/bin/sockcreator:$PATH
 export PATH
 
-PYTHONPATH=@abs_top_builddir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs:$PYTHONPATH
+PYTHONPATH=@abs_top_builddir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python/isc/cc:@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:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs:$PYTHONPATH
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/tests/system/Makefile.am b/tests/system/Makefile.am
index 663258b..aed1d79 100644
--- a/tests/system/Makefile.am
+++ b/tests/system/Makefile.am
@@ -6,7 +6,7 @@ distclean-local:
 
 # Most of the files under this directory (including test subdirectories)
 # must be listed in EXTRA_DIST.
-EXTRA_DIST = README cleanall.sh ifconfig.sh start.pl stop.pl run.sh runall.sh
+EXTRA_DIST = README cleanall.sh ifconfig.sh start.pl stop.pl runall.sh
 EXTRA_DIST += common/default_user.csv
 EXTRA_DIST += glue/auth.good glue/example.good glue/noglue.good glue/test.good
 EXTRA_DIST += glue/tests.sh glue/clean.sh
diff --git a/tests/system/bindctl/tests.sh b/tests/system/bindctl/tests.sh
index 75c91de..e1e533a 100755
--- a/tests/system/bindctl/tests.sh
+++ b/tests/system/bindctl/tests.sh
@@ -25,12 +25,66 @@ status=0
 n=0
 
 # TODO: consider consistency with statistics definition in auth.spec
-cnt_name1="\<queries\.tcp\>"
-cnt_name2="\<queries\.udp\>"
-cnt_name3="\<opcode\.query\>"
-cnt_value1=0
-cnt_value2=0
-cnt_value3=0
+
+# flatten JSON
+awk_flatten_json='
+function join(ary, len) {
+    ret = "";
+    for (i = 1; i <= len; ++i) {
+        ret = ret""ary[i];
+    }
+    return ret;
+}
+BEGIN {
+    depth = 0;
+}
+/.+{$/ {
+    label[++depth] = $1;
+    next;
+}
+/},?/ {
+    --depth;
+    next;
+}
+/:/ {
+    print join(label,depth)""$1" "$2;
+}
+'
+# Check the counters have expected values given with 1st argument.
+# This function tests only these counters will be incremented in every checks
+# since the content of datasource and requests are not changed in this test. 
+test_counters () {
+    status=0
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"request":"v4": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"request":"v6": '0 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"request":"udp": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"request":"tcp": '0 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"opcode":"query": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"responses": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"rcode":"noerror": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"qrysuccess": '$1 > \
+        /dev/null || status=1
+    $AWK "$awk_flatten_json" bindctl.out.$n | \
+        grep '"Auth":"zones":"_SERVER_":"qryauthans": '$1 > \
+        /dev/null || status=1
+    return $status
+}
+expected_count=0
 
 echo "I:Checking b10-auth is disabled by default ($n)"
 $DIG +norec @10.53.0.1 -p 53210 ns.example.com. A > /dev/null && status=1
@@ -38,8 +92,8 @@ if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Starting b10-auth and checking that it works ($n)"
-echo 'config add Boss/components b10-auth
-config set Boss/components/b10-auth { "special": "auth", "kind": "needed" }
+echo 'config add Init/components b10-auth
+config set Init/components/b10-auth { "special": "auth", "kind": "needed" }
 config commit
 quit
 ' | $RUN_BINDCTL \
@@ -56,19 +110,14 @@ sleep 2
 echo 'Stats show
 ' | $RUN_BINDCTL \
 	--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
-# the server should have received 1 UDP and 0 TCP queries (the server
-# startup script no longer sends any TCP queries)
-cnt_value1=`expr $cnt_value1 + 0`
-cnt_value2=`expr $cnt_value2 + 1`
-cnt_value3=`expr $cnt_value1 + $cnt_value2`
-grep $cnt_name1".*\<"$cnt_value1"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name2".*\<"$cnt_value2"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name3".*\<"$cnt_value3"\>" bindctl.out.$n > /dev/null || status=1
-if [ $status != 0 ]; then echo "I:failed"; fi
+# the server should have received 1 request
+expected_count=`expr $expected_count + 1`
+test_counters $expected_count
+if [ $? != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Stopping b10-auth and checking that ($n)"
-echo 'config remove Boss/components b10-auth
+echo 'config remove Init/components b10-auth
 config commit
 quit
 ' | $RUN_BINDCTL \
@@ -79,8 +128,8 @@ if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Restarting b10-auth and checking that ($n)"
-echo 'config add Boss/components b10-auth
-config set Boss/components/b10-auth { "special": "auth", "kind": "needed" }
+echo 'config add Init/components b10-auth
+config set Init/components/b10-auth { "special": "auth", "kind": "needed" }
 config commit
 quit
 ' | $RUN_BINDCTL \
@@ -102,13 +151,9 @@ echo 'Stats show
 # auth sent. Then it cumulates them and new counts which the living
 # auth sends. This note assumes that the issue would have been
 # resolved : "#1941 stats lossage (multiple auth servers)".
-cnt_value1=`expr $cnt_value1 + 0`
-cnt_value2=`expr $cnt_value2 + 1`
-cnt_value3=`expr $cnt_value1 + $cnt_value2`
-grep $cnt_name1".*\<"$cnt_value1"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name2".*\<"$cnt_value2"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name3".*\<"$cnt_value3"\>" bindctl.out.$n > /dev/null || status=1
-if [ $status != 0 ]; then echo "I:failed"; fi
+expected_count=`expr $expected_count + 1`
+test_counters $expected_count
+if [ $? != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Changing the data source from sqlite3 to in-memory ($n)"
@@ -131,20 +176,16 @@ echo 'Stats show
 ' | $RUN_BINDCTL \
 	--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
 # The statistics counters shouldn't be reset due to hot-swapping datasource.
-cnt_value1=`expr $cnt_value1 + 0`
-cnt_value2=`expr $cnt_value2 + 1`
-cnt_value3=`expr $cnt_value1 + $cnt_value2`
-grep $cnt_name1".*\<"$cnt_value1"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name2".*\<"$cnt_value2"\>" bindctl.out.$n > /dev/null || status=1
-grep $cnt_name3".*\<"$cnt_value3"\>" bindctl.out.$n > /dev/null || status=1
-if [ $status != 0 ]; then echo "I:failed"; fi
+expected_count=`expr $expected_count + 1`
+test_counters $expected_count
+if [ $? != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Starting more b10-auths and checking that ($n)"
 for i in 2 3
 do
-    echo 'config add Boss/components b10-auth-'$i'
-config set Boss/components/b10-auth-'$i' { "special": "auth", "kind": "needed" }
+    echo 'config add Init/components b10-auth-'$i'
+config set Init/components/b10-auth-'$i' { "special": "auth", "kind": "needed" }
 config commit
 quit
 ' | $RUN_BINDCTL \
@@ -158,9 +199,7 @@ n=`expr $n + 1`
 
 echo "I:Rechecking BIND 10 statistics consistency after a pause ($n)"
 sleep 2
-cnt_value1=`expr $cnt_value1 + 0`
-cnt_value2=`expr $cnt_value2 + 1`
-cnt_value3=`expr $cnt_value1 + $cnt_value2`
+expected_count=`expr $expected_count + 1`
 # Rechecking some times
 for i in 1 2 3 4
 do
@@ -170,17 +209,15 @@ do
     # The statistics counters should keep being consistent even while
     # multiple b10-auths are running.
 
-    grep $cnt_name1".*\<"$cnt_value1"\>" bindctl.out.$n > /dev/null || status=1
-    grep $cnt_name2".*\<"$cnt_value2"\>" bindctl.out.$n > /dev/null || status=1
-    grep $cnt_name3".*\<"$cnt_value3"\>" bindctl.out.$n > /dev/null || status=1
-    if [ $status != 0 ]; then echo "I:failed "; break ; fi
+    test_counters $expected_count
+    if [ $? != 0 ]; then echo "I:failed "; break ; fi
 done
 n=`expr $n + 1`
 
 echo "I:Stopping extra b10-auths and checking that ($n)"
 for i in 3 2
 do
-    echo 'config remove Boss/components b10-auth-'$i'
+    echo 'config remove Init/components b10-auth-'$i'
 config commit
 quit
 ' | $RUN_BINDCTL \
diff --git a/tests/system/glue/nsx1/b10-config.db.in b/tests/system/glue/nsx1/b10-config.db.in
index 5f93f3b..6802c53 100644
--- a/tests/system/glue/nsx1/b10-config.db.in
+++ b/tests/system/glue/nsx1/b10-config.db.in
@@ -23,7 +23,7 @@
         }
      ]
  },
- "Boss": {
+ "Init": {
    "components": {
      "b10-auth": {"kind": "needed", "special": "auth" },
      "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/system/ifconfig.sh b/tests/system/ifconfig.sh
index c0c365a..7c695e2 100755
--- a/tests/system/ifconfig.sh
+++ b/tests/system/ifconfig.sh
@@ -63,7 +63,7 @@ esac
 case "$1" in
 
     start|up)
-	for ns in 1 2 3 4 5 6 7
+	for ns in 1 2 3 4 5 6 7 8
 	do
 		if test -n "$base"
 		then
@@ -145,7 +145,7 @@ case "$1" in
 	;;
 
     stop|down)
-	for ns in 7 6 5 4 3 2 1
+	for ns in 8 7 6 5 4 3 2 1
 	do
 		if test -n "$base"
 		then
diff --git a/tests/system/ixfr/b10-config.db.in b/tests/system/ixfr/b10-config.db.in
index b3b27a4..a36117d 100644
--- a/tests/system/ixfr/b10-config.db.in
+++ b/tests/system/ixfr/b10-config.db.in
@@ -38,7 +38,7 @@
             "class": "IN"
         }]
     },
-    "Boss": {
+    "Init": {
         "components": {
             "b10-auth": {"kind": "needed", "special": "auth" },
             "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am
index b4c1394..ac10c40 100644
--- a/tests/tools/Makefile.am
+++ b/tests/tools/Makefile.am
@@ -1,5 +1 @@
-# perfdhcp uses getifaddrs, which is not a standard library and is not
-# portable (at least not exist on our Solaris buildbot).  For a short term
-# workaround we stop building it until it's resolved.
-#SUBDIRS = badpacket perfdhcp
 SUBDIRS = badpacket perfdhcp
diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc
index 9de07ca..9433442 100644
--- a/tests/tools/perfdhcp/command_options.cc
+++ b/tests/tools/perfdhcp/command_options.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -87,7 +87,7 @@ CommandOptions::reset() {
 }
 
 bool
-CommandOptions::parse(int argc, char** const argv) {
+CommandOptions::parse(int argc, char** const argv, bool print_cmd_line) {
     // Reset internal variables used by getopt
     // to eliminate undefined behavior when
     // parsing different command lines multiple times
@@ -125,7 +125,7 @@ CommandOptions::parse(int argc, char** const argv) {
     reset();
 
     // Informs if program has been run with 'h' or 'v' option.
-    bool help_or_version_mode = initialize(argc, argv);
+    bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
     if (!help_or_version_mode) {
         validate();
     }
@@ -133,8 +133,8 @@ CommandOptions::parse(int argc, char** const argv) {
 }
 
 bool
-CommandOptions::initialize(int argc, char** argv) {
-    char opt = 0;               // Subsequent options returned by getopt()
+CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
+    int opt = 0;                // Subsequent options returned by getopt()
     std::string drop_arg;       // Value of -D<value>argument
     size_t percent_loc = 0;     // Location of % sign in -D<value>
     double drop_percent = 0;    // % value (1..100) in -D<value%>
@@ -151,10 +151,10 @@ CommandOptions::initialize(int argc, char** argv) {
     // they will be tuned and validated elsewhere
     while((opt = getopt(argc, argv, "hv46r:t:R:b:n:p:d:D:l:P:a:L:"
                         "s:iBc1T:X:O:E:S:I:x:w:")) != -1) {
-        stream << " -" << opt;
+        stream << " -" << static_cast<char>(opt);
         if (optarg) {
             stream << " " << optarg;
-        }  
+        }
         switch (opt) {
         case '1':
             use_first_ = true;
@@ -416,7 +416,9 @@ CommandOptions::initialize(int argc, char** argv) {
         }
     }
 
-    std::cout << "Running: " << stream.str() << std::endl;
+    if (print_cmd_line) {
+        std::cout << "Running: " << stream.str() << std::endl;
+    }
 
     // Handle the local '-l' address/interface
     if (!localname_.empty()) {
diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h
index cbb6236..4b804dc 100644
--- a/tests/tools/perfdhcp/command_options.h
+++ b/tests/tools/perfdhcp/command_options.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -56,9 +56,10 @@ public:
     ///
     /// \param argc Argument count passed to main().
     /// \param argv Argument value array passed to main().
+    /// \param print_cmd_line Print the command line being run to the console.
     /// \throws isc::InvalidParameter if parse fails.
     /// \return true if program has been run in help or version mode ('h' or 'v' flag).
-    bool parse(int argc, char** const argv);
+    bool parse(int argc, char** const argv, bool print_cmd_line = false);
 
     /// \brief Returns IP version.
     ///
@@ -261,9 +262,10 @@ private:
     ///
     /// \param argc Argument count passed to main().
     /// \param argv Argument value array passed to main().
+    /// \param print_cmd_line Print the command line being run to the console.
     /// \throws isc::InvalidParameter if command line options initialization fails.
     /// \return true if program has been run in help or version mode ('h' or 'v' flag).
-    bool initialize(int argc, char** argv);
+    bool initialize(int argc, char** argv, bool print_cmd_line);
 
     /// \brief Validates initialized options.
     ///
diff --git a/tests/tools/perfdhcp/main.cc b/tests/tools/perfdhcp/main.cc
index aa202f1..a5254fc 100644
--- a/tests/tools/perfdhcp/main.cc
+++ b/tests/tools/perfdhcp/main.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -32,7 +32,11 @@ main(int argc, char* argv[]) {
         // If parser returns true it means that user specified
         // 'h' or 'v' command line option. Program shows the
         // help or version message and exits here.
-        if (command_options.parse(argc, argv)) {
+        // The third argument indicates that the command line
+        // should be printed when it gets parsed. This is useful
+        // in particular when the command line needs to be
+        // extracted from the log file.
+        if (command_options.parse(argc, argv, true)) {
             return (ret_code);
         }
     } catch(isc::Exception& e) {
diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc
index f7f4978..e51065f 100644
--- a/tests/tools/perfdhcp/test_control.cc
+++ b/tests/tools/perfdhcp/test_control.cc
@@ -13,27 +13,28 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#include <fstream>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#include <boost/date_time/posix_time/posix_time.hpp>
-
 #include <exceptions/exceptions.h>
 #include <asiolink/io_address.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/option6_ia.h>
+#include <util/unittests/check_valgrind.h>
 #include "test_control.h"
 #include "command_options.h"
 #include "perf_pkt4.h"
 #include "perf_pkt6.h"
 
+#include <fstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+
 using namespace std;
 using namespace boost::posix_time;
 using namespace isc;
@@ -724,7 +725,7 @@ TestControl::printDiagnostics() const {
         std::cout << "Set MAC to " << vector2Hex(options.getMacTemplate(), "::")
                   << std::endl;
         if (options.getDuidTemplate().size() > 0) {
-            std::cout << "Set DUID to " << vector2Hex(options.getDuidTemplate()) << std::endl; 
+            std::cout << "Set DUID to " << vector2Hex(options.getDuidTemplate()) << std::endl;
         }
     }
 }
diff --git a/tools/query_cmp/src/lib/handledns.py b/tools/query_cmp/src/lib/handledns.py
index e33ce9e..e906bae 100755
--- a/tools/query_cmp/src/lib/handledns.py
+++ b/tools/query_cmp/src/lib/handledns.py
@@ -187,7 +187,7 @@ def send_req(query, server, port=53, timeout=5):
 
 	msg = Message(Message.RENDER)
 	msg.set_qid(int(qheader['id']))
-	msg.set_opcode(Opcode.QUERY())
+	msg.set_opcode(Opcode.QUERY)
 	msg.set_rcode(Rcode(int(qheader['rcode'])))
 
 	if qheader['qr'] == 1: 
diff --git a/tools/system_messages.py b/tools/system_messages.py
index fd4c186..08a35e1 100644
--- a/tools/system_messages.py
+++ b/tools/system_messages.py
@@ -71,15 +71,10 @@ SEC_HEADER="""<?xml version="1.0" encoding="UTF-8"?>
     <title>BIND 10 Messages Manual</title>
 
     <copyright>
-      <year>2011-2012</year><holder>Internet Systems Consortium, Inc.</holder>
+      <year>2011-2013</year><holder>Internet Systems Consortium, Inc.</holder>
     </copyright>
 
     <abstract>
-      <para>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.
-      </para>
       <para>
         This is the messages manual for BIND 10 version &__VERSION__;.
 	    The most up-to-date version of this document, along with



More information about the bind10-changes mailing list