BIND 10 trac2342, updated. 4e7a8f7575704052e70432f1e2508d310e8f6bb0 [2342] Merge branch 'master' into trac2342

BIND 10 source code commits bind10-changes at lists.isc.org
Sun Nov 11 22:58:48 UTC 2012


The branch, trac2342 has been updated
       via  4e7a8f7575704052e70432f1e2508d310e8f6bb0 (commit)
       via  51adf02fc69bf854a8b73b97cd481a009c5b428b (commit)
       via  b3526430f02aa3dc3273612524d23137b8f1fe87 (commit)
       via  f9e9ca679889cd4b177c72c588931d4e79300989 (commit)
       via  c8b32f1adba0c274dc765bb162e3b67a1fa43ca9 (commit)
       via  4067c8bb2f66712c4d442fe07d39dbab84afbf27 (commit)
       via  e97b6bb7995463200de064519d705023f578da96 (commit)
       via  fed0360031161014bfdbc11d4e38adeaed697150 (commit)
       via  b560a5942b3b16afb01e1ddc12846030118ffb5a (commit)
       via  3a32db0518e8ea18bad9f04df67ad04dcc7afe45 (commit)
       via  00c64fb762435af9154d0dde6e3123de3ac482cd (commit)
       via  2d1b56424ae5dba08a03f4c09038a50037c7746f (commit)
       via  a0bd58df7cece9187f8a962cb60eda4ada388857 (commit)
       via  ec63a9a5baf587354f220b5a3a306dbb36fc7fb6 (commit)
       via  86ed7ae9cfb4184f5637a2e478242f0a646ba2e1 (commit)
       via  88c9fb48d7c314e16a28555ba7c2c45e6fb24604 (commit)
       via  0590b6d313c25728cb13a8738ba3ceeb4e6cdd2c (commit)
       via  98a3c1b57bdac399863b18fc100af9264cbc0538 (commit)
       via  1b828baa8eb1af112a0e2c2e39750a62316e98df (commit)
       via  89886bb661e47985e05643ced62d0da4c14fdd8d (commit)
       via  beca6b4aefcb8aeb6f54added3bcd025c2196613 (commit)
       via  08630dbbb0a9ff4ac81c0ef2b9a45030455fa0a5 (commit)
       via  82ad5754e3df260373096d3fc44320bea114b629 (commit)
       via  9d9c83375c4fd9d67436030bbfc6f285e271d399 (commit)
       via  c778e931a645b277b7e18a83f702bb08a0173ffb (commit)
       via  aa1643faad572dfc6c91d0fac707f4cac4d5b7a6 (commit)
       via  48509346472b0e2d84a97a6bbab2e9d3199e38ce (commit)
       via  b4921859312474c4cd3f1c3d3f78392f85698c41 (commit)
       via  560a71919bda37ad20e54efed07183acc5413a8a (commit)
       via  dce5a5557d44d52455e9cfbafe2ad882e6b930db (commit)
       via  5946fa677b76b4b6a16173b9c9f5d835ead4e945 (commit)
       via  d5deb4caf172b2d8109b7bfab40b1d3e49526cdb (commit)
       via  430b6e2f075a64df9e22d1a63dcf2ecade935cdc (commit)
       via  5017e9a8d6993c8604722b2385c450b0b54b5cf8 (commit)
       via  24862b62d9a01d277ea5c5b99666f04b1951de64 (commit)
       via  31745f2d5978086e2d0cc40524efc2e5a45b832b (commit)
       via  ff7cec44f4ee5c59593278558269bdd41a6e5719 (commit)
       via  265fb98ba1f1daab43779b8eaeb6d7f8775dd772 (commit)
       via  44da058a8a9f2f7bfca5be797823a6b43bb1865e (commit)
       via  36514ddc884c02a063e166d44319467ce6fb1d8f (commit)
       via  f25544eeedb66a4f5bb0e0c41387e2e58555daa9 (commit)
       via  f5c629c8fa3da5089a4260187901b2d36799a2f2 (commit)
       via  c1e1248555eddb771d776fe614d3078d7dfab26c (commit)
       via  2c70372efd0b0ddb8059d5bbe9eb195f024d4df8 (commit)
       via  f94b033cbf46821f0391b5512a5fdcb70ffbc6e4 (commit)
       via  b966ebcc19a55c4d01825010ee1e707ba95293e8 (commit)
       via  9af419deb6691876904d456faf0da731cb5c96b5 (commit)
       via  ccb0973459b702152f79ea23841269a379580850 (commit)
       via  4d7d67838cb15ce75ceab0664e7b25e4b58d658a (commit)
       via  ed1a2ad7dfa4d0c87e9ab3fa446acdbc29f6cc24 (commit)
       via  9f5232047b3a68299192a7885068430af6f8859b (commit)
       via  282cb2ff2eb38f9ad46653c55d0d2974ca1df541 (commit)
       via  7a72794ffa529568a9a962a1fa62161dd7f6b906 (commit)
       via  f15deef54e5c162260abfa2e9deae226f85c4220 (commit)
       via  b2fe684c2f5ddeceb5e45400c5990ee9106caf5a (commit)
       via  d0a51e7f91ec66f4b00f6011fa713e2713f24821 (commit)
       via  5654a073196ca1ab1b4998d4621ef1ea9f117e61 (commit)
       via  fadf2a8a91581c95e080de2d4f60e9115e35416b (commit)
       via  38ebe09ee1c3ed6906f6a439e5ac9088b665420e (commit)
       via  50c262d64042f0350cc887b1f51000294bc74b5c (commit)
       via  18520152ce6097c22024bca864ec53643be3ef84 (commit)
       via  c19c1fff5013cec501f7c36fe272ecf2bc65d695 (commit)
       via  1f2f8e9d497246e335dcbb9604521eb70ccd4524 (commit)
       via  75622a763d3a717f00efa2cc831108a60f5d2ed8 (commit)
       via  cad4fb56e85555a48088a9f1e915f32057c2f8ee (commit)
       via  9833efc0691e4b80f29a135bfd56fc97e6b0c847 (commit)
       via  80b227af0bf08ac9e7bdf645b11e8593b717add3 (commit)
       via  a2090f1d5702cbc00da7b52a2c1247bd37334ebc (commit)
       via  f142087f73411145565baf4a3280607413162e06 (commit)
       via  a77ea5d4e9e7a0edf0be99d8b7e1f98a9b1d490c (commit)
       via  cb7e1e285e788e48afe26c3d18532299af41bd91 (commit)
       via  3cafab05e08e6aeb0eac010a3f12ffa3e8e734dc (commit)
       via  4838e909a1458198896cd2911488b2d3d442952f (commit)
       via  fd94c6a10376330c5e87d9b618c422b9f9832708 (commit)
       via  961921abc4ca4874d46f39f8db391601b184e6af (commit)
       via  ae39613c152173ff88cfbaa32f379613c81b5a7d (commit)
       via  3d69190c34d28e64ddbd31439968402b8c903475 (commit)
       via  81cf2b7ac4c5ee295c0d654c4ce24911dd23c2c4 (commit)
       via  3d7a6b9c7e01032d583a61f5aa10065cb31fd5e1 (commit)
       via  686594e391c645279cc4a95e0e0020d1c01fba7e (commit)
       via  b1b6e109cda0458811ab61be4263a51b5520ce0b (commit)
       via  29a6cb5fb2ceebdd45c343619e9d49fbd9d75558 (commit)
       via  e32617d592d204e4c5c27ff3ecab77ea4e258cb7 (commit)
       via  eb92bed532b40a0904f8397ba108d96f152abbbf (commit)
       via  5ac6e8b56caad02994fd9352e3427e975e72f44a (commit)
       via  710bac35169ec02b73a82cab2c4ce31874a8e440 (commit)
       via  b27d601b91d09bbaa5c20805331c7efa95eac944 (commit)
       via  6b8bf7d03e221e9a1802bcddda66b2b424930042 (commit)
       via  6847454e58c65b33e61fe03b16b3aa5a63df8d8d (commit)
       via  9a15250b2c74f8b637cf1f32f79cc626cb05d0e5 (commit)
       via  fd7e25adfafa0696f3c13ae5f504ceb7a110c23e (commit)
       via  8a8750b7ee739de6208df6b25c9c9c7e11fb0434 (commit)
       via  f66ffd87e1d460956a8c0bd22700f03b7c3fd0f8 (commit)
       via  f2b5789e89f48e5a045f8c921f09b5c3caddea3a (commit)
       via  d12d0c3368d26ab81c5a3c63bad696ee2282530f (commit)
       via  8df24b61c35bf2e4963c195e1c927980e16c4a9c (commit)
       via  9f360b39c79ef71edb474fb6fe443ff30b479fb6 (commit)
       via  5e97750478c1a655d85107bbbda556c8e8bcfec0 (commit)
       via  b1f95f0359a425b9d758cfacffc75a4517fb342f (commit)
       via  82c05da76c188848bb0c0fa2e93c0e90178b5008 (commit)
       via  5ee9df691d301f7a6b3c422013336f229292da35 (commit)
       via  240c5dfdc3f777eb49b41423dbaec2f9479c4eb6 (commit)
       via  6ad5fcf5b5bf4ca4f0295585ac8ad1521baf062a (commit)
       via  e8a6aee2464c295e476eff03448e39d386747140 (commit)
       via  d9c1638e3498459671b8257a8c3529569a3a8fd9 (commit)
       via  b8b87c941fa3b5973dddd0e88220dd435bec699c (commit)
       via  42298cee62c386318f248bcae47d99a39094a10a (commit)
       via  88a8de015f4652fd73164457414f72ab43dcf681 (commit)
       via  0192fd73649d14ade8dc284c64f38d5e0d8b0705 (commit)
       via  e75c686cd9c14f4d6c2a242a0a0853314704fee9 (commit)
       via  cb8128c933f47c23596bce0dd4eaaf77c6af2b6e (commit)
       via  0dd898f80907bcb0180858a3a1b2811c803012a9 (commit)
       via  ba71154440e841836726bbc6b9088f095d14f7d1 (commit)
       via  51e26dc96b447d4f60b6aa2c428bfcfe6e6a4d04 (commit)
       via  c8d6f38ab7cea07e3bc75a5b4cec8207c2db61fd (commit)
       via  f63a6cabd8ecfca7465f1856a3836bdd72ea34f3 (commit)
       via  90bb56b150b1c51690dffce834bff4b91f754111 (commit)
       via  ae8d436d86973d85dbf512ca39167b41dcdb6a7c (commit)
       via  17749f1ef367d560e5b878e814352e8b8082542e (commit)
       via  ecaa3bfbcea80a640778d8f0629e7976d87bde92 (commit)
       via  bd3faa6a3d1d5628509b725ecb61ef91ee3c2bb0 (commit)
       via  4d2adcc95c4a49ff7efa67a1f9e188a9e3e96dca (commit)
       via  53a57b7f2a75f4dded32297f3f95d5700f536036 (commit)
       via  23d08556872bff7288ccd690a09010769639bff1 (commit)
       via  08baa5371d0939356ba56f24f2d537834f7e9bac (commit)
       via  fdcffb798707a238b43f24a7dcc725acc4a4c962 (commit)
       via  2e7420da8bcb358bb4c8bb6d3a8c42e3fc26d53a (commit)
       via  8b36f92a0e51a40702a2fa5db7eabe5344adfeaa (commit)
       via  fd51de64c1738d586791060e3855f414f3cdcdc7 (commit)
       via  cfcad4db4f9da2525f7c9cddcdd52660f60e4afa (commit)
       via  127e416cb3b2d08b2cd9356ca7c8bd109dbef95d (commit)
       via  c4159fc5c746ee7df7aae8c590789e675050d75c (commit)
       via  b2d9be92c95432c92d4996bd999960e08edcc9bc (commit)
       via  d3bdb3c1c1dca514322fefdaac18a253364dfd2f (commit)
       via  0be210a2f53811e07a7ff0aad0aa388c3ef6048c (commit)
       via  8d2205ed3fc327862a0e3a7169e0432f221d514b (commit)
       via  67500d3bd8ae816e5ad73cf475d49f34546db639 (commit)
       via  698ad7c5546e6f0e44be3d9ee1ae57e541a9f968 (commit)
       via  61d7c3959eb991b22bc1c0ef8f4ecb96b65d9325 (commit)
       via  9843e33b58ce12f13fc34fe27c7ef0e4042bd506 (commit)
       via  b5ca6ac342e49edb73ab75938de20c8fd3f6e8b8 (commit)
       via  213e364291339b5e8367de470c02af695065d1ba (commit)
       via  37d79010dbca71da368021ca2b8c252deec41a1d (commit)
       via  706499470094cbc0e5084e1eac1678f0b349cde4 (commit)
       via  ffcecb945009df0085dd917cbacd2233d15cc9e8 (commit)
       via  1f1131d4f9085063781869fba3a578eb9b3cd7bf (commit)
       via  b237d10894d0eebe0affdc13bf781cc7f7a15b05 (commit)
       via  24e75ceec06dd94df77bec50b61a19d93962c10b (commit)
       via  27e863962f01a9dc8ac5c756ff881cb585c00abf (commit)
       via  1c12d2036d9e92d0475f421406bdca6839b04326 (commit)
       via  7735c8e85cb8275ee5bd1918bff809612248c43d (commit)
       via  59a449f506948e2371ffa87dcd19059388bd1657 (commit)
       via  7ec750c09a3828d28362bc557816e24a6b2207cf (commit)
       via  041dbf514a284b9c14f3a803dbaa8e4260b804f2 (commit)
       via  7dff35a176bcf41d83a14eb5b3fbca6a7dcfafb8 (commit)
       via  0187917d0b77b34997c4666d27f916cd8f6b4dd4 (commit)
       via  7187c1bb9c1b8a1d01843b8b3328454a9bce4d4d (commit)
       via  105208c1e8cd0a77cb8960013a391cc7b48f7a22 (commit)
       via  f4390da9f83529b6c3ed4383d7709e9ede1c3d5b (commit)
       via  40ae159a7ae9c1c1049bd8c18e37ed086c1aafae (commit)
       via  9281b972a87becd0f85b747d5d939f8f2e317247 (commit)
       via  8a0af829c62d143ebb80f99131f7bcb2918add82 (commit)
       via  61fc577d38615b1a25b5a94fa3bbaca9ec2f6ddf (commit)
       via  4965591081ad8457f5ff0f3fe3c581f8e1a4da54 (commit)
       via  83a6c4414e87db481e684f8b6757182a5b8a2cae (commit)
       via  7b11fd33ba9b3b0548a1b0e72b337fe5e3843b3b (commit)
       via  7151128386c71f20f2e51a156d1fb1746fcd7bfa (commit)
       via  4163ddf6d718bc6239a92a592687701053a5cf06 (commit)
       via  98947382e572f239b57f3f79a928636ea42d3696 (commit)
       via  b2964261a72d6eff164cafe4b24fd5bfce0fa469 (commit)
       via  fb8ce6a031254899bc2fdc101e5e279bed51829d (commit)
       via  869e658fbc3e33c5037f3866beb2ff76c03cbdf4 (commit)
       via  3271dcc47f185103c208585d1df8a92e50274f7a (commit)
       via  7e2dedc024cd77a301d7e30d180e16fa2132cbf5 (commit)
       via  ce0a6a9742cd2c18cb4c33ad0f174690ed1cbfc9 (commit)
       via  2c8d3ac2d8d62ef77c0f888a7c334689ebcd9b5b (commit)
       via  a6093a8ef88a556bb0c6094d11863e700ec8242f (commit)
       via  cb9e761c578cc1de9421eb5e5c1a45c3d9145239 (commit)
       via  7fb91131cdfc5778e241cb247e3c2713dfe2ca3a (commit)
       via  8aa5e22a0fc048058c3b45d1c2fc76065e0ac8bd (commit)
       via  8aa188a10298e3a55b725db36502a99d2a8d638a (commit)
       via  4e98f9c8aec4fbe707bf4f5aa8de9e3ce4737f79 (commit)
       via  05dbb62986e1b0260156658896c051cde3c6d53f (commit)
       via  5a9bc9bc1467bfd5d0be7de9db40824a967be9b0 (commit)
       via  e62b6417336ebdaeda560e47b177e617ee4551e5 (commit)
       via  a88ab93f5a8722d16f96a4e58952042ff2564751 (commit)
       via  33fd1fb0ed8ebfceb01e8a84b1196af29dffde92 (commit)
       via  844348f6a9c5d4670f96750a2c94ade6778891d9 (commit)
       via  57b907eddc75241956102dd4de70d882c1b1fe63 (commit)
       via  a311ab52fe83d602a2ac3daa12314df7de258bae (commit)
       via  85ccee0ac4c1397c8a5bf225470467c55623a28c (commit)
       via  f4dd53d74dfa8496e8f846960ac7424493858848 (commit)
       via  1b63f7d9df1621053c71ec3ef546a8cae024dffb (commit)
       via  84df8fb3d06ad81e04fee73b6a31890ddc03c33e (commit)
       via  b9afd797dee6f7ede5c387466547ac5a06277ecd (commit)
       via  dba0f070ef3f4a78db630b3002eef5fd2ba757e0 (commit)
       via  b77e7ed31d3121c8fb3826c9a8909044e0f4f6ab (commit)
       via  cf72f036909c786091f845a736bfd6fcfd15a7ac (commit)
       via  e4850b8e75f2d8fd4924b5060cbf3c4458d3513d (commit)
       via  aade8ac800d58c46dad9ab862cf0d6e85174b17d (commit)
       via  7900248aec3191e202066f5dfaad98f6469c32df (commit)
       via  0c8f4961f3f2b8884e5567e51bf629016a35e9d7 (commit)
       via  dcf59e93fadc2df047e4cb9dba138ffc0f619d3e (commit)
       via  414a83fefbb7374f31f362e80efef262722660eb (commit)
       via  9394d67b638a84409c3491fee821f347ca2acbcf (commit)
       via  6a8228eb8556681c30c7163010f7fb354a9ef66c (commit)
       via  29ff6bebc9eef580849d063cfb58bc8e053a03e6 (commit)
       via  a5a98d2f3e44ebec0de30f4f0905b83ca3a5df75 (commit)
       via  a54864927bc88eebbfb0f9515207ba9a3cacaa3e (commit)
       via  f49a40682835963334f3d5f2014bfed6b0895400 (commit)
       via  462af9f5a374d7c60c8ac2b38e6d663f2af41cc3 (commit)
       via  f48cb0979513b642ab8cea30be5a3caa10fff958 (commit)
       via  30873bc3691ff9be1d9ce56dfb4c3dc30e4dabbc (commit)
       via  ab6215d2e93f0bc0206f4503a9e5b0ea62bf65f3 (commit)
       via  fd2e13361be9f4e4fb4e1098bae2058de33432f7 (commit)
       via  f6af1e6965348482deb45174ba7b4dcb6e9cef61 (commit)
       via  1114159c5b113a98db20ecaed992022917300216 (commit)
       via  dc3884d6b3e3f80144d57a6edc0223d97f5a46af (commit)
       via  195617a1fd88af3bfbb397263cd67a148d0e7d67 (commit)
       via  6ead8f2bc21f09b34f842dda074d121a9f511ed5 (commit)
       via  bd8b562bcf016c70f229ba1cb7fa084035eff9e0 (commit)
       via  653d1d854ad6574806ed09f6b42aaa4a17f27b57 (commit)
       via  d8b60408e4843a88d15e3cd95dfeb898cea2a8fd (commit)
       via  99bdc7de647ee1abb8401cc1fd8337462173e7f8 (commit)
       via  a6ca17646b6bdf23f36d523bb56f3bb91e1dbf39 (commit)
       via  4b1c96c8a9bba522a512d07b23e36feebaec10bd (commit)
       via  d12b460fbb26cfbd968bf0db25c1d0d3a8d5fb4a (commit)
       via  3b3b42295d636901e0647d0bba3a4f3677af50a0 (commit)
       via  0bc630b2e4ab6efd3f837f2dd6f5e771e6a71b3c (commit)
       via  c37eaa23d920b79d3f344c8fbafbdcda37231b47 (commit)
       via  a2224a3c4ea8bcfc685190d78e539608e76006f4 (commit)
       via  eac4d4fdbc978c037d83081a3a7d99db4a8135bd (commit)
       via  edcbc935eb6ddc4bb5fac1e76e8eac100e783e74 (commit)
       via  7ff2ddee910f9a53bd1dd47c432c99a280a6d076 (commit)
       via  3519306b1c9d4bcaf8d6758ca65ad4a371296346 (commit)
       via  64b2a61c6d242b974169b72542be45a57630ec8d (commit)
       via  03499b185e1dca3807f4c09cd36ba066f25bc918 (commit)
       via  ecabe80cbb2483d8057a83c84faeb84ce903b555 (commit)
       via  f609865c302b87caa3f5721557b0e5491c3eba3e (commit)
       via  70473ce1f70543029936a6c5c6c055ea7a33581b (commit)
       via  4475bf75419cba6488628a2eb6f3b19fc795ae05 (commit)
       via  9e5e49a5c857b592cc08ba8e3db6a00c9a7fd179 (commit)
       via  5da59e27b2f165d089a8a2a936b4e9eb21387fcc (commit)
       via  0eb033a6b10eac2e2767923ccfe5e74f2d2b2680 (commit)
       via  5744cc1cf3c348d120ef5dc3f1f97e23a0aa6fea (commit)
       via  08e5c7f5394f449a3e5b7128eacdf5b7a096aa5e (commit)
       via  cb330a06847987bfacacc7a9333b70666750b66d (commit)
       via  c7123c288ebc9a1ac9aa86c43219877c86a6a032 (commit)
       via  566ab87733df04e288749e8ab5fb7c1a2c1156cf (commit)
       via  f687a6f097f17344cdf298e33b6592fd41fc8e43 (commit)
       via  c6f40e97e8cde76793b79c54d3611fe9914bc166 (commit)
       via  461164b527fd4b7f047820e7d1f7b22eb1b3458c (commit)
       via  88259891ae9cdc24ac5e48b5c3b0cb6615f73d19 (commit)
       via  3f3183672b5d824d03fb494dd0d21eaf5d1241cb (commit)
       via  683f4b7420d46fe6a92d3e40225b427eaca1d9f7 (commit)
       via  d899142df0fe588d8f4fa02f4120993f69cdea31 (commit)
       via  ad46427a54b6169859924c37e3966625f3a3b0b4 (commit)
       via  42c8b84a3fc7c45bfb3df671b5c4a7f7a9b3d376 (commit)
       via  2c5059119b843646ca59612cf69c4439b04494c8 (commit)
       via  fa6cef4dfbadd457c75ef5fc5f7ffe42d916a2de (commit)
       via  e710685dced3b2f30ecda4ead1d0dc9f6ae64361 (commit)
       via  059a2a175193e5c60a3a5e647acf95e0eb6b9a6a (commit)
       via  6d1358617343e061a6b2ac16a7830853674d1c5c (commit)
       via  29047b54a17c2bc1d27096ea21522e928b51989f (commit)
       via  dbabdcc3c8c103a56a6da5187a97f2748adfa467 (commit)
       via  54ae641d1c1fa87baeb702ec0ee25b28c2b7aebd (commit)
       via  1d4d9e796c10786417099a69e8c4e6e4c1cdfb8b (commit)
       via  503a7b06ae96ef13d1f1a5344e07c06786b5eb83 (commit)
       via  7eb5518a386019fd723fb2484eb40f13ff283515 (commit)
       via  0aa3d59397af2c127758616bdd93c22d3176d28b (commit)
       via  a4560fb5f2093d4619fb159d77501dd7e6978d35 (commit)
       via  01c85b2bf83b55be659ebe1526eaa1c5aa55b6aa (commit)
       via  07085635d4c12c77ac979ea9755d38a2a40f77b4 (commit)
       via  7d777cee74391169cd589dab1330eda699d2b8d6 (commit)
       via  54a03955995437e3cb380ef5ffba44d61be04213 (commit)
       via  0dfa29e875e3a668e7b6718b510c12df590faec7 (commit)
       via  b4a991767173f93daa5100909740413530c4445d (commit)
       via  a582a2143369f6848cae1bb82301f5a657293f17 (commit)
       via  71a249c1564261f2643515451a68e388603eaf4c (commit)
       via  296e119946e9fb8d6eebdabf6eb166f47c47fbd0 (commit)
       via  2ce8ea317bf920ec540ed40f10738cb2f65426df (commit)
       via  80210bc17829ab209d714a10daa35bebad2f6dc0 (commit)
       via  718ab061bfe0fbad59c5d829d32d1fb71608c324 (commit)
       via  265fc0cc3154f8963e5ab68fd2890eeec64e13be (commit)
       via  3e189b431fd39c99aaf4fa8f78a3e41d722f37ed (commit)
       via  4a9e338f845772c9a0888a276c30449f89beea9c (commit)
       via  daaa9544987cf61adb4a16fb955885019cce8885 (commit)
       via  41fa47c50d302aa71e9aee629c28ed9cb4fcd065 (commit)
       via  c4690c43b4856170b4da2c789d1605d5430b7cb8 (commit)
       via  35300a55ab8bc113428142ea764a54173eb8f07f (commit)
       via  c59f610bf61bbc374b401a0ac6f595240bd4c629 (commit)
       via  3404981c39241b4463e661981614ec0d157b924d (commit)
       via  aa9c2bbcf4e4522525194310791d94fcf84fc605 (commit)
       via  d02295dada44afbbfe9c8b7878cecca536ba3a13 (commit)
       via  d0b0208ae8f3de712fa1329c8b01d16e3eaf8ac4 (commit)
       via  ebdd232061e3d9ced4660541cd3ad1c2ca8ed645 (commit)
       via  5fd4177340e6abaec9f8ca6a1194900001671665 (commit)
       via  9ba0013f74bf3ed03d95add7c1d46c2d28a94492 (commit)
       via  d709ef90b8f23a6c41a05d2f5a62cb91840fde0d (commit)
       via  246a87a4a681a574a0ecff9b26a49e471a60138a (commit)
       via  113201b72be892ffd8af815806ccbb0e14ad6b67 (commit)
       via  a8dcc73698a14603967aec4dfb09e183e559f84a (commit)
       via  a92defd1deceebc13a7bcc93cee6579ed42be41e (commit)
       via  a09e57e212a102d719315aff8d0f3c4ce74268d8 (commit)
       via  6c12b4328d0c49d039abc56ee22e09f8ca431647 (commit)
       via  80b0cf61a83ef37110d4b86c15704a923f0b9d6e (commit)
       via  5765f9d6485ed12a16a65f89639d0d88bc2c3692 (commit)
       via  7c4e02c157bf7a4baaa81c448ff485e7dec31182 (commit)
       via  2eaf01995b4c0d6c007afd51c94b8453cbb797ca (commit)
       via  8b19f3a80a57b4a0c41e58460920924d5613e606 (commit)
       via  98db15a31fea52ec2b1952846c61d20f9f373305 (commit)
       via  4f4b3724e1e06933646dcbee14f31eb2713a514d (commit)
       via  4ea73cff14dfd8c6898f1c79e7de860a2ca83b33 (commit)
       via  77e32834470282fe08ae7fb8c8fb9a4afb163677 (commit)
       via  a9688bc111e1cf1b62cfad222c2dab1351c81a4e (commit)
       via  bb59b815c94d86c6d5d34cdfd707b7e6e3522122 (commit)
       via  e13d083a39e86bcb60867b281ccd0a045bb55993 (commit)
       via  07b436b864bd3193ecafbfe1f9c1fa54f90ac342 (commit)
       via  1eda789420a1914f61ee720043a15516157f23b4 (commit)
       via  61d475331f841b3d5f1b2461ae99fe45f5d554fe (commit)
       via  252ef7278171213c9e54338939423e72b3d51257 (commit)
       via  812392465ae1ffa4a583186fd48f4c7aff1640dd (commit)
       via  f0c56bb2f6bc3a8118acd5f27e0be45d23b6be21 (commit)
       via  20fdec048d51fa193425ebb284278ffeec37b93f (commit)
       via  3a5e410f451b3254df6bf454e50af98b80ce4f16 (commit)
       via  9a52c2a5a52c35056f650594216366cac5560af1 (commit)
       via  c974d3a5e481c63242f128f630b9e7e5ac4f1359 (commit)
       via  82d164c20e0dd8a359b8493a2bc1216436549a4d (commit)
       via  2fa49003caec9837963fdee5c8ef7ca5ed1b6413 (commit)
       via  61256f84ff903ba7f0bddd2569f9fddcdbb194d2 (commit)
       via  ae2e285fb9abc9295563206d86ebbf94dc4f8918 (commit)
       via  e6ba20b0907ab7e861e608a71a35f71ab228e79f (commit)
       via  4e199b28f4247ba178c4a066d77c6ff6dbebfd19 (commit)
       via  c3a8f64b91fd9f1b7525fa8d46f0db2d6b4a0889 (commit)
       via  73f49fc9d917907e6b8990e137cd8414acb852ce (commit)
       via  59d1e7799c13b01d24276dbd6377934d50ca0749 (commit)
       via  d7a95438792f96696ced4559ee6bd465ae652f2f (commit)
       via  1bb3279cc1b0c3b156a749cdef80b625371afaa9 (commit)
       via  9a85c00b1675644dcdfea3e344ee72a42558d1aa (commit)
       via  9de48090c09919a7926664e26697dca42693b258 (commit)
       via  11df86c57f35ed344838b787ecc1caf1382805dc (commit)
       via  699a941cab0ce6969a8f93a17e7659b75876b14b (commit)
       via  a80cd447a1458b6c2d5d654f31e2e4a1a7d3f66e (commit)
       via  48bfbccf4e01c6b0b9c8c716b09155f16fabf3ab (commit)
       via  13e9951ecd5877f8942fee9af7065d8c6c20d1ac (commit)
       via  f8fb9a002db020b90f423fd82cf5f7f10a050bc7 (commit)
       via  1b638d681316a66b6c1de3ca2937068f81d4f634 (commit)
       via  638f92b82b6b3e74e4b7222f238fb9cf2b8a4fe1 (commit)
       via  1c5c694f663811e02a40acdaa0ba2b71a38c44fa (commit)
       via  b09b4308af92511dde35d87a23bf159b2f71848b (commit)
       via  2d014223ce8d34ce0efb19fbd78c5123f4a2cd60 (commit)
       via  0a4ef3221c7ea7347a11e02b9e8175598e3eb2ec (commit)
       via  c9ba8373e271fb3c966fb59813c21ca8c575354d (commit)
       via  7868cb5a0cb2c276114c8d762a89bc59d8169df8 (commit)
       via  08e8d762ad041672b156204c21b42b32a510e94c (commit)
       via  6cf94944f1431422449f5740299ee2d6ae5fd988 (commit)
       via  a61ab28f80639eb289b7b1cf74e89932fb11f1f5 (commit)
       via  5ac7c2d114c23a7bdf4c15a96d619027d2092d63 (commit)
       via  2f6a2e484a7c4838a11e0696323c5a38efa1c6cc (commit)
       via  15a048bef56f34ac35ac38f6b43512129dac0350 (commit)
       via  a9af8c8a7a7d2448c86949fca578ec942e5413dd (commit)
       via  86fe8fce9db80466c67e0553c9f5ef404cdbb185 (commit)
       via  c9b8a023d197a3726f4177409847c29e523a69fc (commit)
       via  0e56f890880b684ebb71245155d0ecd435c75fdf (commit)
       via  0e70ad361ad0d42b3d0aa63c51355e20c48b9c32 (commit)
       via  adc18e7e1019626410a642aa8271627659ff1d3b (commit)
       via  8a4c6f4bbfd10a372fa4c4d40a6cb5ec64047cb6 (commit)
       via  77d522cf9e3b0cfd5325461b76bbaa2cc8a859f2 (commit)
       via  eb90dff94fbb2df0632f51982fc2c512af6e9c65 (commit)
       via  bef1229c90595e4aa4a6c483fc99f7cac768a1b3 (commit)
       via  21170f738cf943a5750c26eb8b418972a673a27f (commit)
       via  213bd813ebe0eacec4bda6d11301f81315494364 (commit)
       via  ee7d5cf20406b4ff00a52ce8218304c6623571ea (commit)
       via  3a0cd3a067fdf94078764b082c8139220a0ce917 (commit)
       via  307b9baac8a90337fc6de440efe0ed3685aa97ed (commit)
       via  396d1867ce3420d759bd5eaaed64ce3f83b0b874 (commit)
       via  c1e16071d91f9db0b3f78f7a09551c66278ace5e (commit)
       via  451973cb26da61f3e5d56c441ea54a28c34acaa3 (commit)
       via  d1c32c6bd6bb7621968266b09ca979ecce428530 (commit)
       via  f6f16611034e7b8bb0bd1ce506d6d61ed5228b02 (commit)
       via  c62976b616bd2b44a9f791c47afde5d89ef9913a (commit)
       via  7161d9d899723f1be561125087e1daaf820e80ed (commit)
       via  3ac353a5a561e5a0ecae750bd0d52afb2fa86037 (commit)
       via  9e8803c63d45a0a2abe9cd615c41f0a0f1fd8ac1 (commit)
       via  0002fc16bf300d9a2ccfca9e26fdfd5a73eaf519 (commit)
       via  6319666e91e5f3f20d9e2fdb920ce90c2539d4ad (commit)
       via  d97fa9cb68dea0cf8873f9b28ac6671ee321a1f6 (commit)
       via  3d7fea6b15278d8f66840bff3cc4f9a3b1d60d23 (commit)
       via  c13d57b516b4ed381a51916a5b726aebcc564f8f (commit)
       via  fc846d678c69d29dc9055a943288c4adfe41fb07 (commit)
       via  f0fc85c74eff8a53f2387e4c48a8043ad3994b08 (commit)
       via  c627111eeec6f80e5f66020c7613b4e408d2b193 (commit)
       via  a82ee1d047fe786113491226f7e81a08ed58e8c4 (commit)
       via  7c40eaf7779f7fb3b80ad141c58f60e69a2f3e4e (commit)
       via  fa78c4ba3aff851955576ec7e98f8fe98dacd889 (commit)
       via  149df5a690bc874b8814669c19a8666e2cddf961 (commit)
       via  2a6f0764001c25acb40eae27d7a2f7691d4c767b (commit)
       via  4887037cd08e567596339dbb3d65557b8e25560d (commit)
       via  7e1c4328789fc66d6fb7f4840112d89024d00eef (commit)
       via  8580400e9333574d49de88aaf34dac87bd270020 (commit)
       via  9b439f1bf7dc415312be57570b092459fad4caf7 (commit)
       via  7b598ee429c070c4c784e41822a4904ee71ebf95 (commit)
       via  8334de9f905bc792b0ec866a03a2dde05e5330fe (commit)
       via  667ecc41e7f8c0a47a1d701cb5cf16ecc7264205 (commit)
       via  9904c81d783e8e4678ba6de3db438ddbb186dcaa (commit)
       via  110a33e6c237d71d2efa42d27ae2434b35ddcaa3 (commit)
       via  0582539b207817d0ab63a2f07923d9cd69b520a7 (commit)
       via  59ca62327546854c22cf8caae902f023a79f3272 (commit)
       via  f34ff8e2e66798f4dc2fc63d1aeb4c198431beb1 (commit)
       via  d5afffd2e3db401cafb5ac2ca80215afffddf7da (commit)
       via  949aded6b4682df0f07e78cd4620df303f789236 (commit)
       via  c2608e7b395881e9953962d923dfd1de6eb50f5f (commit)
       via  5080ddf460167c252502db23b97cdb69fce7f240 (commit)
       via  6fca5f367bef49f3c3002ee6abb4c5c19ab971d9 (commit)
       via  b617d1a26e4e4fd536b37848b1dd39ff40f5213b (commit)
       via  83f878b651eb1be66dfcb1453cc074c2b5d3dc3f (commit)
       via  9bb3d27efdf09dd2e429086767cdee275f3df115 (commit)
       via  100929f3fab349338ecbd8cbcdf090e1006f8ab0 (commit)
       via  7265ccb300bd2a2e1789d8ce99182e787d97181c (commit)
       via  399e4f0030d226010f2156e978fc2b7c179fe7b7 (commit)
       via  f0f7efe331713b84e4e95f872373d6d2906b5870 (commit)
       via  0c3a609fdde1fe14de8d2c032e1350c3f10c3058 (commit)
       via  ce585a075a28df8b5815b38cd461da1dce17406d (commit)
       via  650655fd267d652ec1b0d5e57a261ab767ada447 (commit)
       via  b4f9ae7bf9569106d47a0ff227552eb6a956aa4e (commit)
       via  8422f4dd15cbdd9bd33f3a570bdf40b991665ab9 (commit)
       via  c450d77e81322fb6a3c6753d721f5d3bb62fff71 (commit)
       via  39faa67b7a8e9b3680792582bb65372ddf610b77 (commit)
       via  16041df526aeb519ff158aa4cd89e0b4f503aece (commit)
       via  6430d56ffc6be92717f50e576101546be2f4d6c9 (commit)
       via  ccfb2bf2c5226f21e793df4abaa9b98a993b6eb3 (commit)
       via  4601f7ef87135a559b4fa7a1daaf2f1de8f040c3 (commit)
       via  84e0dc1be1b2f22d46028944a3ce1a599aa24090 (commit)
       via  2530e97e662406cb168e80358c764ff8692866cb (commit)
       via  5b77cd205f08b1bc76ec5ff4248f4c9cb4e0ac27 (commit)
       via  1ae2321d7183470ad3540d2a92436893724ea773 (commit)
       via  03b8bddd309adeb39a99474aea530f05989b99ed (commit)
       via  0d336b6f23ca4518b38f1e26e8b8b9998f426e5f (commit)
       via  4b2997b783ed2f9a29842735dad130cfdb41e38a (commit)
       via  c857ced99825b35644c2abdbad8be14644da237c (commit)
       via  e7bcdb44ef51c4f8fcf81a11d247494384fa0c41 (commit)
       via  e21b1a26b3f78d69975c5735c1965a37c67359c9 (commit)
       via  07e1f1ddbd299b60ee4009f53723b4271b5cea16 (commit)
       via  2252c5776f5447f47e567262f8a5a05753fc6ce9 (commit)
       via  f559b99dcccd35703989fce985ff200cd664ccc0 (commit)
       via  c91151db16e215692830bf9b6211c22aae8619dc (commit)
       via  7ffd1e0cad3bd125b490953dbea9f22c67e40fae (commit)
       via  34701adba7f7390640c70ba769cdb0b20f01f82c (commit)
       via  26313fafb0f28d8bb1e440c83a780cdb6fc6fda2 (commit)
       via  42c638e07a45b69d902a51b35838ae21ac19d116 (commit)
       via  82c0737d3d63da1a1c2b001d0306a32a1e55f5f5 (commit)
       via  5735b337b8e78502bd54cba748bb622b150f6667 (commit)
       via  b57f65e686286f211ef1b177f69a81fa5baf3021 (commit)
       via  579b92381b604c84f70ae5fe6237ca5dc45a9302 (commit)
       via  93c198a7b9afd341809b954e76f5e2773e0010ff (commit)
       via  8d321e3ea9f85227296cfac94a9ce79c7db70fdf (commit)
       via  5bf4005eb7dd34a08b6070bc17f0e416448062d2 (commit)
       via  83d00dc305a33e69e4bee379895697742a1eaab7 (commit)
       via  15724e5de168271303268a09627c3f197833f20d (commit)
       via  f8181bb72251fd3d5f33e157d1f2a2a75a58d765 (commit)
       via  6adfc244341c07a70eb0984536390486649316ae (commit)
       via  16d31a6793cedc28c8acb1bebf4c891c039321cb (commit)
       via  f05b0be9d267baab1003963e231a3511dfcd7d5e (commit)
       via  ae89f6e491d018953ac03d1810c1b467564c281b (commit)
       via  b4ec1b3e236ae2dabfbf6b0fb9c182da27f52596 (commit)
       via  d2009fd950bc48ec3a2294a9064c4fbd9bfa0f79 (commit)
       via  0c6ad26d377dfa84e4cf4ee202b8f1c912d296a1 (commit)
       via  8c02f8a83f011816c3fb19f655a1e57edf0c1048 (commit)
       via  a439004524335feb296ee7477a5b450a2a7d7953 (commit)
       via  410987bf3c9299053c07aee46591193c97af6ea4 (commit)
       via  7f94f671e0da9c98cabcc38433852732294bee4a (commit)
       via  453b58784344390cbc5375624e6e92a86b4ff3f1 (commit)
       via  405d85c8a0042ba807a3a123611ff383c4081ee1 (commit)
       via  671005eea2c18ad34bb0bad435b538447cdc7a50 (commit)
       via  b6d2a03ff5dfc0b1269e69e44defb2999e8a5d33 (commit)
       via  d504c06cbe387363d11ae091eeaa980444cc5190 (commit)
       via  50500e62ac0b43e3579e98832b06bde19d01302c (commit)
       via  66524e1594263bb19fd73660fef31f4e49dbe81d (commit)
       via  6920774dd67be1221c379e9d5161f0cc932fbd73 (commit)
       via  3a73fff8f44f18188c1f810f3f5395e6ea107a7d (commit)
       via  9565a7939e66bb0f3bbb4f3be8778dec13582db1 (commit)
       via  9c2e94bb8ae9368aac3e0991dbebe3738ee914d7 (commit)
       via  efded5c3713a67a6eaa0284a322195b2f5075a27 (commit)
       via  d5569a62a30b26294197381dadf4b28317fba3d9 (commit)
       via  b06d8d764e01652ef5d3e1eb50ed482ddeae8308 (commit)
       via  51580fd1a4953d554b80306eec4f9fc89f166241 (commit)
       via  c55218e6bebfeec753b01e4cd724adcda40b3a5f (commit)
       via  5b781744ac6f909958754f7e5947115ec799ac18 (commit)
       via  4ed683ce42d061905a4e5b06fcc1a38c64136e7a (commit)
       via  e6ac5ef47d9885e20e247697c8c3d1fe55fd2500 (commit)
       via  48e80a5c7505df708999ef817911d1eb505deaad (commit)
       via  fff8929b13d8c2cd725b861c7e930c0060b54d83 (commit)
       via  ecef170dd0af4f282d4426ef663b667c76873737 (commit)
       via  350c775f7bd5c7777f0345754dac4ecaa0a9af18 (commit)
       via  666bfa9c7b6de4ee31e210d7f3e0f2f68704f2de (commit)
       via  932edbb0ec8a4dbb820c6cccf4a0becd9df533c2 (commit)
       via  0e2c14089b820cbb0bdef6e813042992896375bc (commit)
       via  45f0d1f2e771efaf7ca21e7f0450626847e75d90 (commit)
       via  31d092681cc44a6d742474090430c7ddba3f81e6 (commit)
       via  3744e7a8584a1c51bc5163751975af8e297c53c5 (commit)
       via  c0e090f453d3a1627ccd0591e0ec0abc3e80a01b (commit)
       via  70aa7bfa24600d5492056c860838d94c9243c6aa (commit)
       via  419020c407ac9f1ca0ab1f5a5c8b8b6219fb5d5b (commit)
       via  58c41ea9cdb2df726b4b54015500acab3ae34040 (commit)
       via  26ea6b0e3045489e542b95d02052fc7565a4ca87 (commit)
       via  4629279de0b7bec2a019b063e27074182a8f4ebd (commit)
       via  d3983e1e68f66bbf6c69838aebe01a8f95b7bc33 (commit)
       via  0bacd458152b7909f3d8e9ef4a338f261dad7f99 (commit)
       via  ae0565a4ed6e8a947120a7bfe826c1cf9d672760 (commit)
       via  e93e6f3873ca08ae835dfd883c36f19b42df247f (commit)
       via  95a47e7f0ac9e87d3d0c6c51c07e4761d0a50932 (commit)
       via  26483ea27726d4c1097485196a0908c565478188 (commit)
       via  9062cbabaeebead0b95bde1559d107fc35eeda1d (commit)
       via  3f6ddec37ff9bb49440ce6ceaf02842c74d0b865 (commit)
       via  f3414d4ba60432e36785c23ca55c633ad35298ab (commit)
       via  c638fb4e2776b24b7ecf3c071086056d5cc9d78f (commit)
       via  0e1a1b2ee0fc9a3a510d348d5449a825779c03b2 (commit)
       via  e2b120a2e016f249eabaf7753b97a79ece0bffa1 (commit)
       via  1e6d2102d1402cfcd6d2c1ecd88c6aa83133daa2 (commit)
       via  8b59a7d661ce81cb47c2f18d2908a01a8ab9ded0 (commit)
       via  f17651217197a8006509ef121f1a3d7a5eada1b4 (commit)
       via  e77ef46d0c78265ab0bd0ca12b541aaee2a52898 (commit)
       via  97a6125c538e5f44790b55ded90fccf363416496 (commit)
       via  2150123bd60f00e070198b9c9717eb685dd0eebe (commit)
       via  6bceaa250bef898410db1555341887b6a6f7e900 (commit)
       via  65c54c90ed874825b0418acade6179bd905bd470 (commit)
       via  c1ce5449aa72d538cbfca94f88cda0b8617081ba (commit)
       via  2768eb3551fdaa2c4728563535dfb69f732dc033 (commit)
       via  9c655172a298766a37cc83173438f70fff83264c (commit)
       via  1e0c106c45251a61579d37a5148e9f258b3e5cea (commit)
       via  9e11459509c9223201dcbe10636b15ba923e1516 (commit)
       via  9dac9afb2569288bb630b00d2a89a490ad944710 (commit)
       via  c9de286421049dc1a75a981c511506d16c014501 (commit)
       via  92f2cc51478005befb016e410a4fcb9c768ea3b8 (commit)
       via  c64356e9fdf3be868bb2d624200219d68aca45e8 (commit)
       via  e5ad36f38f6066c50059ea02e06245d7bc5c7efd (commit)
       via  f97ecbe97b6b3e098ebde2c984041dd24ce2dbbe (commit)
       via  e70da63e4aa5a075928c5cdef4fed11d15eeaa5a (commit)
       via  030aef19982a37a8b81376adb15864097b208ff8 (commit)
       via  eb84acab80c1a4f59f7c49ef5214279358e8ed79 (commit)
       via  31fdd062b59d6ac480ff48cde57e5abad2b3487c (commit)
       via  a6c74caf3dc0aef52b89c78ebbcd02fcc5e47609 (commit)
       via  f6616492db24a4831ca25258c4bc234e5bd148bb (commit)
       via  07b793c8f104dbb9116e3f94af7098498509288a (commit)
       via  ca61588dc2c1ad17200416ac7f07ac272adc8903 (commit)
       via  dc5492b8401c85daf1b0c8801e497bac3d5eeea5 (commit)
       via  6962458ec49390d007dbf0fa9d5d3befa53deb23 (commit)
       via  28b3efcf6100d2eab66c407a8f7ec54a87ac5f87 (commit)
       via  43959b29a67ba17054bd4bb70b6fe3b8be3b2f2a (commit)
       via  c0d50a204134b57f36a9e83cc694abcb5924f357 (commit)
       via  bc7551cca83bf060410a5645f014ddb0eb233834 (commit)
       via  8722bc208f5a232707824f3537fe0f6d073151f1 (commit)
       via  1adba86b37b9c11a8120e31cc4eeb137f8cde6d9 (commit)
       via  234026e024d6c4f35d2b7e1f34213949f79e614c (commit)
       via  85627bca2677b4e68d67c8ecd35fbfe409eda251 (commit)
       via  d042cd04c0784641738a0f06e5a6b193b433d39f (commit)
       via  55178c917f014922f8213921a44f0443b3dc40f8 (commit)
       via  7bb6309fbc34c32a0e37ea2b2175738b6110bcf7 (commit)
       via  fd45bcdb5182e09d33b92e222772b54c6e744d01 (commit)
       via  c887cb05e27289bf5a80130c1a196dbbc1903234 (commit)
       via  cd86c2c845e03de172d832256ea3542203f40a5f (commit)
       via  b59e1eb450e7f4630ee4ee8e67b7dbb3cf6092de (commit)
       via  43f01176f71c387638ff876b7ce31dd42f6bdb9d (commit)
       via  98127986d0baa2f87e455035d778c823bbe59397 (commit)
       via  124780d941405d05a2a2906160a3c479a8417abc (commit)
       via  67a6dccbdd9fe5b08b80224fd395fab676cb704c (commit)
       via  e4f9ff3f23810d365e13ee2e204f70eac5ffdc8f (commit)
       via  fb4eb0b2229e58f19526247193c427fe7af8b9b2 (commit)
       via  c522619b6b3555c5fa0fc8367b6ebc4e72e9335d (commit)
       via  35eb49f72a3dceb354e300469d0c4f342ddb3c8a (commit)
       via  ed2b8eb0e3f827c89ba16200312424384a54a9a7 (commit)
       via  2975fbae44dbaacdff7b9039a395b00c4375f01b (commit)
       via  593b348cbb8207fca3e9d01620794cfe118455b2 (commit)
       via  c16c1ab29b3a52012a806974dd6afaddc01c9436 (commit)
       via  2eb96fb05e736e2f16d03174f663d030cc883f00 (commit)
       via  c6f7cced73d38d5108862be4a104cb89d0f832e4 (commit)
       via  c0d25c429a4f2026bb97b9e013730b8f265862e6 (commit)
       via  e71cd13c5cb261635f7115e0d30fbd7dcc5fe151 (commit)
       via  66424553f3fa05e46e558f3b4e16677463e0e412 (commit)
       via  e562ac798865d18ece6a7ddd28ed79d8b4abe0ae (commit)
       via  f4f708e4e93579989bf716d5851311a2b5aff6b5 (commit)
       via  71e12e0bc1d27327a0f3f520ae80041af38ce657 (commit)
       via  587a13699275e9a582fb9358463047362ef9f21e (commit)
       via  ec2aecacc46f071cc6479881418825920e8f8f50 (commit)
       via  83a27d452c13b468d2103b0314ecf2bae17cd6b1 (commit)
       via  ece07281abf99ae142b20b4aead428e3333121a9 (commit)
       via  d05029362843411c46c6d8d278fcf17ba9d8d32a (commit)
       via  ef49adadf64f56558c75d34483895e1e8d8bcf66 (commit)
       via  31c8d5e0b4cdec573baf77f09fca75a362f641b6 (commit)
       via  273e195ef434e87ebf9838381d4b49e8a3081acb (commit)
       via  b2d0a03b1efe54b85736d22932f311fd376473ba (commit)
       via  a8a40b6805377c49a9671bd93cb510bfef946a87 (commit)
       via  55ca986dc44bb8059712619dadb64c359356e00a (commit)
       via  a475756bf185c9e364ed00e245e307789e22fed3 (commit)
       via  27be672609dde261c85ffc671f1026277cfc3e9a (commit)
       via  18cff787ef721f58322db5c5662ab7980357fe68 (commit)
       via  34020849e9b1d560fdc21b25ac0fe03c64f71a01 (commit)
       via  ae53c8fd697e2cd037facfccc8205d580b27f04e (commit)
       via  97fb03f6b015205da25e9c5be3cd90d4f9948d04 (commit)
       via  23d2eaf5f8e5febc4732f3fdc851e1b04914daf8 (commit)
       via  1137e979e1a22465feb03ee0a48499bebcdf6aae (commit)
       via  12bc8985691e22aad1811322fe1f550b3f710ab8 (commit)
       via  bf382bba28e32de82649284620e36749a183472d (commit)
       via  247cb9c1d6ca73bb212cb9dfe0aa85dcf342e924 (commit)
       via  25cd191443ffd0cffc036c53a0ff57ad2391cead (commit)
       via  3c35688d9945077bceba65131bf0f9954181c7f4 (commit)
       via  e01716291c402d11710387fa6a9b2cfcd8e3953f (commit)
       via  b3d273056fa988f289ae4bf3f0a677808613b97b (commit)
       via  b9250ecc03ef6854def286e388e9042fbd579971 (commit)
       via  8de132995eade03f030a3a66c0f0bf4bc1b0726c (commit)
       via  86fcb73a66e62bda72bf5d6aea7f1f852c7f5739 (commit)
       via  61beda153425bfbd855c9bca9ff51fb0e99f2943 (commit)
       via  038ba06b6e663343e93e63e0d77d3e3c1abf66bf (commit)
       via  b643e4ef3098a5671687031b2b1348ef60c780fa (commit)
       via  371a652b90f43c0a2759b2be4d2fb6ef95d57ff0 (commit)
       via  c1d90c602c39b7b49e7c8ab802956118f8846cd7 (commit)
       via  72941a64efbe4843657cbb05f8945f7c6dc0e3a0 (commit)
       via  3c3bea55f38dac4d8fcc9c0cda55c6382d6c2cd7 (commit)
       via  307071b44a3b5e5e3e8d3cc75b00c69d81fefaee (commit)
       via  a7adf4e4fe023903dd4ca362a6cfa6cafc06241d (commit)
       via  98cdad7fa22451ef1ca067ee747c70a31262ee61 (commit)
       via  c76e3fc072e8b1b771b55b6547889863ba263f31 (commit)
       via  50c395e0d786b2330919498c37149edf22808a52 (commit)
      from  fb185ed8c6c0b67fe710225c87b7e106cc405885 (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 4e7a8f7575704052e70432f1e2508d310e8f6bb0
Merge: fb185ed 51adf02
Author: Stephen Morris <stephen at isc.org>
Date:   Sun Nov 11 22:55:41 2012 +0000

    [2342] Merge branch 'master' into trac2342
    
    Conflicts:
    	doc/devel/mainpage.dox
    	src/lib/dhcp/Makefile.am
    	src/lib/dhcp/lease_mgr.cc
    	src/lib/dhcp/lease_mgr.h
    	src/lib/dhcp/tests/Makefile.am
    	src/lib/dhcp/tests/lease_mgr_unittest.cc
    
    A number of other files were modified to resolve incompatibilities
    in the way lease managers were created, and to promote the dummy
    "memfile" lease manager to a fully-fledged lease manager with
    unit tests.

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

Summary of changes:
 ChangeLog                                          |   82 ++-
 Makefile.am                                        |    2 +-
 configure.ac                                       |   59 +-
 doc/Doxyfile                                       |    2 +-
 doc/devel/02-dhcp.dox                              |   72 --
 doc/devel/mainpage.dox                             |    4 +
 examples/README                                    |   15 +
 examples/configure.ac                              |   16 +-
 examples/m4/ax_boost_include.m4                    |    4 +-
 examples/m4/ax_isc_bind10.m4                       |   40 +-
 examples/m4/ax_isc_rpath.m4                        |   46 ++
 src/bin/auth/Makefile.am                           |    4 +-
 src/bin/auth/auth.spec.pre.in                      |  140 ++--
 src/bin/auth/auth_config.h                         |    6 +-
 src/bin/auth/auth_log.cc                           |    6 +
 src/bin/auth/auth_log.h                            |   16 +-
 src/bin/auth/auth_messages.mes                     |  113 +++-
 src/bin/auth/auth_srv.cc                           |  165 ++---
 src/bin/auth/auth_srv.h                            |  135 +---
 src/bin/auth/benchmarks/Makefile.am                |    3 +-
 src/bin/auth/benchmarks/query_bench.cc             |   12 +-
 src/bin/auth/command.cc                            |   51 +-
 src/bin/auth/command.h                             |    6 +-
 src/bin/auth/common.h                              |    6 +-
 src/bin/auth/datasrc_clients_mgr.h                 |  660 ++++++++++++++++++
 src/bin/auth/datasrc_config.cc                     |    3 +-
 src/bin/auth/datasrc_config.h                      |   15 +-
 src/bin/auth/main.cc                               |   44 +-
 src/bin/auth/statistics.cc                         |  296 +++++---
 src/bin/auth/statistics.h                          |  229 ++++---
 src/bin/auth/statistics_items.h                    |  609 +++++++++++++++++
 src/bin/auth/tests/Makefile.am                     |    6 +-
 src/bin/auth/tests/auth_srv_unittest.cc            |  334 +++++----
 src/bin/auth/tests/command_unittest.cc             |  283 +-------
 .../auth/tests/datasrc_clients_builder_unittest.cc |  517 ++++++++++++++
 src/bin/auth/tests/datasrc_clients_mgr_unittest.cc |  254 +++++++
 src/bin/auth/tests/datasrc_config_unittest.cc      |   12 +-
 src/bin/auth/tests/datasrc_util.h                  |    6 +-
 src/bin/auth/tests/statistics_unittest.cc          |  372 ++--------
 src/bin/auth/tests/test_datasrc_clients_mgr.cc     |   95 +++
 src/bin/auth/tests/test_datasrc_clients_mgr.h      |  223 ++++++
 src/bin/bind10/bind10_messages.mes                 |   51 +-
 src/bin/bind10/bind10_src.py.in                    |   77 ++-
 src/bin/bind10/tests/bind10_test.py.in             |   36 +-
 src/bin/bindctl/bindcmd.py                         |   13 +-
 src/bin/bindctl/tests/bindctl_test.py              |    5 +-
 src/bin/cfgmgr/Makefile.am                         |    2 +-
 src/bin/cfgmgr/local_plugins/Makefile.am           |   11 +
 src/bin/cfgmgr/plugins/Makefile.am                 |    2 +-
 src/bin/cfgmgr/plugins/datasrc.spec.pre.in         |    4 +-
 src/bin/dbutil/tests/dbutil_test.sh.in             |   42 +-
 src/bin/dhcp4/dhcp4_log.h                          |    6 +-
 src/bin/dhcp6/Makefile.am                          |    1 +
 src/bin/dhcp6/config_parser.cc                     |  472 ++++++++++++-
 src/bin/dhcp6/dhcp6.dox                            |    8 +-
 src/bin/dhcp6/dhcp6.spec                           |   69 +-
 src/bin/dhcp6/dhcp6_log.h                          |    6 +-
 src/bin/dhcp6/dhcp6_messages.mes                   |   66 +-
 src/bin/dhcp6/dhcp6_srv.cc                         |  354 ++++++++--
 src/bin/dhcp6/dhcp6_srv.h                          |   77 ++-
 src/bin/dhcp6/tests/Makefile.am                    |    1 +
 src/bin/dhcp6/tests/config_parser_unittest.cc      |  534 ++++++++++++++-
 src/bin/dhcp6/tests/dhcp6_srv_unittest.cc          |  708 ++++++++++++++++++--
 src/bin/msgq/msgq.py.in                            |    9 +-
 src/bin/resolver/resolver.h                        |    6 +-
 src/bin/resolver/resolver_log.h                    |    6 +-
 src/bin/resolver/resolver_messages.mes             |    2 +-
 src/bin/resolver/response_scrubber.h               |    6 +-
 src/bin/sockcreator/sockcreator.h                  |    6 +-
 src/bin/stats/tests/b10-stats-httpd_test.py        |    3 +
 src/bin/sysinfo/.gitignore                         |    3 +-
 src/bin/sysinfo/Makefile.am                        |    1 +
 .../run_sysinfo.sh.in}                             |   22 +-
 src/bin/sysinfo/sysinfo.py.in                      |    6 +-
 src/bin/tests/process_rename_test.py.in            |    7 +
 src/lib/acl/dnsname_check.h                        |    6 +-
 src/lib/acl/ip_check.h                             |    6 +-
 src/lib/acl/tests/sockaddr.h                       |    6 +-
 src/lib/asiodns/asiodns.h                          |    6 +-
 src/lib/asiodns/dns_answer.h                       |    6 +-
 src/lib/asiodns/dns_lookup.h                       |    6 +-
 src/lib/asiodns/dns_server.h                       |    6 +-
 src/lib/asiodns/dns_service.h                      |    6 +-
 src/lib/asiodns/io_fetch.h                         |    6 +-
 src/lib/asiodns/sync_udp_server.h                  |    6 +-
 src/lib/asiodns/tcp_server.h                       |    6 +-
 src/lib/asiodns/udp_server.h                       |    6 +-
 src/lib/asiolink/asiolink.h                        |    6 +-
 src/lib/asiolink/dummy_io_cb.h                     |    6 +-
 src/lib/asiolink/interval_timer.h                  |    6 +-
 src/lib/asiolink/io_address.h                      |    6 +-
 src/lib/asiolink/io_asio_socket.h                  |    6 +-
 src/lib/asiolink/io_endpoint.h                     |    6 +-
 src/lib/asiolink/io_error.h                        |    6 +-
 src/lib/asiolink/io_message.h                      |    6 +-
 src/lib/asiolink/io_service.h                      |    6 +-
 src/lib/asiolink/io_socket.h                       |    6 +-
 src/lib/asiolink/simple_callback.h                 |    6 +-
 src/lib/asiolink/tcp_endpoint.h                    |    6 +-
 src/lib/asiolink/tcp_socket.h                      |    6 +-
 src/lib/asiolink/udp_endpoint.h                    |    6 +-
 src/lib/asiolink/udp_socket.h                      |    6 +-
 src/lib/bench/benchmark.h                          |    6 +-
 src/lib/bench/benchmark_util.h                     |    6 +-
 src/lib/bench/example/search_bench.cc              |    1 -
 src/lib/cache/cache_entry_key.h                    |    6 +-
 src/lib/cache/local_zone_data.h                    |    6 +-
 src/lib/cache/logger.h                             |    4 +-
 src/lib/cache/message_cache.h                      |    6 +-
 src/lib/cache/message_entry.h                      |    6 +-
 src/lib/cache/message_utility.h                    |    6 +-
 src/lib/cache/resolver_cache.h                     |    6 +-
 src/lib/cache/rrset_cache.h                        |    6 +-
 src/lib/cache/rrset_copy.h                         |    6 +-
 src/lib/cache/rrset_entry.h                        |    6 +-
 src/lib/cc/data.cc                                 |   16 +-
 src/lib/cc/data.h                                  |   50 +-
 src/lib/cc/session.h                               |    6 +-
 src/lib/cc/tests/data_unittests.cc                 |  249 +++++--
 src/lib/config/ccsession.h                         |    6 +-
 src/lib/config/config_data.h                       |    4 +-
 src/lib/config/config_log.h                        |    6 +-
 src/lib/config/module_spec.h                       |    4 +-
 src/lib/config/tests/fake_session.h                |    6 +-
 src/lib/cryptolink/crypto_hmac.h                   |    6 +-
 src/lib/cryptolink/cryptolink.h                    |    6 +-
 src/lib/datasrc/client.h                           |    4 +-
 src/lib/datasrc/client_list.cc                     |  123 +++-
 src/lib/datasrc/client_list.h                      |   59 +-
 src/lib/datasrc/data_source.h                      |    4 +-
 src/lib/datasrc/database.h                         |    6 +-
 src/lib/datasrc/datasrc_config.h.pre.in            |    7 +-
 src/lib/datasrc/factory.h                          |    4 +-
 src/lib/datasrc/iterator.h                         |    6 +-
 src/lib/datasrc/logger.h                           |    4 +-
 src/lib/datasrc/memory/Makefile.am                 |    8 +-
 .../memory/benchmarks/rdata_reader_bench.cc        |    1 -
 .../memory/benchmarks/rrset_render_bench.cc        |    1 -
 src/lib/datasrc/memory/domaintree.h                |    6 +-
 .../{zone_table_segment_local.cc => load_action.h} |   42 +-
 src/lib/datasrc/memory/memory_client.cc            |  659 ++----------------
 src/lib/datasrc/memory/memory_client.h             |   62 +-
 src/lib/datasrc/memory/treenode_rrset.cc           |    2 +-
 src/lib/datasrc/memory/zone_data_loader.cc         |  250 +++++++
 src/lib/datasrc/memory/zone_data_loader.h          |   80 +++
 src/lib/datasrc/memory/zone_data_updater.cc        |  347 ++++++++++
 src/lib/datasrc/memory/zone_data_updater.h         |  180 +++++
 src/lib/datasrc/memory/zone_table.cc               |    9 +-
 src/lib/datasrc/memory/zone_table.h                |   16 +-
 src/lib/datasrc/memory/zone_table_segment.cc       |    7 +-
 src/lib/datasrc/memory/zone_table_segment.h        |   57 +-
 src/lib/datasrc/memory/zone_table_segment_local.cc |   26 +
 src/lib/datasrc/memory/zone_table_segment_local.h  |   17 +-
 src/lib/datasrc/memory/zone_writer.h               |   92 +++
 src/lib/datasrc/memory/zone_writer_local.cc        |   93 +++
 src/lib/datasrc/memory/zone_writer_local.h         |   95 +++
 src/lib/datasrc/memory_datasrc.h                   |    6 +-
 src/lib/datasrc/rbnode_rrset.h                     |    6 +-
 src/lib/datasrc/rbtree.h                           |    6 +-
 src/lib/datasrc/result.h                           |    4 +-
 src/lib/datasrc/sqlite3_accessor.h                 |    6 +-
 src/lib/datasrc/tests/client_list_unittest.cc      |  175 +++--
 src/lib/datasrc/tests/memory/Makefile.am           |    2 +
 .../datasrc/tests/memory/memory_client_unittest.cc |  158 +++--
 .../datasrc/tests/memory/zone_finder_unittest.cc   |  276 +++-----
 .../datasrc/tests/memory/zone_table_segment_test.h |  116 ++++
 .../tests/memory/zone_table_segment_unittest.cc    |   66 +-
 .../datasrc/tests/memory/zone_table_unittest.cc    |   29 +-
 .../datasrc/tests/memory/zone_writer_unittest.cc   |  240 +++++++
 src/lib/datasrc/tests/test_client.h                |    6 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |   22 +-
 src/lib/datasrc/zone.h                             |    6 +-
 src/lib/datasrc/zonetable.h                        |    6 +-
 src/lib/dhcp/Makefile.am                           |   26 +-
 src/lib/dhcp/addr_utilities.cc                     |   21 +-
 src/lib/dhcp/addr_utilities.h                      |    5 +
 src/lib/dhcp/alloc_engine.cc                       |  276 ++++++++
 src/lib/dhcp/alloc_engine.h                        |  228 +++++++
 src/lib/dhcp/cfgmgr.cc                             |    2 +-
 src/lib/dhcp/cfgmgr.h                              |    2 +-
 src/lib/dhcp/dhcp6.h                               |   11 +-
 src/lib/dhcp/duid.cc                               |   19 +-
 src/lib/dhcp/duid.h                                |   23 +-
 src/lib/dhcp/iface_mgr.cc                          |    9 +
 src/lib/dhcp/iface_mgr.h                           |    2 +-
 src/lib/dhcp/lease_mgr.cc                          |   35 +-
 src/lib/dhcp/lease_mgr.h                           |   34 +-
 src/lib/dhcp/lease_mgr_factory.cc                  |    5 +
 src/lib/dhcp/libdhcp++.cc                          |  102 +++
 src/lib/dhcp/libdhcp++.dox                         |   79 +++
 src/lib/dhcp/libdhcp++.h                           |   57 +-
 src/lib/dhcp/libdhcsrv.dox                         |   86 +++
 src/lib/dhcp/memfile_lease_mgr.cc                  |  132 ++++
 .../lease_mgr_unittest.cc => memfile_lease_mgr.h}  |  191 ++----
 src/lib/dhcp/option4_addrlst.h                     |    1 +
 src/lib/dhcp/option6_ia.cc                         |    2 +-
 src/lib/dhcp/option6_int.h                         |  189 ++++++
 src/lib/dhcp/option6_int_array.h                   |  228 +++++++
 src/lib/dhcp/option_data_types.h                   |   89 +++
 src/lib/dhcp/option_definition.cc                  |  257 +++++++
 src/lib/dhcp/option_definition.h                   |  464 +++++++++++++
 src/lib/dhcp/pool.h                                |    2 +
 src/lib/dhcp/subnet.cc                             |   72 +-
 src/lib/dhcp/subnet.h                              |  313 ++++++++-
 src/lib/dhcp/tests/Makefile.am                     |    7 +-
 src/lib/dhcp/tests/alloc_engine_unittest.cc        |  341 ++++++++++
 src/lib/dhcp/tests/cfgmgr_unittest.cc              |   26 +-
 src/lib/dhcp/tests/duid_unittest.cc                |    8 +
 src/lib/dhcp/tests/lease_mgr_unittest.cc           |  214 +++---
 src/lib/dhcp/tests/libdhcp++_unittest.cc           |   82 +++
 src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc   |  130 ++++
 src/lib/dhcp/tests/option6_int_array_unittest.cc   |  420 ++++++++++++
 src/lib/dhcp/tests/option6_int_unittest.cc         |  413 ++++++++++++
 src/lib/dhcp/tests/option_definition_unittest.cc   |  660 ++++++++++++++++++
 src/lib/dhcp/tests/pool_unittest.cc                |    1 -
 src/lib/dhcp/tests/subnet_unittest.cc              |  259 ++++++-
 src/lib/dns/Makefile.am                            |    4 +
 src/lib/dns/benchmarks/message_renderer_bench.cc   |    1 -
 src/lib/dns/benchmarks/oldmessagerenderer.h        |    6 +-
 src/lib/dns/character_string.h                     |    6 +-
 src/lib/dns/edns.h                                 |    6 +-
 src/lib/dns/exceptions.h                           |    6 +-
 src/lib/dns/gen-rdatacode.py.in                    |    2 +-
 src/lib/dns/labelsequence.h                        |    4 +-
 src/lib/dns/master_lexer.cc                        |  119 ++++
 src/lib/dns/master_lexer.h                         |  379 +++++++++++
 src/lib/dns/master_lexer_inputsource.cc            |  158 +++++
 src/lib/dns/master_lexer_inputsource.h             |  167 +++++
 src/lib/dns/masterload.h                           |    6 +-
 src/lib/dns/message.h                              |    6 +-
 src/lib/dns/messagerenderer.h                      |    6 +-
 src/lib/dns/name.cc                                |  135 +++-
 src/lib/dns/name.h                                 |   48 +-
 src/lib/dns/name_internal.h                        |    6 +-
 src/lib/dns/nsec3hash.h                            |    6 +-
 src/lib/dns/opcode.h                               |    4 +-
 src/lib/dns/python/edns_python.h                   |    6 +-
 src/lib/dns/python/message_python.h                |    6 +-
 src/lib/dns/python/messagerenderer_python.h        |    6 +-
 src/lib/dns/python/name_python.h                   |    6 +-
 src/lib/dns/python/nsec3hash_python.h              |    6 +-
 src/lib/dns/python/opcode_python.h                 |    6 +-
 src/lib/dns/python/pydnspp_common.h                |    6 +-
 src/lib/dns/python/pydnspp_towire.h                |    6 +-
 src/lib/dns/python/question_python.h               |    6 +-
 src/lib/dns/python/rcode_python.h                  |    6 +-
 src/lib/dns/python/rdata_python.h                  |    6 +-
 src/lib/dns/python/rrclass_python.h                |    6 +-
 src/lib/dns/python/rrset_python.h                  |    6 +-
 src/lib/dns/python/rrttl_python.h                  |    6 +-
 src/lib/dns/python/rrtype_python.h                 |    6 +-
 src/lib/dns/python/serial_python.h                 |    6 +-
 src/lib/dns/python/tsig_python.h                   |    6 +-
 src/lib/dns/python/tsig_rdata_python.h             |    6 +-
 src/lib/dns/python/tsigerror_python.h              |    6 +-
 src/lib/dns/python/tsigkey_python.h                |    6 +-
 src/lib/dns/python/tsigrecord_python.h             |    6 +-
 src/lib/dns/question.h                             |    6 +-
 src/lib/dns/rcode.h                                |    4 +-
 src/lib/dns/rdata.h                                |    6 +-
 src/lib/dns/rdata/generic/detail/ds_like.h         |    6 +-
 .../dns/rdata/generic/detail/nsec3param_common.h   |    6 +-
 src/lib/dns/rdata/generic/detail/nsec_bitmap.h     |    6 +-
 src/lib/dns/rdata/generic/detail/txt_like.h        |    6 +-
 src/lib/dns/rdatafields.h                          |    6 +-
 src/lib/dns/rrclass-placeholder.h                  |    6 +-
 src/lib/dns/rrparamregistry.h                      |    6 +-
 src/lib/dns/rrset.cc                               |    6 +-
 src/lib/dns/rrset.h                                |   11 +-
 src/lib/dns/rrttl.h                                |    6 +-
 src/lib/dns/rrtype-placeholder.h                   |   14 +-
 src/lib/dns/serial.h                               |    6 +-
 src/lib/dns/tests/Makefile.am                      |    5 +-
 .../dns/tests/master_lexer_inputsource_unittest.cc |  325 +++++++++
 src/lib/dns/tests/master_lexer_token_unittest.cc   |  156 +++++
 src/lib/dns/tests/master_lexer_unittest.cc         |  127 ++++
 src/lib/dns/tests/name_unittest.cc                 |  124 +++-
 src/lib/dns/tests/rdata_unittest.h                 |    6 +-
 src/lib/dns/tests/rrset_unittest.cc                |    8 +
 src/lib/dns/tests/unittest_util.h                  |    6 +-
 src/lib/dns/tsig.h                                 |    6 +-
 src/lib/dns/tsigerror.h                            |    6 +-
 src/lib/dns/tsigkey.h                              |    6 +-
 src/lib/dns/tsigrecord.h                           |    6 +-
 src/lib/exceptions/exceptions.h                    |    6 +-
 src/lib/log/compiler/message.cc                    |    4 +-
 src/lib/log/dummylog.h                             |    6 +-
 src/lib/log/log_dbglevels.h                        |    6 +-
 src/lib/log/log_formatter.h                        |    4 +-
 src/lib/log/log_messages.h                         |    6 +-
 src/lib/log/logger.h                               |   16 +-
 src/lib/log/logger_impl.h                          |    6 +-
 src/lib/log/logger_level.h                         |    6 +-
 src/lib/log/logger_level_impl.h                    |    6 +-
 src/lib/log/logger_manager.h                       |    6 +-
 src/lib/log/logger_manager_impl.h                  |    6 +-
 src/lib/log/logger_name.h                          |    6 +-
 src/lib/log/logger_specification.h                 |    8 +-
 src/lib/log/logger_support.h                       |    6 +-
 src/lib/log/logger_unittest_support.h              |    6 +-
 src/lib/log/logimpl_messages.h                     |    6 +-
 src/lib/log/macros.h                               |    4 +-
 src/lib/log/message_dictionary.h                   |    6 +-
 src/lib/log/message_exception.h                    |    6 +-
 src/lib/log/message_initializer.h                  |    6 +-
 src/lib/log/message_reader.h                       |    6 +-
 src/lib/log/message_types.h                        |    6 +-
 src/lib/log/output_option.h                        |    6 +-
 src/lib/log/tests/log_formatter_unittest.cc        |   14 +-
 src/lib/log/tests/logger_unittest.cc               |   21 +-
 .../log/tests/message_initializer_2_unittest.cc    |   11 +-
 src/lib/log/tests/tempdir.h.in                     |    6 +-
 src/lib/nsas/address_entry.h                       |    6 +-
 src/lib/nsas/address_request_callback.h            |    6 +-
 src/lib/nsas/asiolink.h                            |    6 +-
 src/lib/nsas/fetchable.h                           |    6 +-
 src/lib/nsas/glue_hints.h                          |    6 +-
 src/lib/nsas/hash.h                                |    6 +-
 src/lib/nsas/hash_deleter.h                        |    6 +-
 src/lib/nsas/hash_key.h                            |    6 +-
 src/lib/nsas/hash_table.h                          |    6 +-
 src/lib/nsas/nameserver_address.h                  |    6 +-
 src/lib/nsas/nameserver_address_store.h            |    6 +-
 src/lib/nsas/nameserver_entry.h                    |    6 +-
 src/lib/nsas/nsas_entry.h                          |    6 +-
 src/lib/nsas/nsas_entry_compare.h                  |    6 +-
 src/lib/nsas/nsas_log.h                            |    6 +-
 src/lib/nsas/nsas_types.h                          |    6 +-
 src/lib/nsas/tests/nsas_test.h                     |    6 +-
 src/lib/nsas/zone_entry.h                          |    6 +-
 src/lib/python/bind10_config.py.in                 |    4 +-
 src/lib/python/isc/acl/dns.h                       |    6 +-
 src/lib/python/isc/acl/dns_requestacl_python.h     |    6 +-
 src/lib/python/isc/acl/dns_requestcontext_python.h |    6 +-
 src/lib/python/isc/acl/dns_requestloader_python.h  |    6 +-
 src/lib/python/isc/bind10/sockcreator.py           |   45 +-
 src/lib/python/isc/datasrc/client_python.h         |    6 +-
 .../isc/datasrc/configurableclientlist_python.h    |    6 +-
 src/lib/python/isc/datasrc/datasrc.h               |    6 +-
 src/lib/python/isc/datasrc/finder_python.h         |    6 +-
 src/lib/python/isc/datasrc/iterator_python.h       |    6 +-
 src/lib/python/isc/datasrc/journal_reader_python.h |    6 +-
 src/lib/python/isc/datasrc/updater_python.h        |    6 +-
 src/lib/python/isc/sysinfo/sysinfo.py              |   37 +-
 src/lib/python/isc/sysinfo/tests/sysinfo_test.py   |   65 +-
 src/lib/python/isc/util/cio/socketsession_python.h |    6 +-
 .../isc/util/cio/socketsessionforwarder_python.h   |    6 +-
 .../isc/util/cio/socketsessionreceiver_python.h    |    6 +-
 src/lib/resolve/recursive_query.cc                 |   47 +-
 src/lib/resolve/recursive_query.h                  |   51 +-
 src/lib/resolve/resolve.h                          |    4 +-
 src/lib/resolve/resolve_log.h                      |    6 +-
 src/lib/resolve/resolver_callback.h                |    4 +-
 src/lib/resolve/resolver_interface.h               |    6 +-
 src/lib/resolve/response_classifier.h              |    6 +-
 src/lib/resolve/tests/recursive_query_unittest.cc  |   48 +-
 .../resolve/tests/recursive_query_unittest_2.cc    |   22 +-
 .../resolve/tests/recursive_query_unittest_3.cc    |   21 +-
 src/lib/server_common/client.h                     |    6 +-
 src/lib/server_common/logger.h                     |    4 +-
 src/lib/server_common/socket_request.h             |    6 +-
 src/lib/server_common/tests/portconfig_unittest.cc |   67 +-
 src/lib/statistics/Makefile.am                     |   11 +-
 src/lib/statistics/counter.cc                      |   82 ---
 src/lib/statistics/counter.h                       |   48 +-
 src/lib/statistics/counter_dict.cc                 |  265 --------
 src/lib/statistics/counter_dict.h                  |  184 ++---
 src/lib/statistics/tests/Makefile.am               |    1 -
 src/lib/testutils/dnsmessage_test.h                |  122 ++--
 src/lib/testutils/mockups.h                        |    6 +-
 src/lib/testutils/portconfig.h                     |    6 +-
 src/lib/testutils/socket_request.h                 |    6 +-
 src/lib/testutils/srv_test.h                       |    6 +-
 src/lib/util/buffer.h                              |    6 +-
 src/lib/util/encode/base32hex.h                    |    6 +-
 src/lib/util/encode/base64.h                       |    6 +-
 src/lib/util/encode/hex.h                          |    6 +-
 src/lib/util/filename.h                            |    6 +-
 src/lib/util/hash/sha1.h                           |    4 +-
 src/lib/util/interprocess_sync.h                   |    6 +-
 src/lib/util/interprocess_sync_file.cc             |    6 +-
 src/lib/util/interprocess_sync_file.h              |    6 +-
 src/lib/util/interprocess_sync_null.h              |    6 +-
 src/lib/util/io/fd.h                               |    6 +-
 src/lib/util/io/pktinfo_utilities.h                |    6 +-
 src/lib/util/io/sockaddr_util.h                    |    6 +-
 src/lib/util/io/socketsession.h                    |    6 +-
 src/lib/util/io_utilities.h                        |    6 +-
 src/lib/util/locks.h                               |    6 +-
 src/lib/util/lru_list.h                            |    6 +-
 src/lib/util/memory_segment.h                      |    6 +-
 src/lib/util/memory_segment_local.h                |    6 +-
 src/lib/util/python/pycppwrapper_util.h            |    6 +-
 src/lib/util/python/wrapper_template.h             |    6 +-
 src/lib/util/random/qid_gen.h                      |    6 +-
 src/lib/util/random/random_number_generator.h      |    6 +-
 src/lib/util/range_utilities.h                     |   25 +-
 src/lib/util/strutil.h                             |    6 +-
 src/lib/util/tests/buffer_unittest.cc              |   23 +-
 src/lib/util/threads/Makefile.am                   |    2 +-
 src/lib/util/threads/lock.h                        |  128 ----
 src/lib/util/threads/{lock.cc => sync.cc}          |  126 +++-
 src/lib/util/threads/sync.h                        |  229 +++++++
 src/lib/util/threads/tests/Makefile.am             |    1 +
 src/lib/util/threads/tests/condvar_unittest.cc     |  169 +++++
 src/lib/util/threads/tests/lock_unittest.cc        |   45 +-
 src/lib/util/threads/thread.cc                     |    2 +-
 src/lib/util/time_utilities.h                      |    8 +-
 src/lib/util/unittests/Makefile.am                 |    1 +
 .../unittests/{resource.cc => check_valgrind.cc}   |   28 +-
 src/lib/util/unittests/check_valgrind.h            |   50 ++
 src/lib/util/unittests/fork.h                      |    6 +-
 src/lib/util/unittests/mock_socketsession.h        |    6 +-
 src/lib/util/unittests/newhook.h                   |    6 +-
 src/lib/util/unittests/resource.h                  |    6 +-
 src/lib/util/unittests/run_all.h                   |    6 +-
 src/lib/util/unittests/testdata.h                  |    6 +-
 src/lib/util/unittests/textdata.h                  |    6 +-
 src/lib/util/unittests/wiredata.h                  |    6 +-
 src/lib/xfr/xfrout_client.h                        |    4 +-
 tests/lettuce/configurations/auth/.gitignore       |    1 +
 .../auth_basic.config.orig}                        |    5 +-
 tests/lettuce/features/auth_basic.feature          |   20 +
 tests/lettuce/features/ddns_system.feature         |    7 +-
 .../lettuce/features/inmemory_over_sqlite3.feature |    2 +-
 tests/lettuce/features/terrain/terrain.py          |    2 +
 tests/tools/badpacket/command_options.h            |    6 +-
 tests/tools/badpacket/header_flags.h               |    6 +-
 tests/tools/badpacket/option_info.h                |    6 +-
 tests/tools/badpacket/scan.h                       |    6 +-
 tests/tools/badpacket/version.h                    |    6 +-
 tests/tools/perfdhcp/command_options.cc            |    5 +-
 tests/tools/perfdhcp/command_options.h             |    6 +-
 tests/tools/perfdhcp/localized_option.h            |    6 +-
 tests/tools/perfdhcp/perf_pkt4.h                   |    6 +-
 tests/tools/perfdhcp/perf_pkt6.h                   |    6 +-
 tests/tools/perfdhcp/pkt_transform.h               |    6 +-
 tests/tools/perfdhcp/stats_mgr.h                   |    6 +-
 tests/tools/perfdhcp/test_control.h                |    8 +-
 .../tools/perfdhcp/tests/command_options_helper.h  |    6 +-
 440 files changed, 17012 insertions(+), 4901 deletions(-)
 create mode 100644 examples/m4/ax_isc_rpath.m4
 create mode 100644 src/bin/auth/datasrc_clients_mgr.h
 create mode 100644 src/bin/auth/statistics_items.h
 create mode 100644 src/bin/auth/tests/datasrc_clients_builder_unittest.cc
 create mode 100644 src/bin/auth/tests/datasrc_clients_mgr_unittest.cc
 create mode 100644 src/bin/auth/tests/test_datasrc_clients_mgr.cc
 create mode 100644 src/bin/auth/tests/test_datasrc_clients_mgr.h
 create mode 100644 src/bin/cfgmgr/local_plugins/Makefile.am
 copy src/bin/{loadzone/run_loadzone.sh.in => sysinfo/run_sysinfo.sh.in} (60%)
 copy src/lib/datasrc/memory/{zone_table_segment_local.cc => load_action.h} (52%)
 create mode 100644 src/lib/datasrc/memory/zone_data_loader.cc
 create mode 100644 src/lib/datasrc/memory/zone_data_loader.h
 create mode 100644 src/lib/datasrc/memory/zone_data_updater.cc
 create mode 100644 src/lib/datasrc/memory/zone_data_updater.h
 create mode 100644 src/lib/datasrc/memory/zone_writer.h
 create mode 100644 src/lib/datasrc/memory/zone_writer_local.cc
 create mode 100644 src/lib/datasrc/memory/zone_writer_local.h
 create mode 100644 src/lib/datasrc/tests/memory/zone_table_segment_test.h
 create mode 100644 src/lib/datasrc/tests/memory/zone_writer_unittest.cc
 create mode 100644 src/lib/dhcp/alloc_engine.cc
 create mode 100644 src/lib/dhcp/alloc_engine.h
 create mode 100644 src/lib/dhcp/libdhcp++.dox
 create mode 100644 src/lib/dhcp/libdhcsrv.dox
 create mode 100644 src/lib/dhcp/memfile_lease_mgr.cc
 copy src/lib/dhcp/{tests/lease_mgr_unittest.cc => memfile_lease_mgr.h} (62%)
 create mode 100644 src/lib/dhcp/option6_int.h
 create mode 100644 src/lib/dhcp/option6_int_array.h
 create mode 100644 src/lib/dhcp/option_data_types.h
 create mode 100644 src/lib/dhcp/option_definition.cc
 create mode 100644 src/lib/dhcp/option_definition.h
 create mode 100644 src/lib/dhcp/tests/alloc_engine_unittest.cc
 create mode 100644 src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc
 create mode 100644 src/lib/dhcp/tests/option6_int_array_unittest.cc
 create mode 100644 src/lib/dhcp/tests/option6_int_unittest.cc
 create mode 100644 src/lib/dhcp/tests/option_definition_unittest.cc
 create mode 100644 src/lib/dns/master_lexer.cc
 create mode 100644 src/lib/dns/master_lexer.h
 create mode 100644 src/lib/dns/master_lexer_inputsource.cc
 create mode 100644 src/lib/dns/master_lexer_inputsource.h
 create mode 100644 src/lib/dns/tests/master_lexer_inputsource_unittest.cc
 create mode 100644 src/lib/dns/tests/master_lexer_token_unittest.cc
 create mode 100644 src/lib/dns/tests/master_lexer_unittest.cc
 delete mode 100644 src/lib/statistics/counter.cc
 delete mode 100644 src/lib/statistics/counter_dict.cc
 delete mode 100644 src/lib/util/threads/lock.h
 rename src/lib/util/threads/{lock.cc => sync.cc} (54%)
 create mode 100644 src/lib/util/threads/sync.h
 create mode 100644 src/lib/util/threads/tests/condvar_unittest.cc
 copy src/lib/util/unittests/{resource.cc => check_valgrind.cc} (67%)
 create mode 100644 src/lib/util/unittests/check_valgrind.h
 create mode 100644 tests/lettuce/configurations/auth/.gitignore
 copy tests/lettuce/configurations/{bindctl/bindctl.config.orig => auth/auth_basic.config.orig} (79%)
 create mode 100644 tests/lettuce/features/auth_basic.feature

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index b421f01..d69f499 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,83 @@
+501.	[func]      tomek
+	Added DHCPv6 allocation engine, now used in the processing of DHCPv6
+	messages.
+	(Trac #2414, git b3526430f02aa3dc3273612524d23137b8f1fe87)
+
+500.	[bug]		jinmei
+	Corrected the autoconf example in the examples directory so it can
+	use the configured path to Boost to check availability of the BIND 10
+	library.  Previously the sample configure script could fail if
+	Boost is installed in an uncommon place.  Also, it now provides a
+	helper m4 function and example usage for embedding the library
+	path to executable (using linker options like -Wl,-R) to help
+	minimize post-build hassles.
+	(Trac #2356, git 36514ddc884c02a063e166d44319467ce6fb1d8f)
+
+499.	[func]		team
+	The b10-auth 'loadzone' command now uses the internal thread
+	introduced in 495 to (re)load a zone in the background, so that
+	query processing isn't blocked while loading a zone.
+	(Trac #2213, git 686594e391c645279cc4a95e0e0020d1c01fba7e)
+
+498.	[func]		marcin
+	Implemented DHCPv6 option values configuration using configuration
+	manager. In order to set values for data fields carried by the
+	particular option, user specifies the string of hexadecimal digits
+	that is in turn converted to binary data and stored into option buffer.
+	More user friendly way of option content specification is planned.
+	(Trac #2318, git e75c686cd9c14f4d6c2a242a0a0853314704fee9)
+
+497.	[bug]		jinmei
+	Fixed several issues in isc-sysinfo:
+	- make sure it doesn't report a negative value for free memory
+	  size (this happened on FreeBSD, but can possibly occur on other
+	  BSD variants)
+	- correctly identifies the SMP support in kernel on FreeBSD
+	- print more human readable uptime as well as the time in seconds
+	(Trac #2297, git 59a449f506948e2371ffa87dcd19059388bd1657)
+
+496.	[func]		tomek
+	DHCPv6 Allocation Engine implemented. It allows address allocation
+	from the configured subnets/pools. It currently features a single
+	allocator: IterativeAllocator, which assigns addresses iteratively.
+	Other allocators (hashed, random) are planned.
+	(Trac #2324, git 8aa188a10298e3a55b725db36502a99d2a8d638a)
+
+495.	[func]		team
+	b10-auth now handles reconfiguration of data sources in
+	background using a separate thread.  This means even if the new
+	configuration includes a large amount of data to be loaded into
+	memory (very large zones and/or a very large number of zones),
+	the reconfiguration doesn't block query handling.
+	(Multiple Trac tickets up to #2211)
+
+494.	[bug]		jinmei
+	Fixed a problem that shutting down BIND 10 kept some of the
+	processes alive.  It was two-fold: when the main bind10 process
+	started as a root, started b10-sockcreator with the privilege, and
+	then dropped the privilege, the bind10 process cannot kill the
+	sockcreator via signal any more (when it has to), but it kept
+	sending the signal and didn't stop.  Also, when running on Python
+	3.1 (or older), the sockcreator had some additional file
+	descriptor open, which prevented it from exiting even after the
+	bind10 process terminated.  Now the bind10 process simply gives up
+	killing a subprocess if it fails due to lack of permission, and it
+	makes sure the socket creator is spawned without any unnecessary
+	FDs open.
+	(Trac #1858, git 405d85c8a0042ba807a3a123611ff383c4081ee1)
+
+493.	[build]		jinmei
+	Fixed build failure with newer versions of clang++.  These
+	versions are stricter regarding "unused variable" and "unused
+	(driver) arguments" warnings, and cause fatal build error
+	with -Werror.  The affected versions of clang++ include Apple's
+	customized version 4.1 included in Xcode 4.5.1.  So this fix
+	will solve build errors for Mac OS X that uses newer versions of
+	Xcode.
+	(Trac #2340, git 55be177fc4f7537143ab6ef5a728bd44bdf9d783,
+	3e2a372012e633d017a97029d13894e743199741 and commits before it
+	with [2340] in the commit log)
+
 492.	[func]		tomek
 	libdhcpsrv: The DHCP Configuration Manager is now able to store
 	information about IPv4 subnets and pools. It is still not possible
@@ -27,7 +107,7 @@
 
 488.	[build]		jinmei
 	On configure, changed the search order for Python executable.
-	It first ties more specific file names such as "python3.2" before
+	It first tries more specific file names such as "python3.2" before
 	more generic "python3".  This will prevent configure failure on
 	Mac OS X that installs Python3 via recent versions of Homebrew.
 	(Trac #2339, git 88db890d8d1c64de49be87f03c24a2021bcf63da)
diff --git a/Makefile.am b/Makefile.am
index 1ed0d63..2f3ce85 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-ACLOCAL_AMFLAGS = -I m4macros ${ACLOCAL_FLAGS}
+ACLOCAL_AMFLAGS = -I m4macros -I examples/m4 ${ACLOCAL_FLAGS}
 # ^^^^^^^^ This has to be the first line and cannot come later in this
 # Makefile.am due to some bork in some versions of autotools.
 
diff --git a/configure.ac b/configure.ac
index 1c7c0d8..f432499 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,6 +12,20 @@ AC_CONFIG_MACRO_DIR([m4macros])
 # Checks for programs.
 AC_PROG_CXX
 
+# Enable low-performing debugging facilities? This option optionally
+# enables some debugging aids that perform slowly and hence aren't built
+# by default.
+AC_ARG_ENABLE([debug],
+  AS_HELP_STRING([--enable-debug],
+    [enable debugging (default is no)]),
+  [case "${enableval}" in
+    yes) debug_enabled=yes ;;
+    no)  debug_enabled=no ;;
+    *)   AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
+  esac],[debug_enabled=no])
+AM_CONDITIONAL([DEBUG_ENABLED], [test x$debug_enabled = xyes])
+AM_COND_IF([DEBUG_ENABLED], [AC_DEFINE([ENABLE_DEBUG], [1], [Enable low-performing debugging facilities?])])
+
 # Libtool configuration
 #
 
@@ -50,25 +64,9 @@ AM_CONDITIONAL(USE_CLANGPP, test "X${CLANGPP}" = "Xyes")
 
 # Linker options
 
-# check -R and -Wl,-R rather than gcc specific -rpath to be as portable
-# as possible.
-AC_MSG_CHECKING([whether -R flag is available in linker])
-LDFLAGS_SAVED="$LDFLAGS"
-LDFLAGS="$LDFLAGS -R/usr/lib"
-AC_TRY_LINK([],[],
-    [ AC_MSG_RESULT(yes)
-        rpath_flag=-R
-    ],[ AC_MSG_RESULT(no)
-        AC_MSG_CHECKING([whether -Wl,-R flag is available in linker])
-        LDFLAGS="$LDFLAGS_SAVED -Wl,-R"
-        AC_TRY_LINK([], [],
-            [ AC_MSG_RESULT(yes)
-                rpath_flag=-Wl,-R
-            ],[ AC_MSG_RESULT(no)
-                 rpath_flag=no
-            ])
-    ])
-LDFLAGS=$LDFLAGS_SAVED
+# check -R, "-Wl,-R" or -rpath (we share the AX function defined in
+#  examples/m4)
+AX_ISC_RPATH
 
 # Compiler dependent settings: define some mandatory CXXFLAGS here.
 # We also use a separate variable B10_CXXFLAGS.  This will (and should) be
@@ -203,6 +201,10 @@ case "$host" in
 	CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
 	# "now" binding is necessary to prevent deadlocks in C++ static initialization code
 	LDFLAGS="$LDFLAGS -z now"
+	# Destroying locked mutexes, condition variables being waited
+	# on, etc. are undefined behavior on Solaris, so we set it as
+	# such here.
+	AC_DEFINE([HAS_UNDEFINED_PTHREAD_BEHAVIOR], [1], [Does this platform have some undefined pthreads behavior?])
 	;;
 *-apple-darwin*)
 	# Starting with OSX 10.7 (Lion) we must choose which IPv6 API to use
@@ -314,10 +316,10 @@ fi
 # modules, we embed the path to the modules when possible.  We do this even
 # when the path is known in the common operational environment (e.g. when
 # it's stored in a common "hint" file) for simplicity.
-if test $rpath_flag != no; then
+if test "x$ISC_RPATH_FLAG" != "x"; then
 	python_rpath=
 	for flag in ${PYTHON_LDFLAGS}; do
-		python_rpath="${python_rpath} `echo $flag | sed -ne "s/^\(\-L\)/${rpath_flag}/p"`"
+		python_rpath="${python_rpath} `echo $flag | sed -ne "s/^\(\-L\)/${ISC_RPATH_FLAG}/p"`"
 	done
 	PYTHON_LDFLAGS="${PYTHON_LDFLAGS} ${python_rpath}"
 fi
@@ -683,10 +685,10 @@ for flag in ${BOTAN_LIBS}; do
 done
 
 # See python_rpath for some info on why we do this
-if test $rpath_flag != no; then
+if test "x$ISC_RPATH_FLAG" != "x"; then
     BOTAN_RPATH=
     for flag in ${BOTAN_LIBS}; do
-            BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne "s/^\(\-L\)/${rpath_flag}/p"`"
+            BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne "s/^\(\-L\)/${ISC_RPATH_FLAG}/p"`"
     done
 AC_SUBST(BOTAN_RPATH)
 
@@ -1121,6 +1123,13 @@ AM_COND_IF([ENABLE_LOGGER_CHECKS], [AC_DEFINE([ENABLE_LOGGER_CHECKS], [1], [Chec
 AC_PATH_PROG(VALGRIND, valgrind, no)
 AM_CONDITIONAL(HAVE_VALGRIND, test "x$VALGRIND" != "xno")
 
+# Also check for valgrind headers
+# We could consider adding them to the source code tree, as this
+# is the encouraged method of using them; they are BSD-licensed.
+# However, until we find that this is a problem, we just use
+# the system-provided ones, if available
+AC_CHECK_HEADERS(valgrind/valgrind.h, [AC_DEFINE([HAVE_VALGRIND_HEADERS], [1], [Check valgrind headers])])
+
 found_valgrind="not found"
 if test "x$VALGRIND" != "xno"; then
    found_valgrind="found"
@@ -1159,6 +1168,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/bindctl/Makefile
                  src/bin/bindctl/tests/Makefile
                  src/bin/cfgmgr/Makefile
+                 src/bin/cfgmgr/local_plugins/Makefile
                  src/bin/cfgmgr/plugins/Makefile
                  src/bin/cfgmgr/plugins/tests/Makefile
                  src/bin/cfgmgr/tests/Makefile
@@ -1327,6 +1337,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
            src/bin/sysinfo/sysinfo.py
+           src/bin/sysinfo/run_sysinfo.sh
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
            src/bin/bind10/bind10_src.py
@@ -1405,6 +1416,7 @@ AC_OUTPUT([doc/version.ent
            chmod +x src/bin/loadzone/run_loadzone.sh
            chmod +x src/bin/loadzone/tests/correct/correct_test.sh
            chmod +x src/bin/loadzone/tests/error/error_test.sh
+           chmod +x src/bin/sysinfo/run_sysinfo.sh
            chmod +x src/bin/usermgr/run_b10-cmdctl-usermgr.sh
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/msgq/tests/msgq_test
@@ -1480,6 +1492,7 @@ Features:
   $enable_features
 
 Developer:
+  Enable Debugging: $debug_enabled
   Google Tests: $enable_gtest
   Valgrind: $found_valgrind
   C++ Code Coverage: $USE_LCOV
diff --git a/doc/Doxyfile b/doc/Doxyfile
index f6b9fa0..cc3b595 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -580,7 +580,7 @@ INPUT                  = ../src/lib/exceptions ../src/lib/cc \
     ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
     ../src/bin/sockcreator/ ../src/lib/util/ ../src/lib/util/io/ \
     ../src/lib/util/threads/ ../src/lib/resolve ../src/lib/acl \
-    ../src/bin/dhcp6 ../src/lib/dhcp ../src/bin/dhcp4 \
+    ../src/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/bin/dhcp4 \
     ../tests/tools/perfdhcp devel
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/doc/devel/02-dhcp.dox b/doc/devel/02-dhcp.dox
index a4bbff9..5c59daa 100644
--- a/doc/devel/02-dhcp.dox
+++ b/doc/devel/02-dhcp.dox
@@ -57,76 +57,4 @@
  * that does not support msgq. That is useful for embedded environments.
  * It may also be useful in validation.
  *
- * @page libdhcp libdhcp++
- *
- * @section libdhcpIntro Libdhcp++ Library Introduction
- *
- * libdhcp++ is an all-purpose DHCP-manipulation library, written in
- * C++. It offers packet parsing and assembly, DHCPv4 and DHCPv6
- * options parsing and ssembly, interface detection (currently on
- * Linux systems only) and socket operations. Following classes are
- * implemented:
- *
- * - isc::dhcp::Pkt4 - represents DHCPv4 packet.
- * - isc::dhcp::Pkt6 - represents DHCPv6 packet.
- *
- * There are two pointer types defined: Pkt4Ptr and Pkt6Ptr. They are
- * smart pointer and are using boost::shared_ptr. There are not const
- * versions defined, as we assume that hooks can modify any aspect of
- * the packet at almost any stage of processing.
- *
- * Both packets use collection of Option objects to represent DHCPv4
- * and DHCPv6 options. The base class -- Option -- can be used to
- * represent generic option that contains collection of
- * bytes. Depending on if the option is instantiated as v4 or v6
- * option, it will adjust its header (DHCPv4 options use 1 octet for
- * type and 1 octet for length, while DHCPv6 options use 2 bytes for
- * each).
- *
- * There are many specialized classes that are intended to handle options with
- * specific content:
- * - isc::dhcp::Option4AddrLst -- DHCPv4 option, contains one or more IPv4 addresses;
- * - isc::dhcp::Option6AddrLst -- DHCPv6 option, contains one or more IPv6 addresses;
- * - isc::dhcp::Option6IAAddr -- DHCPv6 option, represents IAADDR_OPTION (an option that
- *                     contains IPv6 address with extra parameters);
- * - isc::dhcp::Option6IA -- DHCPv6 option used to store IA_NA and its suboptions.
- *
- * All options can store sub-options (i.e. options that are stored within option
- * rather than in a message directly). This functionality is commonly used in
- * DHCPv6, but is rarely used in DHCPv4. isc::dhcp::Option::addOption(),
- * isc::dhcp::Option::delOption(), isc::dhcp::Option::getOption() can be used
- * for that purpose.
- *
- * @section libdhcpIfaceMgr Interface Manager
- *
- * Interface Manager (or IfaceMgr) is an abstraction layer about low-level
- * network operations. In particlar, it provides information about existing
- * network interfaces See isc::dhcp::IfaceMgr::Iface class and
- * isc::dhcp::IfaceMgr::detectIfaces() and isc::dhcp::IfaceMgr::getIface().
- *
- * Currently there is interface detection is implemented in Linux only. There
- * are plans to implement such support for other OSes, but they remain low
- * priority for now.
- *
- * Generic parts of the code are isc::dhcp::IfaceMgr class in
- * src/lib/dhcp/iface_mgr.cc file. OS-specific code is located in separate
- * files, e.g. iface_mgr_linux.cc. Such separation should be maintained when
- * additional code will be developed.
- *
- * For systems that interface detection is not supported on, there is a stub
- * mechanism implemented. It assumes that interface name is read from a text
- * file. This is a temporary solution and will be removed as soon as proper
- * interface detection is implemented. It is not going to be developed further.
- * To use this feature, store interfaces.txt file. It uses a simple syntax.
- * Each line represents an interface name, followed by IPv4 or IPv6 address
- * that follows it. This is usually link-local IPv6 address that the server
- * should bind to. In theory this mechanism also supports IPv4, but it was
- * never tested. The code currently supports only a single interface defined
- * that way.
- *
- * Another useful methods are dedicated to transmission
- * (isc::dhcp::IfaceMgr::send(), 2 overloads) and reception
- * (isc::dhcp::IfaceMgr::receive4() and isc::dhcp::IfaceMgr::receive6()).
- * 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/doc/devel/mainpage.dox b/doc/devel/mainpage.dox
index a36d227..db42c14 100644
--- a/doc/devel/mainpage.dox
+++ b/doc/devel/mainpage.dox
@@ -29,6 +29,10 @@
  * - @subpage libdhcp
  *   - @subpage libdhcpIntro
  *   - @subpage libdhcpIfaceMgr
+ * - @subpage libdhcpsrv
+ *   - @subpage leasemgr
+ *   - @subpage cfgmgr
+ *   - @subpage allocengine
  * - @subpage dhcp-database-backends
  * - @subpage perfdhcpInternals
  *
diff --git a/examples/README b/examples/README
index 65f777b..08f53fa 100644
--- a/examples/README
+++ b/examples/README
@@ -30,3 +30,18 @@ to the configure.ac file:
 sinclude(m4/ax_boost_include.m4)
 sinclude(m4/ax_isc_bind10.m4)
 (and same for other m4 files as they are added under m4/)
+
+On some systems, espeically if you have installed the BIND 10
+libraries in an uncommon path, programs linked with the BIND 10
+library may not work at run time due to the "missing" shared library.
+Normally, you should be able to avoid this problem by making sure
+to invoking the program explicitly specifying the path to the library,
+e.g., "LD_LIBRARY_PATH=/usr/local/lib/bind10 ./my_bind10_app", or
+you may not even notice the issue if you have installed BIND 10
+library in a common library path on your system (sometimes you may
+still need to run ldconfig(8) beforehand).  Another option is to embed
+the path to the library in your program.  While this approach is
+controversial, and some people rather choose the alternatives, we
+provide a helper tool in case you want to use this option: see the
+lines using BIND10_RPATH in the sample configure.ac file of this
+directory.
diff --git a/examples/configure.ac b/examples/configure.ac
index 9379687..37515d9 100644
--- a/examples/configure.ac
+++ b/examples/configure.ac
@@ -14,7 +14,21 @@ AC_LANG([C++])
 # Checks for BIND 10 headers and libraries
 AX_ISC_BIND10
 
-# For the example host program, we require the BIND 10 DNS library
+# We use -R, -rpath 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.
+if test "x$BIND10_RPATH" != "x"; then
+   LDFLAGS="$LDFLAGS $BIND10_RPATH"
+fi
+
+# For the example host program, we require some socket API library
+# and the BIND 10 DNS library.
+
+# In practice, these are specific to Solaris, but wouldn't do any harm for
+# others except for the checking overhead.
+AC_SEARCH_LIBS(inet_pton, [nsl])
+AC_SEARCH_LIBS(recvfrom, [socket])
+
 if test "x$BIND10_DNS_LIB" = "x"; then
    AC_MSG_ERROR([unable to find BIND 10 DNS library needed to build 'host'])
 fi
diff --git a/examples/m4/ax_boost_include.m4 b/examples/m4/ax_boost_include.m4
index e41614d..77d19ca 100644
--- a/examples/m4/ax_boost_include.m4
+++ b/examples/m4/ax_boost_include.m4
@@ -34,7 +34,7 @@ if test -z "$with_boost_include"; then
 		fi
 	done
 fi
-CPPFLAGS_SAVES="$CPPFLAGS"
+CPPFLAGS_SAVED="$CPPFLAGS"
 if test "${boost_include_path}" ; then
 	BOOST_CPPFLAGS="-I${boost_include_path}"
 	CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
@@ -57,7 +57,7 @@ AC_TRY_COMPILE([
  CPPFLAGS_BOOST_THREADCONF="-DBOOST_DISABLE_THREADS=1"],
 [AC_MSG_RESULT(yes)])
 
-CPPFLAGS="$CPPFLAGS_SAVES $CPPFLAGS_BOOST_THREADCONF"
+CPPFLAGS="$CPPFLAGS_SAVED $CPPFLAGS_BOOST_THREADCONF"
 AC_SUBST(BOOST_CPPFLAGS)
 
 AC_LANG_RESTORE
diff --git a/examples/m4/ax_isc_bind10.m4 b/examples/m4/ax_isc_bind10.m4
index 63e028c..75c37c5 100644
--- a/examples/m4/ax_isc_bind10.m4
+++ b/examples/m4/ax_isc_bind10.m4
@@ -1,4 +1,4 @@
-dnl @synopsis AX_BIND10
+dnl @synopsis AX_ISC_BIND10
 dnl
 dnl @summary figure out how to build C++ programs using ISC BIND 10 libraries
 dnl
@@ -20,9 +20,18 @@ dnl Checks for other BIND 10 module libraries are option, as not all
 dnl applications need all libraries.  The main configure.ac can handle any
 dnl missing library as fatal by checking whether the corresponding
 dnl BIND10_xxx_LIB is defined.
+dnl
+dnl In addition, it sets the BIND10_RPATH variable to a usable linker option
+dnl to embed the path to the BIND 10 library to the programs that are to be
+dnl linked with the library.  If the developer wants to use the option,
+dnl it can be used as follows:
+dnl if test "x$BIND10_RPATH" != "x"; then
+dnl     LDFLAGS="$LDFLAGS $BIND10_RPATH"
+dnl fi
 
 AC_DEFUN([AX_ISC_BIND10], [
 AC_REQUIRE([AX_BOOST_INCLUDE])
+AC_REQUIRE([AX_ISC_RPATH])
 AC_LANG_SAVE
 AC_LANG([C++])
 
@@ -42,19 +51,20 @@ if test "$bind10_inc_path" = "no"; then
 	fi
    done
 fi
-CPPFLAGS_SAVES="$CPPFLAGS"
+CPPFLAGS_SAVED="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" # boost headers will be used in buffer.h
 if test "${bind10_inc_path}" != "no"; then
    BIND10_CPPFLAGS="-I${bind10_inc_path}"
    CPPFLAGS="$CPPFLAGS $BIND10_CPPFLAGS"
 fi
 AC_CHECK_HEADERS([util/buffer.h],,
-  AC_MSG_ERROR([Missing a commonly used BIND 10 header files]))
-CPPFLAGS="$CPPFLAGS_SAVES"
+  AC_MSG_ERROR([Missing a commonly used BIND 10 header file]))
+CPPFLAGS="$CPPFLAGS_SAVED"
 AC_SUBST(BIND10_CPPFLAGS)
 
 # Check for BIND10 libraries
 CPPFLAGS_SAVED="$CPPFLAGS"
-CPPFLAGS="$CPPFLAGS $BIND10_CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS $BIND10_CPPFLAGS"
 
 AC_ARG_WITH(bind10-lib,
   AS_HELP_STRING([--with-bind10-lib=PATH],
@@ -70,21 +80,25 @@ fi
 # make sure we have buildable libraries
 AC_MSG_CHECKING([for BIND 10 common library])
 BIND10_COMMON_LIB="-lb10-util -lb10-exceptions"
-LDFLAGS="$LDFLAGS $BIND10_LDFLAGS"
+LDFLAGS_SAVED="$LDFLAGS"
+LDFLAGS_CHECK_COMMON="$LDFLAGS $BIND10_LDFLAGS"
+LIBS_SAVED="$LIBS"
 LIBS="$LIBS $BIND10_COMMON_LIB"
 for d in $bind10_lib_dirs
 do
-  LDFLAGS_SAVED="$LDFLAGS"
-  LDFLAGS="$LDFLAGS -L$d"
+  LDFLAGS="$LDFLAGS_CHECK_COMMON -L$d"
   AC_TRY_LINK([
 #include <util/buffer.h>
 ],[
 isc::util::OutputBuffer buffer(0);
-], [BIND10_LDFLAGS="-L${d}"])
+], [BIND10_LDFLAGS="-L${d}"
+    if test "x$ISC_RPATH_FLAG" != "x"; then
+       BIND10_RPATH="${ISC_RPATH_FLAG}${d}"
+    fi
+    ])
   if test "x$BIND10_LDFLAGS" != "x"; then
      break
   fi
-  LDFLAGS="$LDFLAGS_SAVED"
 done
 if test "x$BIND10_LDFLAGS" != "x"; then
   AC_MSG_RESULT(yes)
@@ -94,7 +108,7 @@ else
 fi
 
 # restore LIBS once at this point
-LIBS="$LIBS_SAVES"
+LIBS="$LIBS_SAVED"
 
 AC_SUBST(BIND10_LDFLAGS)
 AC_SUBST(BIND10_COMMON_LIB)
@@ -111,12 +125,12 @@ isc::dns::RRType rrtype(1);
 ], [BIND10_DNS_LIB="-lb10-dns++"
     AC_MSG_RESULT(yes)],
    [AC_MSG_RESULT(no)])
-LIBS="$LIBS_SAVES"
+LIBS="$LIBS_SAVED"
 AC_SUBST(BIND10_DNS_LIB)
 
 # Restore other flags
 CPPFLAGS="$CPPFLAGS_SAVED"
-LDFLAGS="$LDFLAGS_SAVES"
+LDFLAGS="$LDFLAGS_SAVED"
 
 AC_LANG_RESTORE
 ])dnl AX_ISC_BIND10
diff --git a/examples/m4/ax_isc_rpath.m4 b/examples/m4/ax_isc_rpath.m4
new file mode 100644
index 0000000..91d9b8a
--- /dev/null
+++ b/examples/m4/ax_isc_rpath.m4
@@ -0,0 +1,46 @@
+dnl @synopsis AX_ISC_RPATH
+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 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
+
+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"
+
+# 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
+
+])dnl AX_ISC_RPATH
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 9eee9d4..7d29fcc 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -54,7 +54,8 @@ 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
+b10_auth_SOURCES += statistics.cc statistics.h statistics_items.h
+b10_auth_SOURCES += datasrc_clients_mgr.h
 b10_auth_SOURCES += datasrc_config.h datasrc_config.cc
 b10_auth_SOURCES += main.cc
 
@@ -73,7 +74,6 @@ b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 b10_auth_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
 b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
-b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 b10_auth_LDADD += $(top_builddir)/src/lib/util/threads/libb10-threads.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 
diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in
index a471b7a..30a455d 100644
--- a/src/bin/auth/auth.spec.pre.in
+++ b/src/bin/auth/auth.spec.pre.in
@@ -145,7 +145,7 @@
         "item_type": "integer",
         "item_optional": false,
         "item_default": 0,
-        "item_title": "Queries TCP ",
+        "item_title": "Queries TCP",
         "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
       },
       {
@@ -181,14 +181,6 @@
         "item_description": "The number of total request counts whose opcode is status"
       },
       {
-        "item_name": "opcode.reserved3",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 3",
-        "item_description": "The number of total request counts whose opcode is 3 (reserved)"
-      },
-      {
         "item_name": "opcode.notify",
         "item_type": "integer",
         "item_optional": true,
@@ -205,84 +197,12 @@
         "item_description": "The number of total request counts whose opcode is update"
       },
       {
-        "item_name": "opcode.reserved6",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 6",
-        "item_description": "The number of total request counts whose opcode is 6 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved7",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 7",
-        "item_description": "The number of total request counts whose opcode is 7 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved8",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 8",
-        "item_description": "The number of total request counts whose opcode is 8 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved9",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 9",
-        "item_description": "The number of total request counts whose opcode is 9 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved10",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 10",
-        "item_description": "The number of total request counts whose opcode is 10 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved11",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 11",
-        "item_description": "The number of total request counts whose opcode is 11 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved12",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 12",
-        "item_description": "The number of total request counts whose opcode is 12 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved13",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 13",
-        "item_description": "The number of total request counts whose opcode is 13 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved14",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 0,
-        "item_title": "Received requests opcode 14",
-        "item_description": "The number of total request counts whose opcode is 14 (reserved)"
-      },
-      {
-        "item_name": "opcode.reserved15",
+        "item_name": "opcode.other",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Received requests opcode 15",
-        "item_description": "The number of total request counts whose opcode is 15 (reserved)"
+        "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",
@@ -373,52 +293,68 @@
         "item_description": "The number of total responses with rcode 10 (NOTZONE)"
       },
       {
-        "item_name": "rcode.reserved11",
+        "item_name": "rcode.badsigvers",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Sent response with rcode 11",
-        "item_description": "The number of total responses with rcode 11 (reserved)"
+        "item_title": "Sent 'EDNS version not implemented' response",
+        "item_description": "The number of total responses with rcode 16 (BADVERS)"
       },
       {
-        "item_name": "rcode.reserved12",
+        "item_name": "rcode.badkey",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Sent response with rcode 12",
-        "item_description": "The number of total responses with rcode 12 (reserved)"
+        "item_title": "Sent 'Key not recognized' response",
+        "item_description": "The number of total responses with rcode 17 (BADKEY)"
       },
       {
-        "item_name": "rcode.reserved13",
+        "item_name": "rcode.badtime",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Sent response with rcode 13",
-        "item_description": "The number of total responses with rcode 13 (reserved)"
+        "item_title": "Sent 'Signature out of time window' response",
+        "item_description": "The number of total responses with rcode 18 (BADTIME)"
       },
       {
-        "item_name": "rcode.reserved14",
+        "item_name": "rcode.badmode",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Sent response with rcode 14",
-        "item_description": "The number of total responses with rcode 14 (reserved)"
+        "item_title": "Sent 'Bad TKEY Mode' response",
+        "item_description": "The number of total responses with rcode 19 (BADMODE)"
       },
       {
-        "item_name": "rcode.reserved15",
+        "item_name": "rcode.badname",
         "item_type": "integer",
         "item_optional": true,
         "item_default": 0,
-        "item_title": "Sent response with rcode 15",
-        "item_description": "The number of total responses with rcode 15 (reserved)"
+        "item_title": "Sent 'Duplicate key name' response",
+        "item_description": "The number of total responses with rcode 20 (BADNAME)"
       },
       {
-        "item_name": "rcode.badvers",
+        "item_name": "rcode.badalg",
         "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_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.h b/src/bin/auth/auth_config.h
index 8e816a3..57fd270 100644
--- a/src/bin/auth/auth_config.h
+++ b/src/bin/auth/auth_config.h
@@ -18,8 +18,8 @@
 
 #include <cc/data.h>
 
-#ifndef __CONFIG_H
-#define __CONFIG_H 1
+#ifndef CONFIG_H
+#define CONFIG_H 1
 
 class AuthSrv;
 
@@ -195,7 +195,7 @@ void configureAuthServer(AuthSrv& server,
 AuthConfigParser* createAuthConfigParser(AuthSrv& server,
                                          const std::string& config_id);
 
-#endif // __CONFIG_H
+#endif // CONFIG_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/auth_log.cc b/src/bin/auth/auth_log.cc
index d41eaea..fae7bd3 100644
--- a/src/bin/auth/auth_log.cc
+++ b/src/bin/auth/auth_log.cc
@@ -21,6 +21,12 @@ namespace auth {
 
 isc::log::Logger auth_logger("auth");
 
+const int DBG_AUTH_START = DBGLVL_START_SHUT;
+const int DBG_AUTH_SHUT = DBGLVL_START_SHUT;
+const int DBG_AUTH_OPS = DBGLVL_COMMAND;
+const int DBG_AUTH_DETAIL = DBGLVL_TRACE_BASIC;
+const int DBG_AUTH_MESSAGES = DBGLVL_TRACE_DETAIL_DATA;
+
 } // namespace auth
 } // namespace isc
 
diff --git a/src/bin/auth/auth_log.h b/src/bin/auth/auth_log.h
index 33d4432..52b973e 100644
--- a/src/bin/auth/auth_log.h
+++ b/src/bin/auth/auth_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __AUTH_LOG__H
-#define __AUTH_LOG__H
+#ifndef AUTH_LOG_H
+#define AUTH_LOG_H
 
 #include <log/macros.h>
 #include <auth/auth_messages.h>
@@ -28,21 +28,21 @@ namespace auth {
 /// output.
 
 // Debug messages indicating normal startup are logged at this debug level.
-const int DBG_AUTH_START = DBGLVL_START_SHUT;
+extern const int DBG_AUTH_START;
 // Debug messages upon shutdown
-const int DBG_AUTH_SHUT = DBGLVL_START_SHUT;
+extern const int DBG_AUTH_SHUT;
 
 // Debug level used to log setting information (such as configuration changes).
-const int DBG_AUTH_OPS = DBGLVL_COMMAND;
+extern const int DBG_AUTH_OPS;
 
 // Trace detailed operations, including errors raised when processing invalid
 // packets.  (These are not logged at severities of WARN or higher for fear
 // that a set of deliberately invalid packets set to the authoritative server
 // could overwhelm the logging.)
-const int DBG_AUTH_DETAIL = DBGLVL_TRACE_BASIC;
+extern const int DBG_AUTH_DETAIL;
 
 // This level is used to log the contents of packets received and sent.
-const int DBG_AUTH_MESSAGES = DBGLVL_TRACE_DETAIL_DATA;
+extern const int DBG_AUTH_MESSAGES;
 
 /// Define the logger for the "auth" module part of b10-auth.  We could define
 /// a logger in each file, but we would want to define a common name to avoid
@@ -53,4 +53,4 @@ extern isc::log::Logger auth_logger;
 } // namespace nsas
 } // namespace isc
 
-#endif // __AUTH_LOG__H
+#endif // AUTH_LOG_H
diff --git a/src/bin/auth/auth_messages.mes b/src/bin/auth/auth_messages.mes
index ae7be1e..3780499 100644
--- a/src/bin/auth/auth_messages.mes
+++ b/src/bin/auth/auth_messages.mes
@@ -47,16 +47,116 @@ available. It is issued during server startup is an indication that
 the initialization is proceeding normally.
 
 % AUTH_CONFIG_LOAD_FAIL load of configuration failed: %1
-An attempt to configure the server with information from the configuration
-database during the startup sequence has failed. (The reason for
-the failure is given in the message.) The server will continue its
-initialization although it may not be configured in the desired way.
+An attempt to configure the server with information from the
+configuration database during the startup sequence has failed.  The
+server will continue its initialization although it may not be
+configured in the desired way.  The reason for the failure is given in
+the message.  One common reason is that the server failed to acquire a
+socket bound to a privileged port (53 for DNS).  In that case the
+reason in the log message should show something like "permission
+denied", and the solution would be to restart BIND 10 as a super
+(root) user.
 
 % AUTH_CONFIG_UPDATE_FAIL update of configuration failed: %1
 At attempt to update the configuration the server with information
 from the configuration database has failed, the reason being given in
 the message.
 
+% AUTH_DATASRC_CLIENTS_BUILDER_COMMAND data source builder received command: %1
+A debug message, showing when the separate thread for maintaining data
+source clients receives a command from the manager.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_COMMAND_ERROR command execution failure: %1
+The separate thread for maintaining data source clients failed to complete a
+command given by the main thread.  In most cases this is some kind of
+configuration or temporary error such as an attempt to load a non-existent
+zone or a temporary DB connection failure.  So the event is just logged and
+the thread keeps running.  In some rare cases, however, this may indicate an
+internal bug and it may be better to restart the entire program, so the log
+message should be carefully examined.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_FAILED data source builder thread stopped due to an exception: %1
+The separate thread for maintaining data source clients has been
+terminated due to some uncaught exception.  When this happens, the
+thread immediately terminates the entire process because the manager
+cannot always catch this condition in a timely fashion and it would be
+worse to keep running with such a half-broken state.  This is really
+an unexpected event and should generally indicate an internal bug.
+It's advisable to file a bug report when this message is logged (and
+b10-auth subsequently stops).
+
+% AUTH_DATASRC_CLIENTS_BUILDER_FAILED_UNEXPECTED data source builder thread stopped due to an unexpected exception
+This is similar to AUTH_DATASRC_CLIENTS_BUILDER_FAILED, but the
+exception type indicates it's not thrown either within the BIND 10
+implementation or other standard-compliant libraries.  This may rather
+indicate some run time failure than program errors.  As in the other
+failure case, the thread terminates the entire process immediately
+after logging this message.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE loaded zone %1/%2
+This debug message is issued when the separate thread for maintaining data
+source clients successfully loaded the named zone of the named class as a
+result of the 'loadzone' command.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_CONFIG_ERROR Error in data source configuration: %1
+The thread for maintaining data source clients has received a command to
+reconfigure, but the parameter data (the new configuration) contains an
+error. The most likely cause is that the datasource-specific configuration
+data is not what the data source expects. The system is still running with
+the data sources that were previously configured (i.e. as if the
+configuration has not changed), and the configuration data needs to be
+checked.
+The specific problem is printed in the log message.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_DATASRC_ERROR Error setting up data source: %1
+The thread for maintaining data source clients has received a command to
+reconfigure, but a data source failed to set up. This may be a problem with
+the data that is configured (e.g. unreadable files, inconsistent data,
+parser problems, database connection problems, etc.), but it could be a bug
+in the data source implementation as well. The system is still running with
+the data sources that were previously configured (i.e. as if the
+configuration has not changed).
+The specific problem is printed in the log message.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_ERROR Internal error setting up data source: %1
+The thread for maintaining data source clients has received a command to
+reconfigure, but raised an exception while setting up data sources. This is
+most likely an internal error in a data source, or a bug in the data source
+or the system itself, but it is probably a good idea to verify the
+configuration first. The system is still running with the data sources that
+were previously configured (i.e. as if the configuration has not changed).
+The specific problem is printed in the log message.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_STARTED data source reconfiguration started
+The thread for maintaining data source clients has received a command to
+reconfigure, and has now started this process.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_SUCCESS data source reconfiguration completed succesfully
+The thread for maintaining data source clients has finished reconfiguring
+the data source clients, and is now running with the new configuration.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_STARTED data source builder thread started
+A separate thread for maintaining data source clients has been started.
+
+% AUTH_DATASRC_CLIENTS_BUILDER_STOPPED data source builder thread stopped
+The separate thread for maintaining data source clients has been stopped.
+
+% AUTH_DATASRC_CLIENTS_SHUTDOWN_ERROR error on waiting for data source builder thread: %1
+This indicates that the separate thread for maintaining data source
+clients had been terminated due to an uncaught exception, and the
+manager notices that at its own termination.  This is not an expected
+event, because the thread is implemented so it catches all exceptions
+internally.  So, if this message is logged it's most likely some internal
+bug, and it would be nice to file a bug report.
+
+% AUTH_DATASRC_CLIENTS_SHUTDOWN_UNEXPECTED_ERROR Unexpected error on waiting for data source builder thread
+Some exception happens while waiting for the termination of the
+separate thread for maintaining data source clients.  This shouldn't
+happen in normal conditions; it should be either fatal system level
+errors such as severe memory shortage or some internal bug.  If that
+happens, and if it's not in the middle of terminating b10-auth, it's
+probably better to stop and restart it.
+
 % AUTH_DATA_SOURCE data source database file: %1
 This is a debug message produced by the authoritative server when it accesses a
 datebase data source, listing the file that is being accessed.
@@ -83,11 +183,6 @@ has requested the keyring holding TSIG keys from the configuration
 database. It is issued during server startup is an indication that the
 initialization is proceeding normally.
 
-% AUTH_LOAD_ZONE loaded zone %1/%2
-This debug message is issued during the processing of the 'loadzone' command
-when the authoritative server has successfully loaded the named zone of the
-named class.
-
 % AUTH_MEM_DATASRC_DISABLED memory data source is disabled for class %1
 This is a debug message reporting that the authoritative server has
 discovered that the memory data source is disabled for the given class.
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index e73eb52..dca8fd0 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -26,7 +26,6 @@
 #include <exceptions/exceptions.h>
 
 #include <util/buffer.h>
-#include <util/threads/lock.h>
 
 #include <dns/edns.h>
 #include <dns/exceptions.h>
@@ -53,6 +52,7 @@
 #include <auth/query.h>
 #include <auth/statistics.h>
 #include <auth/auth_log.h>
+#include <auth/datasrc_clients_mgr.h>
 
 #include <boost/bind.hpp>
 #include <boost/lexical_cast.hpp>
@@ -85,6 +85,7 @@ using namespace isc::xfr;
 using namespace isc::asiolink;
 using namespace isc::asiodns;
 using namespace isc::server_common::portconfig;
+using isc::auth::statistics::Counters;
 
 namespace {
 // A helper class for cleaning up message renderer.
@@ -260,7 +261,7 @@ public:
     AbstractSession* xfrin_session_;
 
     /// Query counters for statistics
-    AuthCounters counters_;
+    Counters counters_;
 
     /// Addresses we listen on
     AddressList listen_addresses_;
@@ -268,24 +269,8 @@ public:
     /// The TSIG keyring
     const shared_ptr<TSIGKeyRing>* keyring_;
 
-    /// The data source client list
-    AuthSrv::DataSrcClientListsPtr datasrc_client_lists_;
-
-    shared_ptr<ConfigurableClientList> getDataSrcClientList(
-        const RRClass& rrclass)
-    {
-        // TODO: Debug-build only check
-        if (!mutex_.locked()) {
-            isc_throw(isc::Unexpected, "Not locked!");
-        }
-        const std::map<RRClass, shared_ptr<ConfigurableClientList> >::
-            const_iterator it(datasrc_client_lists_->find(rrclass));
-        if (it == datasrc_client_lists_->end()) {
-            return (shared_ptr<ConfigurableClientList>());
-        } else {
-            return (it->second);
-        }
-    }
+    /// The data source client list manager
+    auth::DataSrcClientsMgr datasrc_clients_mgr_;
 
     /// Bind the ModuleSpec object in config_session_ with
     /// isc:config::ModuleSpec::validateStatistics.
@@ -301,29 +286,29 @@ public:
 
     /// \brief Resume the server
     ///
-    /// This is a wrapper call for DNSServer::resume(done), if 'done' is true,
-    /// the Rcode set in the given Message is counted in the statistics
-    /// counter.
+    /// This is a wrapper call for DNSServer::resume(done). Query/Response
+    /// statistics counters are incremented in this method.
     ///
     /// This method is expected to be called by processMessage()
     ///
     /// \param server The DNSServer as passed to processMessage()
     /// \param message The response as constructed by processMessage()
-    /// \param done If true, the Rcode from the given message is counted,
-    ///             this value is then passed to server->resume(bool)
+    /// \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,
-                      bool done);
-
-    mutable util::thread::Mutex mutex_;
+                      statistics::QRAttributes& stats_attrs,
+                      const bool done);
 
 private:
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
 
-    /// Increment query counter
-    void incCounter(const int protocol);
-
     // validateStatistics
     bool validateStatistics(isc::data::ConstElementPtr data) const;
 
@@ -336,8 +321,6 @@ AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client,
     xfrin_session_(NULL),
     counters_(),
     keyring_(NULL),
-    datasrc_client_lists_(new std::map<RRClass,
-                          shared_ptr<ConfigurableClientList> >()),
     ddns_base_forwarder_(ddns_forwarder),
     ddns_forwarder_(NULL),
     xfrout_connected_(false),
@@ -488,6 +471,11 @@ AuthSrv::getIOService() {
     return (impl_->io_service_);
 }
 
+isc::auth::DataSrcClientsMgr&
+AuthSrv::getDataSrcClientsMgr() {
+    return (impl_->datasrc_clients_mgr_);
+}
+
 void
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
     impl_->xfrin_session_ = xfrin_session;
@@ -509,6 +497,12 @@ 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;
+
+    // statistics: check transport carrying the message (IP, transport)
+    stats_attrs.setQueryIPVersion(io_message.getRemoteEndpoint().getFamily());
+    stats_attrs.setQueryTransportProtocol(
+        io_message.getRemoteEndpoint().getProtocol());
 
     // First, check the header part.  If we fail even for the base header,
     // just drop the message.
@@ -518,13 +512,13 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         // Ignore all responses.
         if (message.getHeaderFlag(Message::HEADERFLAG_QR)) {
             LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_RECEIVED);
-            impl_->resumeServer(server, message, false);
+            impl_->resumeServer(server, message, stats_attrs, false);
             return;
         }
     } catch (const Exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_HEADER_PARSE_FAIL)
                   .arg(ex.what());
-        impl_->resumeServer(server, message, false);
+        impl_->resumeServer(server, message, stats_attrs, false);
         return;
     }
 
@@ -535,13 +529,13 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
                   .arg(error.getRcode().toText()).arg(error.what());
         makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode());
-        impl_->resumeServer(server, message, true);
+        impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } catch (const Exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
                   .arg(ex.what());
         makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
-        impl_->resumeServer(server, message, true);
+        impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } // other exceptions will be handled at a higher layer.
 
@@ -564,21 +558,35 @@ 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());
     }
 
     if (tsig_error != TSIGError::NOERROR()) {
         makeErrorMessage(impl_->renderer_, message, buffer,
                          tsig_error.toRcode(), tsig_context);
-        impl_->resumeServer(server, message, true);
+        impl_->resumeServer(server, message, stats_attrs, true);
         return;
     }
 
     const Opcode opcode = message.getOpcode();
     bool send_answer = true;
     try {
-        // update per opcode statistics counter.  This can only be reliable
-        // after TSIG check succeeds.
-        impl_->counters_.inc(message.getOpcode());
+        // statistics: check EDNS
+        //     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());
+        }
+
+        // statistics: check OpCode
+        //     note: This can only be reliable after TSIG check succeeds.
+        stats_attrs.setQueryOpCode(opcode.getCode());
 
         if (opcode == Opcode::NOTIFY()) {
             send_answer = impl_->processNotify(io_message, message, buffer,
@@ -620,7 +628,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE_UNKNOWN);
         makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
     }
-    impl_->resumeServer(server, message, send_answer);
+    impl_->resumeServer(server, message, stats_attrs, send_answer);
 }
 
 bool
@@ -637,24 +645,21 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
     message.setHeaderFlag(Message::HEADERFLAG_AA);
     message.setRcode(Rcode::NOERROR());
 
-    // Increment query counter.
-    incCounter(io_message.getSocket().getProtocol());
-
     if (remote_edns) {
         EDNSPtr local_edns = EDNSPtr(new EDNS());
         local_edns->setDNSSECAwareness(dnssec_ok);
         local_edns->setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
         message.setEDNS(local_edns);
     }
-    // Lock the client lists and keep them under the lock until the processing
-    // and rendering is done (this is the same mutex as from
-    // AuthSrv::getDataSrcClientListMutex()).
-    isc::util::thread::Mutex::Locker locker(mutex_);
+    // Get access to data source client list through the holder and keep the
+    // holder until the processing and rendering is done to avoid inter-thread
+    // race.
+    auth::DataSrcClientsMgr::Holder datasrc_holder(datasrc_clients_mgr_);
 
     try {
         const ConstQuestionPtr question = *message.beginQuestion();
         const shared_ptr<datasrc::ClientList>
-            list(getDataSrcClientList(question->getClass()));
+            list(datasrc_holder.findClientList(question->getClass()));
         if (list) {
             const RRType& qtype = question->getType();
             const Name& qname = question->getName();
@@ -690,9 +695,6 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
                              OutputBuffer& buffer,
                              auto_ptr<TSIGContext> tsig_context)
 {
-    // Increment query counter.
-    incCounter(io_message.getSocket().getProtocol());
-
     if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_UDP);
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
@@ -825,19 +827,6 @@ AuthSrvImpl::processUpdate(const IOMessage& io_message) {
 }
 
 void
-AuthSrvImpl::incCounter(const int protocol) {
-    // Increment query counter.
-    if (protocol == IPPROTO_UDP) {
-        counters_.inc(AuthCounters::SERVER_UDP_QUERY);
-    } else if (protocol == IPPROTO_TCP) {
-        counters_.inc(AuthCounters::SERVER_TCP_QUERY);
-    } else {
-        // unknown protocol
-        isc_throw(Unexpected, "Unknown protocol: " << protocol);
-    }
-}
-
-void
 AuthSrvImpl::registerStatisticsValidator() {
     counters_.registerStatisticsValidator(
         boost::bind(&AuthSrvImpl::validateStatistics, this, _1));
@@ -854,10 +843,15 @@ AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
 }
 
 void
-AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) {
+AuthSrvImpl::resumeServer(DNSServer* server, Message& message,
+                          statistics::QRAttributes& stats_attrs,
+                          const bool done) {
     if (done) {
-        counters_.inc(message.getRcode());
+        stats_attrs.answerWasSent();
+        // isTruncated from MessageRenderer
+        stats_attrs.setResponseTruncated(renderer_.isTruncated());
     }
+    counters_.inc(stats_attrs, message);
     server->resume(done);
 }
 
@@ -880,21 +874,6 @@ ConstElementPtr AuthSrv::getStatistics() const {
     return (impl_->counters_.getStatistics());
 }
 
-uint64_t
-AuthSrv::getCounter(const AuthCounters::ServerCounterType type) const {
-    return (impl_->counters_.getCounter(type));
-}
-
-uint64_t
-AuthSrv::getCounter(const Opcode opcode) const {
-    return (impl_->counters_.getCounter(opcode));
-}
-
-uint64_t
-AuthSrv::getCounter(const Rcode rcode) const {
-    return (impl_->counters_.getCounter(rcode));
-}
-
 const AddressList&
 AuthSrv::getListenAddresses() const {
     return (impl_->listen_addresses_);
@@ -933,26 +912,6 @@ AuthSrv::destroyDDNSForwarder() {
     }
 }
 
-AuthSrv::DataSrcClientListsPtr
-AuthSrv::swapDataSrcClientLists(DataSrcClientListsPtr new_lists) {
-    // TODO: Debug-build only check
-    if (!impl_->mutex_.locked()) {
-        isc_throw(isc::Unexpected, "Not locked!");
-    }
-    std::swap(new_lists, impl_->datasrc_client_lists_);
-    return (new_lists);
-}
-
-shared_ptr<ConfigurableClientList>
-AuthSrv::getDataSrcClientList(const RRClass& rrclass) {
-    return (impl_->getDataSrcClientList(rrclass));
-}
-
-util::thread::Mutex&
-AuthSrv::getDataSrcClientListMutex() const {
-    return (impl_->mutex_);
-}
-
 void
 AuthSrv::setTCPRecvTimeout(size_t timeout) {
     dnss_->setTCPRecvTimeout(timeout);
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index 0849bdd..ebd3034 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -12,13 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __AUTH_SRV_H
-#define __AUTH_SRV_H 1
+#ifndef AUTH_SRV_H
+#define AUTH_SRV_H 1
 
 #include <config/ccsession.h>
 
 #include <datasrc/factory.h>
 #include <datasrc/client_list.h>
+#include <datasrc/datasrc_config.h>
 
 #include <dns/message.h>
 #include <dns/opcode.h>
@@ -34,7 +35,9 @@
 
 #include <asiolink/asiolink.h>
 #include <server_common/portconfig.h>
+
 #include <auth/statistics.h>
+#include <auth/datasrc_clients_mgr.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -193,6 +196,11 @@ public:
     /// \brief Return pointer to the Checkin callback function
     isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
 
+    /// \brief Return data source clients manager.
+    ///
+    /// \throw None
+    isc::auth::DataSrcClientsMgr& getDataSrcClientsMgr();
+
     /// \brief Set the communication session with a separate process for
     /// outgoing zone transfers.
     ///
@@ -214,55 +222,11 @@ public:
     /// \brief Returns statistics data
     ///
     /// This function can throw an exception from
-    /// AuthCounters::getStatistics().
+    /// Counters::getStatistics().
     ///
     /// \return JSON format statistics data.
     isc::data::ConstElementPtr getStatistics() const;
 
-    /// \brief Get the value of counter in the AuthCounters.
-    ///
-    /// This function calls AuthCounters::getStatistics() and
-    /// returns its return value.
-    ///
-    /// This function never throws an exception as far as
-    /// AuthCounters::getStatistics() doesn't throw.
-    ///
-    /// Note: Currently this function is for testing purpose only.
-    ///
-    /// \param type Type of a counter to get the value of
-    ///
-    /// \return the value of the counter.
-
-    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
-
-    /// \brief Get the value of per Opcode counter in the Auth Counters.
-    ///
-    /// This function calls AuthCounters::getCounter(isc::dns::Opcode) and
-    /// returns its return value.
-    ///
-    /// \note This is a tentative interface as an attempt of experimentally
-    /// supporting more statistics counters.  This should eventually be more
-    /// generalized.  In any case, this method is mainly for testing.
-    ///
-    /// \throw None
-    /// \param opcode The opcode of the counter to get the value of
-    /// \return the value of the counter.
-    uint64_t getCounter(const isc::dns::Opcode opcode) const;
-
-    /// \brief Get the value of per Rcode counter in the Auth Counters.
-    ///
-    /// This function calls AuthCounters::getCounter(isc::dns::Rcode) and
-    /// returns its return value.
-    ///
-    /// \note This is a tentative interface as an attempt of experimentally
-    /// supporting more statistics counters.  This should eventually be more
-    /// generalized.  In any case, this method is mainly for testing.
-    ///
-    /// \throw None
-    /// \param rcode The rcode of the counter to get the value of
-    /// \return the value of the counter.
-    uint64_t getCounter(const isc::dns::Rcode rcode) const;
-
     /**
      * \brief Set and get the addresses we listen on.
      */
@@ -302,83 +266,10 @@ public:
     /// If there was no forwarder yet, this method does nothing.
     void destroyDDNSForwarder();
 
-    /// \brief Shortcut typedef used for swapDataSrcClientLists().
-    typedef boost::shared_ptr<std::map<
-        isc::dns::RRClass, boost::shared_ptr<
-                               isc::datasrc::ConfigurableClientList> > >
-    DataSrcClientListsPtr;
-
-    /// \brief Swap the currently used set of data source client lists with
-    /// given one.
-    ///
-    /// The "set" of lists is actually given in the form of map from
-    /// RRClasses to shared pointers to isc::datasrc::ConfigurableClientList.
-    ///
-    /// This method returns the swapped set of lists, which was previously
-    /// used by the server.
-    ///
-    /// This method is intended to be used by a separate method to update
-    /// the data source configuration "at once".  The caller must hold
-    /// a lock for the mutex object returned by  \c getDataSrcClientListMutex()
-    /// before calling this method.
-    ///
-    /// The ownership of the returned pointer is transferred to the caller.
-    /// The caller is generally expected to release the resources used in
-    /// the old lists.  Note that it could take longer time if some of the
-    /// data source clients contain a large size of in-memory data.
-    ///
-    /// The caller can pass a NULL pointer.  This effectively disables
-    /// any data source for the server.
-    ///
-    /// \param new_lists Shared pointer to a new set of data source client
-    /// lists.
-    /// \return The previous set of lists.  It can be NULL.
-    DataSrcClientListsPtr swapDataSrcClientLists(DataSrcClientListsPtr
-                                                 new_lists);
-
-    /// \brief Returns the currently used client list for the class.
-    ///
-    /// \param rrclass The class for which to get the list.
-    /// \return The list, or NULL if no list is set for the class.
-    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        getDataSrcClientList(const isc::dns::RRClass& rrclass);
-
-    /// \brief Return a mutex for the client lists.
-    ///
-    /// Background loading of data uses threads. Therefore we need to protect
-    /// the client lists by a mutex, so they don't change (or get destroyed)
-    /// during query processing. Get (and lock) this mutex whenever you do
-    /// something with the lists and keep it locked until you finish. This
-    /// is correct:
-    /// \code
-    /// {
-    ///  Mutex::Locker locker(auth->getDataSrcClientListMutex());
-    ///  boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-    ///    list(auth->getDataSrcClientList(RRClass::IN()));
-    ///  // Do some processing here
-    /// }
-    /// \endcode
-    ///
-    /// But this is not (it releases the mutex too soon):
-    /// \code
-    /// boost::shared_ptr<isc::datasrc::ConfigurableClientList> list;
-    /// {
-    ///     Mutex::Locker locker(auth->getDataSrcClientListMutex());
-    ///     list = auth->getDataSrcClientList(RRClass::IN()));
-    /// }
-    /// // Do some processing here
-    /// \endcode
-    ///
-    /// \note This method is const even if you are allowed to modify
-    ///    (lock) the mutex. It's because locking of the mutex is not really
-    ///    a modification of the server object and it is needed to protect the
-    ///    lists even on read-only operations.
-    isc::util::thread::Mutex& getDataSrcClientListMutex() const;
-
     /// \brief Sets the timeout for incoming TCP connections
     ///
     /// Incoming TCP connections that have not sent their data
-    /// withing this time are dropped.
+    /// within this time are dropped.
     ///
     /// \param timeout The timeout (in milliseconds). If se to
     /// zero, no timeouts are used, and the connection will remain
@@ -393,7 +284,7 @@ private:
     isc::asiodns::DNSServiceBase* dnss_;
 };
 
-#endif // __AUTH_SRV_H
+#endif // AUTH_SRV_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index c525b66..27ddfc5 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -15,7 +15,7 @@ query_bench_SOURCES = query_bench.cc
 query_bench_SOURCES += ../query.h  ../query.cc
 query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
 query_bench_SOURCES += ../auth_config.h ../auth_config.cc
-query_bench_SOURCES += ../statistics.h ../statistics.cc
+query_bench_SOURCES += ../statistics.h ../statistics.cc ../statistics_items.h
 query_bench_SOURCES += ../auth_log.h ../auth_log.cc
 query_bench_SOURCES += ../datasrc_config.h ../datasrc_config.cc
 
@@ -34,7 +34,6 @@ query_bench_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
 query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 query_bench_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
 query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
-query_bench_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 query_bench_LDADD += $(top_builddir)/src/lib/util/threads/libb10-threads.la
 query_bench_LDADD += $(SQLITE_LIBS)
 
diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc
index 37976a3..77b3377 100644
--- a/src/bin/auth/benchmarks/query_bench.cc
+++ b/src/bin/auth/benchmarks/query_bench.cc
@@ -18,7 +18,6 @@
 #include <bench/benchmark_util.h>
 
 #include <util/buffer.h>
-#include <util/threads/lock.h>
 
 #include <dns/message.h>
 #include <dns/name.h>
@@ -33,6 +32,7 @@
 #include <auth/auth_srv.h>
 #include <auth/auth_config.h>
 #include <auth/datasrc_config.h>
+#include <auth/datasrc_clients_mgr.h>
 #include <auth/query.h>
 
 #include <asiodns/asiodns.h>
@@ -127,9 +127,9 @@ public:
                           OutputBuffer& buffer) :
         QueryBenchMark(queries, query_message, buffer)
     {
-        isc::util::thread::Mutex::Locker locker(
-                server_->getDataSrcClientListMutex());
-        server_->swapDataSrcClientLists(
+        // Note: setDataSrcClientLists() may be deprecated, but until then
+        // we use it because we want to be synchronized with the server.
+        server_->getDataSrcClientsMgr().setDataSrcClientLists(
             configureDataSource(
                 Element::fromJSON("{\"IN\":"
                                   "  [{\"type\": \"sqlite3\","
@@ -148,9 +148,7 @@ public:
                          OutputBuffer& buffer) :
         QueryBenchMark(queries, query_message, buffer)
     {
-        isc::util::thread::Mutex::Locker locker(
-                server_->getDataSrcClientListMutex());
-        server_->swapDataSrcClientLists(
+        server_->getDataSrcClientsMgr().setDataSrcClientLists(
             configureDataSource(
                 Element::fromJSON("{\"IN\":"
                                   "  [{\"type\": \"MasterFiles\","
diff --git a/src/bin/auth/command.cc b/src/bin/auth/command.cc
index d26cf09..9fbfb42 100644
--- a/src/bin/auth/command.cc
+++ b/src/bin/auth/command.cc
@@ -15,13 +15,13 @@
 #include <auth/command.h>
 #include <auth/auth_log.h>
 #include <auth/auth_srv.h>
+#include <auth/datasrc_clients_mgr.h>
 
 #include <cc/data.h>
 #include <datasrc/client_list.h>
 #include <config/ccsession.h>
 #include <exceptions/exceptions.h>
 #include <dns/rrclass.h>
-#include <util/threads/lock.h>
 
 #include <string>
 
@@ -176,54 +176,7 @@ public:
     virtual ConstElementPtr exec(AuthSrv& server,
                                  isc::data::ConstElementPtr args)
     {
-        if (args == NULL) {
-            isc_throw(AuthCommandError, "Null argument");
-        }
-
-        ConstElementPtr class_elem = args->get("class");
-        RRClass zone_class(class_elem ? RRClass(class_elem->stringValue()) :
-            RRClass::IN());
-
-        ConstElementPtr origin_elem = args->get("origin");
-        if (!origin_elem) {
-            isc_throw(AuthCommandError, "Zone origin is missing");
-        }
-        Name origin(origin_elem->stringValue());
-
-        // We're going to work with the client lists. They may be used
-        // from a different thread too, protect them.
-        isc::util::thread::Mutex::Locker locker(
-            server.getDataSrcClientListMutex());
-        const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-            list(server.getDataSrcClientList(zone_class));
-
-        if (!list) {
-            isc_throw(AuthCommandError, "There's no client list for "
-                      "class " << zone_class);
-        }
-
-        switch (list->reload(origin)) {
-            case ConfigurableClientList::ZONE_RELOADED:
-                // Everything worked fine.
-                LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
-                    .arg(zone_class).arg(origin);
-                return (createAnswer());
-            case ConfigurableClientList::ZONE_NOT_FOUND:
-                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
-                          zone_class << " was not found in any configured "
-                          "data source. Configure it first.");
-            case ConfigurableClientList::ZONE_NOT_CACHED:
-                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
-                          zone_class << " is not served from memory, but "
-                          "directly from the data source. It is not possible "
-                          "to reload it into memory. Configure it to be cached "
-                          "first.");
-            case ConfigurableClientList::CACHE_DISABLED:
-                // This is an internal error. Auth server must have the cache
-                // enabled.
-                isc_throw(isc::Unexpected, "Cache disabled in client list of "
-                          "class " << zone_class);
-        }
+        server.getDataSrcClientsMgr().loadZone(args);
         return (createAnswer());
     }
 };
diff --git a/src/bin/auth/command.h b/src/bin/auth/command.h
index 7db5cd6..5058b81 100644
--- a/src/bin/auth/command.h
+++ b/src/bin/auth/command.h
@@ -16,8 +16,8 @@
 
 #include <cc/data.h>
 
-#ifndef __COMMAND_H
-#define __COMMAND_H 1
+#ifndef COMMAND_H
+#define COMMAND_H 1
 
 class AuthSrv;
 
@@ -54,7 +54,7 @@ isc::data::ConstElementPtr
 execAuthServerCommand(AuthSrv& server, const std::string& command_id,
                       isc::data::ConstElementPtr args);
 
-#endif // __COMMAND_H
+#endif // COMMAND_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/common.h b/src/bin/auth/common.h
index 0964217..908a7d1 100644
--- a/src/bin/auth/common.h
+++ b/src/bin/auth/common.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COMMON_H
-#define __COMMON_H 1
+#ifndef COMMON_H
+#define COMMON_H 1
 
 #include <stdexcept>
 #include <string>
@@ -62,7 +62,7 @@ extern const char* const AUTH_NAME;
 /// This is sent to interested modules (currently only b10-ddns)
 extern const char* const AUTH_STARTED_NOTIFICATION;
 
-#endif // __COMMON_H
+#endif // COMMON_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/datasrc_clients_mgr.h b/src/bin/auth/datasrc_clients_mgr.h
new file mode 100644
index 0000000..38bf162
--- /dev/null
+++ b/src/bin/auth/datasrc_clients_mgr.h
@@ -0,0 +1,660 @@
+// 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 DATASRC_CLIENTS_MGR_H
+#define DATASRC_CLIENTS_MGR_H 1
+
+#include <util/threads/thread.h>
+#include <util/threads/sync.h>
+
+#include <log/logger_support.h>
+#include <log/log_dbglevels.h>
+
+#include <dns/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/data_source.h>
+#include <datasrc/client_list.h>
+#include <datasrc/memory/zone_writer.h>
+
+#include <auth/auth_log.h>
+#include <auth/datasrc_config.h>
+
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <exception>
+#include <cassert>
+#include <list>
+#include <utility>
+
+namespace isc {
+namespace auth {
+
+/// \brief An exception that is thrown if initial checks for a command fail
+///
+/// This is raised *before* the command to the thread is constructed and
+/// sent, so the application can still handle them (and therefore it is
+/// public, as opposed to InternalCommandError).
+///
+/// And example of its use is currently in loadZone().
+class CommandError : public isc::Exception {
+public:
+    CommandError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+namespace datasrc_clientmgr_internal {
+// This namespace is essentially private for DataSrcClientsMgr(Base) and
+// DataSrcClientsBuilder(Base).  This is exposed in the public header
+// only because these classes are templated (for testing purposes) and
+// class internal has to be defined here.
+
+/// \brief ID of commands from the DataSrcClientsMgr to DataSrcClientsBuilder.
+enum CommandID {
+    NOOP,         ///< Do nothing.  Only useful for tests; no argument
+    RECONFIGURE,  ///< Reconfigure the datasource client lists,
+                  ///  the argument to the command is the full new
+                  ///  datasources configuration.
+    LOADZONE,     ///< Load a new version of zone into a memory,
+                  ///  the argument to the command is a map containing 'class'
+                  ///  and 'origin' elements, both should have been validated.
+    SHUTDOWN,     ///< Shutdown the builder; no argument
+    NUM_COMMANDS
+};
+
+/// \brief The data type passed from DataSrcClientsMgr to
+/// DataSrcClientsBuilder.
+///
+/// The first element of the pair is the command ID, and the second element
+/// is its argument.  If the command doesn't take an argument it should be
+/// a null pointer.
+typedef std::pair<CommandID, data::ConstElementPtr> Command;
+} // namespace datasrc_clientmgr_internal
+
+/// \brief Frontend to the manager object for data source clients.
+///
+/// This class provides interfaces for configuring and updating a set of
+/// data source clients "in the background".  The user of this class can
+/// assume any operation on this class can be done effectively non-blocking,
+/// not suspending any delay-sensitive operations such as DNS query
+/// processing.  The only exception is the time when this class object
+/// is destroyed (normally as a result of an implicit call to the destructor);
+/// in the current implementation it can take time depending on what is
+/// running "in the background" at the time of the call.
+///
+/// Internally, an object of this class invokes a separate thread to perform
+/// time consuming operations such as loading large zone data into memory,
+/// but such details are completely hidden from the user of this class.
+///
+/// This class is templated only so that we can test the class without
+/// involving actual threads or mutex.  Normal applications will only
+/// need one specific specialization that has a typedef of
+/// \c DataSrcClientsMgr.
+template <typename ThreadType, typename BuilderType, typename MutexType,
+          typename CondVarType>
+class DataSrcClientsMgrBase : boost::noncopyable {
+private:
+    typedef std::map<dns::RRClass,
+                     boost::shared_ptr<datasrc::ConfigurableClientList> >
+    ClientListsMap;
+
+public:
+    /// \brief Thread-safe accessor to the data source client lists.
+    ///
+    /// This class provides a simple wrapper for searching the client lists
+    /// stored in the DataSrcClientsMgr in a thread-safe manner.
+    /// It ensures the result of \c getClientList() can be used without
+    /// causing a race condition with other threads that can possibly use
+    /// the same manager throughout the lifetime of the holder object.
+    ///
+    /// This also means the holder object is expected to have a short lifetime.
+    /// The application shouldn't try to keep it unnecessarily long.
+    /// It's normally expected to create the holder object on the stack
+    /// of a small scope and automatically let it be destroyed at the end
+    /// of the scope.
+    class Holder {
+    public:
+        Holder(DataSrcClientsMgrBase& mgr) :
+            mgr_(mgr), locker_(mgr_.map_mutex_)
+        {}
+
+        /// \brief Find a data source client list of a specified RR class.
+        ///
+        /// It returns a pointer to the list stored in the manager if found,
+        /// otherwise it returns NULL.  The manager keeps the ownership of
+        /// the pointed object.  Also, it's not safe to get access to the
+        /// object beyond the scope of the holder object.
+        ///
+        /// \note Since the ownership isn't transferred the return value
+        /// could be a bare pointer (and it's probably better in several
+        /// points).  Unfortunately, some unit tests currently don't work
+        /// unless this method effectively shares the ownership with the
+        /// tests.  That's the only reason why we return a shared pointer
+        /// for now.  We should eventually fix it and change the return value
+        /// type (see Trac ticket #2395).  Other applications must not
+        /// assume the ownership is actually shared.
+        boost::shared_ptr<datasrc::ConfigurableClientList> findClientList(
+            const dns::RRClass& rrclass)
+        {
+            const ClientListsMap::const_iterator
+                it = mgr_.clients_map_->find(rrclass);
+            if (it == mgr_.clients_map_->end()) {
+                return (boost::shared_ptr<datasrc::ConfigurableClientList>());
+            } else {
+                return (it->second);
+            }
+        }
+    private:
+        DataSrcClientsMgrBase& mgr_;
+        typename MutexType::Locker locker_;
+    };
+
+    /// \brief Constructor.
+    ///
+    /// It internally invokes a separate thread and waits for further
+    /// operations from the user application.
+    ///
+    /// This method is basically exception free except in case of really
+    /// rare system-level errors.  When that happens the only reasonable
+    /// action that the application can take would be to terminate the program
+    /// in practice.
+    ///
+    /// \throw std::bad_alloc internal memory allocation failure.
+    /// \throw isc::Unexpected general unexpected system errors.
+    DataSrcClientsMgrBase() :
+        clients_map_(new ClientListsMap),
+        builder_(&command_queue_, &cond_, &queue_mutex_, &clients_map_,
+                 &map_mutex_),
+        builder_thread_(boost::bind(&BuilderType::run, &builder_))
+    {}
+
+    /// \brief The destructor.
+    ///
+    /// It tells the internal thread to stop and waits for it completion.
+    /// In the current implementation, it can block for some unpredictably
+    /// long period depending on what the thread is doing at that time
+    /// (in future we may want to implement a rapid way of killing the thread
+    /// and/or provide a separate interface for waiting so that the application
+    /// can choose the timing).
+    ///
+    /// The waiting operation can result in an exception, but this method
+    /// catches any of them so this method itself is exception free.
+    ~DataSrcClientsMgrBase() {
+        // We share class member variables with the builder, which will be
+        // invalidated after the call to the destructor, so we need to make
+        // sure the builder thread is terminated.  Depending on the timing
+        // this could take a long time; if we don't want that to happen in
+        // this context, we may want to introduce a separate 'shutdown()'
+        // method.
+        // Also, since we don't want to propagate exceptions from a destructor,
+        // we catch any possible ones.  In fact the only really expected one
+        // is Thread::UncaughtException when the builder thread died due to
+        // an exception.  We specifically log it and just ignore others.
+        try {
+            sendCommand(datasrc_clientmgr_internal::SHUTDOWN,
+                        data::ConstElementPtr());
+            builder_thread_.wait();
+        } catch (const util::thread::Thread::UncaughtException& ex) {
+            // technically, logging this could throw, which will be propagated.
+            // But such an exception would be a fatal one anyway, so we
+            // simply let it go through.
+            LOG_ERROR(auth_logger, AUTH_DATASRC_CLIENTS_SHUTDOWN_ERROR).
+                arg(ex.what());
+        } catch (...) {
+            LOG_ERROR(auth_logger,
+                      AUTH_DATASRC_CLIENTS_SHUTDOWN_UNEXPECTED_ERROR);
+        }
+
+        cleanup();              // see below
+    }
+
+    /// \brief Handle new full configuration for data source clients.
+    ///
+    /// This method simply passes the new configuration to the builder
+    /// and immediately returns.  This method is basically exception free
+    /// as long as the caller passes a non NULL value for \c config_arg;
+    /// it doesn't validate the argument further.
+    ///
+    /// \brief isc::InvalidParameter config_arg is NULL.
+    /// \brief std::bad_alloc
+    ///
+    /// \param config_arg The new data source configuration.  Must not be NULL.
+    void reconfigure(data::ConstElementPtr config_arg) {
+        if (!config_arg) {
+            isc_throw(InvalidParameter, "Invalid null config argument");
+        }
+        sendCommand(datasrc_clientmgr_internal::RECONFIGURE, config_arg);
+        reconfigureHook();      // for test's customization
+    }
+
+    /// \brief Set the underlying data source client lists to new lists.
+    ///
+    /// This is provided only for some existing tests until we support a
+    /// cleaner way to use faked data source clients.  Non test code or
+    /// newer tests must not use this.
+    void setDataSrcClientLists(datasrc::ClientListMapPtr new_lists) {
+        typename MutexType::Locker locker(map_mutex_);
+        clients_map_ = new_lists;
+    }
+
+    /// \brief Instruct internal thread to (re)load a zone
+    ///
+    /// \param args Element argument that should be a map of the form
+    /// { "class": "IN", "origin": "example.com" }
+    /// (but class is optional and will default to IN)
+    ///
+    /// \exception CommandError if the args value is null, or not in
+    ///                                 the expected format, or contains
+    ///                                 a bad origin or class string
+    void
+    loadZone(data::ConstElementPtr args) {
+        if (!args) {
+            isc_throw(CommandError, "loadZone argument empty");
+        }
+        if (args->getType() != isc::data::Element::map) {
+            isc_throw(CommandError, "loadZone argument not a map");
+        }
+        if (!args->contains("origin")) {
+            isc_throw(CommandError,
+                      "loadZone argument has no 'origin' value");
+        }
+        // Also check if it really is a valid name
+        try {
+            dns::Name(args->get("origin")->stringValue());
+        } catch (const isc::Exception& exc) {
+            isc_throw(CommandError, "bad origin: " << exc.what());
+        }
+
+        if (args->get("origin")->getType() != data::Element::string) {
+            isc_throw(CommandError,
+                      "loadZone argument 'origin' value not a string");
+        }
+        if (args->contains("class")) {
+            if (args->get("class")->getType() != data::Element::string) {
+                isc_throw(CommandError,
+                          "loadZone argument 'class' value not a string");
+            }
+            // Also check if it is a valid class
+            try {
+                dns::RRClass(args->get("class")->stringValue());
+            } catch (const isc::Exception& exc) {
+                isc_throw(CommandError, "bad class: " << exc.what());
+            }
+        }
+
+        // Note: we could do some more advanced checks here,
+        // e.g. check if the zone is known at all in the configuration.
+        // For now these are skipped, but one obvious way to
+        // implement it would be to factor out the code from
+        // the start of doLoadZone(), and call it here too
+
+        sendCommand(datasrc_clientmgr_internal::LOADZONE, args);
+    }
+
+private:
+    // This is expected to be called at the end of the destructor.  It
+    // actually does nothing, but provides a customization point for
+    // specialized class for tests so that the tests can inspect the last
+    // state of the class.
+    void cleanup() {}
+
+    // same as cleanup(), for reconfigure().
+    void reconfigureHook() {}
+
+    void sendCommand(datasrc_clientmgr_internal::CommandID command,
+                     data::ConstElementPtr arg)
+    {
+        // The lock will be held until the end of this method.  Only
+        // push_back has to be protected, but we can avoid having an extra
+        // block this way.
+        typename MutexType::Locker locker(queue_mutex_);
+        command_queue_.push_back(
+            datasrc_clientmgr_internal::Command(command, arg));
+        cond_.signal();
+    }
+
+    //
+    // The following are shared with the builder.
+    //
+    // The list is used as a one-way queue: back-in, front-out
+    std::list<datasrc_clientmgr_internal::Command> command_queue_;
+    CondVarType cond_;          // condition variable for queue operations
+    MutexType queue_mutex_;     // mutex to protect the queue
+    datasrc::ClientListMapPtr clients_map_;
+                                // map of actual data source client objects
+    MutexType map_mutex_;       // mutex to protect the clients map
+
+    BuilderType builder_;
+    ThreadType builder_thread_; // for safety this should be placed last
+};
+
+namespace datasrc_clientmgr_internal {
+
+/// \brief A class that maintains a set of data source clients.
+///
+/// An object of this class is supposed to run on a dedicated thread, whose
+/// main function is a call to its \c run() method.  It runs in a loop
+/// waiting for commands from the manager and handles each command (including
+/// reloading a new version of zone data into memory or fully reconfiguration
+/// of specific set of data source clients).  When it receives a SHUTDOWN
+/// command, it exits from the loop, which will terminate the thread.
+///
+/// While this class is defined in a publicly visible namespace, it's
+/// essentially private to \c DataSrcClientsMgr.  Except for tests,
+/// applications should not directly access this class.
+///
+/// This class is templated so that we can test it without involving actual
+/// threads or locks.
+template <typename MutexType, typename CondVarType>
+class DataSrcClientsBuilderBase : boost::noncopyable {
+private:
+    typedef std::map<dns::RRClass,
+                     boost::shared_ptr<datasrc::ConfigurableClientList> >
+    ClientListsMap;
+
+public:
+    /// \brief Internal errors in handling commands.
+    ///
+    /// This exception is expected to be caught within the
+    /// \c DataSrcClientsBuilder implementation, but is defined as public
+    /// so tests can be checked it.
+    class InternalCommandError : public isc::Exception {
+    public:
+        InternalCommandError(const char* file, size_t line, const char* what) :
+            isc::Exception(file, line, what) {}
+    };
+
+    /// \brief Constructor.
+    ///
+    /// It simply sets up a local copy of shared data with the manager.
+    ///
+    /// \throw None
+    DataSrcClientsBuilderBase(std::list<Command>* command_queue,
+                              CondVarType* cond, MutexType* queue_mutex,
+                              datasrc::ClientListMapPtr* clients_map,
+                              MutexType* map_mutex
+        ) :
+        command_queue_(command_queue), cond_(cond), queue_mutex_(queue_mutex),
+        clients_map_(clients_map), map_mutex_(map_mutex)
+    {}
+
+    /// \brief The main loop.
+    void run();
+
+    /// \brief Handle one command from the manager.
+    ///
+    /// This is a dedicated subroutine of run() and is essentially private,
+    /// but is defined as a separate public method so we can test each
+    /// command test individually.  In any case, this class itself is
+    /// generally considered private.
+    ///
+    /// \return true if the builder should keep running; false otherwise.
+    bool handleCommand(const Command& command);
+
+private:
+    // NOOP command handler.  We use this so tests can override it; the default
+    // implementation really does nothing.
+    void doNoop() {}
+
+    void doReconfigure(const data::ConstElementPtr& config) {
+        if (config) {
+            LOG_INFO(auth_logger,
+                     AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_STARTED);
+            try {
+                // Define new_clients_map outside of the block that
+                // has the lock scope; this way, after the swap,
+                // the lock is guaranteed to be released before
+                // the old data is destroyed, minimizing the lock
+                // duration.
+                datasrc::ClientListMapPtr new_clients_map =
+                    configureDataSource(config);
+                {
+                    typename MutexType::Locker locker(*map_mutex_);
+                    new_clients_map.swap(*clients_map_);
+                } // lock is released by leaving scope
+                LOG_INFO(auth_logger,
+                         AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_SUCCESS);
+            } catch (const datasrc::ConfigurableClientList::ConfigurationError&
+                     config_error) {
+                LOG_ERROR(auth_logger,
+                    AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_CONFIG_ERROR).
+                    arg(config_error.what());
+            } catch (const datasrc::DataSourceError& ds_error) {
+                LOG_ERROR(auth_logger,
+                    AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_DATASRC_ERROR).
+                    arg(ds_error.what());
+            } catch (const isc::Exception& isc_error) {
+                LOG_ERROR(auth_logger,
+                    AUTH_DATASRC_CLIENTS_BUILDER_RECONFIGURE_ERROR).
+                    arg(isc_error.what());
+            }
+            // other exceptions are propagated, see
+            // http://bind10.isc.org/ticket/2210#comment:13
+
+            // old clients_map_ data is released by leaving scope
+        }
+    }
+
+    void doLoadZone(const isc::data::ConstElementPtr& arg);
+    boost::shared_ptr<datasrc::memory::ZoneWriter> getZoneWriter(
+        datasrc::ConfigurableClientList& client_list,
+        const dns::RRClass& rrclass, const dns::Name& origin);
+
+    // The following are shared with the manager
+    std::list<Command>* command_queue_;
+    CondVarType* cond_;
+    MutexType* queue_mutex_;
+    datasrc::ClientListMapPtr* clients_map_;
+    MutexType* map_mutex_;
+};
+
+// Shortcut typedef for normal use
+typedef DataSrcClientsBuilderBase<util::thread::Mutex, util::thread::CondVar>
+DataSrcClientsBuilder;
+
+template <typename MutexType, typename CondVarType>
+void
+DataSrcClientsBuilderBase<MutexType, CondVarType>::run() {
+    LOG_INFO(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_STARTED);
+
+    try {
+        bool keep_running = true;
+        while (keep_running) {
+            std::list<Command> current_commands;
+            {
+                // Move all new commands to local queue under the protection of
+                // queue_mutex_.
+                typename MutexType::Locker locker(*queue_mutex_);
+                while (command_queue_->empty()) {
+                    cond_->wait(*queue_mutex_);
+                }
+                current_commands.swap(*command_queue_);
+            } // the lock is released here.
+
+            while (keep_running && !current_commands.empty()) {
+                try {
+                    keep_running = handleCommand(current_commands.front());;
+                } catch (const InternalCommandError& e) {
+                    LOG_ERROR(auth_logger,
+                              AUTH_DATASRC_CLIENTS_BUILDER_COMMAND_ERROR).
+                        arg(e.what());
+                }
+                current_commands.pop_front();
+            }
+        }
+
+        LOG_INFO(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_STOPPED);
+    } catch (const std::exception& ex) {
+        // We explicitly catch exceptions so we can log it as soon as possible.
+        LOG_FATAL(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_FAILED).
+            arg(ex.what());
+        std::terminate();
+    } catch (...) {
+        LOG_FATAL(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_FAILED_UNEXPECTED);
+        std::terminate();
+    }
+}
+
+template <typename MutexType, typename CondVarType>
+bool
+DataSrcClientsBuilderBase<MutexType, CondVarType>::handleCommand(
+    const Command& command)
+{
+    const CommandID cid = command.first;
+    if (cid >= NUM_COMMANDS) {
+        // This shouldn't happen except for a bug within this file.
+        isc_throw(Unexpected, "internal bug: invalid command, ID: " << cid);
+    }
+
+    const boost::array<const char*, NUM_COMMANDS> command_desc = {
+        {"NOOP", "RECONFIGURE", "LOADZONE", "SHUTDOWN"}
+    };
+    LOG_DEBUG(auth_logger, DBGLVL_TRACE_BASIC,
+              AUTH_DATASRC_CLIENTS_BUILDER_COMMAND).arg(command_desc.at(cid));
+    switch (command.first) {
+    case RECONFIGURE:
+        doReconfigure(command.second);
+        break;
+    case LOADZONE:
+        doLoadZone(command.second);
+        break;
+    case SHUTDOWN:
+        return (false);
+    case NOOP:
+        doNoop();
+        break;
+    case NUM_COMMANDS:
+        assert(false);          // we rejected this case above
+    }
+    return (true);
+}
+
+template <typename MutexType, typename CondVarType>
+void
+DataSrcClientsBuilderBase<MutexType, CondVarType>::doLoadZone(
+    const isc::data::ConstElementPtr& arg)
+{
+    // We assume some basic level validation as this method can only be
+    // called via the manager in practice.  manager is expected to do the
+    // minimal validation.
+    assert(arg);
+    assert(arg->get("origin"));
+
+    // TODO: currently, we hardcode IN as the default for the optional
+    // 'class' argument. We should really derive this from the specification,
+    // but at the moment the config/command API does not allow that to be
+    // done easily. Once that is in place (tickets have yet to be created,
+    // as we need to do a tiny bit of design work for that), this
+    // code can be replaced with the original part:
+    // assert(arg->get("class"));
+    // const dns::RRClass(arg->get("class")->stringValue());
+    isc::data::ConstElementPtr class_elem = arg->get("class");
+    const dns::RRClass rrclass(class_elem ?
+                                dns::RRClass(class_elem->stringValue()) :
+                                dns::RRClass::IN());
+    const dns::Name origin(arg->get("origin")->stringValue());
+    ClientListsMap::iterator found = (*clients_map_)->find(rrclass);
+    if (found == (*clients_map_)->end()) {
+        isc_throw(InternalCommandError, "failed to load a zone " << origin <<
+                  "/" << rrclass << ": not configured for the class");
+    }
+
+    boost::shared_ptr<datasrc::ConfigurableClientList> client_list =
+        found->second;
+    assert(client_list);
+
+    try {
+        boost::shared_ptr<datasrc::memory::ZoneWriter> zwriter =
+            getZoneWriter(*client_list, rrclass, origin);
+
+        zwriter->load(); // this can take time but doesn't cause a race
+        {   // install() can cause a race and must be in a critical section
+            typename MutexType::Locker locker(*map_mutex_);
+            zwriter->install();
+        }
+        LOG_DEBUG(auth_logger, DBG_AUTH_OPS,
+                  AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE)
+            .arg(origin).arg(rrclass);
+
+        // same as load(). We could let the destructor do it, but do it
+        // ourselves explicitly just in case.
+        zwriter->cleanup();
+    } catch (const InternalCommandError& ex) {
+        throw;     // this comes from getZoneWriter.  just let it go through.
+    } catch (const isc::Exception& ex) {
+        // We catch our internal exceptions (which will be just ignored) and
+        // propagated others (which should generally be considered fatal and
+        // will make the thread terminate)
+        isc_throw(InternalCommandError, "failed to load a zone " << origin <<
+                  "/" << rrclass << ": error occurred in reload: " <<
+                  ex.what());
+    }
+}
+
+// A dedicated subroutine of doLoadZone().  Separated just for keeping the
+// main method concise.
+template <typename MutexType, typename CondVarType>
+boost::shared_ptr<datasrc::memory::ZoneWriter>
+DataSrcClientsBuilderBase<MutexType, CondVarType>::getZoneWriter(
+    datasrc::ConfigurableClientList& client_list,
+    const dns::RRClass& rrclass, const dns::Name& origin)
+{
+    const datasrc::ConfigurableClientList::ZoneWriterPair writerpair =
+        client_list.getCachedZoneWriter(origin);
+
+    switch (writerpair.first) {
+    case datasrc::ConfigurableClientList::ZONE_SUCCESS:
+        assert(writerpair.second);
+        return (writerpair.second);
+    case datasrc::ConfigurableClientList::ZONE_NOT_FOUND:
+        isc_throw(InternalCommandError, "failed to load zone " << origin
+                  << "/" << rrclass << ": not found in any configured "
+                  "data source.");
+    case datasrc::ConfigurableClientList::ZONE_NOT_CACHED:
+        isc_throw(InternalCommandError, "failed to load zone " << origin
+                  << "/" << rrclass << ": not served from memory");
+    case datasrc::ConfigurableClientList::CACHE_DISABLED:
+        // This is an internal error. Auth server must have the cache
+        // enabled.
+        isc_throw(InternalCommandError, "failed to load zone " << origin
+                  << "/" << rrclass << ": internal failure, in-memory cache "
+                  "is somehow disabled");
+    }
+
+    // all cases above should either return or throw, but some compilers
+    // still need a return statement
+    return (boost::shared_ptr<datasrc::memory::ZoneWriter>());
+}
+} // namespace datasrc_clientmgr_internal
+
+/// \brief Shortcut type for normal data source clients manager.
+///
+/// In fact, for non test applications this is the only type of this kind
+/// to be considered.
+typedef DataSrcClientsMgrBase<
+    util::thread::Thread,
+    datasrc_clientmgr_internal::DataSrcClientsBuilder,
+    util::thread::Mutex, util::thread::CondVar> DataSrcClientsMgr;
+} // namespace auth
+} // namespace isc
+
+#endif  // DATASRC_CLIENTS_MGR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/auth/datasrc_config.cc b/src/bin/auth/datasrc_config.cc
index 62c3c7a..4869050 100644
--- a/src/bin/auth/datasrc_config.cc
+++ b/src/bin/auth/datasrc_config.cc
@@ -13,12 +13,11 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <cc/data.h>
-#include "auth_srv.h"
 #include "datasrc_config.h"
 
 // This is a trivial specialization for the commonly used version.
 // Defined in .cc to avoid accidental creation of multiple copies.
-AuthSrv::DataSrcClientListsPtr
+isc::datasrc::ClientListMapPtr
 configureDataSource(const isc::data::ConstElementPtr& config) {
     return (configureDataSourceGeneric<
             isc::datasrc::ConfigurableClientList>(config));
diff --git a/src/bin/auth/datasrc_config.h b/src/bin/auth/datasrc_config.h
index 5707c6c..1723161 100644
--- a/src/bin/auth/datasrc_config.h
+++ b/src/bin/auth/datasrc_config.h
@@ -12,10 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef DATASRC_CONFIG_H
-#define DATASRC_CONFIG_H
-
-#include "auth_srv.h"
+#ifndef AUTH_DATASRC_CONFIG_H
+#define AUTH_DATASRC_CONFIG_H
 
 #include <cc/data.h>
 #include <datasrc/client_list.h>
@@ -23,7 +21,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include <utility>
-#include <set>
+#include <map>
 
 /// \brief Configure data source client lists
 ///
@@ -48,6 +46,8 @@
 /// \param config The configuration value to parse. It is in the form
 ///     as an update from the config manager.
 /// \return A map from RR classes to configured lists.
+/// \throw ConfigurationError if the config element is not in the expected
+///        format (A map of lists)
 template<class List>
 boost::shared_ptr<std::map<isc::dns::RRClass,
                            boost::shared_ptr<List> > > // = ListMap below
@@ -58,7 +58,6 @@ configureDataSourceGeneric(const isc::data::ConstElementPtr& config) {
 
     boost::shared_ptr<ListMap> new_lists(new ListMap);
 
-    // Go through the configuration and create corresponding list.
     const Map& map(config->mapValue());
     for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
         const isc::dns::RRClass rrclass(it->first);
@@ -73,10 +72,10 @@ configureDataSourceGeneric(const isc::data::ConstElementPtr& config) {
 
 /// \brief Concrete version of configureDataSource() for the
 ///     use with authoritative server implementation.
-AuthSrv::DataSrcClientListsPtr
+isc::datasrc::ClientListMapPtr
 configureDataSource(const isc::data::ConstElementPtr& config);
 
-#endif  // DATASRC_CONFIG_H
+#endif  // AUTH_DATASRC_CONFIG_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index 9908066..1fe0f48 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -18,7 +18,6 @@
 
 #include <util/buffer.h>
 #include <util/io/socketsession.h>
-#include <util/threads/lock.h>
 
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -36,6 +35,8 @@
 #include <auth/auth_srv.h>
 #include <auth/auth_log.h>
 #include <auth/datasrc_config.h>
+#include <auth/datasrc_clients_mgr.h>
+
 #include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 #include <log/logger_support.h>
@@ -93,32 +94,23 @@ datasrcConfigHandler(AuthSrv* server, bool* first_time,
                      const isc::config::ConfigData&)
 {
     assert(server != NULL);
-    if (config->contains("classes")) {
-        AuthSrv::DataSrcClientListsPtr lists;
-
-        if (*first_time) {
-            // HACK: The default is not passed to the handler in the first
-            // callback. This one will get the default (or, current value).
-            // Further updates will work the usual way.
-            assert(config_session != NULL);
-            *first_time = false;
-            lists = configureDataSource(
-                config_session->getRemoteConfigValue("data_sources",
-                                                     "classes"));
-        } else {
-            lists = configureDataSource(config->get("classes"));
-        }
 
-        // Replace the server's lists.  The returned lists will be stored
-        // in a local variable 'lists', and will be destroyed outside of
-        // the temporary block for the lock scope.  That way we can minimize
-        // the range of the critical section.
-        {
-            isc::util::thread::Mutex::Locker locker(
-                server->getDataSrcClientListMutex());
-            lists = server->swapDataSrcClientLists(lists);
-        }
-        // The previous lists are destroyed here.
+    // Note: remote config handler is requested to be exception free.
+    // While the code below is not 100% exception free, such an exception
+    // is really fatal and the server should actually stop.  So we don't
+    // bother to catch them; the exception would be propagated to the
+    // top level of the server and terminate it.
+
+    if (*first_time) {
+        // HACK: The default is not passed to the handler in the first
+        // callback. This one will get the default (or, current value).
+        // Further updates will work the usual way.
+        assert(config_session != NULL);
+        *first_time = false;
+        server->getDataSrcClientsMgr().reconfigure(
+            config_session->getRemoteConfigValue("data_sources", "classes"));
+    } else if (config->contains("classes")) {
+        server->getDataSrcClientsMgr().reconfigure(config->get("classes"));
     }
 }
 
diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc
index 2d5f336..b310b23 100644
--- a/src/bin/auth/statistics.cc
+++ b/src/bin/auth/statistics.cc
@@ -13,9 +13,11 @@
 // 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>
@@ -32,107 +34,206 @@
 
 #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;
 
-// TODO: We need a namespace ("auth_server"?) to hold
-// AuthSrv and AuthCounters.
+namespace isc {
+namespace auth {
+namespace statistics {
 
 // TODO: Make use of wrappers like isc::dns::Opcode
 // for counter item type.
 
-class AuthCountersImpl : boost::noncopyable {
+class CountersImpl : boost::noncopyable {
 public:
-    AuthCountersImpl();
-    ~AuthCountersImpl();
-    void inc(const AuthCounters::ServerCounterType type);
-    void inc(const Opcode opcode) {
-        opcode_counter_.inc(opcode.getCode());
-    }
-    void inc(const Rcode rcode) {
-        rcode_counter_.inc(rcode.getCode());
-    }
-    void inc(const std::string& zone,
-             const AuthCounters::PerZoneCounterType type);
+    CountersImpl();
+    ~CountersImpl();
+    void inc(const QRAttributes& qrattrs, const Message& response);
     isc::data::ConstElementPtr getStatistics() const;
-    void registerStatisticsValidator
-    (AuthCounters::validator_type validator);
-    // Currently for testing purpose only
-    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
-    uint64_t getCounter(const Opcode opcode) const {
-        return (opcode_counter_.get(opcode.getCode()));
-    }
-    uint64_t getCounter(const Rcode rcode) const {
-        return (rcode_counter_.get(rcode.getCode()));
-    }
+    void registerStatisticsValidator(Counters::validator_type validator);
 private:
-    Counter server_counter_;
-    Counter opcode_counter_;
-    static const size_t NUM_OPCODES = 16;
-    Counter rcode_counter_;
-    static const size_t NUM_RCODES = 17;
-    CounterDictionary per_zone_counter_;
-    AuthCounters::validator_type validator_;
+    // counter for query/response
+    Counter server_qr_counter_;
+    // set of counters for zones
+    CounterDictionary zone_qr_counters_;
+    // validator
+    Counters::validator_type validator_;
 };
 
-AuthCountersImpl::AuthCountersImpl() :
-    // initialize counter
-    // size of server_counter_: AuthCounters::SERVER_COUNTER_TYPES
-    // size of per_zone_counter_: AuthCounters::PER_ZONE_COUNTER_TYPES
-    server_counter_(AuthCounters::SERVER_COUNTER_TYPES),
-    opcode_counter_(NUM_OPCODES), rcode_counter_(NUM_RCODES),
-    per_zone_counter_(AuthCounters::PER_ZONE_COUNTER_TYPES)
-{
-    per_zone_counter_.addElement("_SERVER_");
-}
+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_()
+{}
 
-AuthCountersImpl::~AuthCountersImpl()
+CountersImpl::~CountersImpl()
 {}
 
 void
-AuthCountersImpl::inc(const AuthCounters::ServerCounterType type) {
-    server_counter_.inc(type);
-}
+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);
+    }
 
-void
-AuthCountersImpl::inc(const std::string& zone,
-                      const AuthCounters::PerZoneCounterType type)
-{
-    per_zone_counter_[zone].inc(type);
+    // 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
-AuthCountersImpl::getStatistics() const {
+CountersImpl::getStatistics() const {
     std::stringstream statistics_string;
     statistics_string << "{ \"queries.udp\": "
-                      << server_counter_.get(AuthCounters::SERVER_UDP_QUERY)
+                      << server_qr_counter_.get(QR_REQUEST_UDP)
                       << ", \"queries.tcp\": "
-                      << server_counter_.get(AuthCounters::SERVER_TCP_QUERY);
+                      << server_qr_counter_.get(QR_REQUEST_TCP);
     // Insert non 0 Opcode counters.
-    for (int i = 0; i < NUM_OPCODES; ++i) {
-        const Counter::Type counter = opcode_counter_.get(i);
+    for (int i = QR_OPCODE_QUERY; i <= QR_OPCODE_OTHER; ++i) {
+        const Counter::Type counter = server_qr_counter_.get(i);
         if (counter != 0) {
-            // The counter item name should be derived lower-cased textual
-            // representation of the code.
-            std::string opcode_txt = Opcode(i).toText();
-            std::transform(opcode_txt.begin(), opcode_txt.end(),
-                           opcode_txt.begin(), ::tolower);
-            statistics_string << ", \"opcode." << opcode_txt << "\": "
-                              << counter;
+            statistics_string << ", \"" << "opcode." <<
+                                 QRCounterOpcode[i - QR_OPCODE_QUERY].name <<
+                                 "\": " << counter;
         }
     }
     // Insert non 0 Rcode counters.
-    for (int i = 0; i < NUM_RCODES; ++i) {
-        const Counter::Type counter = rcode_counter_.get(i);
+    for (int i = QR_RCODE_NOERROR; i <= QR_RCODE_OTHER; ++i) {
+        const Counter::Type counter = server_qr_counter_.get(i);
         if (counter != 0) {
-            // The counter item name should be derived lower-cased textual
-            // representation of the code.
-            std::string rcode_txt = Rcode(i).toText();
-            std::transform(rcode_txt.begin(), rcode_txt.end(),
-                           rcode_txt.begin(), ::tolower);
-            statistics_string << ", \"rcode." << rcode_txt << "\": "
-                              << counter;
+            statistics_string << ", \"" << "rcode." <<
+                                 QRCounterRcode[i - QR_RCODE_NOERROR].name <<
+                                 "\": " << counter;
         }
     }
     statistics_string << "}";
@@ -150,61 +251,34 @@ AuthCountersImpl::getStatistics() const {
 }
 
 void
-AuthCountersImpl::registerStatisticsValidator
-    (AuthCounters::validator_type validator)
+CountersImpl::registerStatisticsValidator
+    (Counters::validator_type validator)
 {
     validator_ = validator;
 }
 
-// Currently for testing purpose only
-uint64_t
-AuthCountersImpl::getCounter(const AuthCounters::ServerCounterType type) const {
-    return (server_counter_.get(type));
-}
-
-AuthCounters::AuthCounters() : impl_(new AuthCountersImpl())
+Counters::Counters() : impl_(new CountersImpl())
 {}
 
-AuthCounters::~AuthCounters() {}
+Counters::~Counters() {}
 
 void
-AuthCounters::inc(const AuthCounters::ServerCounterType type) {
-    impl_->inc(type);
-}
-
-void
-AuthCounters::inc(const Opcode opcode) {
-    impl_->inc(opcode);
-}
-
-void
-AuthCounters::inc(const Rcode rcode) {
-    impl_->inc(rcode);
+Counters::inc(const QRAttributes& qrattrs, const Message& response) {
+    impl_->inc(qrattrs, response);
 }
 
 isc::data::ConstElementPtr
-AuthCounters::getStatistics() const {
+Counters::getStatistics() const {
     return (impl_->getStatistics());
 }
 
-uint64_t
-AuthCounters::getCounter(const AuthCounters::ServerCounterType type) const {
-    return (impl_->getCounter(type));
-}
-
-uint64_t
-AuthCounters::getCounter(const Opcode opcode) const {
-    return (impl_->getCounter(opcode));
-}
-
-uint64_t
-AuthCounters::getCounter(const Rcode rcode) const {
-    return (impl_->getCounter(rcode));
-}
-
 void
-AuthCounters::registerStatisticsValidator
-    (AuthCounters::validator_type validator) const
+Counters::registerStatisticsValidator
+    (Counters::validator_type validator) const
 {
     return (impl_->registerStatisticsValidator(validator));
 }
+
+} // namespace statistics
+} // namespace auth
+} // namespace isc
diff --git a/src/bin/auth/statistics.h b/src/bin/auth/statistics.h
index 0ca8da4..d60c681 100644
--- a/src/bin/auth/statistics.h
+++ b/src/bin/auth/statistics.h
@@ -12,22 +12,136 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __STATISTICS_H
-#define __STATISTICS_H 1
+#ifndef STATISTICS_H
+#define STATISTICS_H 1
 
-#include <dns/opcode.h>
-#include <dns/rcode.h>
 #include <cc/session.h>
 #include <cc/data.h>
 
+#include <dns/message.h>
+
+#include <string>
+
 #include <stdint.h>
 #include <boost/scoped_ptr.hpp>
 
-class AuthCountersImpl;
+namespace isc {
+namespace auth {
+namespace statistics {
+
+class CountersImpl;
+
+class QRAttributes {
+/// \brief Query/Response attributes for statistics.
+///
+/// This class holds some attributes related to a query/response
+/// for statistics data collection.
+///
+/// This class does not have getter methods since it exposes private members
+/// to \c CountersImpl directly.
+friend class CountersImpl;
+private:
+    // request attributes
+    int req_ip_version_;            // 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
+public:
+    /// 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();
+    };
+
+    /// The destructor.
+    ///
+    /// This method never throws an exception.
+    ///
+    ~QRAttributes() {};
+    /// \brief Set query opcode.
+    /// \throw None
+    void setQueryOpCode(const int opcode) {
+        req_opcode_ = opcode;
+    };
+    /// \brief Set IP version carrying a query.
+    /// \throw None
+    void setQueryIPVersion(const int ip_version) {
+        req_ip_version_ = ip_version;
+    };
+    /// \brief Set transport protocol carrying a query.
+    /// \throw None
+    void setQueryTransportProtocol(const int transport_protocol) {
+        req_transport_protocol_ = transport_protocol;
+    };
+    /// \brief Set query EDNS attributes.
+    /// \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.
+    /// \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.
+    /// \throw None
+    void setOrigin(const std::string& origin) {
+        zone_origin_ = origin;
+    };
+    /// \brief Set if the answer was sent.
+    /// \throw None
+    void answerWasSent() {
+        answer_sent_ = true;
+    };
+    /// \brief Set 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;
+    };
+};
 
 /// \brief Set of query counters.
 ///
-/// \c AuthCounters is set of query counters class. It holds query 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).
 ///
@@ -35,9 +149,7 @@ class AuthCountersImpl;
 /// statistics module.
 ///
 /// This class is designed to be a part of \c AuthSrv.
-/// Call \c inc() to increment a counter for specific type of query in
-/// the query processing function. use \c enum \c CounterType to specify
-/// the type of query.
+/// 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.
 ///
@@ -50,61 +162,31 @@ class AuthCountersImpl;
 /// construction overhead of this approach should be acceptable.
 ///
 /// \todo Hold counters for each query types (Notify, Axfr, Ixfr, Normal)
-/// \todo Consider overhead of \c AuthCounters::inc()
-class AuthCounters {
+/// \todo Consider overhead of \c Counters::inc()
+class Counters {
 private:
-    boost::scoped_ptr<AuthCountersImpl> impl_;
+    boost::scoped_ptr<CountersImpl> impl_;
 public:
-    // Enum for the type of counter
-    enum ServerCounterType {
-        SERVER_UDP_QUERY,       ///< SERVER_UDP_QUERY: counter for UDP queries
-        SERVER_TCP_QUERY,       ///< SERVER_TCP_QUERY: counter for TCP queries
-        SERVER_COUNTER_TYPES    ///< The number of defined counters
-    };
-    enum PerZoneCounterType {
-        ZONE_UDP_QUERY,         ///< ZONE_UDP_QUERY: counter for UDP queries
-        ZONE_TCP_QUERY,         ///< ZONE_TCP_QUERY: counter for TCP queries
-        PER_ZONE_COUNTER_TYPES  ///< The number of defined counters
-    };
     /// The constructor.
     ///
     /// This constructor is mostly exception free. But it may still throw
     /// a standard exception if memory allocation fails inside the method.
     ///
-    AuthCounters();
+    Counters();
     /// The destructor.
     ///
     /// This method never throws an exception.
     ///
-    ~AuthCounters();
+    ~Counters();
 
-    /// \brief Increment the counter specified by the parameter.
-    ///
-    /// \param type Type of a counter to increment.
+    /// \brief Increment counters according to the parameters.
     ///
-    /// \throw std::out_of_range \a type is unknown.
-    ///
-    /// usage: counter.inc(AuthCounters::SERVER_UDP_QUERY);
-    /// 
-    void inc(const ServerCounterType type);
-
-    /// \brief Increment the counter of a per opcode counter.
-    ///
-    /// \note This is a tentative interface.  See \c getCounter().
-    ///
-    /// \param opcode The opcode of the counter to increment.
+    /// \param qrattrs Query/Response attributes.
+    /// \param response DNS response message.
     ///
     /// \throw None
-    void inc(const isc::dns::Opcode opcode);
-
-    /// \brief Increment the counter of a per rcode counter.
-    ///
-    /// \note This is a tentative interface.  See \c getCounter().
     ///
-    /// \param rcode The rcode of the counter to increment.
-    ///
-    /// \throw None
-    void inc(const isc::dns::Rcode rcode);
+    void inc(const QRAttributes& qrattrs, const isc::dns::Message& response);
 
     /// \brief Answers statistics counters to statistics module.
     ///
@@ -116,47 +198,6 @@ public:
     ///
     isc::data::ConstElementPtr getStatistics() const;
 
-    /// \brief Get the value of a counter in the AuthCounters.
-    ///
-    /// This function returns a value of the counter specified by \a type.
-    /// This method never throws an exception.
-    ///
-    /// Note: Currently this function is for testing purpose only.
-    ///
-    /// \param type Type of a counter to get the value of
-    ///
-    /// \return the value of the counter specified by \a type.
-    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
-
-    /// \brief Get the value of a per opcode counter.
-    ///
-    /// This method returns the value of the per opcode counter for the
-    /// specified \c opcode.
-    ///
-    /// \note This is a tentative interface as an attempt of experimentally
-    /// supporting more statistics counters.  This should eventually be more
-    /// generalized.  In any case, this method is mainly for testing.
-    ///
-    /// \throw None
-    /// \param opcode The opcode of the counter to get the value of
-    /// \return the value of the counter.
-    uint64_t getCounter(const isc::dns::Opcode opcode) const;
-
-    /// \brief Get the value of a per rcode counter.
-    ///
-    /// This method returns the value of the per rcode counter for the
-    /// specified \c rcode.
-    ///
-    /// \note As mentioned in getCounter(const isc::dns::Opcode opcode),
-    /// This is a tentative interface as an attempt of experimentally
-    /// supporting more statistics counters.  This should eventually be more
-    /// generalized.  In any case, this method is mainly for testing.
-    ///
-    /// \throw None
-    /// \param rcode The rcode of the counter to get the value of
-    /// \return the value of the counter.
-    uint64_t getCounter(const isc::dns::Rcode rcode) const;
-
     /// \brief A type of validation function for the specification in
     /// isc::config::ModuleSpec.
     ///
@@ -168,17 +209,21 @@ public:
     validator_type;
 
     /// \brief Register a function type of the statistics validation
-    /// function for AuthCounters.
+    /// function for Counters.
     ///
     /// This method never throws an exception.
     ///
     /// \param validator A function type of the validation of
     /// statistics specification.
     ///
-    void registerStatisticsValidator(AuthCounters::validator_type validator) const;
+    void registerStatisticsValidator(Counters::validator_type validator) const;
 };
 
-#endif // __STATISTICS_H
+} // namespace statistics
+} // namespace auth
+} // namespace isc
+
+#endif // STATISTICS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/statistics_items.h b/src/bin/auth/statistics_items.h
new file mode 100644
index 0000000..5839206
--- /dev/null
+++ b/src/bin/auth/statistics_items.h
@@ -0,0 +1,609 @@
+// 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/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 6b9d385..6a91309 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -41,7 +41,7 @@ run_unittests_SOURCES += ../query.h ../query.cc
 run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
 run_unittests_SOURCES += ../command.h ../command.cc
 run_unittests_SOURCES += ../common.h ../common.cc
-run_unittests_SOURCES += ../statistics.h ../statistics.cc
+run_unittests_SOURCES += ../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 += auth_srv_unittest.cc
@@ -51,6 +51,9 @@ 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
 run_unittests_SOURCES += datasrc_config_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 
@@ -72,7 +75,6 @@ run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libb10-threads.la
 run_unittests_LDADD += $(GTEST_LDADD)
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index e248e81..8015043 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -15,7 +15,6 @@
 #include <config.h>
 
 #include <util/io/sockaddr_util.h>
-#include <util/memory_segment_local.h>
 
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -36,10 +35,10 @@
 #include <auth/command.h>
 #include <auth/common.h>
 #include <auth/statistics.h>
+#include <auth/statistics_items.h>
 #include <auth/datasrc_config.h>
 
 #include <util/unittests/mock_socketsession.h>
-#include <util/threads/lock.h>
 #include <dns/tests/unittest_util.h>
 #include <testutils/dnsmessage_test.h>
 #include <testutils/srv_test.h>
@@ -70,12 +69,15 @@ using namespace isc::util::unittests;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::xfr;
+using namespace isc::auth;
 using namespace isc::asiodns;
 using namespace isc::asiolink;
 using namespace isc::testutils;
 using namespace isc::server_common::portconfig;
+using isc::datasrc::memory::ZoneTableSegment;
 using isc::UnitTestUtil;
 using boost::scoped_ptr;
+using isc::auth::statistics::Counters;
 
 namespace {
 const char* const CONFIG_TESTDB =
@@ -123,29 +125,47 @@ protected:
 
     // Helper for checking Rcode statistic counters;
     // Checks for one specific Rcode statistics counter value
-    void checkRcodeCounter(const Rcode& rcode, int expected_value) const {
-        EXPECT_EQ(expected_value, server.getCounter(rcode)) <<
-                  "Expected Rcode count for " << rcode.toText() <<
-                  " " << expected_value << ", was: " <<
-                  server.getCounter(rcode);
+    void checkRcodeCounter(const std::string& rcode_name, const int rcode_value,
+                           const int expected_value) const
+    {
+            EXPECT_EQ(expected_value, rcode_value) <<
+                      "Expected Rcode count for " << rcode_name <<
+                      " " << expected_value << ", was: " <<
+                      rcode_value;
     }
 
     // Checks whether all Rcode counters are set to zero
     void checkAllRcodeCountersZero() const {
-        for (int i = 0; i < 17; i++) {
-            checkRcodeCounter(Rcode(i), 0);
-        }
+        // 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 {
-        for (int i = 0; i < 17; i++) {
-            const Rcode rc(i);
-            if (rc == rcode) {
-                checkRcodeCounter(Rcode(i), value);
-            } else {
-                checkRcodeCounter(Rcode(i), 0);
+        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());
+
+        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);
+                }
             }
         }
     }
@@ -222,6 +242,29 @@ 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(),
@@ -405,7 +448,9 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
         "It should be unsigned with this error";
     // TSIG should have failed, and so the per opcode counter shouldn't be
     // incremented.
-    EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
+    ConstElementPtr stats = server.getStatistics();
+    expectCounterItem(stats, "opcode.normal", 0);
+    expectCounterItem(stats, "opcode.other", 0);
 
     checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
 }
@@ -726,11 +771,11 @@ TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
 }
 
 void
-installDataSrcClientLists(AuthSrv& server,
-                          AuthSrv::DataSrcClientListsPtr lists)
-{
-    thread::Mutex::Locker locker(server.getDataSrcClientListMutex());
-    server.swapDataSrcClientLists(lists);
+installDataSrcClientLists(AuthSrv& server, ClientListMapPtr lists) {
+    // For now, we use explicit swap than reconfigure() because the latter
+    // involves a separate thread and cannot guarantee the new config is
+    // available for the subsequent test.
+    server.getDataSrcClientsMgr().setDataSrcClientLists(lists);
 }
 
 void
@@ -1041,8 +1086,12 @@ TEST_F(AuthSrvTest,
 
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
+    // 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"),
@@ -1050,18 +1099,25 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    // After processing UDP query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
-    // The counter for opcode Query should also be one
-    EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
-    // The counter for REFUSED responses should also be one, the rest zero
-    checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
+    // 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);
 }
 
 // Submit TCP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPNormal) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // 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"),
@@ -1069,18 +1125,24 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
     createRequestPacket(request_message, IPPROTO_TCP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    // After processing TCP query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
-    // The counter for SUCCESS responses should also be one
-    EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
-    // The counter for REFUSED responses should also be one, the rest zero
-    checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
+    // 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);
 }
 
 // Submit TCP AXFR query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // 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);
@@ -1089,16 +1151,24 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
-    // After processing TCP AXFR query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
-    // No rcodes should be incremented
-    checkAllRcodeCountersZero();
+    // 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);
 }
 
 // Submit TCP IXFR query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // 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);
@@ -1107,14 +1177,27 @@ TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
-    // After processing TCP IXFR query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // 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);
 }
 
 TEST_F(AuthSrvTest, queryCounterOpcodes) {
-    for (int i = 0; i < 16; ++i) {
+    // 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.
-        EXPECT_EQ(0, server.getCounter(Opcode(i)));
+        expectCounterItem(server.getStatistics(),
+                          std::string("opcode.") +
+                              QRCounterOpcode[QROpCodeToQRCounterType[i] -
+                                                  QR_OPCODE_QUERY].name,
+                          0);
 
         // For each possible opcode, create a request message and send it
         UnitTestUtil::createRequestMessage(request_message, Opcode(i),
@@ -1132,7 +1215,45 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) {
         }
 
         // Confirm the counter.
-        EXPECT_EQ(i + 1, server.getCounter(Opcode(i)));
+        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);
     }
 }
 
@@ -1401,7 +1522,9 @@ public:
              real_list, ThrowWhen throw_when, bool isc_exception,
              ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
         ConfigurableClientList(RRClass::IN()),
-        real_(real_list)
+        real_(real_list),
+        config_(Element::fromJSON("{}")),
+        ztable_segment_(ZoneTableSegment::create(*config_, RRClass::IN()))
     {
         BOOST_FOREACH(const DataSourceInfo& info, real_->getDataSources()) {
              const isc::datasrc::DataSourceClientPtr
@@ -1413,13 +1536,14 @@ public:
              data_sources_.push_back(
                  DataSourceInfo(client.get(),
                                 isc::datasrc::DataSourceClientContainerPtr(),
-                                false, RRClass::IN(), mem_sgmt_));
+                                false, RRClass::IN(), ztable_segment_));
         }
     }
 private:
     const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
+    const ConstElementPtr config_;
+    boost::shared_ptr<ZoneTableSegment> ztable_segment_;
     vector<isc::datasrc::DataSourceClientPtr> clients_;
-    MemorySegmentLocal mem_sgmt_;
 };
 
 } // end anonymous namespace for throwing proxy classes
@@ -1438,16 +1562,16 @@ TEST_F(AuthSrvTest,
 {
     // Set real inmem client to proxy
     updateInMemory(server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList> list;
+    DataSrcClientsMgr& mgr = server.getDataSrcClientsMgr();
     {
-        isc::util::thread::Mutex::Locker locker(
-            server.getDataSrcClientListMutex());
-        boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-            list(new FakeList(server.getDataSrcClientList(RRClass::IN()),
-                              THROW_NEVER, false));
-        AuthSrv::DataSrcClientListsPtr lists(new std::map<RRClass, ListPtr>);
-        lists->insert(pair<RRClass, ListPtr>(RRClass::IN(), list));
-        server.swapDataSrcClientLists(lists);
+        DataSrcClientsMgr::Holder holder(mgr);
+        list.reset(new FakeList(holder.findClientList(RRClass::IN()),
+                                THROW_NEVER, false));
     }
+    ClientListMapPtr lists(new std::map<RRClass, ListPtr>);
+    lists->insert(pair<RRClass, ListPtr>(RRClass::IN(), list));
+    server.getDataSrcClientsMgr().setDataSrcClientLists(lists);
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1470,14 +1594,16 @@ setupThrow(AuthSrv& server, ThrowWhen throw_when, bool isc_exception,
 {
     updateInMemory(server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
-    isc::util::thread::Mutex::Locker locker(
-        server.getDataSrcClientListMutex());
-    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        list(new FakeList(server.getDataSrcClientList(RRClass::IN()),
-                          throw_when, isc_exception, rrset));
-    AuthSrv::DataSrcClientListsPtr lists(new std::map<RRClass, ListPtr>);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList> list;
+    DataSrcClientsMgr& mgr = server.getDataSrcClientsMgr();
+    {           // we need to limit the scope so swap is outside of it
+        DataSrcClientsMgr::Holder holder(mgr);
+        list.reset(new FakeList(holder.findClientList(RRClass::IN()),
+                                throw_when, isc_exception, rrset));
+    }
+    ClientListMapPtr lists(new std::map<RRClass, ListPtr>);
     lists->insert(pair<RRClass, ListPtr>(RRClass::IN(), list));
-    server.swapDataSrcClientLists(lists);
+    mgr.setDataSrcClientLists(lists);
 }
 
 TEST_F(AuthSrvTest,
@@ -1713,6 +1839,15 @@ namespace {
         isc::config::parseAnswer(command_result, response);
         EXPECT_EQ(0, command_result);
     }
+
+    void sendCommand(AuthSrv& server, const std::string& command,
+                     ConstElementPtr args, int expected_result) {
+        ConstElementPtr response = execAuthServerCommand(server, command,
+                                                         args);
+        int command_result = -1;
+        isc::config::parseAnswer(command_result, response);
+        EXPECT_EQ(expected_result, command_result);
+    }
 } // end anonymous namespace
 
 TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
@@ -1784,57 +1919,18 @@ TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
                 Opcode::UPDATE().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 
-// Check the client list accessors
-TEST_F(AuthSrvTest, clientList) {
-    // We need to lock the mutex to make the (get|set)ClientList happy.
-    // There's a debug-build only check in them to make sure everything
-    // locks them and we call them directly here.
-    isc::util::thread::Mutex::Locker locker(
-        server.getDataSrcClientListMutex());
-
-    AuthSrv::DataSrcClientListsPtr lists; // initially empty
-
-    // The lists don't exist. Therefore, the list of RRClasses is empty.
-    EXPECT_TRUE(server.swapDataSrcClientLists(lists)->empty());
+TEST_F(AuthSrvTest, loadZoneCommand) {
+    // Just some very basic tests, to check the command is accepted, and that
+    // it raises on bad arguments, but not on correct ones (full testing
+    // is handled in the unit tests for the corresponding classes)
 
-    // Put something in.
-    const ListPtr list(new ConfigurableClientList(RRClass::IN()));
-    const ListPtr list2(new ConfigurableClientList(RRClass::CH()));
-
-    lists.reset(new std::map<RRClass, ListPtr>);
-    lists->insert(pair<RRClass, ListPtr>(RRClass::IN(), list));
-    lists->insert(pair<RRClass, ListPtr>(RRClass::CH(), list2));
-    server.swapDataSrcClientLists(lists);
-
-    // And the lists can be retrieved.
-    EXPECT_EQ(list, server.getDataSrcClientList(RRClass::IN()));
-    EXPECT_EQ(list2, server.getDataSrcClientList(RRClass::CH()));
-
-    // Replace the lists with new lists containing only one list.
-    lists.reset(new std::map<RRClass, ListPtr>);
-    lists->insert(pair<RRClass, ListPtr>(RRClass::IN(), list));
-    lists = server.swapDataSrcClientLists(lists);
-
-    // Old one had two lists.  That confirms our swap for IN and CH classes
-    // (i.e., no other entries were there).
-    EXPECT_EQ(2, lists->size());
-
-    // The CH list really got deleted.
-    EXPECT_EQ(list, server.getDataSrcClientList(RRClass::IN()));
-    EXPECT_FALSE(server.getDataSrcClientList(RRClass::CH()));
-}
-
-// We just test the mutex can be locked (exactly once).
-TEST_F(AuthSrvTest, mutex) {
-    isc::util::thread::Mutex::Locker l1(server.getDataSrcClientListMutex());
-    // TODO: Once we have non-debug build, this one will not work, since
-    // we currently use the fact that we can't lock twice from the same
-    // thread. In the non-debug mode, this would deadlock.
-    // Skip then.
-    EXPECT_THROW({
-        isc::util::thread::Mutex::Locker l2(
-            server.getDataSrcClientListMutex());
-    }, isc::InvalidOperation);
+    // Empty map should fail
+    ElementPtr args(Element::createMap());
+    sendCommand(server, "loadzone", args, 1);
+    // Setting an origin should be enough (even if it isn't actually loaded,
+    // it should be initially accepted)
+    args->set("origin", Element::create("example.com"));
+    sendCommand(server, "loadzone", args, 0);
 }
 
 }
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index 8aa2322..be90d73 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -16,10 +16,7 @@
 
 #include "datasrc_util.h"
 
-#include <util/threads/lock.h>
-
 #include <auth/auth_srv.h>
-#include <auth/auth_config.h>
 #include <auth/command.h>
 #include <auth/datasrc_config.h>
 
@@ -58,6 +55,7 @@ using namespace isc::datasrc;
 using namespace isc::config;
 using namespace isc::util::unittests;
 using namespace isc::testutils;
+using namespace isc::auth;
 using namespace isc::auth::unittest;
 
 namespace {
@@ -171,285 +169,6 @@ TEST_F(AuthCommandTest, shutdownIncorrectPID) {
     EXPECT_EQ(0, rcode_);
 }
 
-// A helper function commonly used for the "loadzone" command tests.
-// It configures the server with a memory data source containing two
-// zones, and checks the zones are correctly loaded.
-void
-zoneChecks(AuthSrv& server) {
-    isc::util::thread::Mutex::Locker locker(
-        server.getDataSrcClientListMutex());
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test1.example")).finder_->
-              find(Name("ns.test1.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test1.example")).finder_->
-              find(Name("ns.test1.example"), RRType::AAAA())->code);
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test2.example")).finder_->
-              find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test2.example")).finder_->
-              find(Name("ns.test2.example"), RRType::AAAA())->code);
-}
-
-void
-installDataSrcClientLists(AuthSrv& server,
-                          AuthSrv::DataSrcClientListsPtr lists)
-{
-    isc::util::thread::Mutex::Locker locker(
-        server.getDataSrcClientListMutex());
-    server.swapDataSrcClientLists(lists);
-}
-
-void
-configureZones(AuthSrv& server) {
-    ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR "/test1.zone.in "
-                        TEST_DATA_BUILDDIR "/test1.zone.copied"));
-    ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
-                        TEST_DATA_BUILDDIR "/test2.zone.copied"));
-
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"IN\": [{"
-        "   \"type\": \"MasterFiles\","
-        "   \"params\": {"
-        "       \"test1.example\": \"" +
-                string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\","
-        "       \"test2.example\": \"" +
-                string(TEST_DATA_BUILDDIR "/test2.zone.copied") + "\""
-        "   },"
-        "   \"cache-enable\": true"
-        "}]}"));
-
-    installDataSrcClientLists(server, configureDataSource(config));
-
-    zoneChecks(server);
-}
-
-void
-newZoneChecks(AuthSrv& server) {
-    isc::util::thread::Mutex::Locker locker(
-        server.getDataSrcClientListMutex());
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test1.example")).finder_->
-              find(Name("ns.test1.example"), RRType::A())->code);
-    // now test1.example should have ns/AAAA
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test1.example")).finder_->
-              find(Name("ns.test1.example"), RRType::AAAA())->code);
-
-    // test2.example shouldn't change
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test2.example")).finder_->
-              find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET,
-              server.getDataSrcClientList(RRClass::IN())->
-              find(Name("ns.test2.example")).finder_->
-              find(Name("ns.test2.example"), RRType::AAAA())->code);
-}
-
-TEST_F(AuthCommandTest, loadZone) {
-    configureZones(server_);
-
-    ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
-                        "/test1-new.zone.in "
-                        TEST_DATA_BUILDDIR "/test1.zone.copied"));
-    ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
-                        "/test2-new.zone.in "
-                        TEST_DATA_BUILDDIR "/test2.zone.copied"));
-
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\"}"));
-    checkAnswer(0);
-    newZoneChecks(server_);
-}
-
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadZoneSQLite3
-#else
-       loadZoneSQLite3
-#endif
-    )
-{
-    // Prepare the database first
-    const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
-    const string bad_db = TEST_DATA_BUILDDIR "/does-not-exist.sqlite3";
-    stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
-    createSQLite3DB(RRClass::IN(), Name("example.org"), test_db.c_str(), ss);
-    // This describes the data source in the configuration
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"IN\": [{"
-        "    \"type\": \"sqlite3\","
-        "    \"params\": {\"database_file\": \"" + test_db + "\"},"
-        "    \"cache-enable\": true,"
-        "    \"cache-zones\": [\"example.org\"]"
-        "}]}"));
-    installDataSrcClientLists(server_, configureDataSource(config));
-
-    {
-        isc::util::thread::Mutex::Locker locker(
-            server_.getDataSrcClientListMutex());
-        // Check that the A record at www.example.org does not exist
-        EXPECT_EQ(ZoneFinder::NXDOMAIN,
-                  server_.getDataSrcClientList(RRClass::IN())->
-                  find(Name("example.org")).finder_->
-                  find(Name("www.example.org"), RRType::A())->code);
-
-        // Add the record to the underlying sqlite database, by loading
-        // it as a separate datasource, and updating it
-        ConstElementPtr sql_cfg = Element::fromJSON("{ \"type\": \"sqlite3\","
-                                                    "\"database_file\": \""
-                                                    + test_db + "\"}");
-        DataSourceClientContainer sql_ds("sqlite3", sql_cfg);
-        ZoneUpdaterPtr sql_updater =
-            sql_ds.getInstance().getUpdater(Name("example.org"), false);
-        RRsetPtr rrset(new RRset(Name("www.example.org."), RRClass::IN(),
-                                 RRType::A(), RRTTL(60)));
-        rrset->addRdata(rdata::createRdata(rrset->getType(),
-                                           rrset->getClass(),
-                                           "192.0.2.1"));
-        sql_updater->addRRset(*rrset);
-        sql_updater->commit();
-
-        EXPECT_EQ(ZoneFinder::NXDOMAIN,
-                  server_.getDataSrcClientList(RRClass::IN())->
-                  find(Name("example.org")).finder_->
-                  find(Name("www.example.org"), RRType::A())->code);
-    }
-
-    // Now send the command to reload it
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"example.org\"}"));
-    checkAnswer(0, "Successful load");
-
-    {
-        isc::util::thread::Mutex::Locker locker(
-            server_.getDataSrcClientListMutex());
-        // And now it should be present too.
-        EXPECT_EQ(ZoneFinder::SUCCESS,
-                  server_.getDataSrcClientList(RRClass::IN())->
-                  find(Name("example.org")).finder_->
-                  find(Name("www.example.org"), RRType::A())->code);
-    }
-
-    // Some error cases. First, the zone has no configuration. (note .com here)
-    result_ = execAuthServerCommand(server_, "loadzone",
-        Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1, "example.com");
-
-    {
-        isc::util::thread::Mutex::Locker locker(
-            server_.getDataSrcClientListMutex());
-        // The previous zone is not hurt in any way
-        EXPECT_EQ(ZoneFinder::SUCCESS,
-                  server_.getDataSrcClientList(RRClass::IN())->
-                  find(Name("example.org")).finder_->
-                  find(Name("example.org"), RRType::SOA())->code);
-    }
-
-    const ConstElementPtr config2(Element::fromJSON("{"
-        "\"IN\": [{"
-        "    \"type\": \"sqlite3\","
-        "    \"params\": {\"database_file\": \"" + bad_db + "\"},"
-        "    \"cache-enable\": true,"
-        "    \"cache-zones\": [\"example.com\"]"
-        "}]}"));
-    EXPECT_THROW(configureDataSource(config2),
-                 ConfigurableClientList::ConfigurationError);
-
-    result_ = execAuthServerCommand(server_, "loadzone",
-        Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1, "Unreadable");
-
-    isc::util::thread::Mutex::Locker locker(
-        server_.getDataSrcClientListMutex());
-    // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS,
-              server_.getDataSrcClientList(RRClass::IN())->
-              find(Name("example.org")).finder_->
-              find(Name("example.org"), RRType::SOA())->code);
-}
-
-TEST_F(AuthCommandTest, loadBrokenZone) {
-    configureZones(server_);
-
-    ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
-                        "/test1-broken.zone.in "
-                        TEST_DATA_BUILDDIR "/test1.zone.copied"));
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\"}"));
-    checkAnswer(1);
-    zoneChecks(server_);     // zone shouldn't be replaced
-}
-
-TEST_F(AuthCommandTest, loadUnreadableZone) {
-    configureZones(server_);
-
-    // install the zone file as unreadable
-    ASSERT_EQ(0, system(INSTALL_PROG " -c -m 000 " TEST_DATA_DIR
-                        "/test1.zone.in "
-                        TEST_DATA_BUILDDIR "/test1.zone.copied"));
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\"}"));
-    checkAnswer(1);
-    zoneChecks(server_);     // zone shouldn't be replaced
-}
-
-TEST_F(AuthCommandTest, loadZoneWithoutDataSrc) {
-    // try to execute load command without configuring the zone beforehand.
-    // it should fail.
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\"}"));
-    checkAnswer(1);
-}
-
-TEST_F(AuthCommandTest, loadZoneInvalidParams) {
-    configureZones(server_);
-
-    // null arg
-    result_ = execAuthServerCommand(server_, "loadzone", ElementPtr());
-    checkAnswer(1, "Null arg");
-
-    // zone class is bogus
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"class\": \"no_such_class\"}"));
-    checkAnswer(1, "No such class");
-
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"class\": 1}"));
-    checkAnswer(1, "Integral class");
-
-
-    // origin is missing
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON("{}"));
-    checkAnswer(1, "Missing origin");
-
-    // zone doesn't exist in the data source
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON("{\"origin\": \"xx\"}"));
-    checkAnswer(1, "No such zone");
-
-    // origin is bogus
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"...\"}"));
-    checkAnswer(1, "Wrong name");
-
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON("{\"origin\": 10}"));
-    checkAnswer(1, "Integral name");
-}
-
 TEST_F(AuthCommandTest, getStats) {
     result_ = execAuthServerCommand(server_, "getstats", ConstElementPtr());
     parseAnswer(rcode_, result_);
diff --git a/src/bin/auth/tests/datasrc_clients_builder_unittest.cc b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
new file mode 100644
index 0000000..585e7c3
--- /dev/null
+++ b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
@@ -0,0 +1,517 @@
+// 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 <util/unittests/check_valgrind.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/client.h>
+#include <datasrc/factory.h>
+
+#include <auth/datasrc_clients_mgr.h>
+#include <auth/datasrc_config.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include "test_datasrc_clients_mgr.h"
+#include "datasrc_util.h"
+
+#include <gtest/gtest.h>
+
+#include <boost/function.hpp>
+
+#include <cstdlib>
+#include <string>
+#include <sstream>
+
+using isc::data::ConstElementPtr;
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::datasrc;
+using namespace isc::auth::datasrc_clientmgr_internal;
+using namespace isc::auth::unittest;
+using namespace isc::testutils;
+
+namespace {
+class DataSrcClientsBuilderTest : public ::testing::Test {
+protected:
+    DataSrcClientsBuilderTest() :
+        clients_map(new std::map<RRClass,
+                    boost::shared_ptr<ConfigurableClientList> >),
+        builder(&command_queue, &cond, &queue_mutex, &clients_map, &map_mutex),
+        cond(command_queue, delayed_command_queue), rrclass(RRClass::IN()),
+        shutdown_cmd(SHUTDOWN, ConstElementPtr()),
+        noop_cmd(NOOP, ConstElementPtr())
+    {}
+
+    void configureZones();      // used for loadzone related tests
+
+    ClientListMapPtr clients_map; // configured clients
+    std::list<Command> command_queue; // test command queue
+    std::list<Command> delayed_command_queue; // commands available after wait
+    TestDataSrcClientsBuilder builder;
+    TestCondVar cond;
+    TestMutex queue_mutex;
+    TestMutex map_mutex;
+    const RRClass rrclass;
+    const Command shutdown_cmd;
+    const Command noop_cmd;
+};
+
+TEST_F(DataSrcClientsBuilderTest, runSingleCommand) {
+    // A simplest case, just to check the basic behavior.
+    command_queue.push_back(shutdown_cmd);
+    builder.run();
+    EXPECT_TRUE(command_queue.empty());
+    EXPECT_EQ(0, cond.wait_count); // no wait because command queue is not empty
+    EXPECT_EQ(1, queue_mutex.lock_count);
+    EXPECT_EQ(1, queue_mutex.unlock_count);
+}
+
+TEST_F(DataSrcClientsBuilderTest, runMultiCommands) {
+    // Two NOOP commands followed by SHUTDOWN.  We should see two doNoop()
+    // calls.
+    command_queue.push_back(noop_cmd);
+    command_queue.push_back(noop_cmd);
+    command_queue.push_back(shutdown_cmd);
+    builder.run();
+    EXPECT_TRUE(command_queue.empty());
+    EXPECT_EQ(1, queue_mutex.lock_count);
+    EXPECT_EQ(1, queue_mutex.unlock_count);
+    EXPECT_EQ(2, queue_mutex.noop_count);
+}
+
+TEST_F(DataSrcClientsBuilderTest, exception) {
+    // Let the noop command handler throw exceptions and see if we can see
+    // them.  Right now, we simply abort to prevent the system from running
+    // with half-broken state.  Eventually we should introduce a better
+    // error handling.
+    if (!isc::util::unittests::runningOnValgrind()) {
+        command_queue.push_back(noop_cmd);
+        queue_mutex.throw_from_noop = TestMutex::EXCLASS;
+        EXPECT_DEATH_IF_SUPPORTED({builder.run();}, "");
+
+        command_queue.push_back(noop_cmd);
+        queue_mutex.throw_from_noop = TestMutex::INTEGER;
+        EXPECT_DEATH_IF_SUPPORTED({builder.run();}, "");
+    }
+
+    command_queue.push_back(noop_cmd);
+    command_queue.push_back(shutdown_cmd); // we need to stop the loop
+    queue_mutex.throw_from_noop = TestMutex::INTERNAL;
+    builder.run();
+}
+
+TEST_F(DataSrcClientsBuilderTest, condWait) {
+    // command_queue is originally empty, so it will require waiting on
+    // condvar.  specialized wait() will make the delayed command available.
+    delayed_command_queue.push_back(shutdown_cmd);
+    builder.run();
+
+    // There should be one call to wait()
+    EXPECT_EQ(1, cond.wait_count);
+    // wait() effectively involves one more set of lock/unlock, so we have
+    // two in total
+    EXPECT_EQ(2, queue_mutex.lock_count);
+    EXPECT_EQ(2, queue_mutex.unlock_count);
+}
+
+TEST_F(DataSrcClientsBuilderTest, reconfigure) {
+    // Full testing of different configurations is not here, but we
+    // do check a few cases of correct and erroneous input, to verify
+    // the error handling
+
+    // A command structure we'll modify to send different commands
+    Command reconfig_cmd(RECONFIGURE, ConstElementPtr());
+
+    // Initially, no clients should be there
+    EXPECT_TRUE(clients_map->empty());
+
+    // A config that doesn't do much except be accepted
+    ConstElementPtr good_config = Element::fromJSON(
+        "{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {},"
+        "   \"cache-enable\": true"
+        "}]"
+        "}"
+    );
+
+    // A configuration that is 'correct' in the top-level, but contains
+    // bad data for the type it specifies
+    ConstElementPtr bad_config = Element::fromJSON(
+        "{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": { \"foo\": [ 1, 2, 3, 4  ]},"
+        "   \"cache-enable\": true"
+        "}]"
+        "}"
+    );
+
+    reconfig_cmd.second = good_config;
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_EQ(1, clients_map->size());
+    EXPECT_EQ(1, map_mutex.lock_count);
+
+    // Store the nonempty clients map we now have
+    ClientListMapPtr working_config_clients(clients_map);
+
+    // If a 'bad' command argument got here, the config validation should
+    // have failed already, but still, the handler should return true,
+    // and the clients_map should not be updated.
+    reconfig_cmd.second = Element::create("{ \"foo\": \"bar\" }");
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_EQ(working_config_clients, clients_map);
+    // Building failed, so map mutex should not have been locked again
+    EXPECT_EQ(1, map_mutex.lock_count);
+
+    // The same for a configuration that has bad data for the type it
+    // specifies
+    reconfig_cmd.second = bad_config;
+    builder.handleCommand(reconfig_cmd);
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_EQ(working_config_clients, clients_map);
+    // Building failed, so map mutex should not have been locked again
+    EXPECT_EQ(1, map_mutex.lock_count);
+
+    // The same goes for an empty parameter (it should at least be
+    // an empty map)
+    reconfig_cmd.second = ConstElementPtr();
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_EQ(working_config_clients, clients_map);
+    EXPECT_EQ(1, map_mutex.lock_count);
+
+    // Reconfigure again with the same good clients, the result should
+    // be a different map than the original, but not an empty one.
+    reconfig_cmd.second = good_config;
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_NE(working_config_clients, clients_map);
+    EXPECT_EQ(1, clients_map->size());
+    EXPECT_EQ(2, map_mutex.lock_count);
+
+    // And finally, try an empty config to disable all datasource clients
+    reconfig_cmd.second = Element::createMap();
+    EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+    EXPECT_EQ(0, clients_map->size());
+    EXPECT_EQ(3, map_mutex.lock_count);
+
+    // Also check if it has been cleanly unlocked every time
+    EXPECT_EQ(3, map_mutex.unlock_count);
+}
+
+TEST_F(DataSrcClientsBuilderTest, shutdown) {
+    EXPECT_FALSE(builder.handleCommand(shutdown_cmd));
+}
+
+TEST_F(DataSrcClientsBuilderTest, badCommand) {
+    // out-of-range command ID
+    EXPECT_THROW(builder.handleCommand(Command(NUM_COMMANDS,
+                                               ConstElementPtr())),
+                 isc::Unexpected);
+}
+
+// A helper function commonly used for the "loadzone" command tests.
+// It configures the given data source client lists with a memory data source
+// containing two zones, and checks the zones are correctly loaded.
+void
+zoneChecks(ClientListMapPtr clients_map, RRClass rrclass) {
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("ns.test1.example")).finder_->
+              find(Name("ns.test1.example"), RRType::A())->code);
+    EXPECT_EQ(ZoneFinder::NXRRSET, clients_map->find(rrclass)->second->
+              find(Name("ns.test1.example")).finder_->
+              find(Name("ns.test1.example"), RRType::AAAA())->code);
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("ns.test2.example")).finder_->
+              find(Name("ns.test2.example"), RRType::A())->code);
+    EXPECT_EQ(ZoneFinder::NXRRSET, clients_map->find(rrclass)->second->
+              find(Name("ns.test2.example")).finder_->
+              find(Name("ns.test2.example"), RRType::AAAA())->code);
+}
+
+// Another helper that checks after completing loadzone command.
+void
+newZoneChecks(ClientListMapPtr clients_map, RRClass rrclass) {
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("ns.test1.example")).finder_->
+              find(Name("ns.test1.example"), RRType::A())->code);
+    // now test1.example should have ns/AAAA
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("ns.test1.example")).finder_->
+              find(Name("ns.test1.example"), RRType::AAAA())->code);
+
+    // test2.example shouldn't change
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("ns.test2.example")).finder_->
+              find(Name("ns.test2.example"), RRType::A())->code);
+    EXPECT_EQ(ZoneFinder::NXRRSET,
+              clients_map->find(rrclass)->second->
+              find(Name("ns.test2.example")).finder_->
+              find(Name("ns.test2.example"), RRType::AAAA())->code);
+}
+
+void
+DataSrcClientsBuilderTest::configureZones() {
+    ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR "/test1.zone.in "
+                             TEST_DATA_BUILDDIR "/test1.zone.copied"));
+    ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
+                             TEST_DATA_BUILDDIR "/test2.zone.copied"));
+
+    const ConstElementPtr config(
+        Element::fromJSON(
+            "{"
+            "\"IN\": [{"
+            "   \"type\": \"MasterFiles\","
+            "   \"params\": {"
+            "       \"test1.example\": \"" +
+            std::string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\","
+            "       \"test2.example\": \"" +
+            std::string(TEST_DATA_BUILDDIR "/test2.zone.copied") + "\""
+            "   },"
+            "   \"cache-enable\": true"
+            "}]}"));
+    clients_map = configureDataSource(config);
+    zoneChecks(clients_map, rrclass);
+}
+
+TEST_F(DataSrcClientsBuilderTest, loadZone) {
+    // pre test condition checks
+    EXPECT_EQ(0, map_mutex.lock_count);
+    EXPECT_EQ(0, map_mutex.unlock_count);
+
+    configureZones();
+
+    EXPECT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
+                        "/test1-new.zone.in "
+                        TEST_DATA_BUILDDIR "/test1.zone.copied"));
+    EXPECT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
+                        "/test2-new.zone.in "
+                        TEST_DATA_BUILDDIR "/test2.zone.copied"));
+
+    const Command loadzone_cmd(LOADZONE, Element::fromJSON(
+                                   "{\"class\": \"IN\","
+                                   " \"origin\": \"test1.example\"}"));
+    EXPECT_TRUE(builder.handleCommand(loadzone_cmd));
+    EXPECT_EQ(1, map_mutex.lock_count); // we should have acquired the lock
+    EXPECT_EQ(1, map_mutex.unlock_count); // and released it.
+
+    newZoneChecks(clients_map, rrclass);
+}
+
+TEST_F(DataSrcClientsBuilderTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_loadZoneSQLite3
+#else
+       loadZoneSQLite3
+#endif
+    )
+{
+    // 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");
+    createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
+    // This describes the data source in the configuration
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + test_db + "\"},"
+        "    \"cache-enable\": true,"
+        "    \"cache-zones\": [\"example.org\"]"
+        "}]}"));
+    clients_map = configureDataSource(config);
+
+    // Check that the A record at www.example.org does not exist
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              clients_map->find(rrclass)->second->
+              find(Name("example.org")).finder_->
+              find(Name("www.example.org"), RRType::A())->code);
+
+    // Add the record to the underlying sqlite database, by loading
+    // it as a separate datasource, and updating it
+    ConstElementPtr sql_cfg = Element::fromJSON("{ \"type\": \"sqlite3\","
+                                                "\"database_file\": \""
+                                                + test_db + "\"}");
+    DataSourceClientContainer sql_ds("sqlite3", sql_cfg);
+    ZoneUpdaterPtr sql_updater =
+        sql_ds.getInstance().getUpdater(Name("example.org"), false);
+    sql_updater->addRRset(
+        *textToRRset("www.example.org. 60 IN A 192.0.2.1"));
+    sql_updater->commit();
+
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              clients_map->find(rrclass)->second->
+              find(Name("example.org")).finder_->
+              find(Name("www.example.org"), RRType::A())->code);
+
+    // Now send the command to reload it
+    const Command loadzone_cmd(LOADZONE, Element::fromJSON(
+                                   "{\"class\": \"IN\","
+                                   " \"origin\": \"example.org\"}"));
+    EXPECT_TRUE(builder.handleCommand(loadzone_cmd));
+    // And now it should be present too.
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              clients_map->find(rrclass)->second->
+              find(Name("example.org")).finder_->
+              find(Name("www.example.org"), RRType::A())->code);
+
+    // An error case: the zone has no configuration. (note .com here)
+    const Command nozone_cmd(LOADZONE, Element::fromJSON(
+                                 "{\"class\": \"IN\","
+                                 " \"origin\": \"example.com\"}"));
+    EXPECT_THROW(builder.handleCommand(nozone_cmd),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+    // The previous zone is not hurt in any way
+    EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
+              find(Name("example.org")).finder_->
+              find(Name("example.org"), RRType::SOA())->code);
+
+    // attempt of reloading a zone but in-memory cache is disabled.
+    const ConstElementPtr config2(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + test_db + "\"},"
+        "    \"cache-enable\": false,"
+        "    \"cache-zones\": [\"example.org\"]"
+        "}]}"));
+    clients_map = configureDataSource(config2);
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE, Element::fromJSON(
+                                 "{\"class\": \"IN\","
+                                 " \"origin\": \"example.org\"}"))),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+
+    // basically impossible case: in-memory cache is completely disabled.
+    // In this implementation of manager-builder, this should never happen,
+    // but it catches it like other configuration error and keeps going.
+    clients_map->clear();
+    boost::shared_ptr<ConfigurableClientList> nocache_list(
+        new ConfigurableClientList(rrclass));
+    nocache_list->configure(
+        Element::fromJSON(
+            "[{\"type\": \"sqlite3\","
+            "  \"params\": {\"database_file\": \"" + test_db + "\"},"
+            "  \"cache-enable\": true,"
+            "  \"cache-zones\": [\"example.org\"]"
+            "}]"), false);           // false = disable cache
+    (*clients_map)[rrclass] = nocache_list;
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE, Element::fromJSON(
+                                 "{\"class\": \"IN\","
+                                 " \"origin\": \"example.org\"}"))),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+}
+
+TEST_F(DataSrcClientsBuilderTest, loadBrokenZone) {
+    configureZones();
+
+    ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR
+                             "/test1-broken.zone.in "
+                             TEST_DATA_BUILDDIR "/test1.zone.copied"));
+    // there's an error in the new zone file.  reload will be rejected.
+    const Command loadzone_cmd(LOADZONE, Element::fromJSON(
+                                   "{\"class\": \"IN\","
+                                   " \"origin\": \"test1.example\"}"));
+    EXPECT_THROW(builder.handleCommand(loadzone_cmd),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+    zoneChecks(clients_map, rrclass);     // zone shouldn't be replaced
+}
+
+TEST_F(DataSrcClientsBuilderTest, loadUnreadableZone) {
+    configureZones();
+
+    // install the zone file as unreadable
+    ASSERT_EQ(0, std::system(INSTALL_PROG " -c -m 000 " TEST_DATA_DIR
+                             "/test1.zone.in "
+                             TEST_DATA_BUILDDIR "/test1.zone.copied"));
+    const Command loadzone_cmd(LOADZONE, Element::fromJSON(
+                                   "{\"class\": \"IN\","
+                                   " \"origin\": \"test1.example\"}"));
+    EXPECT_THROW(builder.handleCommand(loadzone_cmd),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+    zoneChecks(clients_map, rrclass);     // zone shouldn't be replaced
+}
+
+TEST_F(DataSrcClientsBuilderTest, loadZoneWithoutDataSrc) {
+    // try to execute load command without configuring the zone beforehand.
+    // it should fail.
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"class\": \"IN\", "
+                                 " \"origin\": \"test1.example\"}"))),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+}
+
+TEST_F(DataSrcClientsBuilderTest, loadZoneInvalidParams) {
+    configureZones();
+
+    if (!isc::util::unittests::runningOnValgrind()) {
+        // null arg: this causes assertion failure
+        EXPECT_DEATH_IF_SUPPORTED({
+                builder.handleCommand(Command(LOADZONE, ElementPtr()));
+            }, "");
+    }
+
+    // zone class is bogus (note that this shouldn't happen except in tests)
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"origin\": \"test1.example\","
+                                 " \"class\": \"no_such_class\"}"))),
+                 InvalidRRClass);
+
+    // not a string
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"origin\": \"test1.example\","
+                                 " \"class\": 1}"))),
+                 isc::data::TypeError);
+
+    // class or origin is missing: result in assertion failure
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH_IF_SUPPORTED({
+                builder.handleCommand(Command(LOADZONE,
+                                              Element::fromJSON(
+                                                  "{\"class\": \"IN\"}")));
+            }, "");
+    }
+
+    // zone doesn't exist in the data source
+    EXPECT_THROW(
+        builder.handleCommand(
+            Command(LOADZONE,
+                    Element::fromJSON(
+                        "{\"class\": \"IN\", \"origin\": \"xx\"}"))),
+        TestDataSrcClientsBuilder::InternalCommandError);
+
+    // origin is bogus
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"class\": \"IN\", \"origin\": \"...\"}"))),
+                 EmptyLabel);
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"origin\": 10, \"class\": 1}"))),
+                 isc::data::TypeError);
+}
+
+} // unnamed namespace
diff --git a/src/bin/auth/tests/datasrc_clients_mgr_unittest.cc b/src/bin/auth/tests/datasrc_clients_mgr_unittest.cc
new file mode 100644
index 0000000..c37ef11
--- /dev/null
+++ b/src/bin/auth/tests/datasrc_clients_mgr_unittest.cc
@@ -0,0 +1,254 @@
+// 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/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/client_list.h>
+
+#include <auth/datasrc_clients_mgr.h>
+#include "test_datasrc_clients_mgr.h"
+
+#include <gtest/gtest.h>
+
+#include <boost/function.hpp>
+
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::datasrc;
+using namespace isc::auth;
+using namespace isc::auth::datasrc_clientmgr_internal;
+
+namespace {
+void
+shutdownCheck() {
+    // Check for common points on shutdown.  The manager should have acquired
+    // the lock, put a SHUTDOWN command to the queue, and should have signaled
+    // the builder.
+    EXPECT_EQ(1, FakeDataSrcClientsBuilder::queue_mutex->lock_count);
+    EXPECT_EQ(1, FakeDataSrcClientsBuilder::cond->signal_count);
+    EXPECT_EQ(1, FakeDataSrcClientsBuilder::command_queue->size());
+    const Command& cmd = FakeDataSrcClientsBuilder::command_queue->front();
+    EXPECT_EQ(SHUTDOWN, cmd.first);
+    EXPECT_FALSE(cmd.second);   // no argument
+
+    // Finally, the manager should wait for the thread to terminate.
+    EXPECT_TRUE(FakeDataSrcClientsBuilder::thread_waited);
+}
+
+// Commonly used pattern of checking member variables shared between the
+// manager and builder.
+void
+checkSharedMembers(size_t expected_queue_lock_count,
+                   size_t expected_queue_unlock_count,
+                   size_t expected_map_lock_count,
+                   size_t expected_map_unlock_count,
+                   size_t expected_cond_signal_count,
+                   size_t expected_command_queue_size)
+{
+    EXPECT_EQ(expected_queue_lock_count,
+              FakeDataSrcClientsBuilder::queue_mutex->lock_count);
+    EXPECT_EQ(expected_queue_unlock_count,
+              FakeDataSrcClientsBuilder::queue_mutex->unlock_count);
+    EXPECT_EQ(expected_map_lock_count,
+              FakeDataSrcClientsBuilder::map_mutex->lock_count);
+    EXPECT_EQ(expected_map_unlock_count,
+              FakeDataSrcClientsBuilder::map_mutex->unlock_count);
+    EXPECT_EQ(expected_cond_signal_count,
+              FakeDataSrcClientsBuilder::cond->signal_count);
+    EXPECT_EQ(expected_command_queue_size,
+              FakeDataSrcClientsBuilder::command_queue->size());
+}
+
+TEST(DataSrcClientsMgrTest, start) {
+    // When we create a manager, builder's run() method should be called.
+    FakeDataSrcClientsBuilder::started = false;
+    {
+        TestDataSrcClientsMgr mgr;
+        EXPECT_TRUE(FakeDataSrcClientsBuilder::started);
+        EXPECT_TRUE(FakeDataSrcClientsBuilder::command_queue->empty());
+
+        // Check pre-destroy conditions
+        EXPECT_EQ(0, FakeDataSrcClientsBuilder::cond->signal_count);
+        EXPECT_FALSE(FakeDataSrcClientsBuilder::thread_waited);
+    } // mgr and builder have been destroyed by this point.
+
+    // We stopped the manager implicitly (without shutdown()).  The manager
+    // will internally notify it
+    shutdownCheck();
+}
+
+TEST(DataSrcClientsMgrTest, shutdownWithUncaughtException) {
+    // Emulating the case when the builder exists on exception.  shutdown()
+    // will encounter UncaughtException exception and catch it.
+    EXPECT_NO_THROW({
+            TestDataSrcClientsMgr mgr;
+            FakeDataSrcClientsBuilder::thread_throw_on_wait =
+                FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX;
+        });
+}
+
+TEST(DataSrcClientsMgrTest, shutdownWithException) {
+    EXPECT_NO_THROW({
+            TestDataSrcClientsMgr mgr;
+            FakeDataSrcClientsBuilder::thread_throw_on_wait =
+                FakeDataSrcClientsBuilder::THROW_OTHER;
+        });
+}
+
+TEST(DataSrcClientsMgrTest, reconfigure) {
+    TestDataSrcClientsMgr mgr;
+
+    // Check pre-command condition
+    checkSharedMembers(0, 0, 0, 0, 0, 0);
+
+    // A valid reconfigure argument
+    ConstElementPtr reconfigure_arg = Element::fromJSON(
+        "{""\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
+        "             \"cache-enable\": true}]}");
+
+    // On reconfigure(), it just send the RECONFIGURE command to the builder
+    // thread with the given argument intact.
+    mgr.reconfigure(reconfigure_arg);
+
+    // The manager should have acquired the queue lock, send RECONFIGURE
+    // command with the arg, wake up the builder thread by signal.  It doesn't
+    // touch or refer to the map, so it shouldn't acquire the map lock.
+    checkSharedMembers(1, 1, 0, 0, 1, 1);
+    const Command& cmd1 = FakeDataSrcClientsBuilder::command_queue->front();
+    EXPECT_EQ(RECONFIGURE, cmd1.first);
+    EXPECT_EQ(reconfigure_arg, cmd1.second);
+
+    // Non-null, but semantically invalid argument.  The manager doesn't do
+    // this check, so it should result in the same effect.
+    FakeDataSrcClientsBuilder::command_queue->clear();
+    reconfigure_arg = isc::data::Element::create("{ \"foo\": \"bar\" }");
+    mgr.reconfigure(reconfigure_arg);
+    checkSharedMembers(2, 2, 0, 0, 2, 1);
+    const Command& cmd2 = FakeDataSrcClientsBuilder::command_queue->front();
+    EXPECT_EQ(RECONFIGURE, cmd2.first);
+    EXPECT_EQ(reconfigure_arg, cmd2.second);
+
+    // Passing NULL argument is immediately rejected
+    EXPECT_THROW(mgr.reconfigure(ConstElementPtr()), isc::InvalidParameter);
+    checkSharedMembers(2, 2, 0, 0, 2, 1); // no state change
+}
+
+TEST(DataSrcClientsMgrTest, holder) {
+    TestDataSrcClientsMgr mgr;
+
+    {
+        // Initially it's empty, so findClientList() will always return NULL
+        TestDataSrcClientsMgr::Holder holder(mgr);
+        EXPECT_FALSE(holder.findClientList(RRClass::IN()));
+        EXPECT_FALSE(holder.findClientList(RRClass::CH()));
+        // map should be protected here
+        EXPECT_EQ(1, FakeDataSrcClientsBuilder::map_mutex->lock_count);
+        EXPECT_EQ(0, FakeDataSrcClientsBuilder::map_mutex->unlock_count);
+    }
+    // map lock has been released
+    EXPECT_EQ(1, FakeDataSrcClientsBuilder::map_mutex->unlock_count);
+
+    // Put something in, that should become visible.
+    ConstElementPtr reconfigure_arg = Element::fromJSON(
+        "{\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
+        "           \"cache-enable\": true}],"
+        " \"CH\": [{\"type\": \"MasterFiles\", \"params\": {},"
+        "           \"cache-enable\": true}]}");
+    mgr.reconfigure(reconfigure_arg);
+    {
+        TestDataSrcClientsMgr::Holder holder(mgr);
+        EXPECT_TRUE(holder.findClientList(RRClass::IN()));
+        EXPECT_TRUE(holder.findClientList(RRClass::CH()));
+    }
+    // We need to clear command queue by hand
+    FakeDataSrcClientsBuilder::command_queue->clear();
+
+    // Replace the lists with new lists containing only one list.
+    // The CH will disappear again.
+    reconfigure_arg = Element::fromJSON(
+        "{\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
+        "           \"cache-enable\": true}]}");
+    mgr.reconfigure(reconfigure_arg);
+    {
+        TestDataSrcClientsMgr::Holder holder(mgr);
+        EXPECT_TRUE(holder.findClientList(RRClass::IN()));
+        EXPECT_FALSE(holder.findClientList(RRClass::CH()));
+    }
+
+    // Duplicate lock acquisition is prohibited (only test mgr can detect
+    // this reliably, so this test may not be that useful)
+    TestDataSrcClientsMgr::Holder holder1(mgr);
+    EXPECT_THROW(TestDataSrcClientsMgr::Holder holder2(mgr), isc::Unexpected);
+}
+
+TEST(DataSrcClientsMgrTest, reload) {
+    TestDataSrcClientsMgr mgr;
+    EXPECT_TRUE(FakeDataSrcClientsBuilder::started);
+    EXPECT_TRUE(FakeDataSrcClientsBuilder::command_queue->empty());
+
+    isc::data::ElementPtr args =
+        isc::data::Element::fromJSON("{ \"class\": \"IN\","
+                                     "  \"origin\": \"example.com\" }");
+    mgr.loadZone(args);
+    EXPECT_EQ(1, FakeDataSrcClientsBuilder::command_queue->size());
+    mgr.loadZone(args);
+    EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // Should fail with non-string 'class' value
+    args->set("class", Element::create(1));
+    EXPECT_THROW(mgr.loadZone(args), CommandError);
+    EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // And with badclass
+    args->set("class", Element::create("BADCLASS"));
+    EXPECT_THROW(mgr.loadZone(args), CommandError);
+    EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // Should succeed without 'class'
+    args->remove("class");
+    mgr.loadZone(args);
+    EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // but fail without origin, without sending new commands
+    args->remove("origin");
+    EXPECT_THROW(mgr.loadZone(args), CommandError);
+    EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // And for 'origin' that is not a string
+    args->set("origin", Element::create(1));
+    EXPECT_THROW(mgr.loadZone(args), CommandError);
+    EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // And origin that is not a correct name
+    args->set("origin", Element::create(".."));
+    EXPECT_THROW(mgr.loadZone(args), CommandError);
+    EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
+
+    // same for empty data and data that is not a map
+    EXPECT_THROW(mgr.loadZone(isc::data::ConstElementPtr()), CommandError);
+    EXPECT_THROW(mgr.loadZone(isc::data::Element::createList()), CommandError);
+    EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
+}
+
+TEST(DataSrcClientsMgrTest, realThread) {
+    // Using the non-test definition with a real thread.  Just checking
+    // no disruption happens.
+    DataSrcClientsMgr mgr;
+}
+
+} // unnamed namespace
diff --git a/src/bin/auth/tests/datasrc_config_unittest.cc b/src/bin/auth/tests/datasrc_config_unittest.cc
index 877f921..b555aa6 100644
--- a/src/bin/auth/tests/datasrc_config_unittest.cc
+++ b/src/bin/auth/tests/datasrc_config_unittest.cc
@@ -16,7 +16,6 @@
 
 #include <config/tests/fake_session.h>
 #include <config/ccsession.h>
-#include <util/threads/lock.h>
 
 #include <gtest/gtest.h>
 
@@ -78,12 +77,8 @@ datasrcConfigHandler(DatasrcConfigTest* fake_server, const std::string&,
 
 class DatasrcConfigTest : public ::testing::Test {
 public:
-    // These pretend to be the server
-    isc::util::thread::Mutex& getDataSrcClientListMutex() const {
-        return (mutex_);
-    }
-    void swapDataSrcClientLists(shared_ptr<std::map<dns::RRClass, ListPtr> >
-                                new_lists)
+    void setDataSrcClientLists(shared_ptr<std::map<dns::RRClass, ListPtr> >
+                               new_lists)
     {
         lists_.clear();         // first empty it
 
@@ -156,7 +151,6 @@ protected:
     const string specfile;
     std::map<RRClass, ListPtr> lists_;
     string log_;
-    mutable isc::util::thread::Mutex mutex_;
 };
 
 void
@@ -167,7 +161,7 @@ testConfigureDataSource(DatasrcConfigTest& test,
     // possible to easily look that they were called.
     shared_ptr<std::map<dns::RRClass, ListPtr> > lists =
         configureDataSourceGeneric<FakeList>(config);
-    test.swapDataSrcClientLists(lists);
+    test.setDataSrcClientLists(lists);
 }
 
 // Push there a configuration with a single list.
diff --git a/src/bin/auth/tests/datasrc_util.h b/src/bin/auth/tests/datasrc_util.h
index 07ebc0c..9748332 100644
--- a/src/bin/auth/tests/datasrc_util.h
+++ b/src/bin/auth/tests/datasrc_util.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __AUTH_DATA_SOURCE_UTIL_H
-#define __AUTH_DATA_SOURCE_UTIL_H 1
+#ifndef AUTH_DATA_SOURCE_UTIL_H
+#define AUTH_DATA_SOURCE_UTIL_H 1
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
@@ -51,7 +51,7 @@ createSQLite3DB(dns::RRClass zclass, const dns::Name& zname,
 } // end of auth
 } // end of isc
 
-#endif  // __AUTH_DATA_SOURCE_UTIL_H
+#endif  // AUTH_DATA_SOURCE_UTIL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/auth/tests/statistics_unittest.cc b/src/bin/auth/tests/statistics_unittest.cc
index d2f5a5a..052a70e 100644
--- a/src/bin/auth/tests/statistics_unittest.cc
+++ b/src/bin/auth/tests/statistics_unittest.cc
@@ -27,345 +27,97 @@
 #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 AuthCountersTest : public ::testing::Test {
-private:
-    class MockSession : public AbstractSession {
-    public:
-        MockSession() :
-            // by default we return a simple "success" message.
-            msg_(Element::fromJSON("{\"result\": [0, \"SUCCESS\"]}")),
-            throw_session_error_(false), throw_session_timeout_(false)
-        {}
-        virtual void establish(const char* socket_file);
-        virtual void disconnect();
-        virtual int group_sendmsg(ConstElementPtr msg, string group,
-                                  string instance, string to);
-        virtual bool group_recvmsg(ConstElementPtr& envelope,
-                                   ConstElementPtr& msg,
-                                   bool nonblock, int seq);
-        virtual void subscribe(string group, string instance);
-        virtual void unsubscribe(string group, string instance);
-        virtual void startRead(boost::function<void()> read_callback);
-        virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
-        virtual bool hasQueuedMsgs() const;
-        virtual void setTimeout(size_t) {}
-        virtual size_t getTimeout() const { return (0); };
-
-        void setThrowSessionError(bool flag);
-        void setThrowSessionTimeout(bool flag);
-
-        void setMessage(ConstElementPtr msg) { msg_ = msg; }
-
-        ConstElementPtr sent_msg;
-        string msg_destination;
-    private:
-        ConstElementPtr msg_;
-        bool throw_session_error_;
-        bool throw_session_timeout_;
-    };
-
+class CountersTest : public ::testing::Test {
 protected:
-    AuthCountersTest() : counters() {
-    }
-    ~AuthCountersTest() {
-    }
-    AuthCounters counters;
-    // no need to be inherited from the original class here.
-    class MockModuleSpec {
-    public:
-        bool validateStatistics(ConstElementPtr, const bool valid) const
-            { return (valid); }
-    };
-    MockModuleSpec module_spec_;
+    CountersTest() : counters() {}
+    ~CountersTest() {}
+    Counters counters;
 };
 
+// Test if the values of the counters are all zero except for the items
+// specified in except_for.
 void
-AuthCountersTest::MockSession::establish(const char*) {}
-
-void
-AuthCountersTest::MockSession::disconnect() {}
-
-void
-AuthCountersTest::MockSession::subscribe(string, string)
-{}
-
-void
-AuthCountersTest::MockSession::unsubscribe(string, string)
-{}
-
-void
-AuthCountersTest::MockSession::startRead(boost::function<void()>)
-{}
-
-int
-AuthCountersTest::MockSession::reply(ConstElementPtr, ConstElementPtr) {
-    return (-1);
-}
-
-bool
-AuthCountersTest::MockSession::hasQueuedMsgs() const {
-    return (false);
-}
-
-int
-AuthCountersTest::MockSession::group_sendmsg(ConstElementPtr msg,
-                                              string group, string, string)
-{
-    if (throw_session_error_) {
-        isc_throw(SessionError, "Session Error");
-    }
-    sent_msg = msg;
-    msg_destination = group;
-    return (0);
-}
-
-bool
-AuthCountersTest::MockSession::group_recvmsg(ConstElementPtr&,
-                                              ConstElementPtr& msg, bool, int)
-{
-    if (throw_session_timeout_) {
-        isc_throw(SessionTimeout, "Session Timeout");
-    }
-    msg = msg_;
-    return (true);
-}
-
-void
-AuthCountersTest::MockSession::setThrowSessionError(bool flag) {
-    throw_session_error_ = flag;
-}
-
-void
-AuthCountersTest::MockSession::setThrowSessionTimeout(bool flag) {
-    throw_session_timeout_ = flag;
-}
-
-TEST_F(AuthCountersTest, incrementUDPCounter) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
-    EXPECT_NO_THROW(counters.inc(AuthCounters::SERVER_UDP_QUERY));
-    // After increment, the counter should be 1.
-    EXPECT_EQ(1, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
-}
-
-TEST_F(AuthCountersTest, incrementTCPCounter) {
-    // The counter should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
-    EXPECT_NO_THROW(counters.inc(AuthCounters::SERVER_TCP_QUERY));
-    // After increment, the counter should be 1.
-    EXPECT_EQ(1, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
-}
-
-TEST_F(AuthCountersTest, incrementInvalidCounter) {
-    // Expect to throw an isc::OutOfRange
-    EXPECT_THROW(counters.inc(AuthCounters::SERVER_COUNTER_TYPES),
-                 isc::OutOfRange);
-}
-
-TEST_F(AuthCountersTest, incrementOpcodeCounter) {
-    // The counter should be initialized to 0.  If we increment it by 1
-    // the counter should be 1.
-    for (int i = 0; i < 16; ++i) {
-        EXPECT_EQ(0, counters.getCounter(Opcode(i)));
-        counters.inc(Opcode(i));
-        EXPECT_EQ(1, counters.getCounter(Opcode(i)));
-    }
-}
-
-TEST_F(AuthCountersTest, incrementRcodeCounter) {
-    // The counter should be initialized to 0.  If we increment it by 1
-    // the counter should be 1.
-    for (int i = 0; i < 17; ++i) {
-        EXPECT_EQ(0, counters.getCounter(Rcode(i)));
-        counters.inc(Rcode(i));
-        EXPECT_EQ(1, counters.getCounter(Rcode(i)));
-    }
-}
-
-void
-opcodeDataCheck(ConstElementPtr data, const int expected[16]) {
-    const char* item_names[] = {
-        "query", "iquery", "status", "reserved3", "notify", "update",
-        "reserved6", "reserved7", "reserved8", "reserved9", "reserved10",
-        "reserved11", "reserved12", "reserved13", "reserved14", "reserved15",
-        NULL
-    };
-    int i;
-    for (i = 0; i < 16; ++i) {
-        ASSERT_NE(static_cast<const char*>(NULL), item_names[i]);
-        const string item_name = "opcode." + string(item_names[i]);
-        if (expected[i] == 0) {
-            EXPECT_FALSE(data->get(item_name));
-        } else {
-            EXPECT_EQ(expected[i], data->get(item_name)->intValue());
-        }
-    }
-    // We should have examined all names
-    ASSERT_EQ(static_cast<const char*>(NULL), item_names[i]);
-}
-
-void
-rcodeDataCheck(ConstElementPtr data, const int expected[17]) {
-    const char* item_names[] = {
-        "noerror", "formerr", "servfail", "nxdomain", "notimp", "refused",
-        "yxdomain", "yxrrset", "nxrrset", "notauth", "notzone", "reserved11",
-        "reserved12", "reserved13", "reserved14", "reserved15", "badvers",
-        NULL
-    };
-    int i;
-    for (i = 0; i < 17; ++i) {
-        ASSERT_NE(static_cast<const char*>(NULL), item_names[i]);
-        const string item_name = "rcode." + string(item_names[i]);
-        if (expected[i] == 0) {
-            EXPECT_FALSE(data->get(item_name));
-        } else {
-            EXPECT_EQ(expected[i], data->get(item_name)->intValue());
+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();
     }
-    // We should have examined all names
-    ASSERT_EQ(static_cast<const char*>(NULL), item_names[i]);
 }
 
-TEST_F(AuthCountersTest, getStatisticsWithoutValidator) {
-    // Get statistics data.
-    // Validate if it answers correct data.
+TEST_F(CountersTest, incrementNormalQuery) {
+    Message response(Message::RENDER);
+    QRAttributes qrattrs;
+    std::set<std::string> expect_nonzero;
 
-    // Counters should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    expect_nonzero.clear();
+    checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero);
 
-    // UDP query counter is set to 2.
-    counters.inc(AuthCounters::SERVER_UDP_QUERY);
-    counters.inc(AuthCounters::SERVER_UDP_QUERY);
-    // TCP query counter is set to 1.
-    counters.inc(AuthCounters::SERVER_TCP_QUERY);
-    ConstElementPtr statistics_data = counters.getStatistics();
+    qrattrs.setQueryIPVersion(AF_INET6);
+    qrattrs.setQueryTransportProtocol(IPPROTO_UDP);
+    qrattrs.setQueryOpCode(Opcode::QUERY_CODE);
+    qrattrs.setQueryEDNS(true, false);
+    qrattrs.setQueryDO(true);
+    qrattrs.answerWasSent();
 
-    // UDP query counter is 2 and TCP query counter is 1.
-    EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue());
-    EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
+    response.setRcode(Rcode::REFUSED());
+    response.addQuestion(Question(Name("example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
 
-    // By default opcode counters are all 0 and omitted
-    const int opcode_results[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
-                                     0, 0, 0, 0, 0, 0, 0, 0 };
-    opcodeDataCheck(statistics_data, opcode_results);
-    // By default rcode counters are all 0 and omitted
-    const int rcode_results[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                    0, 0, 0, 0, 0, 0, 0, 0 };
-    rcodeDataCheck(statistics_data, rcode_results);
-}
+    counters.inc(qrattrs, response);
 
-void
-updateOpcodeCounters(AuthCounters &counters, const int expected[16]) {
-    for (int i = 0; i < 16; ++i) {
-        for (int j = 0; j < expected[i]; ++j) {
-            counters.inc(Opcode(i));
-        }
-    }
+    expect_nonzero.clear();
+    expect_nonzero.insert("opcode.query");
+    expect_nonzero.insert("queries.udp");
+    expect_nonzero.insert("rcode.refused");
+    checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero);
 }
 
-void
-updateRcodeCounters(AuthCounters &counters, const int expected[17]) {
-    for (int i = 0; i < 17; ++i) {
-        for (int j = 0; j < expected[i]; ++j) {
-            counters.inc(Rcode(i));
+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_F(AuthCountersTest, getStatisticsWithOpcodeCounters) {
-    // Increment some of the opcode counters.  Then they should appear in the
-    // submitted data; others shouldn't
-    const int opcode_results[16] = { 1, 2, 3, 0, 4, 5, 0, 0,
-                                     0, 0, 0, 0, 0, 0, 0, 0 };
-    updateOpcodeCounters(counters, opcode_results);
-    ConstElementPtr statistics_data = counters.getStatistics();
-    opcodeDataCheck(statistics_data, opcode_results);
-}
-
-TEST_F(AuthCountersTest, getStatisticsWithAllOpcodeCounters) {
-    // Increment all opcode counters.  Then they should appear in the
-    // submitted data.
-    const int opcode_results[16] = { 1, 1, 1, 1, 1, 1, 1, 1,
-                                     1, 1, 1, 1, 1, 1, 1, 1 };
-    updateOpcodeCounters(counters, opcode_results);
-    ConstElementPtr statistics_data = counters.getStatistics();
-    opcodeDataCheck(statistics_data, opcode_results);
-}
-
-TEST_F(AuthCountersTest, getStatisticsWithRcodeCounters) {
-    // Increment some of the rcode counters.  Then they should appear in the
-    // submitted data; others shouldn't
-    const int rcode_results[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,
-                                    10, 0, 0, 0, 0, 0, 0, 11 };
-    updateRcodeCounters(counters, rcode_results);
-    ConstElementPtr statistics_data = counters.getStatistics();
-    rcodeDataCheck(statistics_data, rcode_results);
+TEST(StatisticsItemsTest, QRItemNamesCheck) {
+    EXPECT_EQ(QR_COUNTER_TYPES, countTreeElements(QRCounterTree));
 }
 
-TEST_F(AuthCountersTest, getStatisticsWithAllRcodeCounters) {
-    // Increment all rcode counters.  Then they should appear in the
-    // submitted data.
-    const int rcode_results[17] = { 1, 1, 1, 1, 1, 1, 1, 1, 1,
-                                     1, 1, 1, 1, 1, 1, 1, 1 };
-    updateOpcodeCounters(counters, rcode_results);
-    ConstElementPtr statistics_data = counters.getStatistics();
-    opcodeDataCheck(statistics_data, rcode_results);
-}
-
-TEST_F(AuthCountersTest, getStatisticsWithValidator) {
-
-    //a validator for the unittest
-    AuthCounters::validator_type validator;
-    ConstElementPtr el;
-
-    // Get statistics data with correct statistics validator.
-    validator = boost::bind(
-        &AuthCountersTest::MockModuleSpec::validateStatistics,
-        &module_spec_, _1, true);
-
-    EXPECT_TRUE(validator(el));
-
-    // register validator to AuthCounters
-    counters.registerStatisticsValidator(validator);
-
-    // Counters should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
-
-    // UDP query counter is set to 2.
-    counters.inc(AuthCounters::SERVER_UDP_QUERY);
-    counters.inc(AuthCounters::SERVER_UDP_QUERY);
-    // TCP query counter is set to 1.
-    counters.inc(AuthCounters::SERVER_TCP_QUERY);
-
-    // checks the value returned by getStatistics
-    ConstElementPtr statistics_data = counters.getStatistics();
-
-    // UDP query counter is 2 and TCP query counter is 1.
-    EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue());
-    EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
-
-    // Get statistics data with incorrect statistics validator.
-    validator = boost::bind(
-        &AuthCountersTest::MockModuleSpec::validateStatistics,
-        &module_spec_, _1, false);
-
-    EXPECT_FALSE(validator(el));
-
-    counters.registerStatisticsValidator(validator);
-
-    // checks the value returned by getStatistics
-    EXPECT_FALSE(counters.getStatistics());
-}
 }
diff --git a/src/bin/auth/tests/test_datasrc_clients_mgr.cc b/src/bin/auth/tests/test_datasrc_clients_mgr.cc
new file mode 100644
index 0000000..82937c0
--- /dev/null
+++ b/src/bin/auth/tests/test_datasrc_clients_mgr.cc
@@ -0,0 +1,95 @@
+// 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 <auth/datasrc_config.h>
+
+#include "test_datasrc_clients_mgr.h"
+
+#include <cassert>
+
+namespace isc {
+namespace auth {
+namespace datasrc_clientmgr_internal {
+
+// Define static DataSrcClientsBuilder member variables.
+bool FakeDataSrcClientsBuilder::started = false;
+std::list<Command>* FakeDataSrcClientsBuilder::command_queue = NULL;
+std::list<Command> FakeDataSrcClientsBuilder::command_queue_copy;
+TestCondVar* FakeDataSrcClientsBuilder::cond = NULL;
+TestCondVar FakeDataSrcClientsBuilder::cond_copy;
+TestMutex* FakeDataSrcClientsBuilder::queue_mutex = NULL;
+isc::datasrc::ClientListMapPtr*
+    FakeDataSrcClientsBuilder::clients_map = NULL;
+TestMutex* FakeDataSrcClientsBuilder::map_mutex = NULL;
+TestMutex FakeDataSrcClientsBuilder::queue_mutex_copy;
+bool FakeDataSrcClientsBuilder::thread_waited = false;
+FakeDataSrcClientsBuilder::ExceptionFromWait
+FakeDataSrcClientsBuilder::thread_throw_on_wait =
+    FakeDataSrcClientsBuilder::NOTHROW;
+
+template<>
+void
+TestDataSrcClientsBuilder::doNoop() {
+    ++queue_mutex_->noop_count;
+    switch (queue_mutex_->throw_from_noop) {
+    case TestMutex::NONE:
+        break;                  // no throw
+    case TestMutex::EXCLASS:
+        isc_throw(Exception, "test exception");
+    case TestMutex::INTEGER:
+        throw 42;
+    case TestMutex::INTERNAL:
+        isc_throw(InternalCommandError, "internal error, should be ignored");
+    }
+}
+} // namespace datasrc_clientmgr_internal
+
+template<>
+void
+TestDataSrcClientsMgr::cleanup() {
+    using namespace datasrc_clientmgr_internal;
+    // Make copy of some of the manager's member variables and reset the
+    // corresponding pointers.  The currently pointed objects are in the
+    // manager object, which are going to be invalidated.
+
+    FakeDataSrcClientsBuilder::command_queue_copy = command_queue_;
+    FakeDataSrcClientsBuilder::command_queue =
+        &FakeDataSrcClientsBuilder::command_queue_copy;
+    FakeDataSrcClientsBuilder::queue_mutex_copy = queue_mutex_;
+    FakeDataSrcClientsBuilder::queue_mutex =
+        &FakeDataSrcClientsBuilder::queue_mutex_copy;
+    FakeDataSrcClientsBuilder::cond_copy = cond_;
+    FakeDataSrcClientsBuilder::cond =
+        &FakeDataSrcClientsBuilder::cond_copy;
+}
+
+template<>
+void
+TestDataSrcClientsMgr::reconfigureHook() {
+    using namespace datasrc_clientmgr_internal;
+
+    // Simply replace the local map, ignoring bogus config value.
+    assert(command_queue_.front().first == RECONFIGURE);
+    try {
+        clients_map_ = configureDataSource(command_queue_.front().second);
+    } catch (...) {}
+}
+
+} // namespace auth
+} // namespace isc
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/auth/tests/test_datasrc_clients_mgr.h b/src/bin/auth/tests/test_datasrc_clients_mgr.h
new file mode 100644
index 0000000..9b1a367
--- /dev/null
+++ b/src/bin/auth/tests/test_datasrc_clients_mgr.h
@@ -0,0 +1,223 @@
+// 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 TEST_DATASRC_CLIENTS_MGR_H
+#define TEST_DATASRC_CLIENTS_MGR_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <auth/datasrc_clients_mgr.h>
+#include <datasrc/datasrc_config.h>
+
+#include <boost/function.hpp>
+
+#include <list>
+
+// In this file we provide specialization of thread, mutex, condition variable,
+// and DataSrcClientsBuilder for convenience of tests.  They don't use
+// actual threads or mutex, and allow tests to inspect some internal states
+// of the corresponding objects.
+//
+// In many cases, tests can use TestDataSrcClientsMgr (defined below) where
+// DataSrcClientsMgr is needed.
+
+// Below we extend the isc::auth::datasrc_clientmgr_internal namespace to
+// specialize the doNoop() method.
+namespace isc {
+namespace auth {
+namespace datasrc_clientmgr_internal {
+class TestMutex {
+public:
+    // for throw_from_noop.
+    // None: no throw from specialized doNoop()
+    // EXCLASS: throw some exception class object
+    // INTEGER: throw an integer
+    // INTERNAL: internal error (shouldn't terminate the thread)
+    enum ExceptionFromNoop { NONE, EXCLASS, INTEGER, INTERNAL };
+
+    TestMutex() : lock_count(0), unlock_count(0), noop_count(0),
+                  throw_from_noop(NONE)
+    {}
+    class Locker {
+    public:
+        Locker(TestMutex& mutex) : mutex_(mutex) {
+            if (mutex.lock_count != mutex.unlock_count) {
+                isc_throw(Unexpected,
+                          "attempt of duplicate lock acquisition");
+            }
+
+            ++mutex.lock_count;
+            if (mutex.lock_count > 100) { // 100 is an arbitrary choice
+                isc_throw(Unexpected,
+                          "too many test mutex count, likely a bug in test");
+            }
+        }
+        ~Locker() {
+            ++mutex_.unlock_count;
+        }
+    private:
+        TestMutex& mutex_;
+    };
+    size_t lock_count; // number of lock acquisitions; tests can check this
+    size_t unlock_count; // number of lock releases; tests can check this
+    size_t noop_count;          // allow doNoop() to modify this
+    ExceptionFromNoop throw_from_noop; // tests can set this to control doNoop
+};
+
+class TestCondVar {
+public:
+    TestCondVar() : wait_count(0), signal_count(0), command_queue_(NULL),
+                    delayed_command_queue_(NULL)
+    {}
+    TestCondVar(std::list<Command>& command_queue,
+                std::list<Command>& delayed_command_queue) :
+        wait_count(0),
+        signal_count(0),
+        command_queue_(&command_queue),
+        delayed_command_queue_(&delayed_command_queue)
+    {
+    }
+    void wait(TestMutex& mutex) {
+        // bookkeeping
+        ++mutex.unlock_count;
+        ++wait_count;
+        ++mutex.lock_count;
+
+        if (wait_count > 100) { // 100 is an arbitrary choice
+            isc_throw(Unexpected,
+                      "too many cond wait count, likely a bug in test");
+        }
+
+        // make the delayed commands available
+        command_queue_->splice(command_queue_->end(), *delayed_command_queue_);
+    }
+    void signal() {
+        ++signal_count;
+    }
+    size_t wait_count; // number of calls to wait(); tests can check this
+    size_t signal_count; // number of calls to signal(); tests can check this
+private:
+    std::list<Command>* command_queue_;
+    std::list<Command>* delayed_command_queue_;
+};
+
+// Convenient shortcut
+typedef DataSrcClientsBuilderBase<TestMutex, TestCondVar>
+TestDataSrcClientsBuilder;
+
+// We specialize this command handler for the convenience of tests.
+// It abuses our specialized Mutex to count the number of calls of this method.
+template<>
+void
+TestDataSrcClientsBuilder::doNoop();
+
+// A specialization of DataSrcClientsBuilder that allows tests to inspect
+// its internal states via static class variables.  Using static is suboptimal,
+// but DataSrcClientsMgr is highly encapsulated, this seems to be the best
+// possible compromise.
+class FakeDataSrcClientsBuilder {
+public:
+    // true iff a builder has started.
+    static bool started;
+
+    // These three correspond to the resource shared with the manager.
+    // xxx_copy will be set in the manager's destructor to record the
+    // final state of the manager.
+    static std::list<Command>* command_queue;
+    static TestCondVar* cond;
+    static TestMutex* queue_mutex;
+    static isc::datasrc::ClientListMapPtr* clients_map;
+    static TestMutex* map_mutex;
+    static std::list<Command> command_queue_copy;
+    static TestCondVar cond_copy;
+    static TestMutex queue_mutex_copy;
+
+    // true iff the manager waited on the thread running the builder.
+    static bool thread_waited;
+
+    // If set to true by a test, TestThread::wait() throws an exception
+    // exception.
+    enum ExceptionFromWait { NOTHROW, THROW_UNCAUGHT_EX, THROW_OTHER };
+    static ExceptionFromWait thread_throw_on_wait;
+
+    FakeDataSrcClientsBuilder(
+        std::list<Command>* command_queue,
+        TestCondVar* cond,
+        TestMutex* queue_mutex,
+        isc::datasrc::ClientListMapPtr* clients_map,
+        TestMutex* map_mutex)
+    {
+        FakeDataSrcClientsBuilder::started = false;
+        FakeDataSrcClientsBuilder::command_queue = command_queue;
+        FakeDataSrcClientsBuilder::cond = cond;
+        FakeDataSrcClientsBuilder::queue_mutex = queue_mutex;
+        FakeDataSrcClientsBuilder::clients_map = clients_map;
+        FakeDataSrcClientsBuilder::map_mutex = map_mutex;
+        FakeDataSrcClientsBuilder::thread_waited = false;
+        FakeDataSrcClientsBuilder::thread_throw_on_wait = NOTHROW;
+    }
+    void run() {
+        FakeDataSrcClientsBuilder::started = true;
+    }
+};
+
+// A fake thread class that doesn't really invoke thread but simply calls
+// the given main function (synchronously).  Tests can tweak the wait()
+// behavior via some static variables so it will throw some exceptions.
+class TestThread {
+public:
+    TestThread(const boost::function<void()>& main) {
+        main();
+    }
+    void wait() {
+        FakeDataSrcClientsBuilder::thread_waited = true;
+        switch (FakeDataSrcClientsBuilder::thread_throw_on_wait) {
+        case FakeDataSrcClientsBuilder::NOTHROW:
+            break;
+        case FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX:
+            isc_throw(util::thread::Thread::UncaughtException,
+                      "TestThread wait() saw an exception");
+        case FakeDataSrcClientsBuilder::THROW_OTHER:
+            isc_throw(Unexpected,
+                      "General emulated failure in TestThread wait()");
+        }
+    }
+};
+} // namespace datasrc_clientmgr_internal
+
+// Convenient shortcut
+typedef DataSrcClientsMgrBase<
+    datasrc_clientmgr_internal::TestThread,
+    datasrc_clientmgr_internal::FakeDataSrcClientsBuilder,
+    datasrc_clientmgr_internal::TestMutex,
+    datasrc_clientmgr_internal::TestCondVar> TestDataSrcClientsMgr;
+
+// A specialization of manager's "cleanup" called at the end of the
+// destructor.  We use this to record the final values of some of the class
+// member variables.
+template<>
+void
+TestDataSrcClientsMgr::cleanup();
+
+template<>
+void
+TestDataSrcClientsMgr::reconfigureHook();
+} // namespace auth
+} // namespace isc
+
+#endif  // TEST_DATASRC_CLIENTS_MGR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes
index 2f48325..aba8da5 100644
--- a/src/bin/bind10/bind10_messages.mes
+++ b/src/bin/bind10/bind10_messages.mes
@@ -82,6 +82,21 @@ the boss process will try to force them).
 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.
@@ -94,11 +109,6 @@ and continue running as the specified user, but the user is unknown.
 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_KILL_PROCESS killing process %1
-The boss module is sending a kill signal to process with the given name,
-as part of the process of killing all started processes during a failed
-startup, as described for BIND10_KILLING_ALL_PROCESSES
-
 % 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
@@ -167,6 +177,30 @@ 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.
 
@@ -274,13 +308,6 @@ 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_START_AS_NON_ROOT_AUTH starting b10-auth as a user, not root. This might fail.
-The authoritative server is being started or restarted without root privileges.
-If the module needs these privileges, it may have problems starting.
-Note that this issue should be resolved by the pending 'socket-creator'
-process; once that has been implemented, modules should not need root
-privileges anymore. See tickets #800 and #801 for more information.
-
 % BIND10_START_AS_NON_ROOT_RESOLVER starting b10-resolver as a user, not root. This might fail.
 The resolver is being started or restarted without root privileges.
 If the module needs these privileges, it may have problems starting.
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
index 32c3152..36ad760 100755
--- a/src/bin/bind10/bind10_src.py.in
+++ b/src/bin/bind10/bind10_src.py.in
@@ -331,11 +331,7 @@ class BoB:
             each one.  It then clears that list.
         """
         logger.info(BIND10_KILLING_ALL_PROCESSES)
-
-        for pid in self.components:
-            logger.info(BIND10_KILL_PROCESS, self.components[pid].name())
-            self.components[pid].kill(True)
-        self.components = {}
+        self.__kill_children(True)
 
     def _read_bind10_config(self):
         """
@@ -427,6 +423,7 @@ class BoB:
         while self.cc_session is None:
             # if we have been trying for "a while" give up
             if (time.time() - cc_connect_start) > 5:
+                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
@@ -546,8 +543,6 @@ class BoB:
         """
             Start the Authoritative server
         """
-        if self.uid is not None and self.__started:
-            logger.warn(BIND10_START_AS_NON_ROOT_AUTH)
         authargs = ['b10-auth']
         if self.verbose:
             authargs += ['-v']
@@ -693,32 +688,42 @@ class BoB:
         # from doing so
         if not self.nokill:
             # next try sending a SIGTERM
-            components_to_stop = list(self.components.values())
-            for component in components_to_stop:
-                logger.info(BIND10_SEND_SIGTERM, component.name(), component.pid())
-                try:
-                    component.kill()
-                except OSError:
-                    # ignore these (usually ESRCH because the child
-                    # finally exited)
-                    pass
-            # finally, send SIGKILL (unmaskable termination) until everybody dies
+            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()
-                components_to_stop = list(self.components.values())
-                for component in components_to_stop:
-                    logger.info(BIND10_SEND_SIGKILL, component.name(),
-                                component.pid())
-                    try:
-                        component.kill(True)
-                    except OSError:
-                        # ignore these (usually ESRCH because the child
-                        # finally exited)
-                        pass
+                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)
 
@@ -1137,6 +1142,21 @@ def main():
 
     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("""\
+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.
+""")
+        sys.exit(1)
+
     # Check user ID.
     setuid = None
     setgid = None
@@ -1169,9 +1189,6 @@ def main():
             logger.fatal(BIND10_INVALID_USER, options.user)
             sys.exit(1)
 
-    # Announce startup.
-    logger.info(BIND10_STARTING, VERSION)
-
     # Create wakeup pipe for signal handlers
     wakeup_pipe = os.pipe()
     signal.set_wakeup_fd(wakeup_pipe[1])
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 0b11960..ece6370 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -1181,7 +1181,7 @@ class TestBossComponents(unittest.TestCase):
         # We check somewhere else that the shutdown is actually called
         # from there (the test_kills).
 
-    def __real_test_kill(self, nokill = False):
+    def __real_test_kill(self, nokill=False, ex_on_kill=None):
         """
         Helper function that does the actual kill functionality testing.
         """
@@ -1195,8 +1195,23 @@ class TestBossComponents(unittest.TestCase):
             (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):
@@ -1224,7 +1239,10 @@ class TestBossComponents(unittest.TestCase):
         if nokill:
             self.assertEqual([], killed)
         else:
-            self.assertEqual([False, True], killed)
+            if ex_on_kill is not None:
+                self.assertEqual([False], killed)
+            else:
+                self.assertEqual([False, True], killed)
 
         self.assertTrue(self.__called)
 
@@ -1236,6 +1254,20 @@ class TestBossComponents(unittest.TestCase):
         """
         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
diff --git a/src/bin/bindctl/bindcmd.py b/src/bin/bindctl/bindcmd.py
index b4e71bf..37b74e7 100644
--- a/src/bin/bindctl/bindcmd.py
+++ b/src/bin/bindctl/bindcmd.py
@@ -133,7 +133,18 @@ class BindCmdInterpreter(Cmd):
         return digest
 
     def run(self):
-        '''Parse commands from user and send them to cmdctl. '''
+        '''Parse commands from user and send them to cmdctl.'''
+
+        # Show helper warning about a well known issue.  We only do this
+        # when stdin is attached to a terminal, because otherwise it doesn't
+        # matter and is just noisy, and could even be harmful if the output
+        # is processed by a script that expects a specific format.
+        if my_readline == sys.stdin.readline and sys.stdin.isatty():
+            sys.stdout.write("""\
+WARNING: Python readline module isn't available, so the command line editor
+         (including command history management) does not work.  See BIND 10
+         guide for more details.\n\n""")
+
         try:
             if not self.login_to_cmdctl():
                 return 1
diff --git a/src/bin/bindctl/tests/bindctl_test.py b/src/bin/bindctl/tests/bindctl_test.py
index f598472..b9af5c2 100644
--- a/src/bin/bindctl/tests/bindctl_test.py
+++ b/src/bin/bindctl/tests/bindctl_test.py
@@ -511,10 +511,7 @@ class TestBindCmdInterpreter(unittest.TestCase):
 
     def test_csv_file_dir(self):
         # Checking default value
-        if "HOME" in os.environ:
-            home_dir = os.environ["HOME"]
-        else:
-            home_dir = pwd.getpwnam(getpass.getuser()).pw_dir
+        home_dir = pwd.getpwnam(getpass.getuser()).pw_dir
         self.assertEqual(home_dir + os.sep + '.bind10' + os.sep,
                          bindcmd.BindCmdInterpreter().csv_file_dir)
 
diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am
index e9e0cca..9c73f79 100644
--- a/src/bin/cfgmgr/Makefile.am
+++ b/src/bin/cfgmgr/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . plugins tests
+SUBDIRS = . plugins local_plugins tests
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
diff --git a/src/bin/cfgmgr/local_plugins/Makefile.am b/src/bin/cfgmgr/local_plugins/Makefile.am
new file mode 100644
index 0000000..2f4dd39
--- /dev/null
+++ b/src/bin/cfgmgr/local_plugins/Makefile.am
@@ -0,0 +1,11 @@
+# Nothing is installed from this directory.  This local_plugins
+# directory overrides the plugins directory when lettuce is run, and the
+# spec file here is used to serve the static zone from the source tree
+# for testing (instead of installation prefix).
+
+noinst_DATA = datasrc.spec
+
+datasrc.spec: ../plugins/datasrc.spec.pre
+	$(SED) -e "s|@@STATIC_ZONE_FILE@@|$(abs_top_builddir)/src/lib/datasrc/static.zone|;s|@@SQLITE3_DATABASE_FILE@@|$(abs_top_builddir)/local.zone.sqlite3|" ../plugins/datasrc.spec.pre >$@
+
+CLEANFILES = datasrc.spec
diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am
index e6ed127..5967abd 100644
--- a/src/bin/cfgmgr/plugins/Makefile.am
+++ b/src/bin/cfgmgr/plugins/Makefile.am
@@ -3,7 +3,7 @@ SUBDIRS = tests
 EXTRA_DIST = README logging.spec tsig_keys.spec
 
 datasrc.spec: datasrc.spec.pre
-	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|;s|@@LOCALSTATEDIR@@|$(localstatedir)|" datasrc.spec.pre >$@
+	$(SED) -e "s|@@STATIC_ZONE_FILE@@|$(pkgdatadir)/static.zone|;s|@@SQLITE3_DATABASE_FILE@@|$(localstatedir)/$(PACKAGE)/zone.sqlite3|" datasrc.spec.pre >$@
 
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
 config_plugin_DATA = logging.spec tsig_keys.spec datasrc.spec
diff --git a/src/bin/cfgmgr/plugins/datasrc.spec.pre.in b/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
index f2c6a97..6d5bd77 100644
--- a/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
+++ b/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
@@ -12,7 +12,7 @@
                         {
                             "type": "sqlite3",
                             "params": {
-                                "database_file": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+                                "database_file": "@@SQLITE3_DATABASE_FILE@@"
                             }
                         }
                     ],
@@ -20,7 +20,7 @@
                         {
                             "type": "static",
                             "cache-enable": false,
-                            "params": "@@PKGDATADIR@@/static.zone"
+                            "params": "@@STATIC_ZONE_FILE@@"
                         }
                     ]
                 },
diff --git a/src/bin/dbutil/tests/dbutil_test.sh.in b/src/bin/dbutil/tests/dbutil_test.sh.in
index 35314e8..d60f186 100755
--- a/src/bin/dbutil/tests/dbutil_test.sh.in
+++ b/src/bin/dbutil/tests/dbutil_test.sh.in
@@ -161,7 +161,7 @@ get_schema() {
 # @param $2 Expected backup file
 upgrade_ok_test() {
     copy_file $1 $tempfile
-    ../run_dbutil.sh --upgrade --noconfirm $tempfile
+    ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
     if [ $? -eq 0 ]
     then
         # Compare schema with the reference
@@ -199,7 +199,7 @@ upgrade_ok_test() {
 # @param $2 Expected backup file
 upgrade_fail_test() {
     copy_file $1 $tempfile
-    ../run_dbutil.sh --upgrade --noconfirm $tempfile
+    ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
     failzero $?
     check_backup $1 $backupfile
 }
@@ -222,7 +222,7 @@ record_count_test() {
     records_count=`sqlite3 $tempfile 'select count(*) from records'`
     zones_count=`sqlite3 $tempfile 'select count(*) from zones'`
 
-    ../run_dbutil.sh --upgrade --noconfirm $tempfile
+    ${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
     if [ $? -ne 0 ]
     then
         # Reason for failure should already have been output
@@ -268,12 +268,12 @@ record_count_test() {
 # @param $2 Expected version string
 check_version() {
     copy_file $1 $verfile
-    ../run_dbutil.sh --check $verfile
+    ${SHELL} ../run_dbutil.sh --check $verfile
     if [ $? -gt 2 ]
     then
         fail "version check failed on database $1; return code $?"
     else
-        ../run_dbutil.sh --check $verfile 2>&1 | grep "$2" > /dev/null
+        ${SHELL} ../run_dbutil.sh --check $verfile 2>&1 | grep "$2" > /dev/null
         if [ $? -ne 0 ]
         then
             fail "database $1 not at expected version $2 (output: $?)"
@@ -293,7 +293,7 @@ check_version() {
 # @param $2 Backup file
 check_version_fail() {
     copy_file $1 $verfile
-    ../run_dbutil.sh --check $verfile
+    ${SHELL} ../run_dbutil.sh --check $verfile
     failzero $?
     check_no_backup $tempfile $backupfile
 }
@@ -305,12 +305,12 @@ rm -f $tempfile $backupfile
 
 # Test 1 - check that the utility fails if the database does not exist
 echo "1.1. Non-existent database - check"
-../run_dbutil.sh --check $tempfile
+${SHELL} ../run_dbutil.sh --check $tempfile
 failzero $?
 check_no_backup $tempfile $backupfile
 
 echo "1.2. Non-existent database - upgrade"
-../run_dbutil.sh --upgrade --noconfirm $tempfile
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
 check_no_backup $tempfile $backupfile
 rm -f $tempfile $backupfile
@@ -324,7 +324,7 @@ rm -f $tempfile $backupfile
 
 echo "2.2. Database is an empty file - upgrade"
 touch $tempfile
-../run_dbutil.sh --upgrade --noconfirm $tempfile
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
 # A backup is performed before anything else, so the backup should exist.
 check_backup $tempfile $backupfile
@@ -338,7 +338,7 @@ rm -f $tempfile $backupfile
 
 echo "3.2. Database is not an SQLite file - upgrade"
 echo "This is not an sqlite3 database" > $tempfile
-../run_dbutil.sh --upgrade --noconfirm $tempfile
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile
 failzero $?
 # ...and as before, a backup should have been created
 check_backup $tempfile $backupfile
@@ -421,31 +421,31 @@ rm -f $tempfile $backupfile ${backupfile}-1 ${backupfile}-2
 
 echo "13.1 Command-line errors"
 copy_file $testdata/old_v1.sqlite3 $tempfile
-../run_dbutil.sh $tempfile
+${SHELL} ../run_dbutil.sh $tempfile
 failzero $?
-../run_dbutil.sh --upgrade --check $tempfile
+${SHELL} ../run_dbutil.sh --upgrade --check $tempfile
 failzero $?
-../run_dbutil.sh --noconfirm --check $tempfile
+${SHELL} ../run_dbutil.sh --noconfirm --check $tempfile
 failzero $?
-../run_dbutil.sh --check
+${SHELL} ../run_dbutil.sh --check
 failzero $?
-../run_dbutil.sh --upgrade --noconfirm
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm
 failzero $?
-../run_dbutil.sh --check $tempfile $backupfile
+${SHELL} ../run_dbutil.sh --check $tempfile $backupfile
 failzero $?
-../run_dbutil.sh --upgrade --noconfirm $tempfile $backupfile
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm $tempfile $backupfile
 failzero $?
 rm -f $tempfile $backupfile
 
 echo "13.2 verbose flag"
 copy_file $testdata/old_v1.sqlite3 $tempfile
-../run_dbutil.sh --upgrade --noconfirm --verbose $tempfile
+${SHELL} ../run_dbutil.sh --upgrade --noconfirm --verbose $tempfile
 passzero $?
 rm -f $tempfile $backupfile
 
 echo "13.3 Interactive prompt - yes"
 copy_file $testdata/old_v1.sqlite3 $tempfile
-../run_dbutil.sh --upgrade $tempfile << .
+${SHELL} ../run_dbutil.sh --upgrade $tempfile << .
 Yes
 .
 passzero $?
@@ -454,7 +454,7 @@ rm -f $tempfile $backupfile
 
 echo "13.4 Interactive prompt - no"
 copy_file $testdata/old_v1.sqlite3 $tempfile
-../run_dbutil.sh --upgrade $tempfile << .
+${SHELL} ../run_dbutil.sh --upgrade $tempfile << .
 no
 .
 passzero $?
@@ -464,7 +464,7 @@ rm -f $tempfile $backupfile
 
 echo "13.5 quiet flag"
 copy_file $testdata/old_v1.sqlite3 $tempfile
-../run_dbutil.sh --check --quiet $tempfile 2>&1 | grep .
+${SHELL} ../run_dbutil.sh --check --quiet $tempfile 2>&1 | grep .
 failzero $?
 rm -f $tempfile $backupfile
 
diff --git a/src/bin/dhcp4/dhcp4_log.h b/src/bin/dhcp4/dhcp4_log.h
index 3717b62..b042ea4 100644
--- a/src/bin/dhcp4/dhcp4_log.h
+++ b/src/bin/dhcp4/dhcp4_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DHCP4_LOG__H
-#define __DHCP4_LOG__H
+#ifndef DHCP4_LOG_H
+#define DHCP4_LOG_H
 
 #include <log/macros.h>
 #include <log/logger_support.h>
@@ -56,4 +56,4 @@ extern isc::log::Logger dhcp4_logger;
 } // namespace dhcp4
 } // namespace isc
 
-#endif // __DHCP4_LOG__H
+#endif // DHCP4_LOG_H
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 68aadea..55fe619 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -60,6 +60,7 @@ b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
 endif
 
 b10_dhcp6_LDADD  = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index dbffc40..e330e19 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// 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
@@ -21,10 +21,12 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
+#include <util/encode/hex.h>
 #include <asiolink/io_address.h>
 #include <cc/data.h>
 #include <config/ccsession.h>
 #include <log/logger_support.h>
+#include <dhcp/libdhcp++.h>
 #include <dhcp/triplet.h>
 #include <dhcp/pool.h>
 #include <dhcp/subnet.h>
@@ -60,12 +62,18 @@ typedef std::map<string, string> StringStorage;
 /// no subnet object created yet to store them.
 typedef std::vector<Pool6Ptr> PoolStorage;
 
+/// @brief Collection of options.
+typedef std::vector<OptionPtr> OptionStorage;
+
 /// @brief Global uint32 parameters that will be used as defaults.
 Uint32Storage uint32_defaults;
 
 /// @brief global string parameters that will be used as defaults.
 StringStorage string_defaults;
 
+/// @brief Global storage for options that will be used as defaults.
+OptionStorage option_defaults;
+
 /// @brief a dummy configuration parser
 ///
 /// It is a debugging parser. It does not configure anything,
@@ -135,6 +143,9 @@ protected:
 ///
 /// For overview of usability of this generic purpose parser, see
 /// \ref dhcpv6-config-inherit page.
+///
+/// @todo this class should be turned into the template class which
+/// will handle all uintX_types of data (see ticket #2415).
 class Uint32Parser : public DhcpConfigParser {
 public:
 
@@ -151,12 +162,37 @@ public:
     ///
     /// @param value pointer to the content of parsed values
     virtual void build(ConstElementPtr value) {
+        bool parse_error = false;
+        // Cast the provided value to int64 value to check.
+        int64_t int64value = 0;
         try {
-            value_ = boost::lexical_cast<uint32_t>(value->str());
-        } catch (const boost::bad_lexical_cast &) {
+            // Parsing the value as a int64 value allows to
+            // check if the provided value is within the range
+            // of uint32_t (is not negative or greater than
+            // maximal uint32_t value.
+            int64value = boost::lexical_cast<int64_t>(value->str());
+        } catch (const boost::bad_lexical_cast&) {
+            parse_error = true;
+        }
+        if (!parse_error) {
+            if ((int64value < 0) ||
+                (int64value > std::numeric_limits<uint32_t>::max())) {
+                parse_error = true;
+            } else {
+                try {
+                    value_ = boost::lexical_cast<uint32_t>(value->str());
+                } catch (const boost::bad_lexical_cast &) {
+                    parse_error = true;
+                }
+            }
+
+        }
+
+        if (parse_error) {
             isc_throw(BadValue, "Failed to parse value " << value->str()
                       << " as unsigned 32-bit integer.");
         }
+
         storage_->insert(pair<string, uint32_t>(param_name_, value_));
     }
 
@@ -445,6 +481,296 @@ protected:
     PoolStorage* pools_;
 };
 
+/// @brief Parser for option data value.
+///
+/// This parser parses configuration entries that specify value of
+/// a single option. These entries include option name, option code
+/// and data carried by the option. If parsing is successful than
+/// instance of an option is created and added to the storage provided
+/// by the calling class.
+///
+/// @todo This class parses and validates option name. However it is
+/// not used anywhere util support for option spaces is implemented
+/// (see tickets #2319, #2314). When option spaces are implemented
+/// there will be a way to reference the particular option using
+/// its type (code) or option name.
+class OptionDataParser : public DhcpConfigParser {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Class constructor.
+    OptionDataParser(const std::string&)
+        : options_(NULL) { }
+
+    /// @brief Parses the single option data.
+    ///
+    /// This method parses the data of a single option from the configuration.
+    /// The option data includes option name, option code and data being
+    /// carried by this option. Eventually it creates the instance of the
+    /// option.
+    ///
+    /// @warning setStorage must be called with valid storage pointer prior
+    /// to calling this method.
+    ///
+    /// @param option_data_entries collection of entries that define value
+    /// for a particular option.
+    /// @throw Dhcp6ConfigError if invalid parameter specified in
+    /// the configuration.
+    /// @throw isc::InvalidOperation if failed to set storage prior to
+    /// calling build.
+    /// @throw isc::BadValue if option data storage is invalid.
+    virtual void build(ConstElementPtr option_data_entries) {
+        if (options_ == NULL) {
+            isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
+                      "parsing option data.");
+        }
+        BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
+            ParserPtr parser;
+            if (param.first == "name") {
+                boost::shared_ptr<StringParser>
+                    name_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
+                if (name_parser) {
+                    name_parser->setStorage(&string_values_);
+                    parser = name_parser;
+                }
+            } else if (param.first == "code") {
+                boost::shared_ptr<Uint32Parser>
+                    code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::Factory(param.first)));
+                if (code_parser) {
+                    code_parser->setStorage(&uint32_values_);
+                    parser = code_parser;
+                }
+            } else if (param.first == "data") {
+                boost::shared_ptr<StringParser>
+                    value_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
+                if (value_parser) {
+                    value_parser->setStorage(&string_values_);
+                    parser = value_parser;
+                }
+            } else {
+                isc_throw(Dhcp6ConfigError,
+                          "Parser error: option-data parameter not supported: "
+                          << param.first);
+            }
+            parser->build(param.second);
+        }
+        // Try to create the option instance.
+        createOption();
+    }
+
+    /// @brief Does nothing.
+    ///
+    /// This function does noting because option data is committed
+    /// by a higher level parser.
+    virtual void commit() { }
+
+    /// @brief Set storage for the parser.
+    ///
+    /// Sets storage for the parser. This storage points to the
+    /// vector of options and is used by multiple instances of
+    /// OptionDataParser. Each instance creates exactly one object
+    /// of dhcp::Option or derived type and appends it to this
+    /// storage.
+    ///
+    /// @param storage pointer to the options storage
+    void setStorage(OptionStorage* storage) {
+        options_ = storage;
+    }
+
+private:
+
+    /// @brief Create option instance.
+    ///
+    /// Creates an instance of an option and adds it to the provided
+    /// options storage. If the option data parsed by \ref build function
+    /// are invalid or insufficient it emits exception.
+    ///
+    /// @warning this function does not check if options_ storage pointer
+    /// is intitialized but this is not needed here because it is checked in
+    /// \ref build function.
+    ///
+    /// @throw Dhcp6ConfigError if parameters provided in the configuration
+    /// are invalid.
+    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.
+        uint32_t option_code = getUint32Param("code");
+        if (option_code == 0) {
+            isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
+                      << " be equal to zero. Option code '0' is reserved in"
+                      << " DHCPv6.");
+        } else if (option_code > std::numeric_limits<uint16_t>::max()) {
+            isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
+                      << " exceed " << std::numeric_limits<uint16_t>::max());
+        }
+        // Check 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 = getStringParam("name");
+        if (option_name.empty()) {
+            isc_throw(Dhcp6ConfigError, "Parser error: option name must not be"
+                      << " empty");
+        } else if (option_name.find(" ") != std::string::npos) {
+            isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain"
+                      << " spaces");
+        }
+
+        // Get option data from the configuration database ('data' field).
+        // Option data is specified by the user as case insensitive string
+        // of hexadecimal digits for each option.
+        std::string option_data = getStringParam("data");
+        // Transform string of hexadecimal digits into binary format.
+        std::vector<uint8_t> binary;
+        try {
+            util::encode::decodeHex(option_data, binary);
+        } catch (...) {
+            isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
+                      << " string of hexadecimal digits: " << option_data);
+        }
+        // Get all existing DHCPv6 option definitions. The one that matches
+        // our option will be picked and used to create it.
+        OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
+        // Get search index #1. It allows searching for options definitions
+        // using option type value.
+        const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+        // Get all option definitions matching option code we want to create.
+        const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+        size_t num_defs = std::distance(range.first, range.second);
+        OptionPtr option;
+        // Currently we do not allow duplicated definitions and if there are
+        // any duplicates we issue internal server error.
+        if (num_defs > 1) {
+            isc_throw(Dhcp6ConfigError, "Internal error: currently it is not"
+                      << " supported to initialize multiple option definitions"
+                      << " for the same option code. This will be supported once"
+                      << " there option spaces are implemented.");
+        } else if (num_defs == 0) {
+            // @todo We have a limited set of option definitions intiialized at the moment.
+            // In the future we want to initialize option definitions for all options.
+            // Consequently error will be issued if option definition does not exist
+            // for a particular option code. For now it is ok to create generic option
+            // if definition does not exist.
+            OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
+                                        binary));
+            // If option is created succesfully, add it to the storage.
+            options_->push_back(option);
+        } else {
+            // We have exactly one option definition for the particular option code.
+            // use it to create option instance.
+            const OptionDefinitionPtr& def = *(range.first);
+            // getFactory should never return NULL pointer.
+            Option::Factory* factory = def->getFactory();
+            assert(factory != NULL);
+            try {
+                OptionPtr option = factory(Option::V6, option_code, binary);
+                options_->push_back(option);
+            } catch (const isc::Exception& ex) {
+                isc_throw(Dhcp6ConfigError, "Parser error: option data does not match"
+                          << " option definition (code " << option_code << "): "
+                          << ex.what());
+            }
+        }
+    }
+
+    /// @brief Get a parameter from the strings storage.
+    ///
+    /// @param param_id parameter identifier.
+    /// @throw Dhcp6ConfigError if parameter has not been found.
+    std::string getStringParam(const std::string& param_id) const {
+        StringStorage::const_iterator param = string_values_.find(param_id);
+        if (param == string_values_.end()) {
+            isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
+                      << " '" << param_id << "' not specified");
+        }
+        return (param->second);
+    }
+
+    /// @brief Get a parameter from the uint32 values storage.
+    ///
+    /// @param param_id parameter identifier.
+    /// @throw Dhcp6ConfigError if parameter has not been found.
+    uint32_t getUint32Param(const std::string& param_id) const {
+        Uint32Storage::const_iterator param = uint32_values_.find(param_id);
+        if (param == uint32_values_.end()) {
+            isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
+                      << " '" << param_id << "' not specified");
+        }
+        return (param->second);
+    }
+
+    /// Storage for uint32 values (e.g. option code).
+    Uint32Storage uint32_values_;
+    /// Storage for string values (e.g. option name or data).
+    StringStorage string_values_;
+    /// Pointer to options storage. This storage is provided by
+    /// the calling class and is shared by all OptionDataParser objects.
+    OptionStorage* options_;
+};
+
+/// @brief Parser for option data values with ina subnet.
+///
+/// This parser iterates over all entries that define options
+/// data for a particular subnet and creates a collection of options.
+/// If parsing is successful, all these options are added to the Subnet
+/// object.
+class OptionDataListParser : public DhcpConfigParser {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Unless otherwise specified, parsed options will be stored in
+    /// a global option containers (option_default). That storage location
+    /// is overriden on a subnet basis.
+    OptionDataListParser(const std::string&)
+        : options_(&option_defaults) { }
+
+    /// @brief Parses entries that define options' data for a subnet.
+    ///
+    /// This method iterates over all entries that define option data
+    /// for options within a single subnet and creates options' instances.
+    ///
+    /// @param option_data_list pointer to a list of options' data sets.
+    /// @throw Dhcp6ConfigError if option parsing failed.
+    void build(ConstElementPtr option_data_list) {
+        BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
+            boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
+            // options_ member will hold instances of all options thus
+            // each OptionDataParser takes it as a storage.
+            parser->setStorage(options_);
+            // Build the instance of a singkle option.
+            parser->build(option_value);
+        }
+    }
+
+    /// @brief Set storage for option instances.
+    ///
+    /// @param storage pointer to options storage.
+    void setStorage(OptionStorage* storage) {
+        options_ = storage;
+    }
+
+
+    /// @brief Does nothing.
+    ///
+    /// @todo Currently this function does nothing but in the future
+    /// we may need to extend it to commit at this level.
+    void commit() { }
+
+    /// @brief Create DhcpDataListParser object
+    ///
+    /// @param param_name param name.
+    ///
+    /// @return DhcpConfigParser object.
+    static DhcpConfigParser* Factory(const std::string& param_name) {
+        return (new OptionDataListParser(param_name));
+    }
+
+    /// Pointer to options instances storage.
+    OptionStorage* options_;
+};
+
 /// @brief this class parses a single subnet
 ///
 /// This class parses the whole subnet definition. It creates parsers
@@ -464,35 +790,36 @@ public:
     void build(ConstElementPtr subnet) {
 
         BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
-
             ParserPtr parser(createSubnet6ConfigParser(param.first));
-
-            // if this is an Uint32 parser, tell it to store the values
-            // in values_, rather than in global storage
-            boost::shared_ptr<Uint32Parser> uintParser =
-                boost::dynamic_pointer_cast<Uint32Parser>(parser);
-            if (uintParser) {
-                uintParser->setStorage(&uint32_values_);
-            } else {
-
-                boost::shared_ptr<StringParser> stringParser =
-                    boost::dynamic_pointer_cast<StringParser>(parser);
-                if (stringParser) {
-                    stringParser->setStorage(&string_values_);
-                } else {
-
-                    boost::shared_ptr<PoolParser> poolParser =
-                        boost::dynamic_pointer_cast<PoolParser>(parser);
-                    if (poolParser) {
-                        poolParser->setStorage(&pools_);
-                    }
-                }
+            // The actual type of the parser is unknown here. We have to discover
+            // parser type here to invoke corresponding setStorage function on it.
+            // We discover parser type by trying to cast the parser to various
+            // parser types and checking which one was successful. For this one
+            // a setStorage and build methods are invoked.
+
+            // Try uint32 type parser.
+            if (buildParser<Uint32Parser, Uint32Storage >(parser, uint32_values_,
+                                                          param.second)) {
+                // Storage set, build invoked on the parser, proceed with
+                // next configuration element.
+                continue;
+            }
+            // Try string type parser.
+            if (buildParser<StringParser, StringStorage >(parser, string_values_,
+                                                          param.second)) {
+                continue;
+            }
+            // Try pools parser.
+            if (buildParser<PoolParser, PoolStorage >(parser, pools_,
+                                                      param.second)) {
+                continue;
+            }
+            // Try option data parser.
+            if (buildParser<OptionDataListParser, OptionStorage >(parser, options_,
+                                                                  param.second)) {
+                continue;
             }
-
-            parser->build(param.second);
-            parsers_.push_back(parser);
         }
-
         // Ok, we now have subnet parsed
     }
 
@@ -540,10 +867,78 @@ public:
             subnet->addPool6(*it);
         }
 
+        const Subnet::OptionContainer& options = subnet->getOptions();
+        const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+
+        // Add subnet specific options.
+        BOOST_FOREACH(OptionPtr option, options_) {
+            Subnet::OptionContainerTypeRange range = idx.equal_range(option->getType());
+            if (std::distance(range.first, range.second) > 0) {
+                LOG_WARN(dhcp6_logger, DHCP6_CONFIG_OPTION_DUPLICATE)
+                    .arg(option->getType()).arg(addr.toText());
+            }
+            subnet->addOption(option);
+        }
+
+        // Check all global options and add them to the subnet object if
+        // they have been configured in the global scope. If they have been
+        // configured in the subnet scope we don't add global option because
+        // the one configured in the subnet scope always takes precedense.
+        BOOST_FOREACH(OptionPtr option, option_defaults) {
+            // Get all options specified locally in the subnet and having
+            // code equal to global option's code.
+            Subnet::OptionContainerTypeRange range = idx.equal_range(option->getType());
+            // @todo: In the future we will be searching for options using either
+            // option code or namespace. Currently we have only the option
+            // code available so if there is at least one option found with the
+            // specific code we don't add globally configured option.
+            // @todo with this code the first globally configured option
+            // with the given code will be added to a subnet. We may
+            // want to issue warning about dropping configuration of
+            // global option if one already exsist.
+            if (std::distance(range.first, range.second) == 0) {
+                subnet->addOption(option);
+            }
+        }
+
         CfgMgr::instance().addSubnet6(subnet);
     }
 
-protected:
+private:
+
+    /// @brief Set storage for a parser and invoke build.
+    ///
+    /// This helper method casts the provided parser pointer to specified
+    /// type. If cast is successful it sets the corresponding storage for
+    /// this parser, invokes build on it and save the parser.
+    ///
+    /// @tparam T parser type to which parser argument should be cast.
+    /// @tparam Y storage type for the specified parser type.
+    /// @param parser parser on which build must be invoked.
+    /// @param storage reference to a storage that will be set for a parser.
+    /// @param subnet subnet element read from the configuration and being parsed.
+    /// @return true if parser pointer was successfully cast to specialized
+    /// parser type provided as Y.
+    template<typename T, typename Y>
+    bool buildParser(const ParserPtr& parser, Y& storage, const ConstElementPtr& subnet) {
+        // We need to cast to T in order to set storage for the parser.
+        boost::shared_ptr<T> cast_parser = boost::dynamic_pointer_cast<T>(parser);
+        // It is common that this cast is not successful because we try to cast to all
+        // supported parser types as we don't know the type of a parser in advance.
+        if (cast_parser) {
+            // Cast, successful so we go ahead with setting storage and actual parse.
+            cast_parser->setStorage(&storage);
+            parser->build(subnet);
+            parsers_.push_back(parser);
+            // We indicate that cast was successful so as the calling function
+            // may skip attempts to cast to other parser types and proceed to
+            // next element.
+            return (true);
+        }
+        // It was not successful. Indicate that another parser type
+        // should be tried.
+        return (false);
+    }
 
     /// @brief creates parsers for entries in subnet definition
     ///
@@ -569,6 +964,10 @@ protected:
         factories.insert(pair<string, ParserFactory*>(
                              "pool", PoolParser::Factory));
 
+        factories.insert(pair<string, ParserFactory*>(
+                             "option-data", OptionDataListParser::Factory));
+
+
         FactoryMap::iterator f = factories.find(config_id);
         if (f == factories.end()) {
             // Used for debugging only.
@@ -622,6 +1021,9 @@ protected:
     /// storage for pools belonging to this subnet
     PoolStorage pools_;
 
+    /// storage for options belonging to this subnet
+    OptionStorage options_;
+
     /// parsers are stored here
     ParserCollection parsers_;
 };
@@ -698,7 +1100,6 @@ public:
 DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
     FactoryMap factories;
 
-    //
     factories.insert(pair<string, ParserFactory*>(
                          "preferred-lifetime", Uint32Parser::Factory));
     factories.insert(pair<string, ParserFactory*>(
@@ -714,6 +1115,9 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
                          "subnet6", Subnets6ListConfigParser::Factory));
 
     factories.insert(pair<string, ParserFactory*>(
+                         "option-data", OptionDataListParser::Factory));
+
+    factories.insert(pair<string, ParserFactory*>(
                          "version", StringParser::Factory));
 
     FactoryMap::iterator f = factories.find(config_id);
@@ -749,6 +1153,12 @@ configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) {
                   "Null pointer is passed to configuration parser");
     }
 
+    /// Reset global storage. Containers being reset below may contain
+    /// data from the previous configuration attempts.
+    option_defaults.clear();
+    uint32_defaults.clear();
+    string_defaults.clear();
+
     /// @todo: append most essential info here (like "2 new subnets configured")
     string config_details;
 
diff --git a/src/bin/dhcp6/dhcp6.dox b/src/bin/dhcp6/dhcp6.dox
index fe842de..c234f40 100644
--- a/src/bin/dhcp6/dhcp6.dox
+++ b/src/bin/dhcp6/dhcp6.dox
@@ -35,7 +35,7 @@
 
  This method iterates over list of received configuration elements and creates a
  list of parsers for each received entry. Parser is an object that is derived
- from a \ref isc::dhcp::Dhcp6ConfigParser class. Once a parser is created
+ from a \ref isc::dhcp::DhcpConfigParser class. Once a parser is created
  (constructor), its value is set (using build() method). Once all parsers are
  build, the configuration is then applied ("commited") and commit() method is
  called.
@@ -51,7 +51,7 @@
 
  @section dhcpv6-config-inherit DHCPv6 Configuration Inheritance
 
- One notable useful features of DHCP configuration is its parameter inheritance.
+ One notable useful feature of DHCP configuration is its parameter inheritance.
  For example, renew-timer value may be specified at a global scope and it then
  applies to all subnets. However, some subnets may have it overwritten with more
  specific values that takes precedence over global values that are considered
@@ -64,7 +64,7 @@
  phase (commit() method), appropriate parsers can use apply parameter inheritance.
 
  Debugging configuration parser may be confusing. Therefore there is a special
- class called \ref isc::dhcp::DummyParser. It does not configure anything, but just
+ class called \ref isc::dhcp::DebugParser. It does not configure anything, but just
  accepts any parameter of any type. If requested to commit configuration, it will
  print out received parameter name and its value. This class is not currently used,
  but it is convenient to have it every time a new parameter is added to DHCP
@@ -76,4 +76,6 @@
  simple as possible. In fact, currently the code has to call Subnet6->getT1() and
  do not implement any fancy inheritance logic.
 
+ @todo Add section about setting up options and their definitions with bindctl.
+
  */
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index f35f606..c5e9565 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -40,6 +40,37 @@
         "item_default": 4000
       },
 
+      { "item_name": "option-data",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [],
+        "list_item_spec":
+        {
+          "item_name": "single-option-data",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": {},
+          "map_item_spec": [
+          {
+            "item_name": "name",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          },
+
+          { "item_name": "code",
+            "item_type": "integer",
+            "item_optional": false,
+            "item_default": 0
+          },
+          { "item_name": "data",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          } ]
+        }
+      },
+
       { "item_name": "subnet6",
         "item_type": "list",
         "item_optional": false,
@@ -92,10 +123,40 @@
                         "item_optional": false,
                         "item_default": ""
                     }
-                }
-            ]
-        }
-      }
+                },
+                { "item_name": "option-data",
+                  "item_type": "list",
+                  "item_optional": false,
+                  "item_default": [],
+                  "list_item_spec":
+                  {
+                    "item_name": "single-option-data",
+                    "item_type": "map",
+                    "item_optional": false,
+                    "item_default": {},
+                    "map_item_spec": [
+                    {
+                      "item_name": "name",
+                      "item_type": "string",
+                      "item_optional": false,
+                      "item_default": ""
+                    },
+                    {
+                      "item_name": "code",
+                      "item_type": "integer",
+                      "item_optional": false,
+                      "item_default": 0
+                    },
+                    {
+                      "item_name": "data",
+                      "item_type": "string",
+                      "item_optional": false,
+                      "item_default": ""
+                    } ]
+                  }
+                } ]
+            }
+       }
     ],
     "commands": [
         {
diff --git a/src/bin/dhcp6/dhcp6_log.h b/src/bin/dhcp6/dhcp6_log.h
index 6d7f4e3..fb3c3f9 100644
--- a/src/bin/dhcp6/dhcp6_log.h
+++ b/src/bin/dhcp6/dhcp6_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DHCP6_LOG__H
-#define __DHCP6_LOG__H
+#ifndef DHCP6_LOG_H
+#define DHCP6_LOG_H
 
 #include <log/macros.h>
 #include <log/logger_support.h>
@@ -56,4 +56,4 @@ extern isc::log::Logger dhcp6_logger;
 } // namespace dhcp6
 } // namespace isc
 
-#endif // __DHCP6_LOG__H
+#endif // DHCP6_LOG_H
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 2399c19..5f9cd02 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -30,6 +30,11 @@ from the BIND 10 control system by the IPv6 DHCP server.
 A debug message indicating that the IPv6 DHCP server has received an
 updated configuration from the BIND 10 configuration system.
 
+% DHCP6_DB_BACKEND_STARTED Lease database started (backend type: %1)
+This informational message is printed every time DHCPv6 is started.
+It indicates what database backend type is being to store lease and
+other information.
+
 % DHCP6_NOT_RUNNING IPv6 DHCP server is not running
 A warning message is issued when an attempt is made to shut down the
 IPv6 DHCP server but it is not running.
@@ -42,6 +47,27 @@ interfaces and is therefore shutting down.
 A debug message issued during startup, this indicates that the IPv6 DHCP
 server is about to open sockets on the specified port.
 
+% 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 othe advertised
+and continue allocation with that server. This is a normal behavior and
+indicates successful operation.
+
+% DHCP6_LEASE_ALLOC lease %1 has been allocated (client duid=%2, iaid=%3)
+This debug message indicates that the server successfully granted (in
+response to client's REQUEST message) a lease. This is a normal behavior
+and incicates successful operation.
+
+% DHCP6_LEASE_ADVERT_FAIL failed to advertise a lease for client duid=%1, iaid=%2
+This message indicates that the server failed to advertise (in response to
+received SOLICIT) 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_LEASE_ALLOC_FAIL failed to grant a lease for client duid=%1, iaid=%2
+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_PACKET_PARSE_FAIL failed to parse incoming packet
 The IPv6 DHCP server has received a packet that it is unable to interpret.
 
@@ -50,7 +76,7 @@ The IPv6 DHCP server tried to receive a packet but an error
 occured during this attempt. The reason for the error is included in
 the message.
 
-% DHCP6_PACKET_RECEIVED %1 (type %2) packet received
+% 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
 DHCP packet, just a type not expected by the server (e.g. it will report
@@ -66,10 +92,15 @@ 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_QUERY_DATA received packet length %1, data length %2, data is <%3>
+% 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
+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_RESPONSE_DATA responding with packet type %1 data is <%2>
+% DHCP6_RESPONSE_DATA responding with packet type %1 data is %2
 A debug message listing the data returned to the client.
 
 % DHCP6_SERVER_FAILED server failed: %1
@@ -110,6 +141,28 @@ This is a debug message issued during the IPv6 DHCP server startup.
 It lists some information about the parameters with which the server
 is running.
 
+% DHCP6_SUBNET_SELECTED the %1 subnet was selected for client assignment
+This is a debug message informing that a given subnet was selected. It will
+be used for address and option assignment. This is one of the early steps
+in the processing of incoming client message.
+
+% DHCP6_SUBNET_SELECTION_FAILED failed to select a subnet for incoming packet, src=%1 type=%2
+This warning message is output when a packet was received from a subnet for
+which the DHCPv6 server has not been configured. The cause is most likely due
+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_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_CONFIG_LOAD_FAIL failed to load configuration: %1
 This critical error message indicates that the initial DHCPv6
 configuration has failed. The server will start, but nothing will be
@@ -120,7 +173,7 @@ This is a debug message that is issued every time the server receives a
 configuration. That happens start up and also when a server configuration
 change is committed by the administrator.
 
-% DHCP6_CONFIG_NEW_SUBNET A new subnet has been added to configuration: %1
+% DHCP6_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1
 This is an informational message reporting that the configuration has
 been extended to include the specified subnet.
 
@@ -129,3 +182,8 @@ 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.
+
+% DHCP6_CONFIG_OPTION_DUPLICATE multiple options with the code: %1 added to the subnet: %2
+This warning message is issued on attempt to configure multiple options with the
+same option code for the particular subnet. Adding multiple options is uncommon
+for DHCPv6, yet it is not prohibited.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 7c57a61..5f844a3 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <stdlib.h>
 #include <time.h>
 
@@ -20,13 +22,28 @@
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/libdhcp++.h>
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_ia.h>
+#include <dhcp/option6_int_array.h>
 #include <dhcp/pkt6.h>
+#include <dhcp/subnet.h>
+#include <dhcp/cfgmgr.h>
 #include <exceptions/exceptions.h>
 #include <util/io_utilities.h>
 #include <util/range_utilities.h>
+#include <dhcp/duid.h>
+#include <dhcp/lease_mgr.h>
+#include <dhcp/lease_mgr_factory.h>
+#include <dhcp/cfgmgr.h>
+#include <dhcp/option6_iaaddr.h>
+
+// @todo: Replace this with MySQL_LeaseMgr (or a LeaseMgr factory)
+// once it is merged
+#include <dhcp/memfile_lease_mgr.h>
+
+#include <boost/foreach.hpp>
 
 using namespace isc;
 using namespace isc::asiolink;
@@ -34,50 +51,62 @@ using namespace isc::dhcp;
 using namespace isc::util;
 using namespace std;
 
-const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
-const uint32_t HARDCODED_T1 = 1500; // in seconds
-const uint32_t HARDCODED_T2 = 2600; // in seconds
-const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
-const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
-const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";
+namespace isc {
+namespace dhcp {
 
-Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
-    if (port == 0) {
-        // used for testing purposes. Some tests, e.g. configuration parser,
-        // require Dhcpv6Srv object, but they don't really need it to do
-        // anything. This speed up and simplifies the tests.
-        return;
-    }
+Dhcpv6Srv::Dhcpv6Srv(uint16_t port) : alloc_engine_(), serverid_(),
+                                      shutdown_(false) {
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
 
-    // First call to instance() will create IfaceMgr (it's a singleton)
-    // it may throw something if things go wrong
+    // Initialize objects required for DHCP server operation.
     try {
-
-        if (IfaceMgr::instance().countIfaces() == 0) {
-            LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
-            shutdown_ = true;
-            return;
+        // Initialize standard DHCPv6 option definitions. This function
+        // may throw bad_alloc if system goes out of memory during the
+        // creation if option definitions. It may also throw isc::Unexpected
+        // if definitions are wrong. This would mean error in implementation.
+        initStdOptionDefs();
+
+        // Port 0 is used for testing purposes. It means that the server should
+        // not open any sockets at all. Some tests, e.g. configuration parser,
+        // require Dhcpv6Srv object, but they don't really need it to do
+        // anything. This speed up and simplifies the tests.
+        if (port > 0) {
+            if (IfaceMgr::instance().countIfaces() == 0) {
+                LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
+                shutdown_ = true;
+                return;
+            }
+            IfaceMgr::instance().openSockets6(port);
         }
 
-        IfaceMgr::instance().openSockets6(port);
-
         setServerID();
 
-        /// @todo: instantiate LeaseMgr here once it is imlpemented.
-
     } catch (const std::exception &e) {
         LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what());
         shutdown_ = true;
         return;
     }
 
-    shutdown_ = false;
+    // Instantiate LeaseMgr
+    // @todo: Replace this with MySQL_LeaseMgr (or a LeaseMgr factory)
+    // once it is merged
+#ifdef HAVE_MYSQL
+    LeaseMgrFactory::create("type=mysql user=kea password=kea name=kea host=localhost");
+#else
+    LeaseMgrFactory::create("type=memfile");
+#endif
+    LOG_INFO(dhcp6_logger, DHCP6_DB_BACKEND_STARTED)
+        .arg(LeaseMgrFactory::instance().getName());
+
+    // Instantiate allocation engine
+    alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 }
 
 Dhcpv6Srv::~Dhcpv6Srv() {
     IfaceMgr::instance().closeSockets();
+
+    LeaseMgrFactory::destroy();
 }
 
 void Dhcpv6Srv::shutdown() {
@@ -87,7 +116,12 @@ void Dhcpv6Srv::shutdown() {
 
 bool Dhcpv6Srv::run() {
     while (!shutdown_) {
-        /// @todo: calculate actual timeout once we have lease database
+        /// @todo: calculate actual timeout to the next event (e.g. lease
+        /// expiration) once we have lease database. The idea here is that
+        /// it is possible to do everything in a single process/thread.
+        /// For now, we are just calling select for 1000 seconds. There
+        /// were some issues reported on some systems when calling select()
+        /// with too large values. Unfortunately, I don't recall the details.
         int timeout = 1000;
 
         // client's message and server's response
@@ -107,10 +141,9 @@ bool Dhcpv6Srv::run() {
                 continue;
             }
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
-                      .arg(serverReceivedPacketName(query->getType()))
-                      .arg(query->getType());
+                      .arg(serverReceivedPacketName(query->getType()));
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
-                      .arg(query->getType())
+                      .arg(static_cast<int>(query->getType()))
                       .arg(query->getBuffer().getLength())
                       .arg(query->toText());
 
@@ -196,7 +229,7 @@ void Dhcpv6Srv::setServerID() {
 
     const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
 
-    // let's find suitable interface
+    // Let's find suitable interface.
     for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
          iface != ifaces.end(); ++iface) {
         // All the following checks could be merged into one multi-condition
@@ -217,17 +250,17 @@ void Dhcpv6Srv::setServerID() {
             continue;
         }
 
-        // let's don't use loopback
+        // Let's don't use loopback.
         if (iface->flag_loopback_) {
             continue;
         }
 
-        // let's skip downed interfaces. It is better to use working ones.
+        // Let's skip downed interfaces. It is better to use working ones.
         if (!iface->flag_up_) {
             continue;
         }
 
-        // some interfaces (like lo on Linux) report 6-bytes long
+        // Some interfaces (like lo on Linux) report 6-bytes long
         // MAC adress 00:00:00:00:00:00. Let's not use such weird interfaces
         // to generate DUID.
         if (isRangeZero(iface->getMac(), iface->getMac() + iface->getMacLen())) {
@@ -243,37 +276,37 @@ void Dhcpv6Srv::setServerID() {
         seconds -= DUID_TIME_EPOCH;
 
         OptionBuffer srvid(8 + iface->getMacLen());
-        writeUint16(DUID_LLT, &srvid[0]);
+        writeUint16(DUID::DUID_LLT, &srvid[0]);
         writeUint16(HWTYPE_ETHERNET, &srvid[2]);
         writeUint32(static_cast<uint32_t>(seconds), &srvid[4]);
-        memcpy(&srvid[0]+8, iface->getMac(), iface->getMacLen());
+        memcpy(&srvid[0] + 8, iface->getMac(), iface->getMacLen());
 
         serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
                                          srvid.begin(), srvid.end()));
         return;
     }
 
-    // if we reached here, there are no suitable interfaces found.
+    // If we reached here, there are no suitable interfaces found.
     // Either interface detection is not supported on this platform or
     // this is really weird box. Let's use DUID-EN instead.
     // See Section 9.3 of RFC3315 for details.
 
     OptionBuffer srvid(12);
-    writeUint16(DUID_EN, &srvid[0]);
+    writeUint16(DUID::DUID_EN, &srvid[0]);
     writeUint32(ENTERPRISE_ID_ISC, &srvid[2]);
 
     // Length of the identifier is company specific. I hereby declare
     // ISC "standard" of 6 bytes long pseudo-random numbers.
     srandom(time(NULL));
-    fillRandom(&srvid[6],&srvid[12]);
+    fillRandom(&srvid[6], &srvid[12]);
 
     serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
                                      srvid.begin(), srvid.end()));
 }
 
 void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-    // add client-id
-    boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
+    // Add client-id.
+    OptionPtr clientid = question->getOption(D6O_CLIENTID);
     if (clientid) {
         answer->addOption(clientid);
     }
@@ -281,52 +314,221 @@ 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) {
-    // TODO: question is currently unused, but we need it at least to know
-    // message type we are answering
-
+void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, 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());
+    if (!subnet) {
+        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT)
+            .arg(question->getRemoteAddr().toText());
+        return;
+    }
 
-void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
-    // TODO: question is currently unused, but we need to extract ORO from it
-    // and act on its content. Now we just send DNS-SERVERS option.
+    // Client requests some options using ORO option. Try to
+    // get this option from client's message.
+    boost::shared_ptr<Option6IntArray<uint16_t> > option_oro =
+        boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(question->getOption(D6O_ORO));
+    // Option ORO not found. Don't do anything then.
+    if (!option_oro) {
+        return;
+    }
+    // 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.
+    const Subnet::OptionContainer& options = subnet->getOptions();
+    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) {
+            answer->addOption(desc.option);
+        }
+    }
+}
+
+OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
 
-    // add dns-servers option
-    boost::shared_ptr<Option> dnsservers(new Option6AddrLst(D6O_NAME_SERVERS,
-                                         IOAddress(HARDCODED_DNS_SERVER)));
-    answer->addOption(dnsservers);
+    // @todo: Implement Option6_StatusCode and rewrite this code here
+    vector<uint8_t> data(text.c_str(), text.c_str() + text.length());
+    data.insert(data.begin(), static_cast<uint8_t>(code % 256));
+    data.insert(data.begin(), static_cast<uint8_t>(code >> 8));
+    OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data));
+    return (status);
+}
+
+Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+
+    return (subnet);
 }
 
 void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-    /// TODO Rewrite this once LeaseManager is implemented.
-
-    // answer client's IA (this is mostly a dummy,
-    // so let's answer only first IA and hope there is only one)
-    boost::shared_ptr<Option> ia_opt = question->getOption(D6O_IA_NA);
-    if (ia_opt) {
-        // found IA
-        Option* tmp = ia_opt.get();
-        Option6IA* ia_req = dynamic_cast<Option6IA*>(tmp);
-        if (ia_req) {
-            boost::shared_ptr<Option6IA>
-                ia_rsp(new Option6IA(D6O_IA_NA, ia_req->getIAID()));
-            ia_rsp->setT1(HARDCODED_T1);
-            ia_rsp->setT2(HARDCODED_T2);
-            boost::shared_ptr<Option6IAAddr>
-                addr(new Option6IAAddr(D6O_IAADDR,
-                                       IOAddress(HARDCODED_LEASE),
-                                       HARDCODED_PREFERRED_LIFETIME,
-                                       HARDCODED_VALID_LIFETIME));
-            ia_rsp->addOption(addr);
-            answer->addOption(ia_rsp);
+
+    // We need to allocate addresses for all IA_NA options in the client's
+    // question (i.e. SOLICIT or REQUEST) message.
+
+    // We need to select a subnet the client is connected in.
+    Subnet6Ptr subnet = selectSubnet(question);
+    if (subnet) {
+        // This particular client is out of luck today. We do not have
+        // information about the subnet he is connected to. This likely means
+        // misconfiguration of the server (or some relays). We will continue to
+        // process this message, but our response will be almost useless: no
+        // addresses or prefixes, no subnet specific configuration etc. The only
+        // thing this client can get is some global information (like DNS
+        // servers).
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_SUBNET_SELECTED)
+            .arg(subnet->toText());
+    } else {
+        // perhaps this should be logged on some higher level? This is most likely
+        // configuration bug.
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_SUBNET_SELECTION_FAILED);
+    }
+
+    // @todo: We should implement Option6Duid some day, but we can do without it
+    // just fine for now
+
+    // Let's find client's DUID. Client is supposed to include its client-id
+    // option almost all the time (the only exception is an anonymous inf-request,
+    // but that is mostly a theoretical case). Our allocation engine needs DUID
+    // and will refuse to allocate anything to anonymous clients.
+    DuidPtr duid;
+    OptionPtr opt_duid = question->getOption(D6O_CLIENTID);
+    if (opt_duid) {
+        duid = DuidPtr(new DUID(opt_duid->getData()));
+    }
+
+    // Now that we have all information about the client, let's iterate over all
+    // received options and handle IA_NA options one by one and store our
+    // responses in answer message (ADVERTISE or REPLY).
+    //
+    // @todo: expand this to cover IA_PD and IA_TA once we implement support for
+    // prefix delegation and temporary addresses.
+    for (Option::OptionCollection::iterator opt = question->options_.begin();
+         opt != question->options_.end(); ++opt) {
+        switch (opt->second->getType()) {
+        case D6O_IA_NA: {
+            OptionPtr answer_opt = handleIA_NA(subnet, duid, question,
+                                   boost::dynamic_pointer_cast<Option6IA>(opt->second));
+            if (answer_opt) {
+                answer->addOption(answer_opt);
+            }
+            break;
+        }
+        default:
+            break;
         }
     }
 }
 
+OptionPtr Dhcpv6Srv::handleIA_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,
+    // but different wording below)
+    if (!subnet) {
+        // Create empty IA_NA option with IAID matching the request.
+        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+        // Insert status code NoAddrsAvail.
+        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail, "Sorry, no subnet available."));
+        return (ia_rsp);
+    }
+
+    // Check if the client sent us a hint in his IA_NA. Clients may send an
+    // address in their IA_NA options as a suggestion (e.g. the last address
+    // they used before).
+    boost::shared_ptr<Option6IAAddr> hintOpt = boost::dynamic_pointer_cast<Option6IAAddr>
+                                        (ia->getOption(D6O_IAADDR));
+    IOAddress hint("::");
+    if (hintOpt) {
+        hint = hintOpt->getAddress();
+    }
+
+    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_REQUEST)
+        .arg(duid?duid->toText():"(no-duid)").arg(ia->getIAID())
+        .arg(hintOpt?hint.toText():"(no hint)");
+
+    // "Fake" allocation is processing of SOLICIT message. We pretend to do an
+    // allocation, but we do not put the lease in the database. That is ok,
+    // because we do not guarantee that the user will get that exact lease. If
+    // the user selects this server to do actual allocation (i.e. sends REQUEST)
+    // it should include this hint. That will help us during the actual lease
+    // allocation.
+    bool fake_allocation = false;
+    if (question->getType() == DHCPV6_SOLICIT) {
+        /// @todo: Check if we support rapid commit
+        fake_allocation = true;
+    }
+
+    // Use allocation engine to pick a lease for this client. Allocation engine
+    // will try to honour the hint, but it is just a hint - some other address
+    // may be used instead. If fake_allocation is set to false, the lease will
+    // be inserted into the LeaseMgr as well.
+    Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid, ia->getIAID(),
+                                                      hint, fake_allocation);
+
+    // Create IA_NA that we will put in the response.
+    boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+    if (lease) {
+        // We have a lease! Let's wrap its content into IA_NA option
+        // with IAADDR suboption.
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation?
+                  DHCP6_LEASE_ADVERT:DHCP6_LEASE_ALLOC)
+            .arg(lease->addr_.toText())
+            .arg(duid?duid->toText():"(no-duid)")
+            .arg(ia->getIAID());
+
+        ia_rsp->setT1(subnet->getT1());
+        ia_rsp->setT2(subnet->getT2());
+
+        boost::shared_ptr<Option6IAAddr>
+            addr(new Option6IAAddr(D6O_IAADDR,
+                                   lease->addr_,
+                                   lease->preferred_lft_,
+                                   lease->valid_lft_));
+        ia_rsp->addOption(addr);
+
+        // It would be possible to insert status code=0(success) as well,
+        // but this is considered waste of bandwidth as absence of status
+        // code is considered a success.
+    } else {
+        // Allocation engine did not allocate a lease. The engine logged
+        // 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)
+            .arg(duid?duid->toText():"(no-duid)")
+            .arg(ia->getIAID())
+            .arg(subnet->toText());
+
+        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
+                          "Sorry, no address could be allocated."));
+    }
+    return (ia_rsp);
+}
+
 Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
+
     Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
 
     copyDefaultOptions(solicit, advertise);
@@ -428,3 +630,11 @@ Dhcpv6Srv::serverReceivedPacketName(uint8_t type) {
     }
     return (UNKNOWN);
 }
+
+void
+Dhcpv6Srv::initStdOptionDefs() {
+    LibDHCP::initStdOptionDefs(Option::V6);
+}
+
+};
+};
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 1cb3236..6574226 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -15,23 +15,33 @@
 #ifndef DHCPV6_SRV_H
 #define DHCPV6_SRV_H
 
+#include <iostream>
+
 #include <boost/noncopyable.hpp>
+#include <dhcp/alloc_engine.h>
 #include <dhcp/dhcp6.h>
-#include <dhcp/pkt6.h>
+#include <dhcp/duid.h>
 #include <dhcp/option.h>
-#include <iostream>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/subnet.h>
 
 namespace isc {
 
 namespace dhcp {
 /// @brief DHCPv6 server service.
 ///
-/// This singleton class represents DHCPv6 server. It contains all
+/// This class represents DHCPv6 server. It contains all
 /// top-level methods and routines necessary for server operation.
 /// In particular, it instantiates IfaceMgr, loads or generates DUID
 /// that is going to be used as server-identifier, receives incoming
 /// packets, processes them, manages leases assignment and generates
 /// appropriate responses.
+///
+/// @note Only one instance of this class is instantated as it encompasses
+///       the whole operation of the server.  Nothing, however, enforces the
+///       singleton status of the object.
 class Dhcpv6Srv : public boost::noncopyable {
 
 public:
@@ -52,7 +62,7 @@ public:
     /// @brief Destructor. Used during DHCPv6 service shutdown.
     virtual ~Dhcpv6Srv();
 
-    /// @brief Returns server-intentifier option
+    /// @brief Returns server-intentifier option.
     ///
     /// @return server-id option
     OptionPtr getServerID() { return serverid_; }
@@ -70,7 +80,7 @@ public:
     /// @brief Instructs the server to shut down.
     void shutdown();
 
-    /// @brief Return textual type of packet received by server
+    /// @brief Return textual type of packet received by server.
     ///
     /// Returns the name of valid packet received by the server (e.g. SOLICIT).
     /// If the packet is unknown - or if it is a valid DHCP packet but not one
@@ -147,7 +157,38 @@ protected:
     /// @param infRequest message received from client
     Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
 
-    /// @brief Copies required options from client message to server answer
+    /// @brief Creates status-code option.
+    ///
+    /// @param code status code value (see RFC3315)
+    /// @param text textual explanation (will be sent in status code option)
+    /// @return status-code option
+    OptionPtr createStatusCode(uint16_t code, const std::string& text);
+
+    /// @brief Selects a subnet for a given client's packet.
+    ///
+    /// @param question client's message
+    /// @return selected subnet (or NULL if no suitable subnet was found)
+    isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question);
+
+    /// @brief Processes IA_NA option (and assigns addresses if necessary).
+    ///
+    /// Generates response to IA_NA. This typically includes selecting (and
+    /// allocating a lease in case of REQUEST) a lease and creating
+    /// IAADDR option. In case of allocation failure, it may contain
+    /// status code option with non-zero status, denoting cause of the
+    /// allocation failure.
+    ///
+    /// @param subnet subnet the client is connected to
+    /// @param duid client's duid
+    /// @param question client's message (typically SOLICIT or REQUEST)
+    /// @param ia pointer to client's IA_NA option (client's request)
+    /// @return IA_NA option (server's response)
+    OptionPtr handleIA_NA(const isc::dhcp::Subnet6Ptr& subnet,
+                          const isc::dhcp::DuidPtr& duid,
+                          isc::dhcp::Pkt6Ptr question,
+                          boost::shared_ptr<Option6IA> ia);
+
+    /// @brief Copies required options from client message to server answer.
     ///
     /// Copies options that must appear in any server response (ADVERTISE, REPLY)
     /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE).
@@ -170,8 +211,6 @@ protected:
     /// @brief Appends requested options to server's answer.
     ///
     /// Appends options requested by client to the server's answer.
-    /// TODO: This method is currently a stub. It just appends DNS-SERVERS
-    /// option.
     ///
     /// @param question client's message
     /// @param answer server's message (options will be added here)
@@ -199,10 +238,28 @@ protected:
     ///         interfaces for new DUID generation are detected.
     void setServerID();
 
-    /// server DUID (to be sent in server-identifier option)
+    /// @brief Initializes option definitions for standard options.
+    ///
+    /// Each standard option's format is described by the
+    /// dhcp::OptionDefinition object. This function creates such objects
+    /// for each standard DHCPv6 option.
+    ///
+    /// @todo list thrown exceptions.
+    /// @todo extend this function to cover all standard options. Currently
+    /// it is limited to critical options only.
+    void initStdOptionDefs();
+
+private:
+    /// @brief Allocation Engine.
+    /// Pointer to the allocation engine that we are currently using
+    /// It must be a pointer, because we will support changing engines
+    /// during normal operation (e.g. to use different allocators)
+    boost::shared_ptr<AllocEngine> alloc_engine_;
+
+    /// Server DUID (to be sent in server-identifier option)
     boost::shared_ptr<isc::dhcp::Option> serverid_;
 
-    /// indicates if shutdown is in progress. Setting it to true will
+    /// Indicates if shutdown is in progress. Setting it to true will
     /// initiate server shutdown procedure.
     volatile bool shutdown_;
 };
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index 1629ae6..78caa2f 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -63,6 +63,7 @@ dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp6_unittests_LDADD = $(GTEST_LDADD)
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index 22592e8..780b5db 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -17,14 +17,18 @@
 #include <fstream>
 #include <sstream>
 
+#include <boost/foreach.hpp>
+
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp6/config_parser.h>
 #include <config/ccsession.h>
+#include <dhcp/libdhcp++.h>
 #include <dhcp/subnet.h>
 #include <dhcp/cfgmgr.h>
+#include <dhcp/option6_ia.h>
 
 using namespace std;
 using namespace isc;
@@ -37,19 +41,143 @@ namespace {
 
 class Dhcp6ParserTest : public ::testing::Test {
 public:
-    Dhcp6ParserTest()
-    :rcode_(-1) {
-        // Open port 0 means to not do anything at all. We don't want to
+    Dhcp6ParserTest() :rcode_(-1), srv_(0) {
+        // srv_(0) means to not open any sockets. We don't want to
         // deal with sockets here, just check if configuration handling
         // is sane.
-        srv_ = new Dhcpv6Srv(0);
+
+        // Create instances of option definitions and put them into storage.
+        // This is normally initialized by the server when calling run()
+        // run() function.
+        LibDHCP::initStdOptionDefs(Option::V6);
     }
 
     ~Dhcp6ParserTest() {
-        delete srv_;
     };
 
-    Dhcpv6Srv* srv_;
+    /// @brief Create the simple configuration with single option.
+    ///
+    /// This function allows to set one of the parameters that configure
+    /// option value. These parameters are: "name", "code" and "data".
+    ///
+    /// @param param_value string holiding option parameter value to be
+    /// injected into the configuration string.
+    /// @param parameter name of the parameter to be configured with
+    /// param value.
+    std::string createConfigWithOption(const std::string& param_value,
+                                       const std::string& parameter) {
+        std::map<std::string, std::string> params;
+        if (parameter == "name") {
+            params["name"] = param_value;
+            params["code"] = "80";
+            params["data"] = "AB CDEF0105";
+        } else if (parameter == "code") {
+            params["name"] = "option_foo";
+            params["code"] = param_value;
+            params["data"] = "AB CDEF0105";
+        } else if (parameter == "data") {
+            params["name"] = "option_foo";
+            params["code"] = "80";
+            params["data"] = param_value;
+        }
+        return (createConfigWithOption(params));
+    }
+
+    std::string createConfigWithOption(const std::map<std::string, std::string>& params) {
+        std::ostringstream stream;
+        stream << "{ \"interface\": [ \"all\" ],"
+            "\"preferred-lifetime\": 3000,"
+            "\"rebind-timer\": 2000, "
+            "\"renew-timer\": 1000, "
+            "\"subnet6\": [ { "
+            "    \"pool\": [ \"2001:db8:1::/80\" ],"
+            "    \"subnet\": \"2001:db8:1::/64\", "
+            "    \"option-data\": [ {";
+        bool first = true;
+        typedef std::pair<std::string, std::string> ParamPair;
+        BOOST_FOREACH(ParamPair param, params) {
+            if (!first) {
+                stream << ", ";
+            } else {
+                first = false;
+            }
+            if (param.first == "name") {
+                stream << "\"name\": \"" << param.second << "\"";
+            } else if (param.first == "code") {
+                stream << "\"code\": " << param.second << "";
+            } else if (param.first == "data") {
+                stream << "\"data\": \"" << param.second << "\"";
+            }
+        }
+        stream <<
+            "        } ]"
+            " } ],"
+            "\"valid-lifetime\": 4000 }";
+        return (stream.str());
+    }
+
+    /// @brief Test invalid option parameter value.
+    ///
+    /// This test function constructs the simple configuration
+    /// string and injects invalid option configuration into it.
+    /// It expects that parser will fail with provided option code.
+    ///
+    /// @param param_value string holding invalid option parameter value
+    /// to be injected into configuration string.
+    /// @param parameter name of the parameter to be configured with
+    /// param_value (can be any of "name", "code", "data")
+    void testInvalidOptionParam(const std::string& param_value,
+                                const std::string& parameter) {
+        ConstElementPtr x;
+        std::string config = createConfigWithOption(param_value, parameter);
+        ElementPtr json = Element::fromJSON(config);
+        EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+        ASSERT_TRUE(x);
+        comment_ = parseAnswer(rcode_, x);
+        ASSERT_EQ(1, rcode_);
+    }
+
+    /// @brief Test option against given code and data.
+    ///
+    /// @param option_desc option descriptor that carries the option to
+    /// be tested.
+    /// @param expected_code expected code of the option.
+    /// @param expected_data expected data in the option.
+    /// @param expected_data_len length of the reference data.
+    /// @param extra_data if true extra data is allowed in an option
+    /// after tested data.
+    void testOption(const Subnet::OptionDescriptor& option_desc,
+                    uint16_t expected_code, const uint8_t* expected_data,
+                    size_t expected_data_len,
+                    bool extra_data = false) {
+        // Check if option descriptor contains valid option pointer.
+        ASSERT_TRUE(option_desc.option);
+        // Verify option type.
+        EXPECT_EQ(expected_code, option_desc.option->getType());
+        // We may have many different option types being created. Some of them
+        // have dedicated classes derived from Option class. In such case if
+        // we want to verify the option contents against expected_data we have
+        // to prepare raw buffer with the contents of the option. The easiest
+        // way is to call pack() which will prepare on-wire data.
+        util::OutputBuffer buf(option_desc.option->getData().size());
+        option_desc.option->pack(buf);
+        if (extra_data) {
+            // The length of the buffer must be at least equal to size of the
+            // reference data but it can sometimes be greater than that. This is
+            // because some options carry suboptions that increase the overall
+            // length.
+            ASSERT_GE(buf.getLength() - option_desc.option->getHeaderLen(),
+                      expected_data_len);
+        } else {
+            ASSERT_EQ(buf.getLength() - option_desc.option->getHeaderLen(),
+                      expected_data_len);
+        }
+        // Verify that the data is correct. However do not verify suboptions.
+        const uint8_t* data = static_cast<const uint8_t*>(buf.getData());
+        EXPECT_TRUE(memcmp(expected_data, data, expected_data_len));
+    }
+
+    Dhcpv6Srv srv_;
 
     int rcode_;
     ConstElementPtr comment_;
@@ -62,7 +190,7 @@ TEST_F(Dhcp6ParserTest, version) {
 
     ConstElementPtr x;
 
-    EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_,
                     Element::fromJSON("{\"version\": 0}")));
 
     // returned value must be 0 (configuration accepted)
@@ -73,11 +201,11 @@ TEST_F(Dhcp6ParserTest, version) {
 
 /// The goal of this test is to verify that the code accepts only
 /// valid commands and malformed or unsupported parameters are rejected.
-TEST_F(Dhcp6ParserTest, bogus_command) {
+TEST_F(Dhcp6ParserTest, bogusCommand) {
 
     ConstElementPtr x;
 
-    EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_,
                     Element::fromJSON("{\"bogus\": 5}")));
 
     // returned value must be 1 (configuration parse error)
@@ -89,11 +217,11 @@ TEST_F(Dhcp6ParserTest, bogus_command) {
 /// The goal of this test is to verify if wrongly defined subnet will
 /// be rejected. Properly defined subnet must include at least one
 /// pool definition.
-TEST_F(Dhcp6ParserTest, empty_subnet) {
+TEST_F(Dhcp6ParserTest, emptySubnet) {
 
     ConstElementPtr status;
 
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_,
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
                     Element::fromJSON("{ \"interface\": [ \"all\" ],"
                                       "\"preferred-lifetime\": 3000,"
                                       "\"rebind-timer\": 2000, "
@@ -109,7 +237,7 @@ TEST_F(Dhcp6ParserTest, empty_subnet) {
 
 /// The goal of this test is to verify if defined subnet uses global
 /// parameter timer definitions.
-TEST_F(Dhcp6ParserTest, subnet_global_defaults) {
+TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) {
 
     ConstElementPtr status;
 
@@ -125,7 +253,7 @@ TEST_F(Dhcp6ParserTest, subnet_global_defaults) {
 
     ElementPtr json = Element::fromJSON(config);
 
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
 
     // check if returned status is OK
     ASSERT_TRUE(status);
@@ -144,7 +272,7 @@ TEST_F(Dhcp6ParserTest, subnet_global_defaults) {
 
 // This test checks if it is possible to override global values
 // on a per subnet basis.
-TEST_F(Dhcp6ParserTest, subnet_local) {
+TEST_F(Dhcp6ParserTest, subnetLocal) {
 
     ConstElementPtr status;
 
@@ -164,7 +292,7 @@ TEST_F(Dhcp6ParserTest, subnet_local) {
 
     ElementPtr json = Element::fromJSON(config);
 
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
 
     // returned value should be 0 (configuration success)
     ASSERT_TRUE(status);
@@ -181,7 +309,7 @@ TEST_F(Dhcp6ParserTest, subnet_local) {
 
 // Test verifies that a subnet with pool values that do not belong to that
 // pool are rejected.
-TEST_F(Dhcp6ParserTest, pool_out_of_subnet) {
+TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
 
     ConstElementPtr status;
 
@@ -197,7 +325,7 @@ TEST_F(Dhcp6ParserTest, pool_out_of_subnet) {
 
     ElementPtr json = Element::fromJSON(config);
 
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
 
     // returned value must be 2 (values error)
     // as the pool does not belong to that subnet
@@ -209,7 +337,7 @@ TEST_F(Dhcp6ParserTest, pool_out_of_subnet) {
 // Goal of this test is to verify if pools can be defined
 // using prefix/length notation. There is no separate test for min-max
 // notation as it was tested in several previous tests.
-TEST_F(Dhcp6ParserTest, pool_prefix_len) {
+TEST_F(Dhcp6ParserTest, poolPrefixLen) {
 
     ConstElementPtr x;
 
@@ -225,7 +353,7 @@ TEST_F(Dhcp6ParserTest, pool_prefix_len) {
 
     ElementPtr json = Element::fromJSON(config);
 
-    EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
 
     // returned value must be 1 (configuration parse error)
     ASSERT_TRUE(x);
@@ -240,4 +368,372 @@ TEST_F(Dhcp6ParserTest, pool_prefix_len) {
     EXPECT_EQ(4000, subnet->getValid());
 }
 
+// Goal of this test is to verify that global option
+// data is configured for the subnet if the subnet
+// configuration does not include options configuration.
+TEST_F(Dhcp6ParserTest, optionDataDefaults) {
+    ConstElementPtr x;
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000,"
+        "\"renew-timer\": 1000,"
+        "\"option-data\": [ {"
+        "    \"name\": \"option_foo\","
+        "    \"code\": 100,"
+        "    \"data\": \"AB CDEF0105\""
+        " },"
+        " {"
+        "    \"name\": \"option_foo2\","
+        "    \"code\": 101,"
+        "    \"data\": \"01\""
+        " } ],"
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_);
+
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet);
+    const Subnet::OptionContainer& options = subnet->getOptions();
+    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(100);
+    // Expect single option with the code equal to 100.
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    const uint8_t foo_expected[] = {
+        0xAB, 0xCD, 0xEF, 0x01, 0x05
+    };
+    // Check if option is valid in terms of code and carried data.
+    testOption(*range.first, 100, foo_expected, sizeof(foo_expected));
+
+    range = idx.equal_range(101);
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    // Do another round of testing with second option.
+    const uint8_t foo2_expected[] = {
+        0x01
+    };
+    testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected));
+
+    // Check that options with other option codes are not returned.
+    for (uint16_t code = 102; code < 110; ++code) {
+        range = idx.equal_range(code);
+        EXPECT_EQ(0, std::distance(range.first, range.second));
+    }
+}
+
+// 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;
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"option-data\": [ {"
+        "      \"name\": \"option_foo\","
+        "      \"code\": 100,"
+        "      \"data\": \"AB\""
+        " } ],"
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\", "
+        "    \"option-data\": [ {"
+        "          \"name\": \"option_foo\","
+        "          \"code\": 100,"
+        "          \"data\": \"AB CDEF0105\""
+        "        },"
+        "        {"
+        "          \"name\": \"option_foo2\","
+        "          \"code\": 101,"
+        "          \"data\": \"01\""
+        "        } ]"
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_);
+
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet);
+    const Subnet::OptionContainer& options = subnet->getOptions();
+    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(100);
+    // Expect single option with the code equal to 100.
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    const uint8_t foo_expected[] = {
+        0xAB, 0xCD, 0xEF, 0x01, 0x05
+    };
+    // Check if option is valid in terms of code and carried data.
+    testOption(*range.first, 100, foo_expected, sizeof(foo_expected));
+
+    range = idx.equal_range(101);
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    // Do another round of testing with second option.
+    const uint8_t foo2_expected[] = {
+        0x01
+    };
+    testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected));
+}
+
+// Goal of this test is to verify options configuration
+// for multiple subnets.
+TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
+    ConstElementPtr x;
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\", "
+        "    \"option-data\": [ {"
+        "          \"name\": \"option_foo\","
+        "          \"code\": 100,"
+        "          \"data\": \"0102030405060708090A\""
+        "        } ]"
+        " },"
+        " {"
+        "    \"pool\": [ \"2001:db8:2::/80\" ],"
+        "    \"subnet\": \"2001:db8:2::/64\", "
+        "    \"option-data\": [ {"
+        "          \"name\": \"option_foo2\","
+        "          \"code\": 101,"
+        "          \"data\": \"FFFEFDFCFB\""
+        "        } ]"
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_);
+
+    Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet1);
+    const Subnet::OptionContainer& options1 = subnet1->getOptions();
+    ASSERT_EQ(1, options1.size());
+
+    // Get the search index. Index #1 is to search using option code.
+    const Subnet::OptionContainerTypeIndex& idx1 = options1.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> range1 =
+        idx1.equal_range(100);
+    // Expect single option with the code equal to 100.
+    ASSERT_EQ(1, std::distance(range1.first, range1.second));
+    const uint8_t foo_expected[] = {
+        0x01, 0x02, 0x03, 0x04, 0x05,
+        0x06, 0x07, 0x08, 0x09, 0x0A
+    };
+    // Check if option is valid in terms of code and carried data.
+    testOption(*range1.first, 100, foo_expected, sizeof(foo_expected));
+
+    // Test another subnet in the same way.
+    Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"));
+    ASSERT_TRUE(subnet2);
+    const Subnet::OptionContainer& options2 = subnet2->getOptions();
+    ASSERT_EQ(1, options2.size());
+
+    const Subnet::OptionContainerTypeIndex& idx2 = options2.get<1>();
+    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+              Subnet::OptionContainerTypeIndex::const_iterator> range2 =
+        idx2.equal_range(101);
+    ASSERT_EQ(1, std::distance(range2.first, range2.second));
+
+    const uint8_t foo2_expected[] = {
+        0xFF, 0xFE, 0xFD, 0xFC, 0xFB
+    };
+    testOption(*range2.first, 101, foo2_expected, sizeof(foo2_expected));
+}
+
+// Verify that empty option name is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionNameEmpty) {
+    // Empty option names not allowed.
+    testInvalidOptionParam("", "name");
+}
+
+// Verify that empty option name with spaces is rejected
+// in the configuration.
+TEST_F(Dhcp6ParserTest, optionNameSpaces) {
+    // Spaces in option names not allowed.
+    testInvalidOptionParam("option foo", "name");
+}
+
+// Verify that negative option code is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionCodeNegative) {
+    // Check negative option code -4. This should fail too.
+    testInvalidOptionParam("-4", "code");
+}
+
+// Verify that out of bounds option code is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionCodeNonUint16) {
+    // The valid option codes are uint16_t values so passing
+    // uint16_t maximum value incremented by 1 should result
+    // in failure.
+    testInvalidOptionParam("65536", "code");
+}
+
+// Verify that out of bounds option code is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionCodeHighNonUint16) {
+    // Another check for uint16_t overflow but this time
+    // let's pass even greater option code value.
+    testInvalidOptionParam("70000", "code");
+}
+
+// Verify that zero option code is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionCodeZero) {
+    // Option code 0 is reserved and should not be accepted
+    // by configuration parser.
+    testInvalidOptionParam("0", "code");
+}
+
+// Verify that option data which contains non hexadecimal characters
+// is rejected by the configuration.
+TEST_F(Dhcp6ParserTest, optionDataInvalidChar) {
+    // Option code 0 is reserved and should not be accepted
+    // by configuration parser.
+    testInvalidOptionParam("01020R", "data");
+}
+
+// Verify that option data containins '0x' prefix is rejected
+// by the configuration.
+TEST_F(Dhcp6ParserTest, optionDataUnexpectedPrefix) {
+    // Option code 0 is reserved and should not be accepted
+    // by configuration parser.
+    testInvalidOptionParam("0x0102", "data");
+}
+
+// Verify that option data consisting od an odd number of
+// hexadecimal digits is rejected in the configuration.
+TEST_F(Dhcp6ParserTest, optionDataOddLength) {
+    // Option code 0 is reserved and should not be accepted
+    // by configuration parser.
+    testInvalidOptionParam("123", "data");
+}
+
+// Verify that either lower or upper case characters are allowed
+// to specify the option data.
+TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
+    ConstElementPtr x;
+    std::string config = createConfigWithOption("0a0b0C0D", "data");
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_);
+
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet);
+    const Subnet::OptionContainer& options = subnet->getOptions();
+    ASSERT_EQ(1, 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(80);
+    // Expect single option with the code equal to 100.
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    const uint8_t foo_expected[] = {
+        0x0A, 0x0B, 0x0C, 0x0D
+    };
+    // Check if option is valid in terms of code and carried data.
+    testOption(*range.first, 80, foo_expected, sizeof(foo_expected));
+}
+
+// Verify that specific option object is returned for standard
+// option which has dedicated option class derived from Option.
+TEST_F(Dhcp6ParserTest, stdOptionData) {
+    ConstElementPtr x;
+    std::map<std::string, std::string> params;
+    params["name"] = "OPTION_IA_NA";
+    // Option code 3 means OPTION_IA_NA.
+    params["code"] = "3";
+    params["data"] = "ABCDEF01 02030405 06070809";
+    
+    std::string config = createConfigWithOption(params);
+    ElementPtr json = Element::fromJSON(config);
+
+    EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_);
+
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+    ASSERT_TRUE(subnet);
+    const Subnet::OptionContainer& options = subnet->getOptions();
+    ASSERT_EQ(1, 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_IA_NA);
+    // Expect single option with the code equal to IA_NA option code.
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    // The actual pointer to the option is held in the option field
+    // in the structure returned.
+    OptionPtr option = range.first->option;
+    ASSERT_TRUE(option);
+    // Option object returned for here is expected to be Option6IA
+    // which is derived from Option. This class is dedicated to
+    // represent standard option IA_NA.
+    boost::shared_ptr<Option6IA> optionIA =
+        boost::dynamic_pointer_cast<Option6IA>(option);
+    // If cast is unsuccessful than option returned was of a
+    // differnt type than Option6IA. This is wrong.
+    ASSERT_TRUE(optionIA);
+    // If cast was successful we may use accessors exposed by
+    // Option6IA to validate that the content of this option
+    // has been set correctly.
+    EXPECT_EQ(0xABCDEF01, optionIA->getIAID());
+    EXPECT_EQ(0x02030405, optionIA->getT1());
+    EXPECT_EQ(0x06070809, optionIA->getT2());
+}
+
 };
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 2028706..afb05d1 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -13,73 +13,219 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
-#include <iostream>
+
 #include <fstream>
+#include <iostream>
 #include <sstream>
 
-#include <arpa/inet.h>
 #include <gtest/gtest.h>
 
+#include <asiolink/io_address.h>
+#include <boost/scoped_ptr.hpp>
+#include <config/ccsession.h>
+#include <dhcp/cfgmgr.h>
 #include <dhcp/dhcp6.h>
+#include <dhcp/duid.h>
+#include <dhcp/lease_mgr.h>
+#include <dhcp/lease_mgr_factory.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp6/config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <util/buffer.h>
 #include <util/range_utilities.h>
-#include <boost/scoped_ptr.hpp>
 
-using namespace std;
 using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::config;
+using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::util;
+using namespace std;
 
 // namespace has to be named, because friends are defined in Dhcpv6Srv class
 // Maybe it should be isc::test?
 namespace {
 
 class NakedDhcpv6Srv: public Dhcpv6Srv {
-    // "naked" Interface Manager, exposes internal fields
+    // "naked" Interface Manager, exposes internal members
 public:
-    NakedDhcpv6Srv():Dhcpv6Srv(DHCP6_SERVER_PORT + 10000) { }
+    NakedDhcpv6Srv(uint16_t port):Dhcpv6Srv(port) { }
 
-    boost::shared_ptr<Pkt6>
-    processSolicit(boost::shared_ptr<Pkt6>& request) {
-        return Dhcpv6Srv::processSolicit(request);
-    }
-    boost::shared_ptr<Pkt6>
-    processRequest(boost::shared_ptr<Pkt6>& request) {
-        return Dhcpv6Srv::processRequest(request);
-    }
+    using Dhcpv6Srv::processSolicit;
+    using Dhcpv6Srv::processRequest;
+    using Dhcpv6Srv::createStatusCode;
+    using Dhcpv6Srv::selectSubnet;
 };
 
 class Dhcpv6SrvTest : public ::testing::Test {
 public:
     // these are empty for now, but let's keep them around
-    Dhcpv6SrvTest() {
+    Dhcpv6SrvTest() : rcode_(-1) {
+        subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
+                                         2000, 3000, 4000));
+        pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+        subnet_->addPool6(pool_);
+
+        CfgMgr::instance().addSubnet6(subnet_);
+    }
+
+    // Generate IA_NA option with specified parameters
+    boost::shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
+        boost::shared_ptr<Option6IA> ia =
+            boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
+        ia->setT1(t1);
+        ia->setT2(t2);
+        return (ia);
+    }
+
+    // Generate client-id option
+    OptionPtr generateClientId(size_t duid_size = 32) {
+
+        OptionBuffer clnt_duid(duid_size);
+        for (int i = 0; i < duid_size; i++) {
+            clnt_duid[i] = 100 + i;
+        }
+
+        duid_ = DuidPtr(new DUID(clnt_duid));
+
+        return (OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                     clnt_duid.begin(),
+                                     clnt_duid.begin() + duid_size)));
+    }
+
+    // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
+    void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
+        // check that server included its server-id
+        OptionPtr tmp = rsp->getOption(D6O_SERVERID);
+        EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
+        ASSERT_EQ(tmp->len(), expected_srvid->len() );
+        EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
+    }
+
+    // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
+    void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
+        // check that server included our own client-id
+        OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
+        ASSERT_TRUE(tmp);
+        EXPECT_EQ(expected_clientid->getType(), tmp->getType());
+        ASSERT_EQ(expected_clientid->len(), tmp->len());
+
+        // check that returned client-id is valid
+        EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
+    }
+
+    // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
+    // It returns IAADDR option for each chaining with checkIAAddr method.
+    boost::shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
+                                         uint32_t expected_t1, uint32_t expected_t2) {
+        OptionPtr tmp = rsp->getOption(D6O_IA_NA);
+        // Can't use ASSERT_TRUE() in method that returns something
+        if (!tmp) {
+            ADD_FAILURE() << "IA_NA option not present in response";
+            return (boost::shared_ptr<Option6IAAddr>());
+        }
+
+        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+        EXPECT_EQ(expected_iaid, ia->getIAID() );
+        EXPECT_EQ(expected_t1, ia->getT1());
+        EXPECT_EQ(expected_t2, ia->getT2());
+
+        tmp = ia->getOption(D6O_IAADDR);
+        boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
+        return (addr);
+    }
+
+    // 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) {
+
+        // Check that the assigned address is indeed from the configured pool.
+        // Note that when comparing addresses, we compare the textual
+        // representation. IOAddress does not support being streamed to
+        // an ostream, which means it can't be used in EXPECT_EQ.
+        EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
+        EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
+        EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
+        EXPECT_EQ(addr->getValid(), subnet_->getValid());
+    }
+
+    // Basic checks for generated response (message type and transaction-id).
+    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
+                       uint32_t expected_transid) {
+        ASSERT_TRUE(rsp);
+        EXPECT_EQ(expected_message_type, rsp->getType());
+        EXPECT_EQ(expected_transid, rsp->getTransid());
+    }
+
+    // Checks if the lease sent to client is present in the database
+    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
+                         boost::shared_ptr<Option6IAAddr> addr) {
+        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_na);
+
+        Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(addr->getAddress());
+        if (!lease) {
+            cout << "Lease for " << addr->getAddress().toText()
+                 << " not found in the database backend.";
+            return (Lease6Ptr());
+        }
+
+        EXPECT_EQ(addr->getAddress().toText(), lease->addr_.toText());
+        EXPECT_TRUE(*lease->duid_ == *duid);
+        EXPECT_EQ(ia->getIAID(), lease->iaid_);
+        EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
+
+        return (lease);
     }
+
     ~Dhcpv6SrvTest() {
+        CfgMgr::instance().deleteSubnets6();
     };
+
+    // A subnet used in most tests
+    Subnet6Ptr subnet_;
+
+    // A pool used in most tests
+    Pool6Ptr pool_;
+
+    // A DUID used in most tests (typically as client-id)
+    DuidPtr duid_;
+
+    int rcode_;
+    ConstElementPtr comment_;
 };
 
+// Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
+// without open sockets and with sockets opened on a high port (to not require
+// root privileges).
 TEST_F(Dhcpv6SrvTest, basic) {
     // srv has stubbed interface detection. It will read
     // interfaces.txt instead. It will pretend to have detected
     // fe80::1234 link-local address on eth0 interface. Obviously
     // an attempt to bind this socket will fail.
-    Dhcpv6Srv* srv = NULL;
+    boost::scoped_ptr<Dhcpv6Srv> srv;
+
     ASSERT_NO_THROW( {
+        // Skip opening any sockets
+        srv.reset(new Dhcpv6Srv(0));
+    });
+    srv.reset();
+    ASSERT_NO_THROW({
         // open an unpriviledged port
-        srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
+        srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
     });
-
-    delete srv;
 }
 
+// Test checks that DUID is generated properly
 TEST_F(Dhcpv6SrvTest, DUID) {
-    // tests that DUID is generated properly
 
     boost::scoped_ptr<Dhcpv6Srv> srv;
     ASSERT_NO_THROW( {
-        srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
+        srv.reset(new Dhcpv6Srv(0));
     });
 
     OptionPtr srvid = srv->getServerID();
@@ -101,7 +247,7 @@ TEST_F(Dhcpv6SrvTest, DUID) {
     uint16_t duid_type = data.readUint16();
     cout << "Duid-type=" << duid_type << endl;
     switch(duid_type) {
-    case DUID_LLT: {
+    case DUID::DUID_LLT: {
         // DUID must contain at least 6 bytes long MAC
         // + 8 bytes of fixed header
         EXPECT_GE(14, len);
@@ -125,7 +271,7 @@ TEST_F(Dhcpv6SrvTest, DUID) {
         EXPECT_TRUE(mac != zeros);
         break;
     }
-    case DUID_EN: {
+    case DUID::DUID_EN: {
         // there's not much we can check. Just simple
         // check if it is not all zeros
         vector<uint8_t> content(len-2);
@@ -133,7 +279,7 @@ TEST_F(Dhcpv6SrvTest, DUID) {
         EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
         break;
     }
-    case DUID_LL: {
+    case DUID::DUID_LL: {
         // not supported yet
         cout << "Test not implemented for DUID-LL." << endl;
 
@@ -143,86 +289,467 @@ TEST_F(Dhcpv6SrvTest, DUID) {
         // and keep it despite hardware changes.
         break;
     }
-    case DUID_UUID: // not supported yet
+    case DUID::DUID_UUID: // not supported yet
     default:
         ADD_FAILURE() << "Not supported duid type=" << duid_type << endl;
         break;
     }
 }
 
-TEST_F(Dhcpv6SrvTest, Solicit_basic) {
+// This test checks if Option Request Option (ORO) is parsed correctly
+// and the requested options are actually assigned.
+TEST_F(Dhcpv6SrvTest, advertiseOptions) {
+    ConstElementPtr x;
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/64\" ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"option-data\": [ {"
+        "          \"name\": \"OPTION_DNS_SERVERS\","
+        "          \"code\": 23,"
+        "          \"data\": \"2001 0DB8 1234 FFFF 0000 0000 0000 0001"
+        "2001 0DB8 1234 FFFF 0000 0000 0000 0002\""
+        "        },"
+        "        {"
+        "          \"name\": \"OPTION_FOO\","
+        "          \"code\": 1000,"
+        "          \"data\": \"1234\""
+        "        } ]"
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+
     boost::scoped_ptr<NakedDhcpv6Srv> srv;
-    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv()) );
+    ASSERT_NO_THROW(srv.reset(new NakedDhcpv6Srv(0)));
 
-    // a dummy content for client-id
-    OptionBuffer clntDuid(32);
-    for (int i = 0; i < 32; i++) {
-        clntDuid[i] = 100 + i;
-    }
+    EXPECT_NO_THROW(x = configureDhcp6Server(*srv, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+
+    ASSERT_EQ(0, rcode_);
 
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->addOption(generateIA(234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    boost::shared_ptr<Pkt6> adv = srv->processSolicit(sol);
+
+    // check if we get response at all
+    ASSERT_TRUE(adv);
+
+    // We have not requested option with code 1000 so it should not
+    // be included in the response.
+    ASSERT_FALSE(adv->getOption(1000));
+    ASSERT_FALSE(adv->getOption(D6O_NAME_SERVERS));
+
+    // Let's now request option with code 1000.
+    // We expect that server will include this option in its reply.
+    boost::shared_ptr<Option6IntArray<uint16_t> >
+        option_oro(new Option6IntArray<uint16_t>(D6O_ORO));
+    // Create vector with two option codes.
+    std::vector<uint16_t> codes(2);
+    codes[0] = 1000;
+    codes[1] = D6O_NAME_SERVERS;
+    // Pass this code to option.
+    option_oro->setValues(codes);
+    // Append ORO to SOLICIT message.
+    sol->addOption(option_oro);
+
+    // Need to process SOLICIT again after requesting new option.
+    adv = srv->processSolicit(sol);
+    ASSERT_TRUE(adv);
+
+    OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
+    ASSERT_TRUE(tmp);
+
+    boost::shared_ptr<Option6AddrLst> reply_nameservers =
+        boost::dynamic_pointer_cast<Option6AddrLst>(tmp);
+    ASSERT_TRUE(reply_nameservers);
+
+    Option6AddrLst::AddressContainer addrs = reply_nameservers->getAddresses();
+    ASSERT_EQ(2, addrs.size());
+    EXPECT_TRUE(addrs[0] == IOAddress("2001:db8:1234:FFFF::1"));
+    EXPECT_TRUE(addrs[1] == IOAddress("2001:db8:1234:FFFF::2"));
+
+    // There is a dummy option with code 1000 we requested from a server.
+    // Expect that this option is in server's response.
+    tmp = adv->getOption(1000);
+    ASSERT_TRUE(tmp);
+
+    // Check that the option contains valid data (from configuration).
+    std::vector<uint8_t> data = tmp->getData();
+    ASSERT_EQ(2, data.size());
+
+    const uint8_t foo_expected[] = {
+        0x12, 0x34
+    };
+    EXPECT_EQ(0, memcmp(&data[0], foo_expected, 2));
+
+    // more checks to be implemented
+}
+
+
+// There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
+// as they are indirectly tested in Solicit and Request tests.
+
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
+// really belongs to the configured pool.
+//
+// This test sends a SOLICIT without any hint in IA_NA.
+//
+// constructed very simple SOLICIT message with:
+// - client-id option (mandatory)
+// - IA option (a request for address, without any addresses)
+//
+// expected returned ADVERTISE message:
+// - copy of client-id
+// - server-id
+// - IA that includes IAADDR
+TEST_F(Dhcpv6SrvTest, SolicitBasic) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->addOption(generateIA(234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply = srv->processSolicit(sol);
+
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
 
-    boost::shared_ptr<Option6IA> ia =
-        boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
-    ia->setT1(1501);
-    ia->setT2(2601);
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+
+    // check DUIDs
+    checkServerId(reply, srv->getServerID());
+    checkClientId(reply, clientid);
+}
+
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
+// really belongs to the configured pool.
+//
+// This test sends a SOLICIT with IA_NA that contains a valid hint.
+//
+// constructed very simple SOLICIT message with:
+// - client-id option (mandatory)
+// - IA option (a request for address, with an address that belongs to the
+//              configured pool, i.e. is valid as hint)
+//
+// expected returned ADVERTISE message:
+// - copy of client-id
+// - server-id
+// - IA that includes IAADDR
+TEST_F(Dhcpv6SrvTest, SolicitHint) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    // Let's create a SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
+
+    // with a valid hint
+    IOAddress hint("2001:db8:1:1::dead:beef");
+    ASSERT_TRUE(subnet_->inPool(hint));
+    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+    ia->addOption(hint_opt);
     sol->addOption(ia);
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply = srv->processSolicit(sol);
 
-    // Let's not send address in solicit yet
-    // boost::shared_ptr<Option6IAAddr> addr(new Option6IAAddr(D6O_IAADDR,
-    //    IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
-    // ia->addOption(addr);
-    // sol->addOption(ia);
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
+
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
 
-    // constructed very simple SOLICIT message with:
-    // - client-id option (mandatory)
-    // - IA option (a request for address, without any addresses)
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                subnet_->getT2());
 
-    // expected returned ADVERTISE message:
-    // - copy of client-id
-    // - server-id
-    // - IA that includes IAADDR
+    // check that we've got the address we requested
+    checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
 
-    OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
-                                              clntDuid.begin(),
-                                              clntDuid.begin() + 16));
+    // check DUIDs
+    checkServerId(reply, srv->getServerID());
+    checkClientId(reply, clientid);
+}
+
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
+// really belongs to the configured pool.
+//
+// This test sends a SOLICIT with IA_NA that contains an invalid hint.
+//
+// constructed very simple SOLICIT message with:
+// - client-id option (mandatory)
+// - IA option (a request for address, with an address that does not
+//              belong to the configured pool, i.e. is valid as hint)
+//
+// expected returned ADVERTISE message:
+// - copy of client-id
+// - server-id
+// - IA that includes IAADDR
+TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    // Let's create a SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
+    IOAddress hint("2001:db8:1::cafe:babe");
+    ASSERT_FALSE(subnet_->inPool(hint));
+    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+    ia->addOption(hint_opt);
+    sol->addOption(ia);
+    OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
-    boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply = srv->processSolicit(sol);
+
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
+
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
+
+    // check DUIDs
+    checkServerId(reply, srv->getServerID());
+    checkClientId(reply, clientid);
+}
+
+// This test checks that the server is offering different addresses to different
+// clients in ADVERTISEs. Please note that ADVERTISE is not a guarantee that such
+// and address will be assigned. Had the pool was very small and contained only
+// 2 addresses, the third client would get the same advertise as the first one
+// and this is a correct behavior. It is REQUEST that will fail for the third
+// client. ADVERTISE is basically saying "if you send me a request, you will
+// probably get an address like this" (there are no guarantees).
+TEST_F(Dhcpv6SrvTest, ManySolicits) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    Pkt6Ptr sol1 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    Pkt6Ptr sol2 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 2345));
+    Pkt6Ptr sol3 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 3456));
+
+    sol1->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol2->setRemoteAddr(IOAddress("fe80::1223"));
+    sol3->setRemoteAddr(IOAddress("fe80::3467"));
+
+    sol1->addOption(generateIA(1, 1500, 3000));
+    sol2->addOption(generateIA(2, 1500, 3000));
+    sol3->addOption(generateIA(3, 1500, 3000));
+
+    // different client-id sizes
+    OptionPtr clientid1 = generateClientId(12);
+    OptionPtr clientid2 = generateClientId(14);
+    OptionPtr clientid3 = generateClientId(16);
+
+    sol1->addOption(clientid1);
+    sol2->addOption(clientid2);
+    sol3->addOption(clientid3);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply1 = srv->processSolicit(sol1);
+    Pkt6Ptr reply2 = srv->processSolicit(sol2);
+    Pkt6Ptr reply3 = srv->processSolicit(sol3);
 
     // check if we get response at all
-    ASSERT_TRUE( reply != boost::shared_ptr<Pkt6>() );
+    checkResponse(reply1, DHCPV6_ADVERTISE, 1234);
+    checkResponse(reply2, DHCPV6_ADVERTISE, 2345);
+    checkResponse(reply3, DHCPV6_ADVERTISE, 3456);
+
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
+                                                subnet_->getT2());
+    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
+                                                subnet_->getT2());
+    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+
+    // check DUIDs
+    checkServerId(reply1, srv->getServerID());
+    checkServerId(reply2, srv->getServerID());
+    checkServerId(reply3, srv->getServerID());
+    checkClientId(reply1, clientid1);
+    checkClientId(reply2, clientid2);
+    checkClientId(reply3, clientid3);
+
+    // Finally check that the addresses offered are different
+    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
+    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
+    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
+    cout << "Offered address to client1=" << addr1->getAddress().toText() << endl;
+    cout << "Offered address to client2=" << addr2->getAddress().toText() << endl;
+    cout << "Offered address to client3=" << addr3->getAddress().toText() << endl;
+}
+
+
+// This test verifies that incoming REQUEST can be handled properly, that a
+// REPLY is generated, that the response has an address and that address
+// really belongs to the configured pool.
+//
+// This test sends a REQUEST with IA_NA that contains a valid hint.
+//
+// constructed very simple REQUEST message with:
+// - client-id option (mandatory)
+// - IA option (a request for address, with an address that belongs to the
+//              configured pool, i.e. is valid as hint)
+//
+// expected returned REPLY message:
+// - copy of client-id
+// - server-id
+// - IA that includes IAADDR
+TEST_F(Dhcpv6SrvTest, RequestBasic) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    // Let's create a REQUEST
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
+
+    // with a valid hint
+    IOAddress hint("2001:db8:1:1::dead:beef");
+    ASSERT_TRUE(subnet_->inPool(hint));
+    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+    ia->addOption(hint_opt);
+    req->addOption(ia);
+    OptionPtr clientid = generateClientId();
+    req->addOption(clientid);
 
-    EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
-    EXPECT_EQ( 1234, reply->getTransid() );
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv->processRequest(req);
+
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_REPLY, 1234);
 
     OptionPtr tmp = reply->getOption(D6O_IA_NA);
-    ASSERT_TRUE( tmp );
+    ASSERT_TRUE(tmp);
 
-    Option6IA* reply_ia = dynamic_cast<Option6IA*>(tmp.get());
-    EXPECT_EQ( 234, reply_ia->getIAID() );
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                subnet_->getT2());
 
-    // check that there's an address included
-    EXPECT_TRUE( reply_ia->getOption(D6O_IAADDR));
+    // check that we've got the address we requested
+    checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
 
-    // check that server included our own client-id
-    tmp = reply->getOption(D6O_CLIENTID);
-    ASSERT_TRUE( tmp );
-    EXPECT_EQ(clientid->getType(), tmp->getType() );
-    ASSERT_EQ(clientid->len(), tmp->len() );
+    // check DUIDs
+    checkServerId(reply, srv->getServerID());
+    checkClientId(reply, clientid);
 
-    EXPECT_TRUE( clientid->getData() == tmp->getData() );
+    // check that the lease is really in the database
+    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
+    EXPECT_TRUE(l);
+    LeaseMgrFactory::instance().deleteLease6(addr->getAddress());
+}
 
-    // check that server included its server-id
-    tmp = reply->getOption(D6O_SERVERID);
-    EXPECT_EQ(tmp->getType(), srv->getServerID()->getType() );
-    ASSERT_EQ(tmp->len(),  srv->getServerID()->len() );
+// This test checks that the server is offering different addresses to different
+// clients in REQUEST. Please note that ADVERTISE is not a guarantee that such
+// and address will be assigned. Had the pool was very small and contained only
+// 2 addresses, the third client would get the same advertise as the first one
+// and this is a correct behavior. It is REQUEST that will fail for the third
+// client. ADVERTISE is basically saying "if you send me a request, you will
+// probably get an address like this" (there are no guarantees).
+TEST_F(Dhcpv6SrvTest, ManyRequests) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 
-    EXPECT_TRUE(tmp->getData() == srv->getServerID()->getData());
+    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
+    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
 
-    // more checks to be implemented
+    req1->setRemoteAddr(IOAddress("fe80::abcd"));
+    req2->setRemoteAddr(IOAddress("fe80::1223"));
+    req3->setRemoteAddr(IOAddress("fe80::3467"));
+
+    req1->addOption(generateIA(1, 1500, 3000));
+    req2->addOption(generateIA(2, 1500, 3000));
+    req3->addOption(generateIA(3, 1500, 3000));
+
+    // different client-id sizes
+    OptionPtr clientid1 = generateClientId(12);
+    OptionPtr clientid2 = generateClientId(14);
+    OptionPtr clientid3 = generateClientId(16);
+
+    req1->addOption(clientid1);
+    req2->addOption(clientid2);
+    req3->addOption(clientid3);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply1 = srv->processRequest(req1);
+    Pkt6Ptr reply2 = srv->processRequest(req2);
+    Pkt6Ptr reply3 = srv->processRequest(req3);
+
+    // check if we get response at all
+    checkResponse(reply1, DHCPV6_REPLY, 1234);
+    checkResponse(reply2, DHCPV6_REPLY, 2345);
+    checkResponse(reply3, DHCPV6_REPLY, 3456);
+
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
+                                                subnet_->getT2());
+    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
+                                                subnet_->getT2());
+    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+
+    // check DUIDs
+    checkServerId(reply1, srv->getServerID());
+    checkServerId(reply2, srv->getServerID());
+    checkServerId(reply3, srv->getServerID());
+    checkClientId(reply1, clientid1);
+    checkClientId(reply2, clientid2);
+    checkClientId(reply3, clientid3);
+
+    // Finally check that the addresses offered are different
+    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
+    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
+    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
+    cout << "Assigned address to client1=" << addr1->getAddress().toText() << endl;
+    cout << "Assigned address to client2=" << addr2->getAddress().toText() << endl;
+    cout << "Assigned address to client3=" << addr3->getAddress().toText() << endl;
 }
 
+
 TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) {
     // Check all possible packet types
     for (int itype = 0; itype < 256; ++itype) {
@@ -268,4 +795,41 @@ TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) {
     }
 }
 
+// This test verifies if the status code option is generated properly.
+TEST_F(Dhcpv6SrvTest, StatusCode) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    // a dummy content for client-id
+    uint8_t expected[] = {0x0, 0x3, 0x41, 0x42, 0x43, 0x44, 0x45};
+    OptionBuffer exp(expected, expected + sizeof(expected));
+
+    OptionPtr status = srv->createStatusCode(3, "ABCDE");
+
+    EXPECT_TRUE(status->getData() == exp);
+}
+
+// This test verifies if the selectSubnet() method works as expected.
+TEST_F(Dhcpv6SrvTest, SelectSubnet) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+
+    // check that the packets originating from local addresses can be
+    pkt->setRemoteAddr(IOAddress("fe80::abcd"));
+    EXPECT_EQ(subnet_, srv->selectSubnet(pkt));
+
+    // packets originating from subnet A will select subnet A
+    pkt->setRemoteAddr(IOAddress("2001:db8:1::6789"));
+    EXPECT_EQ(subnet_, srv->selectSubnet(pkt));
+
+    // packets from a subnet that is not supported will not get
+    // a subnet
+    pkt->setRemoteAddr(IOAddress("3000::faf"));
+    EXPECT_FALSE(srv->selectSubnet(pkt));
+
+    /// @todo: expand this test once support for relays is implemented
+}
+
 }   // end of anonymous namespace
diff --git a/src/bin/msgq/msgq.py.in b/src/bin/msgq/msgq.py.in
index 010a1a5..bab193e 100755
--- a/src/bin/msgq/msgq.py.in
+++ b/src/bin/msgq/msgq.py.in
@@ -178,6 +178,8 @@ class MsgQ:
             if os.path.exists(self.socket_file):
                 os.remove(self.socket_file)
             self.listen_socket.close()
+            sys.stderr.write("[b10-msgq] failed to setup listener on %s: %s\n"
+                             % (self.socket_file, str(e)))
             raise e
 
         if self.poller:
@@ -543,9 +545,10 @@ if __name__ == "__main__":
 
     msgq = MsgQ(options.msgq_socket_file, options.verbose)
 
-    setup_result = msgq.setup()
-    if setup_result:
-        sys.stderr.write("[b10-msgq] Error on startup: %s\n" % setup_result)
+    try:
+        msgq.setup()
+    except Exception as e:
+        sys.stderr.write("[b10-msgq] Error on startup: %s\n" % str(e))
         sys.exit(1)
 
     try:
diff --git a/src/bin/resolver/resolver.h b/src/bin/resolver/resolver.h
index e91192e..cc0f09f 100644
--- a/src/bin/resolver/resolver.h
+++ b/src/bin/resolver/resolver.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RESOLVER_H
-#define __RESOLVER_H 1
+#ifndef RESOLVER_H
+#define RESOLVER_H 1
 
 #include <string>
 #include <vector>
@@ -266,7 +266,7 @@ private:
     isc::cache::ResolverCache* cache_;
 };
 
-#endif // __RESOLVER_H
+#endif // RESOLVER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/bin/resolver/resolver_log.h b/src/bin/resolver/resolver_log.h
index e0e3fda..a4b6c44 100644
--- a/src/bin/resolver/resolver_log.h
+++ b/src/bin/resolver/resolver_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RESOLVER_LOG__H
-#define __RESOLVER_LOG__H
+#ifndef RESOLVER_LOG_H
+#define RESOLVER_LOG_H
 
 #include <log/macros.h>
 #include "resolver_messages.h"
@@ -46,4 +46,4 @@ const int RESOLVER_DBG_DETAIL = DBGLVL_TRACE_DETAIL_DATA;
 /// space.
 extern isc::log::Logger resolver_logger;
 
-#endif // __RESOLVER_LOG__H
+#endif // RESOLVER_LOG_H
diff --git a/src/bin/resolver/resolver_messages.mes b/src/bin/resolver/resolver_messages.mes
index 34a97ae..214519b 100644
--- a/src/bin/resolver/resolver_messages.mes
+++ b/src/bin/resolver/resolver_messages.mes
@@ -108,7 +108,7 @@ This error is issued when a resolver configuration update has specified
 a negative retry count: only zero or positive values are valid.  The
 configuration update was abandoned and the parameters were not changed.
 
-% RESOLVER_NON_IN_PACKET non-IN class request received, returning REFUSED message
+% RESOLVER_NON_IN_PACKET non-IN class (%1) request received, returning REFUSED message
 This debug message is issued when resolver has received a DNS packet that
 was not IN (Internet) class.  The resolver cannot handle such packets,
 so is returning a REFUSED response to the sender.
diff --git a/src/bin/resolver/response_scrubber.h b/src/bin/resolver/response_scrubber.h
index c59ac15..cb80b26 100644
--- a/src/bin/resolver/response_scrubber.h
+++ b/src/bin/resolver/response_scrubber.h
@@ -14,8 +14,8 @@
 
 // $Id$
 
-#ifndef __RESPONSE_SCRUBBER_H
-#define __RESPONSE_SCRUBBER_H
+#ifndef RESPONSE_SCRUBBER_H
+#define RESPONSE_SCRUBBER_H
 
 /// \page DataScrubbing Data Scrubbing
 /// \section DataScrubbingIntro Introduction
@@ -419,4 +419,4 @@ public:
     }
 };
 
-#endif // __RESPONSE_SCRUBBER_H
+#endif // RESPONSE_SCRUBBER_H
diff --git a/src/bin/sockcreator/sockcreator.h b/src/bin/sockcreator/sockcreator.h
index e5d4783..8e32c48 100644
--- a/src/bin/sockcreator/sockcreator.h
+++ b/src/bin/sockcreator/sockcreator.h
@@ -18,8 +18,8 @@
 /// This module holds the functionality of the socket creator. It is a separate
 /// module from main to make testing easier.
 
-#ifndef __SOCKCREATOR_H
-#define __SOCKCREATOR_H 1
+#ifndef SOCKCREATOR_H
+#define SOCKCREATOR_H 1
 
 #include <util/io/fd_share.h>
 #include <exceptions/exceptions.h>
@@ -144,4 +144,4 @@ run(const int input_fd, const int output_fd, get_sock_t get_sock_fun,
 }   // namespace socket_creator
 }   // NAMESPACE ISC
 
-#endif // __SOCKCREATOR_H
+#endif // SOCKCREATOR_H
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
index 73ed35b..627d50e 100644
--- a/src/bin/stats/tests/b10-stats-httpd_test.py
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -761,6 +761,7 @@ class TestStatsHttpd(unittest.TestCase):
             self.assertEqual(ht.address_family, socket.AF_INET)
             self.assertTrue(isinstance(ht.socket, socket.socket))
 
+    def test_httpd_anyIPv4(self):
         # any address (IPv4)
         server_addresses = get_availaddr(address='0.0.0.0')
         self.stats_httpd = MyStatsHttpd(server_addresses)
@@ -769,6 +770,7 @@ class TestStatsHttpd(unittest.TestCase):
             self.assertEqual(ht.address_family,socket.AF_INET)
             self.assertTrue(isinstance(ht.socket, socket.socket))
 
+    def test_httpd_anyIPv6(self):
         # any address (IPv6)
         if self.ipv6_enabled:
             server_addresses = get_availaddr(address='::')
@@ -778,6 +780,7 @@ class TestStatsHttpd(unittest.TestCase):
                 self.assertEqual(ht.address_family,socket.AF_INET6)
                 self.assertTrue(isinstance(ht.socket, socket.socket))
 
+    def test_httpd_failed(self):
         # existent hostname
         self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                           get_availaddr(address='localhost'))
diff --git a/src/bin/sysinfo/.gitignore b/src/bin/sysinfo/.gitignore
index 9194aff..b5c759d 100644
--- a/src/bin/sysinfo/.gitignore
+++ b/src/bin/sysinfo/.gitignore
@@ -1,3 +1,4 @@
 /isc-sysinfo
-/sysinfo.py
 /isc-sysinfo.1
+/run_sysinfo.sh
+/sysinfo.py
diff --git a/src/bin/sysinfo/Makefile.am b/src/bin/sysinfo/Makefile.am
index 25a3556..1618535 100644
--- a/src/bin/sysinfo/Makefile.am
+++ b/src/bin/sysinfo/Makefile.am
@@ -1,4 +1,5 @@
 bin_SCRIPTS = isc-sysinfo
+noinst_SCRIPTS = run_sysinfo.sh
 
 CLEANFILES = isc-sysinfo sysinfo.pyc
 
diff --git a/src/bin/sysinfo/run_sysinfo.sh.in b/src/bin/sysinfo/run_sysinfo.sh.in
new file mode 100755
index 0000000..268b5a4
--- /dev/null
+++ b/src/bin/sysinfo/run_sysinfo.sh.in
@@ -0,0 +1,38 @@
+#! /bin/sh
+
+# Copyright (C) 2012  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
+export PYTHON_EXEC
+
+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
+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/sysinfo/sysinfo.py.in b/src/bin/sysinfo/sysinfo.py.in
index 24cf309..477b9de 100755
--- a/src/bin/sysinfo/sysinfo.py.in
+++ b/src/bin/sysinfo/sysinfo.py.in
@@ -22,11 +22,8 @@ ISC sysinfo program.
 
 import sys; sys.path.append ('@@PYTHONPATH@@')
 import getopt
-import isc.util.process
 from isc.sysinfo import *
 
-isc.util.process.rename()
-
 def usage():
     print("Usage: %s [-h] [-o <output-file>]" % sys.argv[0], \
               file=sys.stderr)
@@ -88,7 +85,8 @@ def main():
 
     write_value(f, ' + Machine name: %s\n', s.get_platform_machine)
     write_value(f, ' + Hostname: %s\n', s.get_platform_hostname)
-    write_value(f, ' + Uptime: %d seconds\n', s.get_uptime)
+    write_value(f, ' + Uptime: %d seconds', s.get_uptime)
+    write_value(f, ' (%s)\n', s.get_uptime_desc)
 
     write_value(f, ' + Loadavg: %f %f %f\n', s.get_loadavg)
 
diff --git a/src/bin/tests/process_rename_test.py.in b/src/bin/tests/process_rename_test.py.in
index 1156b29..055ebdc 100644
--- a/src/bin/tests/process_rename_test.py.in
+++ b/src/bin/tests/process_rename_test.py.in
@@ -39,6 +39,11 @@ class TestRename(unittest.TestCase):
         Then scan them by looking at the source text
         (without actually running them)
         """
+
+        # Scripts named in this list are not expected to be renamed and
+        # should be excluded from the scan.
+        EXCLUDED_SCRIPTS = ['isc-sysinfo']
+
         # Regexp to find all the *_SCRIPTS = something lines (except for
         # noinst_SCRIPTS, which are scripts for tests), including line
         # continuations (backslash and newline)
@@ -59,6 +64,8 @@ class TestRename(unittest.TestCase):
                 for (var, _) in lines.findall(re.sub(excluded_lines, '',
                                                      makefile)):
                     for (script, _) in scripts.findall(var):
+                        if script in EXCLUDED_SCRIPTS:
+                            continue
                         self.__scan(d, script, fun)
 
 if __name__ == "__main__":
diff --git a/src/lib/acl/dnsname_check.h b/src/lib/acl/dnsname_check.h
index 7498d99..7403c16 100644
--- a/src/lib/acl/dnsname_check.h
+++ b/src/lib/acl/dnsname_check.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DNSNAME_CHECK_H
-#define __DNSNAME_CHECK_H 1
+#ifndef DNSNAME_CHECK_H
+#define DNSNAME_CHECK_H 1
 
 #include <dns/name.h>
 
@@ -76,7 +76,7 @@ private:
 } // namespace acl
 } // namespace isc
 
-#endif // __DNSNAME_CHECK_H
+#endif // DNSNAME_CHECK_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/acl/ip_check.h b/src/lib/acl/ip_check.h
index 794b943..9d70b0a 100644
--- a/src/lib/acl/ip_check.h
+++ b/src/lib/acl/ip_check.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IP_CHECK_H
-#define __IP_CHECK_H
+#ifndef IP_CHECK_H
+#define IP_CHECK_H
 
 #include <sys/socket.h>
 
@@ -410,7 +410,7 @@ const size_t IPCheck<Context>::IPV4_SIZE;
 } // namespace acl
 } // namespace isc
 
-#endif // __IP_CHECK_H
+#endif // IP_CHECK_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/acl/tests/sockaddr.h b/src/lib/acl/tests/sockaddr.h
index bd30451..2a4457a 100644
--- a/src/lib/acl/tests/sockaddr.h
+++ b/src/lib/acl/tests/sockaddr.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ACL_TEST_SOCKADDR_H
-#define __ACL_TEST_SOCKADDR_H 1
+#ifndef ACL_TEST_SOCKADDR_H
+#define ACL_TEST_SOCKADDR_H 1
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -62,7 +62,7 @@ getSockAddr(const char* const addr) {
 } // end of namespace "acl"
 } // end of namespace "isc"
 
-#endif  // __ACL_TEST_SOCKADDR_H
+#endif  // ACL_TEST_SOCKADDR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/asiodns/asiodns.h b/src/lib/asiodns/asiodns.h
index 8791a72..3032ebd 100644
--- a/src/lib/asiodns/asiodns.h
+++ b/src/lib/asiodns/asiodns.h
@@ -12,12 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIODNS_H
-#define __ASIODNS_H 1
+#ifndef ASIODNS_H
+#define ASIODNS_H 1
 
 #include <asiodns/dns_service.h>
 #include <asiodns/dns_server.h>
 #include <asiodns/dns_lookup.h>
 #include <asiodns/dns_answer.h>
 
-#endif // __ASIODNS_H
+#endif // ASIODNS_H
diff --git a/src/lib/asiodns/dns_answer.h b/src/lib/asiodns/dns_answer.h
index 3654369..4b4576b 100644
--- a/src/lib/asiodns/dns_answer.h
+++ b/src/lib/asiodns/dns_answer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_DNS_ANSWER_H
-#define __ASIOLINK_DNS_ANSWER_H 1
+#ifndef ASIOLINK_DNS_ANSWER_H
+#define ASIOLINK_DNS_ANSWER_H 1
 
 #include <asiolink/io_message.h>
 #include <util/buffer.h>
@@ -74,4 +74,4 @@ public:
 
 }      // namespace asiodns
 }      // namespace isc
-#endif // __ASIOLINK_DNS_ANSWER_H
+#endif // ASIOLINK_DNS_ANSWER_H
diff --git a/src/lib/asiodns/dns_lookup.h b/src/lib/asiodns/dns_lookup.h
index 5dc84ac..309755c 100644
--- a/src/lib/asiodns/dns_lookup.h
+++ b/src/lib/asiodns/dns_lookup.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_DNS_LOOKUP_H
-#define __ASIOLINK_DNS_LOOKUP_H 1
+#ifndef ASIOLINK_DNS_LOOKUP_H
+#define ASIOLINK_DNS_LOOKUP_H 1
 
 #include <asiolink/io_message.h>
 #include <asiodns/dns_server.h>
@@ -84,4 +84,4 @@ private:
 
 }      // namespace asiodns
 }      // namespace isc
-#endif // __ASIOLINK_DNS_LOOKUP_H
+#endif // ASIOLINK_DNS_LOOKUP_H
diff --git a/src/lib/asiodns/dns_server.h b/src/lib/asiodns/dns_server.h
index bc39805..3b8758f 100644
--- a/src/lib/asiodns/dns_server.h
+++ b/src/lib/asiodns/dns_server.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_DNS_SERVER_H
-#define __ASIOLINK_DNS_SERVER_H 1
+#ifndef ASIOLINK_DNS_SERVER_H
+#define ASIOLINK_DNS_SERVER_H 1
 
 #include <asiolink/io_message.h>
 
@@ -152,4 +152,4 @@ private:
 
 } // namespace asiodns
 } // namespace isc
-#endif // __ASIOLINK_DNS_SERVER_H
+#endif // ASIOLINK_DNS_SERVER_H
diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h
index 0b578fb..01b6310 100644
--- a/src/lib/asiodns/dns_service.h
+++ b/src/lib/asiodns/dns_service.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_DNS_SERVICE_H
-#define __ASIOLINK_DNS_SERVICE_H 1
+#ifndef ASIOLINK_DNS_SERVICE_H
+#define ASIOLINK_DNS_SERVICE_H 1
 
 #include <resolve/resolver_interface.h>
 
@@ -210,7 +210,7 @@ private:
 
 } // namespace asiodns
 } // namespace isc
-#endif // __ASIOLINK_DNS_SERVICE_H
+#endif // ASIOLINK_DNS_SERVICE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h
index 78c2da9..c31ee09 100644
--- a/src/lib/asiodns/io_fetch.h
+++ b/src/lib/asiodns/io_fetch.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_FETCH_H
-#define __IO_FETCH_H 1
+#ifndef IO_FETCH_H
+#define IO_FETCH_H 1
 
 #include <config.h>
 
@@ -229,4 +229,4 @@ private:
 } // namespace asiodns
 } // namespace isc
 
-#endif // __IO_FETCH_H
+#endif // IO_FETCH_H
diff --git a/src/lib/asiodns/sync_udp_server.h b/src/lib/asiodns/sync_udp_server.h
index 9718422..ddac1f9 100644
--- a/src/lib/asiodns/sync_udp_server.h
+++ b/src/lib/asiodns/sync_udp_server.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SYNC_UDP_SERVER_H
-#define __SYNC_UDP_SERVER_H 1
+#ifndef SYNC_UDP_SERVER_H
+#define SYNC_UDP_SERVER_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -145,4 +145,4 @@ private:
 
 } // namespace asiodns
 } // namespace isc
-#endif // __SYNC_UDP_SERVER_H
+#endif // SYNC_UDP_SERVER_H
diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h
index 7675daf..46f484b 100644
--- a/src/lib/asiodns/tcp_server.h
+++ b/src/lib/asiodns/tcp_server.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TCP_SERVER_H
-#define __TCP_SERVER_H 1
+#ifndef TCP_SERVER_H
+#define TCP_SERVER_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -147,4 +147,4 @@ private:
 
 } // namespace asiodns
 } // namespace isc
-#endif // __TCP_SERVER_H
+#endif // TCP_SERVER_H
diff --git a/src/lib/asiodns/udp_server.h b/src/lib/asiodns/udp_server.h
index b32c06c..c2b1b96 100644
--- a/src/lib/asiodns/udp_server.h
+++ b/src/lib/asiodns/udp_server.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UDP_SERVER_H
-#define __UDP_SERVER_H 1
+#ifndef UDP_SERVER_H
+#define UDP_SERVER_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -96,4 +96,4 @@ private:
 
 } // namespace asiodns
 } // namespace isc
-#endif // __UDP_SERVER_H
+#endif // UDP_SERVER_H
diff --git a/src/lib/asiolink/asiolink.h b/src/lib/asiolink/asiolink.h
index 51d3a14..708f368 100644
--- a/src/lib/asiolink/asiolink.h
+++ b/src/lib/asiolink/asiolink.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_H
-#define __ASIOLINK_H 1
+#ifndef ASIOLINK_H
+#define ASIOLINK_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -74,4 +74,4 @@
 /// the placeholder of callback handlers:
 /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
 
-#endif // __ASIOLINK_H
+#endif // ASIOLINK_H
diff --git a/src/lib/asiolink/dummy_io_cb.h b/src/lib/asiolink/dummy_io_cb.h
index bcaefe9..c4644c5 100644
--- a/src/lib/asiolink/dummy_io_cb.h
+++ b/src/lib/asiolink/dummy_io_cb.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DUMMY_IO_CB_H
-#define __DUMMY_IO_CB_H
+#ifndef DUMMY_IO_CB_H
+#define DUMMY_IO_CB_H
 
 #include <iostream>
 
@@ -59,4 +59,4 @@ public:
 } // namespace asiolink
 } // namespace isc
 
-#endif // __DUMMY_IO_CB_H
+#endif // DUMMY_IO_CB_H
diff --git a/src/lib/asiolink/interval_timer.h b/src/lib/asiolink/interval_timer.h
index 57ec1c3..620abfa 100644
--- a/src/lib/asiolink/interval_timer.h
+++ b/src/lib/asiolink/interval_timer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_INTERVAL_TIMER_H
-#define __ASIOLINK_INTERVAL_TIMER_H 1
+#ifndef ASIOLINK_INTERVAL_TIMER_H
+#define ASIOLINK_INTERVAL_TIMER_H 1
 
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
@@ -130,4 +130,4 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __ASIOLINK_INTERVAL_TIMER_H
+#endif // ASIOLINK_INTERVAL_TIMER_H
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index a3bb61a..6c18a66 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_ADDRESS_H
-#define __IO_ADDRESS_H 1
+#ifndef IO_ADDRESS_H
+#define IO_ADDRESS_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -215,4 +215,4 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __IO_ADDRESS_H
+#endif // IO_ADDRESS_H
diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h
index aeac63d..f6d64a0 100644
--- a/src/lib/asiolink/io_asio_socket.h
+++ b/src/lib/asiolink/io_asio_socket.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_ASIO_SOCKET_H
-#define __IO_ASIO_SOCKET_H 1
+#ifndef IO_ASIO_SOCKET_H
+#define IO_ASIO_SOCKET_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -385,4 +385,4 @@ private:
 } // namespace asiolink
 } // namespace isc
 
-#endif // __IO_ASIO_SOCKET_H
+#endif // IO_ASIO_SOCKET_H
diff --git a/src/lib/asiolink/io_endpoint.h b/src/lib/asiolink/io_endpoint.h
index 973fc8b..89bc247 100644
--- a/src/lib/asiolink/io_endpoint.h
+++ b/src/lib/asiolink/io_endpoint.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_ENDPOINT_H
-#define __IO_ENDPOINT_H 1
+#ifndef IO_ENDPOINT_H
+#define IO_ENDPOINT_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -184,7 +184,7 @@ public:
 std::ostream& operator<<(std::ostream& os, const IOEndpoint& endpoint);
 } // namespace asiolink
 } // namespace isc
-#endif // __IO_ENDPOINT_H
+#endif // IO_ENDPOINT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/asiolink/io_error.h b/src/lib/asiolink/io_error.h
index c19d91c..2fb2486 100644
--- a/src/lib/asiolink/io_error.h
+++ b/src/lib/asiolink/io_error.h
@@ -13,8 +13,8 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#ifndef __IO_ERROR_H
-#define __IO_ERROR_H
+#ifndef IO_ERROR_H
+#define IO_ERROR_H
 
 #include <exceptions/exceptions.h>
 
@@ -34,4 +34,4 @@ public:
 } // namespace asiolink
 } // namespace isc
 
-#endif // __IO_ERROR_H
+#endif // IO_ERROR_H
diff --git a/src/lib/asiolink/io_message.h b/src/lib/asiolink/io_message.h
index 81f6da1..7607c72 100644
--- a/src/lib/asiolink/io_message.h
+++ b/src/lib/asiolink/io_message.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_MESSAGE_H
-#define __IO_MESSAGE_H 1
+#ifndef IO_MESSAGE_H
+#define IO_MESSAGE_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -99,4 +99,4 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __IO_MESSAGE_H
+#endif // IO_MESSAGE_H
diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h
index 75aaee6..e0198dd 100644
--- a/src/lib/asiolink/io_service.h
+++ b/src/lib/asiolink/io_service.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_IO_SERVICE_H
-#define __ASIOLINK_IO_SERVICE_H 1
+#ifndef ASIOLINK_IO_SERVICE_H
+#define ASIOLINK_IO_SERVICE_H 1
 
 namespace asio {
     class io_service;
@@ -76,4 +76,4 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __ASIOLINK_IO_SERVICE_H
+#endif // ASIOLINK_IO_SERVICE_H
diff --git a/src/lib/asiolink/io_socket.h b/src/lib/asiolink/io_socket.h
index ab6479c..6581faf 100644
--- a/src/lib/asiolink/io_socket.h
+++ b/src/lib/asiolink/io_socket.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_SOCKET_H
-#define __IO_SOCKET_H 1
+#ifndef IO_SOCKET_H
+#define IO_SOCKET_H 1
 
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
@@ -123,4 +123,4 @@ public:
 } // namespace asiolink
 } // namespace isc
 
-#endif // __IO_SOCKET_H
+#endif // IO_SOCKET_H
diff --git a/src/lib/asiolink/simple_callback.h b/src/lib/asiolink/simple_callback.h
index a297a1d..4301bd1 100644
--- a/src/lib/asiolink/simple_callback.h
+++ b/src/lib/asiolink/simple_callback.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_SIMPLE_CALLBACK_H
-#define __ASIOLINK_SIMPLE_CALLBACK_H 1
+#ifndef ASIOLINK_SIMPLE_CALLBACK_H
+#define ASIOLINK_SIMPLE_CALLBACK_H 1
 
 #include <asiolink/io_message.h>
 
@@ -72,4 +72,4 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __ASIOLINK_SIMPLE_CALLBACK_H
+#endif // ASIOLINK_SIMPLE_CALLBACK_H
diff --git a/src/lib/asiolink/tcp_endpoint.h b/src/lib/asiolink/tcp_endpoint.h
index a54f6b2..3d6a87a 100644
--- a/src/lib/asiolink/tcp_endpoint.h
+++ b/src/lib/asiolink/tcp_endpoint.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TCP_ENDPOINT_H
-#define __TCP_ENDPOINT_H 1
+#ifndef TCP_ENDPOINT_H
+#define TCP_ENDPOINT_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -116,7 +116,7 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __TCP_ENDPOINT_H
+#endif // TCP_ENDPOINT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
index 2505d7b..6b0a43c 100644
--- a/src/lib/asiolink/tcp_socket.h
+++ b/src/lib/asiolink/tcp_socket.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TCP_SOCKET_H
-#define __TCP_SOCKET_H 1
+#ifndef TCP_SOCKET_H
+#define TCP_SOCKET_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -415,4 +415,4 @@ TCPSocket<C>::close() {
 } // namespace asiolink
 } // namespace isc
 
-#endif // __TCP_SOCKET_H
+#endif // TCP_SOCKET_H
diff --git a/src/lib/asiolink/udp_endpoint.h b/src/lib/asiolink/udp_endpoint.h
index c5ba3bd..34701b9 100644
--- a/src/lib/asiolink/udp_endpoint.h
+++ b/src/lib/asiolink/udp_endpoint.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UDP_ENDPOINT_H
-#define __UDP_ENDPOINT_H 1
+#ifndef UDP_ENDPOINT_H
+#define UDP_ENDPOINT_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -116,7 +116,7 @@ private:
 
 } // namespace asiolink
 } // namespace isc
-#endif // __UDP_ENDPOINT_H
+#endif // UDP_ENDPOINT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
index c061fba..5712957 100644
--- a/src/lib/asiolink/udp_socket.h
+++ b/src/lib/asiolink/udp_socket.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UDP_SOCKET_H
-#define __UDP_SOCKET_H 1
+#ifndef UDP_SOCKET_H
+#define UDP_SOCKET_H 1
 
 #ifndef ASIO_HPP
 #error "asio.hpp must be included before including this, see asiolink.h as to why"
@@ -321,4 +321,4 @@ UDPSocket<C>::close() {
 } // namespace asiolink
 } // namespace isc
 
-#endif // __UDP_SOCKET_H
+#endif // UDP_SOCKET_H
diff --git a/src/lib/bench/benchmark.h b/src/lib/bench/benchmark.h
index a5c6fd4..3e380dc 100644
--- a/src/lib/bench/benchmark.h
+++ b/src/lib/bench/benchmark.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __BENCHMARK_H
-#define __BENCHMARK_H 1
+#ifndef BENCHMARK_H
+#define BENCHMARK_H 1
 
 #include <sys/time.h>
 
@@ -402,7 +402,7 @@ private:
 
 }
 }
-#endif  // __BENCHMARK_H
+#endif  // BENCHMARK_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/bench/benchmark_util.h b/src/lib/bench/benchmark_util.h
index 3a373f2..2cb6acc 100644
--- a/src/lib/bench/benchmark_util.h
+++ b/src/lib/bench/benchmark_util.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __BENCHMARK_UTIL_H
-#define __BENCHMARK_UTIL_H 1
+#ifndef BENCHMARK_UTIL_H
+#define BENCHMARK_UTIL_H 1
 
 /// \file
 /// Utilities to help write benchmark cases.
@@ -140,7 +140,7 @@ void loadQueryData(std::istream& input, BenchQueries& queries,
                    const isc::dns::RRClass& qclass, const bool strict = false);
 }
 }
-#endif  // __BENCHMARK_UTIL_H
+#endif  // BENCHMARK_UTIL_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/bench/example/search_bench.cc b/src/lib/bench/example/search_bench.cc
index 84f95d9..d022d55 100644
--- a/src/lib/bench/example/search_bench.cc
+++ b/src/lib/bench/example/search_bench.cc
@@ -116,7 +116,6 @@ main(int argc, char* argv[]) {
         }
     }
     argc -= optind;
-    argv += optind;
     if (argc != 0) {
         usage();
     }
diff --git a/src/lib/cache/cache_entry_key.h b/src/lib/cache/cache_entry_key.h
index 674deb0..308a556 100644
--- a/src/lib/cache/cache_entry_key.h
+++ b/src/lib/cache/cache_entry_key.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CACHE_ENTRY_KEY_H
-#define __CACHE_ENTRY_KEY_H
+#ifndef CACHE_ENTRY_KEY_H
+#define CACHE_ENTRY_KEY_H
 
 #include <string>
 #include <dns/name.h>
@@ -50,5 +50,5 @@ genCacheEntryName(const std::string& namestr, const uint16_t type);
 } // namespace cache
 } // namespace isc
 
-#endif // __CACHE_ENTRY_KEY_H
+#endif // CACHE_ENTRY_KEY_H
 
diff --git a/src/lib/cache/local_zone_data.h b/src/lib/cache/local_zone_data.h
index df77f40..4bfdb94 100644
--- a/src/lib/cache/local_zone_data.h
+++ b/src/lib/cache/local_zone_data.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _LOCAL_ZONE_DATA
-#define _LOCAL_ZONE_DATA
+#ifndef LOCAL_ZONE_DATA
+#define LOCAL_ZONE_DATA
 
 #include <map>
 #include <string>
@@ -60,5 +60,5 @@ typedef boost::shared_ptr<const LocalZoneData> ConstLocalZoneDataPtr;
 } // namespace cache
 } // namespace isc
 
-#endif // _LOCAL_ZONE_DATA
+#endif // LOCAL_ZONE_DATA
 
diff --git a/src/lib/cache/logger.h b/src/lib/cache/logger.h
index 52c9743..3cadb54 100644
--- a/src/lib/cache/logger.h
+++ b/src/lib/cache/logger.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATASRC_LOGGER_H
-#define __DATASRC_LOGGER_H
+#ifndef DATASRC_LOGGER_H
+#define DATASRC_LOGGER_H
 
 #include <log/macros.h>
 #include <cache/cache_messages.h>
diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h
index b418f23..0c19139 100644
--- a/src/lib/cache/message_cache.h
+++ b/src/lib/cache/message_cache.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_CACHE_H
-#define __MESSAGE_CACHE_H
+#ifndef MESSAGE_CACHE_H
+#define MESSAGE_CACHE_H
 
 #include <string>
 #include <boost/shared_ptr.hpp>
@@ -90,5 +90,5 @@ typedef boost::shared_ptr<MessageCache> MessageCachePtr;
 } // namespace cache
 } // namespace isc
 
-#endif // __MESSAGE_CACHE_H
+#endif // MESSAGE_CACHE_H
 
diff --git a/src/lib/cache/message_entry.h b/src/lib/cache/message_entry.h
index 6da27cc..206e601 100644
--- a/src/lib/cache/message_entry.h
+++ b/src/lib/cache/message_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_ENTRY_H
-#define __MESSAGE_ENTRY_H
+#ifndef MESSAGE_ENTRY_H
+#define MESSAGE_ENTRY_H
 
 #include <vector>
 #include <dns/message.h>
@@ -199,5 +199,5 @@ typedef boost::shared_ptr<MessageEntry> MessageEntryPtr;
 } // namespace cache
 } // namespace isc
 
-#endif // __MESSAGE_ENTRY_H
+#endif // MESSAGE_ENTRY_H
 
diff --git a/src/lib/cache/message_utility.h b/src/lib/cache/message_utility.h
index a77af07..1a79480 100644
--- a/src/lib/cache/message_utility.h
+++ b/src/lib/cache/message_utility.h
@@ -14,8 +14,8 @@
 
 // $Id$
 
-#ifndef __MESSAGE_UTILITY_H
-#define __MESSAGE_UTILITY_H
+#ifndef MESSAGE_UTILITY_H
+#define MESSAGE_UTILITY_H
 
 #include <dns/message.h>
 
@@ -63,4 +63,4 @@ bool canMessageBeCached(const isc::dns::Message& msg);
 } // namespace isc
 
 
-#endif//__MESSAGE_UTILITY_H
+#endif//MESSAGE_UTILITY_H
diff --git a/src/lib/cache/resolver_cache.h b/src/lib/cache/resolver_cache.h
index 5630bd7..9813cc2 100644
--- a/src/lib/cache/resolver_cache.h
+++ b/src/lib/cache/resolver_cache.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RESOLVER_CACHE_H
-#define __RESOLVER_CACHE_H
+#ifndef RESOLVER_CACHE_H
+#define RESOLVER_CACHE_H
 
 #include <map>
 #include <string>
@@ -319,5 +319,5 @@ private:
 } // namespace cache
 } // namespace isc
 
-#endif // __RESOLVER_CACHE_H
+#endif // RESOLVER_CACHE_H
 
diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h
index a4ea54e..304c6e8 100644
--- a/src/lib/cache/rrset_cache.h
+++ b/src/lib/cache/rrset_cache.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRSET_CACHE_H
-#define __RRSET_CACHE_H
+#ifndef RRSET_CACHE_H
+#define RRSET_CACHE_H
 
 #include <cache/rrset_entry.h>
 #include <nsas/hash_table.h>
@@ -89,5 +89,5 @@ typedef boost::shared_ptr<const RRsetCache> ConstRRsetCachePtr;
 } // namespace cache
 } // namespace isc
 
-#endif // __RRSET_CACHE_H
+#endif // RRSET_CACHE_H
 
diff --git a/src/lib/cache/rrset_copy.h b/src/lib/cache/rrset_copy.h
index e1dc489..6b74bc0 100644
--- a/src/lib/cache/rrset_copy.h
+++ b/src/lib/cache/rrset_copy.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRSET_COPY_
-#define __RRSET_COPY_
+#ifndef RRSET_COPY
+#define RRSET_COPY
 
 #include <dns/rrset.h>
 
@@ -38,5 +38,5 @@ rrsetCopy(const isc::dns::AbstractRRset& src, isc::dns::AbstractRRset& dst);
 } // namespace cache
 } // namespace isc
 
-#endif // __RRSET_COPY_
+#endif // RRSET_COPY
 
diff --git a/src/lib/cache/rrset_entry.h b/src/lib/cache/rrset_entry.h
index 129300d..0efda36 100644
--- a/src/lib/cache/rrset_entry.h
+++ b/src/lib/cache/rrset_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRSET_ENTRY_H
-#define __RRSET_ENTRY_H
+#ifndef RRSET_ENTRY_H
+#define RRSET_ENTRY_H
 
 #include <dns/rrset.h>
 #include <dns/message.h>
@@ -132,5 +132,5 @@ typedef boost::shared_ptr<RRsetEntry> RRsetEntryPtr;
 } // namespace cache
 } // namespace isc
 
-#endif // __RRSET_ENTRY_H
+#endif // RRSET_ENTRY_H
 
diff --git a/src/lib/cc/data.cc b/src/lib/cc/data.cc
index 47b1eb1..8d9b87d 100644
--- a/src/lib/cc/data.cc
+++ b/src/lib/cc/data.cc
@@ -57,32 +57,32 @@ Element::toWire(std::ostream& ss) const {
 }
 
 bool
-Element::getValue(long int&) {
+Element::getValue(long int&) const {
     return (false);
 }
 
 bool
-Element::getValue(double&) {
+Element::getValue(double&) const {
     return (false);
 }
 
 bool
-Element::getValue(bool&) {
+Element::getValue(bool&) const {
     return (false);
 }
 
 bool
-Element::getValue(std::string&) {
+Element::getValue(std::string&) const {
     return (false);
 }
 
 bool
-Element::getValue(std::vector<ConstElementPtr>&) {
+Element::getValue(std::vector<ConstElementPtr>&) const {
     return (false);
 }
 
 bool
-Element::getValue(std::map<std::string, ConstElementPtr>&) {
+Element::getValue(std::map<std::string, ConstElementPtr>&) const {
     return (false);
 }
 
@@ -167,7 +167,7 @@ Element::find(const std::string&) const {
 }
 
 bool
-Element::find(const std::string&, ConstElementPtr) const {
+Element::find(const std::string&, ConstElementPtr&) const {
     return (false);
 }
 
@@ -812,7 +812,7 @@ MapElement::set(const std::string& key, ConstElementPtr value) {
 }
 
 bool
-MapElement::find(const std::string& id, ConstElementPtr t) const {
+MapElement::find(const std::string& id, ConstElementPtr& t) const {
     try {
         ConstElementPtr p = find(id);
         if (p) {
diff --git a/src/lib/cc/data.h b/src/lib/cc/data.h
index 5c731e6..bb84ae2 100644
--- a/src/lib/cc/data.h
+++ b/src/lib/cc/data.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_DATA_H
-#define _ISC_DATA_H 1
+#ifndef ISC_DATA_H
+#define ISC_DATA_H 1
 
 #include <string>
 #include <vector>
@@ -71,7 +71,7 @@ public:
 /// the type in question.
 ///
 class Element {
-    
+
 private:
     // technically the type could be omitted; is it useful?
     // should we remove it or replace it with a pure virtual
@@ -112,7 +112,7 @@ public:
     /// \returns true if the other ElementPtr has the same type and
     ///          value
     virtual bool equals(const Element& other) const = 0;
-    
+
     /// Converts the Element to JSON format and appends it to
     /// the given stringstream.
     virtual void toJSON(std::ostream& ss) const = 0;
@@ -152,12 +152,12 @@ public:
     /// data to the given reference and returning true
     ///
     //@{
-    virtual bool getValue(long int& t);
-    virtual bool getValue(double& t);
-    virtual bool getValue(bool& t);
-    virtual bool getValue(std::string& t);
-    virtual bool getValue(std::vector<ConstElementPtr>& t);
-    virtual bool getValue(std::map<std::string, ConstElementPtr>& t);
+    virtual bool getValue(long int& t) const;
+    virtual bool getValue(double& t) const;
+    virtual bool getValue(bool& t) const;
+    virtual bool getValue(std::string& t) const;
+    virtual bool getValue(std::vector<ConstElementPtr>& t) const;
+    virtual bool getValue(std::map<std::string, ConstElementPtr>& t) const;
     //@}
 
     ///
@@ -209,7 +209,7 @@ public:
     virtual size_t size() const;
     //@}
 
-    
+
     /// \name MapElement functions
     ///
     /// \brief If the Element on which these functions are called are not
@@ -253,12 +253,12 @@ public:
     /// \param identifier The identifier of the element to find
     /// \param t Reference to store the resulting ElementPtr, if found.
     /// \return true if the element was found, false if not.
-    virtual bool find(const std::string& identifier, ConstElementPtr t) const;
+    virtual bool find(const std::string& identifier, ConstElementPtr& t) const;
     //@}
 
 
     /// \name Factory functions
-    
+
     // TODO: should we move all factory functions to a different class
     // so as not to burden the Element base with too many functions?
     // and/or perhaps even to a separate header?
@@ -349,7 +349,7 @@ public:
     /// These function pparse the wireformat at the given stringstream
     /// (of the given length). If there is a parse error an exception
     /// of the type isc::cc::DecodeError is raised.
-    
+
     //@{
     /// Creates an Element from the wire format in the given
     /// stringstream of the given length.
@@ -378,7 +378,7 @@ public:
     IntElement(long int v) : Element(integer), i(v) { }
     long int intValue() const { return (i); }
     using Element::getValue;
-    bool getValue(long int& t) { t = i; return (true); }
+    bool getValue(long int& t) const { t = i; return (true); }
     using Element::setValue;
     bool setValue(const long int v) { i = v; return (true); }
     void toJSON(std::ostream& ss) const;
@@ -392,7 +392,7 @@ public:
     DoubleElement(double v) : Element(real), d(v) {};
     double doubleValue() const { return (d); }
     using Element::getValue;
-    bool getValue(double& t) { t = d; return (true); }
+    bool getValue(double& t) const { t = d; return (true); }
     using Element::setValue;
     bool setValue(const double v) { d = v; return (true); }
     void toJSON(std::ostream& ss) const;
@@ -406,7 +406,7 @@ public:
     BoolElement(const bool v) : Element(boolean), b(v) {};
     bool boolValue() const { return (b); }
     using Element::getValue;
-    bool getValue(bool& t) { t = b; return (true); }
+    bool getValue(bool& t) const { t = b; return (true); }
     using Element::setValue;
     bool setValue(const bool v) { b = v; return (true); }
     void toJSON(std::ostream& ss) const;
@@ -427,7 +427,7 @@ public:
     StringElement(std::string v) : Element(string), s(v) {};
     std::string stringValue() const { return (s); }
     using Element::getValue;
-    bool getValue(std::string& t) { t = s; return (true); }
+    bool getValue(std::string& t) const { t = s; return (true); }
     using Element::setValue;
     bool setValue(const std::string& v) { s = v; return (true); }
     void toJSON(std::ostream& ss) const;
@@ -441,7 +441,7 @@ public:
     ListElement() : Element(list) {}
     const std::vector<ConstElementPtr>& listValue() const { return (l); }
     using Element::getValue;
-    bool getValue(std::vector<ConstElementPtr>& t) {
+    bool getValue(std::vector<ConstElementPtr>& t) const {
         t = l;
         return (true);
     }
@@ -474,7 +474,7 @@ public:
         return (m);
     }
     using Element::getValue;
-    bool getValue(std::map<std::string, ConstElementPtr>& t) {
+    bool getValue(std::map<std::string, ConstElementPtr>& t) const {
         t = m;
         return (true);
     }
@@ -495,7 +495,7 @@ public:
         return (m.find(s) != m.end());
     }
     void toJSON(std::ostream& ss) const;
-    
+
     // we should name the two finds better...
     // find the element at id; raises TypeError if one of the
     // elements at path except the one we're looking for is not a
@@ -507,7 +507,7 @@ public:
     // returns true if found, or false if not found (either because
     // it doesnt exist or one of the elements in the path is not
     // a MapElement)
-    bool find(const std::string& id, ConstElementPtr t) const;
+    bool find(const std::string& id, ConstElementPtr& t) const;
 
     bool equals(const Element& other) const;
 };
@@ -567,8 +567,8 @@ std::ostream& operator<<(std::ostream& out, const Element& e);
 bool operator==(const Element& a, const Element& b);
 bool operator!=(const Element& a, const Element& b);
 } }
-#endif // _ISC_DATA_H
+#endif // ISC_DATA_H
 
-// Local Variables: 
+// Local Variables:
 // mode: c++
-// End: 
+// End:
diff --git a/src/lib/cc/session.h b/src/lib/cc/session.h
index 9b08232..a818291 100644
--- a/src/lib/cc/session.h
+++ b/src/lib/cc/session.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_SESSION_H
-#define _ISC_SESSION_H 1
+#ifndef ISC_SESSION_H
+#define ISC_SESSION_H 1
 
 #include <string>
 
@@ -161,7 +161,7 @@ namespace isc {
     } // namespace cc
 } // namespace isc
 
-#endif // _ISC_SESSION_H
+#endif // ISC_SESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/cc/tests/data_unittests.cc b/src/lib/cc/tests/data_unittests.cc
index 87d92f6..1565418 100644
--- a/src/lib/cc/tests/data_unittests.cc
+++ b/src/lib/cc/tests/data_unittests.cc
@@ -112,7 +112,7 @@ TEST(Element, from_and_to_json) {
         std::string s = std::string(pe.what());
         EXPECT_EQ("String expected in <string>:1:3", s);
     }
-    
+
     sv.clear();
     sv.push_back("{1}");
     //ElementPtr ep = Element::fromJSON("\"aaa\nbbb\"err");
@@ -172,14 +172,14 @@ TEST(Element, from_and_to_json) {
 
 }
 
-TEST(Element, create_and_value_throws) {
-    // this test checks whether elements throw exceptions if the
-    // incorrect type is requested
-    ElementPtr el;
+template <typename T>
+void
+testGetValueInt() {
+    T el;
     long int i;
     double d;
     bool b;
-    std::string s("asdf");
+    std::string s;
     std::vector<ConstElementPtr> v;
     std::map<std::string, ConstElementPtr> m;
 
@@ -196,27 +196,19 @@ TEST(Element, create_and_value_throws) {
     EXPECT_FALSE(el->getValue(s));
     EXPECT_FALSE(el->getValue(v));
     EXPECT_FALSE(el->getValue(m));
-    EXPECT_EQ(i, 1);
-    i = 2;
-    EXPECT_TRUE(el->setValue(i));
-    EXPECT_EQ(2, el->intValue());
-    EXPECT_FALSE(el->setValue(d));
-    EXPECT_FALSE(el->setValue(b));
-    EXPECT_FALSE(el->setValue(s));
-    EXPECT_FALSE(el->setValue(v));
-    EXPECT_FALSE(el->setValue(m));
-    EXPECT_THROW(el->get(1), TypeError);
-    EXPECT_THROW(el->set(1, el), TypeError);
-    EXPECT_THROW(el->add(el), TypeError);
-    EXPECT_THROW(el->remove(1), TypeError);
-    EXPECT_THROW(el->size(), TypeError);
-    EXPECT_THROW(el->get("foo"), TypeError);
-    EXPECT_THROW(el->set("foo", el), TypeError);
-    EXPECT_THROW(el->remove("foo"), TypeError);
-    EXPECT_THROW(el->contains("foo"), TypeError);
-    ConstElementPtr tmp;
-    EXPECT_FALSE(el->find("foo", tmp));
-    
+    EXPECT_EQ(1, i);
+}
+
+template <typename T>
+void
+testGetValueDouble() {
+    T el;
+    long int i;
+    double d;
+    bool b;
+    std::string s;
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
 
     el = Element::create(1.1);
     EXPECT_THROW(el->intValue(), TypeError);
@@ -231,15 +223,19 @@ TEST(Element, create_and_value_throws) {
     EXPECT_FALSE(el->getValue(s));
     EXPECT_FALSE(el->getValue(v));
     EXPECT_FALSE(el->getValue(m));
-    EXPECT_EQ(d, 1.1);
-    d = 2.2;
-    EXPECT_TRUE(el->setValue(d));
-    EXPECT_EQ(2.2, el->doubleValue());
-    EXPECT_FALSE(el->setValue(i));
-    EXPECT_FALSE(el->setValue(b));
-    EXPECT_FALSE(el->setValue(s));
-    EXPECT_FALSE(el->setValue(v));
-    EXPECT_FALSE(el->setValue(m));
+    EXPECT_EQ(1.1, d);
+}
+
+template <typename T>
+void
+testGetValueBool() {
+    T el;
+    long int i;
+    double d;
+    bool b;
+    std::string s;
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
 
     el = Element::create(true);
     EXPECT_THROW(el->intValue(), TypeError);
@@ -254,10 +250,19 @@ TEST(Element, create_and_value_throws) {
     EXPECT_FALSE(el->getValue(s));
     EXPECT_FALSE(el->getValue(v));
     EXPECT_FALSE(el->getValue(m));
-    EXPECT_EQ(b, true);
-    b = false;
-    EXPECT_TRUE(el->setValue(b));
-    EXPECT_FALSE(el->boolValue());
+    EXPECT_EQ(true, b);
+}
+
+template <typename T>
+void
+testGetValueString() {
+    T el;
+    long int i;
+    double d;
+    bool b;
+    std::string s;
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
 
     el = Element::create("foo");
     EXPECT_THROW(el->intValue(), TypeError);
@@ -272,10 +277,19 @@ TEST(Element, create_and_value_throws) {
     EXPECT_TRUE(el->getValue(s));
     EXPECT_FALSE(el->getValue(v));
     EXPECT_FALSE(el->getValue(m));
-    EXPECT_EQ(s, "foo");
-    s = "bar";
-    EXPECT_TRUE(el->setValue(s));
-    EXPECT_EQ("bar", el->stringValue());
+    EXPECT_EQ("foo", s);
+}
+
+template <typename T>
+void
+testGetValueList() {
+    T el;
+    long int i;
+    double d;
+    bool b;
+    std::string s;
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
 
     el = Element::createList();
     EXPECT_THROW(el->intValue(), TypeError);
@@ -291,9 +305,18 @@ TEST(Element, create_and_value_throws) {
     EXPECT_TRUE(el->getValue(v));
     EXPECT_FALSE(el->getValue(m));
     EXPECT_EQ("[  ]", el->str());
-    v.push_back(Element::create(1));
-    EXPECT_TRUE(el->setValue(v));
-    EXPECT_EQ("[ 1 ]", el->str());
+}
+
+template <typename T>
+void
+testGetValueMap() {
+    T el;
+    long int i;
+    double d;
+    bool b;
+    std::string s;
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
 
     el = Element::createMap();
     EXPECT_THROW(el->intValue(), TypeError);
@@ -308,7 +331,128 @@ TEST(Element, create_and_value_throws) {
     EXPECT_FALSE(el->getValue(s));
     EXPECT_FALSE(el->getValue(v));
     EXPECT_TRUE(el->getValue(m));
+    EXPECT_EQ("{  }", el->str());
+}
+
+TEST(Element, create_and_value_throws) {
+    // this test checks whether elements throw exceptions if the
+    // incorrect type is requested
+    ElementPtr el;
+    ConstElementPtr cel;
+    long int i = 0;
+    double d = 0.0;
+    bool b = false;
+    std::string s("asdf");
+    std::vector<ConstElementPtr> v;
+    std::map<std::string, ConstElementPtr> m;
+    ConstElementPtr tmp;
+
+    testGetValueInt<ElementPtr>();
+    testGetValueInt<ConstElementPtr>();
+
+    el = Element::create(1);
+    i = 2;
+    EXPECT_TRUE(el->setValue(i));
+    EXPECT_EQ(2, el->intValue());
+    EXPECT_FALSE(el->setValue(d));
+    EXPECT_FALSE(el->setValue(b));
+    EXPECT_FALSE(el->setValue(s));
+    EXPECT_FALSE(el->setValue(v));
+    EXPECT_FALSE(el->setValue(m));
+    EXPECT_THROW(el->get(1), TypeError);
+    EXPECT_THROW(el->set(1, el), TypeError);
+    EXPECT_THROW(el->add(el), TypeError);
+    EXPECT_THROW(el->remove(1), TypeError);
+    EXPECT_THROW(el->size(), TypeError);
+    EXPECT_THROW(el->get("foo"), TypeError);
+    EXPECT_THROW(el->set("foo", el), TypeError);
+    EXPECT_THROW(el->remove("foo"), TypeError);
+    EXPECT_THROW(el->contains("foo"), TypeError);
+    EXPECT_FALSE(el->find("foo", tmp));
+
+    testGetValueDouble<ElementPtr>();
+    testGetValueDouble<ConstElementPtr>();
+
+    el = Element::create(1.1);
+    d = 2.2;
+    EXPECT_TRUE(el->setValue(d));
+    EXPECT_EQ(2.2, el->doubleValue());
+    EXPECT_FALSE(el->setValue(i));
+    EXPECT_FALSE(el->setValue(b));
+    EXPECT_FALSE(el->setValue(s));
+    EXPECT_FALSE(el->setValue(v));
+    EXPECT_FALSE(el->setValue(m));
+    EXPECT_THROW(el->get(1), TypeError);
+    EXPECT_THROW(el->set(1, el), TypeError);
+    EXPECT_THROW(el->add(el), TypeError);
+    EXPECT_THROW(el->remove(1), TypeError);
+    EXPECT_THROW(el->size(), TypeError);
+    EXPECT_THROW(el->get("foo"), TypeError);
+    EXPECT_THROW(el->set("foo", el), TypeError);
+    EXPECT_THROW(el->remove("foo"), TypeError);
+    EXPECT_THROW(el->contains("foo"), TypeError);
+    EXPECT_FALSE(el->find("foo", tmp));
+
+    testGetValueBool<ElementPtr>();
+    testGetValueBool<ConstElementPtr>();
 
+    el = Element::create(true);
+    b = false;
+    EXPECT_TRUE(el->setValue(b));
+    EXPECT_FALSE(el->boolValue());
+    EXPECT_FALSE(el->setValue(i));
+    EXPECT_FALSE(el->setValue(d));
+    EXPECT_FALSE(el->setValue(s));
+    EXPECT_FALSE(el->setValue(v));
+    EXPECT_FALSE(el->setValue(m));
+    EXPECT_THROW(el->get(1), TypeError);
+    EXPECT_THROW(el->set(1, el), TypeError);
+    EXPECT_THROW(el->add(el), TypeError);
+    EXPECT_THROW(el->remove(1), TypeError);
+    EXPECT_THROW(el->size(), TypeError);
+    EXPECT_THROW(el->get("foo"), TypeError);
+    EXPECT_THROW(el->set("foo", el), TypeError);
+    EXPECT_THROW(el->remove("foo"), TypeError);
+    EXPECT_THROW(el->contains("foo"), TypeError);
+    EXPECT_FALSE(el->find("foo", tmp));
+
+    testGetValueString<ElementPtr>();
+    testGetValueString<ConstElementPtr>();
+
+    el = Element::create("foo");
+    s = "bar";
+    EXPECT_TRUE(el->setValue(s));
+    EXPECT_EQ("bar", el->stringValue());
+    EXPECT_FALSE(el->setValue(i));
+    EXPECT_FALSE(el->setValue(b));
+    EXPECT_FALSE(el->setValue(d));
+    EXPECT_FALSE(el->setValue(v));
+    EXPECT_FALSE(el->setValue(m));
+    EXPECT_THROW(el->get(1), TypeError);
+    EXPECT_THROW(el->set(1, el), TypeError);
+    EXPECT_THROW(el->add(el), TypeError);
+    EXPECT_THROW(el->remove(1), TypeError);
+    EXPECT_THROW(el->size(), TypeError);
+    EXPECT_THROW(el->get("foo"), TypeError);
+    EXPECT_THROW(el->set("foo", el), TypeError);
+    EXPECT_THROW(el->remove("foo"), TypeError);
+    EXPECT_THROW(el->contains("foo"), TypeError);
+    EXPECT_FALSE(el->find("foo", tmp));
+
+    testGetValueList<ElementPtr>();
+    testGetValueList<ConstElementPtr>();
+
+    el = Element::createList();
+    v.push_back(Element::create(1));
+    EXPECT_TRUE(el->setValue(v));
+    EXPECT_EQ("[ 1 ]", el->str());
+
+    testGetValueMap<ElementPtr>();
+    testGetValueMap<ConstElementPtr>();
+
+    el = Element::createMap();
+    EXPECT_NO_THROW(el->set("foo", Element::create("bar")));
+    EXPECT_EQ("{ \"foo\": \"bar\" }", el->str());
 }
 
 // Helper for escape check; it puts the given string in a StringElement,
@@ -382,7 +526,7 @@ TEST(Element, MapElement) {
     // this function checks the specific functions for ListElements
     ElementPtr el = Element::fromJSON("{ \"name\": \"foo\", \"value1\": \"bar\", \"value2\": { \"number\": 42 } }");
     ConstElementPtr el2;
-    
+
     EXPECT_EQ(el->get("name")->stringValue(), "foo");
     EXPECT_EQ(el->get("value2")->getType(), Element::map);
 
@@ -396,11 +540,12 @@ TEST(Element, MapElement) {
 
     EXPECT_EQ(el->find("value2/number")->intValue(), 42);
     EXPECT_TRUE(isNull(el->find("value2/nothing/")));
-   
+
     EXPECT_EQ(el->find("value1")->stringValue(), "bar");
     EXPECT_EQ(el->find("value1/")->stringValue(), "bar");
-    
+
     EXPECT_TRUE(el->find("value1", el2));
+    EXPECT_EQ("bar", el2->stringValue());
     EXPECT_FALSE(el->find("name/error", el2));
 
     // A map element whose (only) element has the maximum length of tag.
@@ -410,7 +555,7 @@ TEST(Element, MapElement) {
                        "9123456789abcdefa123456789abcdefb123456789abcdef"
                        "c123456789abcdefd123456789abcdefe123456789abcdef"
                        "f123456789abcde");
-    
+
     EXPECT_EQ(255, long_maptag.length()); // check prerequisite
     el = Element::fromJSON("{ \"" + long_maptag + "\": \"bar\"}");
     EXPECT_EQ("bar", el->find(long_maptag)->stringValue());
@@ -689,7 +834,7 @@ TEST(Element, merge) {
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     merge(b, a);
     EXPECT_EQ(*b, *c);
-    
+
     // And some tests with multiple values
     a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index 4b99a44..b4a44d0 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CCSESSION_H
-#define __CCSESSION_H 1
+#ifndef CCSESSION_H
+#define CCSESSION_H 1
 
 #include <config/config_data.h>
 #include <config/module_spec.h>
@@ -576,7 +576,7 @@ getRelatedLoggers(isc::data::ConstElementPtr loggers);
 } // namespace config
 
 } // namespace isc
-#endif // __CCSESSION_H
+#endif // CCSESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/config/config_data.h b/src/lib/config/config_data.h
index 3fdbc25..0bb1bfd 100644
--- a/src/lib/config/config_data.h
+++ b/src/lib/config/config_data.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CONFIG_DATA_H
-#define __CONFIG_DATA_H 1
+#ifndef CONFIG_DATA_H
+#define CONFIG_DATA_H 1
 
 #include <string>
 #include <vector>
diff --git a/src/lib/config/config_log.h b/src/lib/config/config_log.h
index 21709fd..14f681e 100644
--- a/src/lib/config/config_log.h
+++ b/src/lib/config/config_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CONFIG_LOG__H
-#define __CONFIG_LOG__H
+#ifndef CONFIG_LOG_H
+#define CONFIG_LOG_H
 
 #include <log/macros.h>
 #include "config_messages.h"
@@ -38,4 +38,4 @@ const int DBG_CONFIG_PROCESS = DBGLVL_TRACE_BASIC;
 } // namespace config
 } // namespace isc
 
-#endif // __CONFIG_LOG__H
+#endif // CONFIG_LOG_H
diff --git a/src/lib/config/module_spec.h b/src/lib/config/module_spec.h
index 27dcfe3..d755125 100644
--- a/src/lib/config/module_spec.h
+++ b/src/lib/config/module_spec.h
@@ -13,8 +13,8 @@
 // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 // WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _MODULE_SPEC_H
-#define _MODULE_SPEC_H 1
+#ifndef MODULE_SPEC_H
+#define MODULE_SPEC_H 1
 
 #include <cc/data.h>
 
diff --git a/src/lib/config/tests/fake_session.h b/src/lib/config/tests/fake_session.h
index c91b519..7d3cfde 100644
--- a/src/lib/config/tests/fake_session.h
+++ b/src/lib/config/tests/fake_session.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_FAKESESSION_H
-#define _ISC_FAKESESSION_H 1
+#ifndef ISC_FAKESESSION_H
+#define ISC_FAKESESSION_H 1
 
 #include <string>
 
@@ -111,7 +111,7 @@ private:
 } // namespace cc
 } // namespace isc
 
-#endif // _ISC_FAKESESSION_H
+#endif // ISC_FAKESESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
index 2eb0d0e..ac82785 100644
--- a/src/lib/cryptolink/crypto_hmac.h
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -18,8 +18,8 @@
 
 #include <cryptolink/cryptolink.h>
 
-#ifndef _ISC_CRYPTO_HMAC_H
-#define _ISC_CRYPTO_HMAC_H
+#ifndef ISC_CRYPTO_HMAC_H
+#define ISC_CRYPTO_HMAC_H
 
 namespace isc {
 namespace cryptolink {
@@ -205,5 +205,5 @@ void deleteHMAC(HMAC* hmac);
 } // namespace cryptolink
 } // namespace isc
 
-#endif // __ISC_CRYPTO_HMAC
+#endif // ISC_CRYPTO_HMAC_H
 
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
index d0f7d38..859065b 100644
--- a/src/lib/cryptolink/cryptolink.h
+++ b/src/lib/cryptolink/cryptolink.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_CRYPTO_H
-#define _ISC_CRYPTO_H
+#ifndef ISC_CRYPTO_H
+#define ISC_CRYPTO_H
 
 #include <string>
 #include <util/buffer.h>
@@ -205,4 +205,4 @@ private:
 } // namespace cryptolink
 } // namespace isc
 
-#endif // _ISC_CRYPTO_H
+#endif // ISC_CRYPTO_H
diff --git a/src/lib/datasrc/client.h b/src/lib/datasrc/client.h
index dab081f..3756a68 100644
--- a/src/lib/datasrc/client.h
+++ b/src/lib/datasrc/client.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATA_SOURCE_CLIENT_H
-#define __DATA_SOURCE_CLIENT_H 1
+#ifndef DATA_SOURCE_CLIENT_H
+#define DATA_SOURCE_CLIENT_H 1
 
 #include <utility>
 
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index 865a1ce..e7fb63b 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -12,17 +12,21 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <util/memory_segment_local.h>
 
 #include "client_list.h"
 #include "client.h"
 #include "factory.h"
 #include "memory/memory_client.h"
+#include "memory/zone_table_segment.h"
+#include "memory/zone_writer.h"
+#include "memory/zone_data_loader.h"
 #include "logger.h"
 #include <dns/masterload.h>
+#include <util/memory_segment_local.h>
 
 #include <memory>
 #include <boost/foreach.hpp>
+#include <boost/bind.hpp>
 
 using namespace isc::data;
 using namespace isc::dns;
@@ -32,6 +36,7 @@ using boost::lexical_cast;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::ZoneTableSegment;
 
 namespace isc {
 namespace datasrc {
@@ -39,21 +44,24 @@ namespace datasrc {
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
     DataSourceClient* data_src_client,
     const DataSourceClientContainerPtr& container, bool has_cache,
-    const RRClass& rrclass, MemorySegment& mem_sgmt) :
+    const RRClass& rrclass, const shared_ptr<ZoneTableSegment>& segment) :
     data_src_client_(data_src_client),
     container_(container)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
+        cache_.reset(new InMemoryClient(segment, rrclass));
+        ztable_segment_ = segment;
     }
 }
 
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
-    const RRClass& rrclass, MemorySegment& mem_sgmt, bool has_cache) :
+    const RRClass& rrclass, const shared_ptr<ZoneTableSegment>& segment,
+    bool has_cache) :
     data_src_client_(NULL)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
+        cache_.reset(new InMemoryClient(segment, rrclass));
+        ztable_segment_ = segment;
     }
 }
 
@@ -64,21 +72,10 @@ ConfigurableClientList::DataSourceInfo::getCacheClient() const {
 
 ConfigurableClientList::ConfigurableClientList(const RRClass& rrclass) :
     rrclass_(rrclass),
-    mem_sgmt_(new util::MemorySegmentLocal),
     configuration_(new isc::data::ListElement),
     allow_cache_(false)
 {}
 
-ConfigurableClientList::~ConfigurableClientList() {
-    // Explicitly clear the contained data source clients, and check memory
-    // leak.  assert() (with abort on failure) may be too harsh, but
-    // it's probably better to find more leaks initially.  Once it's stabilized
-    // we should probably revisit it.
-
-    data_sources_.clear();
-    assert(mem_sgmt_->allMemoryDeallocated());
-}
-
 void
 ConfigurableClientList::configure(const ConstElementPtr& config,
                                   bool allow_cache)
@@ -90,6 +87,8 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
     size_t i(0); // Outside of the try to be able to access it in the catch
     try {
         vector<DataSourceInfo> new_data_sources;
+        shared_ptr<ZoneTableSegment> ztable_segment(
+            ZoneTableSegment::create(*config, rrclass_));
         for (; i < config->size(); ++i) {
             // Extract the parameters
             const ConstElementPtr dconf(config->get(i));
@@ -126,7 +125,8 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                     isc_throw(ConfigurationError, "The cache must be enabled "
                               "for the MasterFiles type");
                 }
-                new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
+                new_data_sources.push_back(DataSourceInfo(rrclass_,
+                                                          ztable_segment,
                                                           true));
             } else {
                 // Ask the factory to create the data source for us
@@ -135,7 +135,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 // And put it into the vector
                 new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
                                                           want_cache, rrclass_,
-                                                          *mem_sgmt_));
+                                                          ztable_segment));
             }
 
             if (want_cache) {
@@ -337,33 +337,93 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
     // and the need_updater parameter is true, get the zone there.
 }
 
+// We still provide this method for backward compatibility. But to not have
+// duplicate code, it is a thin wrapper around getCachedZoneWriter only.
 ConfigurableClientList::ReloadResult
 ConfigurableClientList::reload(const Name& name) {
+    const ZoneWriterPair result(getCachedZoneWriter(name));
+    if (result.first != ZONE_SUCCESS) {
+        return (result.first);
+    }
+
+    assert(result.second);
+    result.second->load();
+    result.second->install();
+    result.second->cleanup();
+
+    return (ZONE_SUCCESS);
+}
+
+namespace {
+
+// We would like to use boost::bind for this. However, the loadZoneData takes
+// a reference, while we have a shared pointer to the iterator -- and we need
+// to keep it alive as long as the ZoneWriter is alive. Therefore we can't
+// really just dereference it and pass it, since it would get destroyed once
+// the getCachedZoneWriter would end. This class holds the shared pointer
+// alive, otherwise is mostly simple.
+//
+// It might be doable with nested boost::bind, but it would probably look
+// more awkward and complicated than this.
+class IteratorLoader {
+public:
+    IteratorLoader(const RRClass& rrclass, const Name& name,
+                   const ZoneIteratorPtr& iterator) :
+        rrclass_(rrclass),
+        name_(name),
+        iterator_(iterator)
+    {}
+    memory::ZoneData* operator()(util::MemorySegment& segment) {
+        return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
+    }
+private:
+    const RRClass rrclass_;
+    const Name name_;
+    ZoneIteratorPtr iterator_;
+};
+
+// We can't use the loadZoneData function directly in boost::bind, since
+// it is overloaded and the compiler can't choose the correct version
+// reliably and fails. So we simply wrap it into an unique name.
+memory::ZoneData*
+loadZoneDataFromFile(util::MemorySegment& segment, const RRClass& rrclass,
+                     const Name& name, const string& filename)
+{
+    return (memory::loadZoneData(segment, rrclass, name, filename));
+}
+
+}
+
+ConfigurableClientList::ZoneWriterPair
+ConfigurableClientList::getCachedZoneWriter(const Name& name) {
     if (!allow_cache_) {
-        return (CACHE_DISABLED);
+        return (ZoneWriterPair(CACHE_DISABLED, ZoneWriterPtr()));
     }
     // Try to find the correct zone.
     MutableResult result;
     findInternal(result, name, true, true);
     if (!result.finder) {
-        return (ZONE_NOT_FOUND);
+        return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
     }
-    // Try to convert the finder to in-memory one. If it is the cache,
-    // it should work.
-    // It is of a different type or there's no cache.
+    // Try to get the in-memory cache for the zone. If there's none,
+    // we can't provide the result.
     if (!result.info->cache_) {
-        return (ZONE_NOT_CACHED);
+        return (ZoneWriterPair(ZONE_NOT_CACHED, ZoneWriterPtr()));
     }
+    memory::LoadAction load_action;
     DataSourceClient* client(result.info->data_src_client_);
-    if (client) {
-        // Now do the final reload. If it does not exist in client,
+    if (client != NULL) {
+        // Now finally provide the writer.
+        // If it does not exist in client,
         // DataSourceError is thrown, which is exactly the result what we
         // want, so no need to handle it.
         ZoneIteratorPtr iterator(client->getIterator(name));
         if (!iterator) {
             isc_throw(isc::Unexpected, "Null iterator from " << name);
         }
-        result.info->cache_->load(name, *iterator);
+        // And wrap the iterator into the correct functor (which
+        // keeps it alive as long as it is needed).
+        load_action = IteratorLoader(rrclass_, name, iterator);
     } else {
         // The MasterFiles special case
         const string filename(result.info->cache_->getFileName(name));
@@ -371,9 +431,14 @@ ConfigurableClientList::reload(const Name& name) {
             isc_throw(isc::Unexpected, "Confused about missing both filename "
                       "and data source");
         }
-        result.info->cache_->load(name, filename);
+        // boost::bind is enough here.
+        load_action = boost::bind(loadZoneDataFromFile, _1, rrclass_, name,
+                                  filename);
     }
-    return (ZONE_RELOADED);
+    return (ZoneWriterPair(ZONE_SUCCESS,
+                           ZoneWriterPtr(
+                               result.info->ztable_segment_->
+                               getZoneWriter(load_action, name, rrclass_))));
 }
 
 // NOTE: This function is not tested, it would be complicated. However, the
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index 61544ef..d1a35b5 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -21,6 +21,7 @@
 #include <dns/rrclass.h>
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
+#include "memory/zone_table_segment.h"
 
 #include <vector>
 #include <boost/shared_ptr.hpp>
@@ -37,12 +38,12 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
 class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
-
 // XXX: it's better to even hide the existence of the "memory" namespace.
 // We should probably consider pimpl for details of ConfigurableClientList
 // and hide real definitions except for itself and tests.
 namespace memory {
 class InMemoryClient;
+class ZoneWriter;
 }
 
 /// \brief The list of data source clients.
@@ -220,9 +221,6 @@ public:
     /// \param rrclass For which class the list should work.
     ConfigurableClientList(const isc::dns::RRClass& rrclass);
 
-    /// \brief Destructor
-    virtual ~ConfigurableClientList();
-
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
     public:
@@ -272,7 +270,8 @@ public:
         CACHE_DISABLED,     ///< The cache is not enabled in this list.
         ZONE_NOT_CACHED,    ///< Zone is served directly, not from cache.
         ZONE_NOT_FOUND,     ///< Zone does not exist or not cached.
-        ZONE_RELOADED       ///< The zone was successfully reloaded.
+        ZONE_SUCCESS        ///< The zone was successfully reloaded or
+                            ///  the writer provided.
     };
 
     /// \brief Reloads a cached zone.
@@ -289,6 +288,36 @@ public:
     ///      the original data source no longer contains the cached zone.
     ReloadResult reload(const dns::Name& zone);
 
+private:
+    /// \brief Convenience type shortcut
+    typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
+public:
+
+    /// \brief Return value of getCachedZoneWriter()
+    ///
+    /// A pair containing status and the zone writer, for the
+    /// getCachedZoneWriter() method.
+    typedef std::pair<ReloadResult, ZoneWriterPtr> ZoneWriterPair;
+
+    /// \brief Return a zone writer that can be used to reload a zone.
+    ///
+    /// This looks up a cached copy of zone and returns the ZoneWriter
+    /// that can be used to reload the content of the zone. This can
+    /// be used instead of reload() -- reload() works synchronously, which
+    /// is not what is needed every time.
+    ///
+    /// \param zone The origin of the zone to reload.
+    /// \return The result has two parts. The first one is a status describing
+    ///     if it worked or not (and in case it didn't, also why). If the
+    ///     status is ZONE_SUCCESS, the second part contains a shared pointer
+    ///     to the writer. If the status is anything else, the second part is
+    ///     NULL.
+    /// \throw DataSourceError or anything else that the data source
+    ///      containing the zone might throw is propagated.
+    /// \throw DataSourceError if something unexpected happens, like when
+    ///      the original data source no longer contains the cached zone.
+    ZoneWriterPair getCachedZoneWriter(const dns::Name& zone);
+
     /// \brief Implementation of the ClientList::find.
     virtual FindResult find(const dns::Name& zone,
                             bool want_exact_match = false,
@@ -300,12 +329,16 @@ public:
     struct DataSourceInfo {
         // Plays a role of default constructor too (for vector)
         DataSourceInfo(const dns::RRClass& rrclass,
-                       util::MemorySegment& mem_sgmt,
+                       const boost::shared_ptr
+                           <isc::datasrc::memory::ZoneTableSegment>&
+                               ztable_segment,
                        bool has_cache = false);
         DataSourceInfo(DataSourceClient* data_src_client,
                        const DataSourceClientContainerPtr& container,
                        bool has_cache, const dns::RRClass& rrclass,
-                       util::MemorySegment& mem_sgmt);
+                       const boost::shared_ptr
+                           <isc::datasrc::memory::ZoneTableSegment>&
+                               ztable_segment);
         DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
 
@@ -316,6 +349,7 @@ public:
         // No other applications or tests may use it.
         const DataSourceClient* getCacheClient() const;
         boost::shared_ptr<memory::InMemoryClient> cache_;
+        boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
     };
 
     /// \brief The collection of data sources.
@@ -370,12 +404,6 @@ private:
                       bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
 
-    /// \brief Memory segment for in-memory cache.
-    ///
-    /// Note that this must be placed before data_sources_ so it won't be
-    /// destroyed before the built objects in the destructor.
-    boost::scoped_ptr<util::MemorySegment> mem_sgmt_;
-
     /// \brief Currently active configuration.
     isc::data::ConstElementPtr configuration_;
 
@@ -391,6 +419,11 @@ protected:
     DataSources data_sources_;
 };
 
+/// \brief Shortcut typedef for maps of client_lists.
+typedef boost::shared_ptr<std::map<
+    isc::dns::RRClass, boost::shared_ptr<ConfigurableClientList> > >
+        ClientListMapPtr;
+
 } // namespace datasrc
 } // namespace isc
 
diff --git a/src/lib/datasrc/data_source.h b/src/lib/datasrc/data_source.h
index 37c536e..bf5a7d7 100644
--- a/src/lib/datasrc/data_source.h
+++ b/src/lib/datasrc/data_source.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATA_SOURCE_H
-#define __DATA_SOURCE_H
+#ifndef DATA_SOURCE_H
+#define DATA_SOURCE_H
 
 #include <stdint.h>
 
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 6895509..320f327 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATABASE_DATASRC_H
-#define __DATABASE_DATASRC_H
+#ifndef DATABASE_DATASRC_H
+#define DATABASE_DATASRC_H
 
 #include <string>
 
@@ -1425,7 +1425,7 @@ private:
 }
 }
 
-#endif  // __DATABASE_DATASRC_H
+#endif  // DATABASE_DATASRC_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/datasrc_config.h.pre.in b/src/lib/datasrc/datasrc_config.h.pre.in
index 9074df6..221cab0 100644
--- a/src/lib/datasrc/datasrc_config.h.pre.in
+++ b/src/lib/datasrc/datasrc_config.h.pre.in
@@ -11,8 +11,9 @@
 // LOSS OF USE, DATA OR PROFITS, WHETHER 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_CONFIG_H
-#define __DATASRC_CONFIG_H 1
+
+#ifndef DATASRC_CONFIG_H
+#define DATASRC_CONFIG_H 1
 
 namespace isc {
 namespace datasrc {
@@ -28,4 +29,4 @@ const char* const BACKEND_LIBRARY_PATH = "@@PKGLIBDIR@@/";
 } // end namespace datasrc
 } // end namespace isc
 
-#endif // __DATASRC_CONFIG_H
+#endif // DATASRC_CONFIG_H
diff --git a/src/lib/datasrc/factory.h b/src/lib/datasrc/factory.h
index 2731f58..45e4f9b 100644
--- a/src/lib/datasrc/factory.h
+++ b/src/lib/datasrc/factory.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATA_SOURCE_FACTORY_H
-#define __DATA_SOURCE_FACTORY_H 1
+#ifndef DATA_SOURCE_FACTORY_H
+#define DATA_SOURCE_FACTORY_H 1
 
 #include <datasrc/data_source.h>
 #include <datasrc/client.h>
diff --git a/src/lib/datasrc/iterator.h b/src/lib/datasrc/iterator.h
index 99d3331..e1c6929 100644
--- a/src/lib/datasrc/iterator.h
+++ b/src/lib/datasrc/iterator.h
@@ -12,8 +12,8 @@
 // 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
+#ifndef DATASRC_ZONE_ITERATOR_H
+#define DATASRC_ZONE_ITERATOR_H 1
 
 #include <dns/rrset.h>
 
@@ -98,7 +98,7 @@ public:
 
 }
 }
-#endif  // __DATASRC_ZONE_ITERATOR_H
+#endif  // DATASRC_ZONE_ITERATOR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/logger.h b/src/lib/datasrc/logger.h
index db4e5cb..a270082 100644
--- a/src/lib/datasrc/logger.h
+++ b/src/lib/datasrc/logger.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATASRC_LOGGER_H
-#define __DATASRC_LOGGER_H
+#ifndef DATASRC_LOGGER_H
+#define DATASRC_LOGGER_H
 
 #include <log/macros.h>
 #include <datasrc/datasrc_messages.h>
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 743caa2..7b82269 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -16,12 +16,18 @@ 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 += segment_object_holder.h
-libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
 libdatasrc_memory_la_SOURCES += logger.h logger.cc
 libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
 libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
 libdatasrc_memory_la_SOURCES += zone_table_segment.h zone_table_segment.cc
 libdatasrc_memory_la_SOURCES += zone_table_segment_local.h zone_table_segment_local.cc
+libdatasrc_memory_la_SOURCES += zone_data_updater.h zone_data_updater.cc
+libdatasrc_memory_la_SOURCES += zone_data_loader.h zone_data_loader.cc
+libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
+libdatasrc_memory_la_SOURCES += zone_writer.h
+libdatasrc_memory_la_SOURCES += zone_writer_local.h zone_writer_local.cc
+libdatasrc_memory_la_SOURCES += load_action.h
+
 nodist_libdatasrc_memory_la_SOURCES = memory_messages.h memory_messages.cc
 
 EXTRA_DIST  = rdata_serialization_priv.cc
diff --git a/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
index 4e6af56..7bb919f 100644
--- a/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
+++ b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
@@ -183,7 +183,6 @@ main(int argc, char* argv[]) {
         }
     }
     argc -= optind;
-    argv += optind;
     if (argc != 0) {
         usage();
     }
diff --git a/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc b/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc
index bc418e8..266f4f5 100644
--- a/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc
+++ b/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc
@@ -179,7 +179,6 @@ main(int argc, char* argv[]) {
         }
     }
     argc -= optind;
-    argv += optind;
     if (argc != 0) {
         usage();
     }
diff --git a/src/lib/datasrc/memory/domaintree.h b/src/lib/datasrc/memory/domaintree.h
index 272245d..4816452 100644
--- a/src/lib/datasrc/memory/domaintree.h
+++ b/src/lib/datasrc/memory/domaintree.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _DOMAINTREE_H
-#define _DOMAINTREE_H 1
+#ifndef DOMAINTREE_H
+#define DOMAINTREE_H 1
 
 //! \file datasrc/memory/domaintree.h
 ///
@@ -2126,7 +2126,7 @@ DomainTree<T>::dumpDotHelper(std::ostream& os,
 } // namespace datasrc
 } // namespace isc
 
-#endif  // _DOMAINTREE_H
+#endif  // DOMAINTREE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/memory/load_action.h b/src/lib/datasrc/memory/load_action.h
new file mode 100644
index 0000000..f9625af
--- /dev/null
+++ b/src/lib/datasrc/memory/load_action.h
@@ -0,0 +1,47 @@
+// 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 LOAD_ACTION_H
+#define LOAD_ACTION_H
+
+#include <boost/function.hpp>
+
+namespace isc {
+// Forward declarations
+namespace util{
+class MemorySegment;
+}
+namespace datasrc {
+namespace memory {
+class ZoneData;
+
+/// \brief Callback to load data into the memory
+///
+/// This is called from the ZoneWriter whenever there's need to load the
+/// zone data. The callback should allocate new ZoneData and fill it with
+/// the zone content. It is up to the callback to know where or how to
+/// load the data, or even the origin and class of the zone (it is assumed
+/// the callback will be some kind of functor).
+///
+/// All data should be allocated from the passed MemorySegment. The ownership
+/// is passed onto the caller.
+///
+/// It must not return NULL.
+typedef boost::function<ZoneData*(util::MemorySegment&)> LoadAction;
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index f421347..65e1e3b 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -17,12 +17,12 @@
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/logger.h>
 #include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/rdata_serialization.h>
 #include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/zone_table_segment.h>
 
 #include <util/memory_segment_local.h>
 
@@ -31,20 +31,10 @@
 #include <datasrc/result.h>
 
 #include <dns/name.h>
-#include <dns/nsec3hash.h>
 #include <dns/rdataclass.h>
 #include <dns/rrclass.h>
-#include <dns/masterload.h>
-
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/noncopyable.hpp>
 
 #include <algorithm>
-#include <map>
 #include <utility>
 #include <cctype>
 #include <cassert>
@@ -53,560 +43,53 @@ using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc::memory;
-using boost::scoped_ptr;
+using namespace isc::util;
 
 namespace isc {
 namespace datasrc {
 namespace memory {
 
 using detail::SegmentObjectHolder;
+using boost::shared_ptr;
 
-namespace {
-// Some type aliases
-typedef DomainTree<std::string> FileNameTree;
-typedef DomainTreeNode<std::string> FileNameNode;
-
-// A functor type used for loading.
-typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
-
-} // end of anonymous namespace
-
-/// 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 {
-private:
-    // The deleter for the filenames stored in the tree.
-    struct FileNameDeleter {
-        FileNameDeleter() {}
-        void operator()(std::string* filename) const {
-            delete filename;
-        }
-    };
+namespace { // unnamed namespace
 
+// A helper internal class used by the memory client, used for deleting
+// filenames stored in an internal tree.
+class FileNameDeleter {
 public:
-    InMemoryClientImpl(util::MemorySegment& mem_sgmt, RRClass rrclass) :
-        mem_sgmt_(mem_sgmt),
-        rrclass_(rrclass),
-        zone_count_(0),
-        zone_table_(ZoneTable::create(mem_sgmt_, rrclass)),
-        file_name_tree_(FileNameTree::create(mem_sgmt_, false))
-    {}
-    ~InMemoryClientImpl() {
-        FileNameDeleter deleter;
-        FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
-
-        ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
-    }
-
-    util::MemorySegment& mem_sgmt_;
-    const RRClass rrclass_;
-    unsigned int zone_count_;
-    ZoneTable* zone_table_;
-    FileNameTree* file_name_tree_;
-
-    // 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.
-    result::Result load(const Name& zone_name, 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 the zone finder,
-    // we must ensure that a node for the wildcarding level exists in the
-    // backend ZoneTree.
-    // 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(const Name& zone_name, ZoneData& zone_data,
-                      const Name& name)
-    {
-        Name wname(name);
-        const unsigned int labels(wname.getLabelCount());
-        const unsigned int origin_labels(zone_name.getLabelCount());
-        for (unsigned int l = labels;
-             l > origin_labels;
-             --l, wname = wname.split(1)) {
-            if (wname.isWildcard()) {
-                LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
-
-                // Ensure a separate level exists for the "wildcarding" name,
-                // and mark the node as "wild".
-                ZoneNode* node;
-                zone_data.insertName(mem_sgmt_, wname.split(1), &node);
-                node->setFlag(ZoneData::WILDCARD_NODE);
-
-                // 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.
-                zone_data.insertName(mem_sgmt_, wname, &node);
-            }
-        }
-    }
-
-    /*
-     * 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 Name& zone_name, const AbstractRRset& rrset,
-                      const RdataSet* set) 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()) {
-            for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
-                if (sp->type != RRType::NSEC()) {
-                    LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
-                        arg(rrset.getName());
-                    isc_throw(AddError, "CNAME can't be added with "
-                              << sp->type << " RRType for "
-                              << rrset.getName());
-                }
-            }
-        } else if ((rrset.getType() != RRType::NSEC()) &&
-                   (RdataSet::find(set, RRType::CNAME()) != NULL)) {
-            LOG_ERROR(logger,
-                      DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
-            isc_throw(AddError, "CNAME and " << rrset.getType() <<
-                      " can't coexist for " << rrset.getName());
-        }
+    FileNameDeleter() {}
 
-        /*
-         * 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() != zone_name &&
-            // Adding DNAME, NS already there
-            ((rrset.getType() == RRType::DNAME() &&
-              RdataSet::find(set, RRType::NS()) != NULL) ||
-            // Adding NS, DNAME already there
-            (rrset.getType() == RRType::NS() &&
-             RdataSet::find(set, RRType::DNAME()) != NULL)))
-        {
-            LOG_ERROR(logger, DATASRC_MEMORY_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 Name& zone_name, 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_MEMORY_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");
-        }
-
-        // For RRSIGs, check consistency of the type covered.
-        // We know the RRset isn't empty, so the following check is safe.
-        if (rrset->getType() == RRType::RRSIG()) {
-            RdataIteratorPtr rit = 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: "
-                              << rrset->toText());
-                }
-            }
-        }
-
-        const NameComparisonResult compare =
-            zone_name.compare(rrset->getName());
-        if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
-            compare.getRelation() != NameComparisonResult::EQUAL)
-        {
-            LOG_ERROR(logger,
-                      DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
-                arg(zone_name);
-            isc_throw(OutOfZone, "The name " << rrset->getName() <<
-                " is not contained in zone " << zone_name);
-        }
-
-        // 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) RFC6672 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_MEMORY_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_MEMORY_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() !=
-             zone_name.getLabelCount() + 1)) {
-            LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
-                arg(rrset->getName());
-            isc_throw(AddError, "Invalid NSEC3 owner name: " <<
-                      rrset->getName());
-        }
-    }
-
-    void addNSEC3(const ConstRRsetPtr rrset,
-                  const ConstRRsetPtr rrsig,
-                  ZoneData& zone_data)
-    {
-        // We know rrset has exactly one RDATA
-        const generic::NSEC3& nsec3_rdata =
-            dynamic_cast<const generic::NSEC3&>(
-                rrset->getRdataIterator()->getCurrent());
-
-        NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
-        if (nsec3_data == NULL) {
-            nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
-            zone_data.setNSEC3Data(nsec3_data);
-            zone_data.setSigned(true);
-        } else {
-            size_t salt_len = nsec3_data->getSaltLen();
-            const uint8_t* salt_data = nsec3_data->getSaltData();
-            const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
-
-            if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
-                (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
-                (salt_data_2.size() != salt_len)) {
-                isc_throw(AddError,
-                          "NSEC3 with inconsistent parameters: " <<
-                          rrset->toText());
-            }
-            if ((salt_len > 0) &&
-                (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
-                isc_throw(AddError,
-                          "NSEC3 with inconsistent parameters: " <<
-                          rrset->toText());
-            }
-        }
-
-        ZoneNode* node;
-        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
-
-        RdataEncoder encoder;
-        RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
-        RdataSet* old_set = node->setData(set);
-        if (old_set != NULL) {
-            RdataSet::destroy(mem_sgmt_, rrclass_, old_set);
-        }
-    }
-
-    void addRdataSet(const Name& zone_name, ZoneData& zone_data,
-                     const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
-    {
-        if (rrset->getType() == RRType::NSEC3()) {
-            addNSEC3(rrset, rrsig, zone_data);
-        } else {
-            ZoneNode* node;
-            zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
-
-            RdataSet* rdataset_head = 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(zone_name, *rrset, rdataset_head);
-
-            if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
-                isc_throw(AddError,
-                          "RRset of the type already exists: "
-                          << rrset->getName() << " (type: "
-                          << rrset->getType() << ")");
-            }
-
-            RdataEncoder encoder;
-            RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
-                                                  rrsig);
-            rdataset->next = rdataset_head;
-            node->setData(rdataset);
-
-            // 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() != zone_name) {
-                node->setFlag(ZoneNode::FLAG_CALLBACK);
-                // If it is DNAME, we have a callback as well here
-            } else if (rrset->getType() == RRType::DNAME()) {
-                node->setFlag(ZoneNode::FLAG_CALLBACK);
-            }
-
-            // 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() == zone_name) {
-                // We know rrset has exactly one RDATA
-                const generic::NSEC3PARAM& param =
-                    dynamic_cast<const generic::NSEC3PARAM&>
-                      (rrset->getRdataIterator()->getCurrent());
-
-                NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
-                if (nsec3_data == NULL) {
-                    nsec3_data = NSEC3Data::create(mem_sgmt_, param);
-                    zone_data.setNSEC3Data(nsec3_data);
-                    zone_data.setSigned(true);
-                } else {
-                    size_t salt_len = nsec3_data->getSaltLen();
-                    const uint8_t* salt_data = nsec3_data->getSaltData();
-                    const vector<uint8_t>& salt_data_2 = param.getSalt();
-
-                    if ((param.getHashalg() != nsec3_data->hashalg) ||
-                        (param.getIterations() != nsec3_data->iterations) ||
-                        (salt_data_2.size() != salt_len)) {
-                        isc_throw(AddError,
-                                  "NSEC3PARAM with inconsistent parameters: "
-                                  << rrset->toText());
-                    }
-
-                    if ((salt_len > 0) &&
-                        (std::memcmp(&salt_data_2[0],
-                                     salt_data, salt_len) != 0)) {
-                        isc_throw(AddError,
-                                  "NSEC3PARAM with inconsistent parameters: "
-                                  << rrset->toText());
-                    }
-                }
-            } else if (rrset->getType() == RRType::NSEC()) {
-                // If it is NSEC signed zone, we mark the zone as signed
-                // (conceptually "signed" is a broader notion but our current
-                // zone finder implementation regards "signed" as "NSEC
-                // signed")
-                zone_data.setSigned(true);
-            }
-        }
-    }
-
-    // Implementation of InMemoryClient::add()
-    void add(const ConstRRsetPtr& rrset, const ConstRRsetPtr& sig_rrset,
-             const Name& zone_name, ZoneData& zone_data)
-    {
-        // Sanitize input.  This will cause an exception to be thrown
-        // if the input RRset is empty.
-        addValidation(zone_name, rrset);
-        if (sig_rrset) {
-            addValidation(zone_name, sig_rrset);
-        }
-
-        // OK, can add the RRset.
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
-            arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
-
-        // Add wildcards possibly contained in the owner name to the domain
-        // tree.  This can only happen for the normal (non-NSEC3) tree.
-        // Note: this can throw an exception, breaking strong exception
-        // guarantee.  (see also the note for the call to contextCheck()
-        // above).
-        if (rrset->getType() != RRType::NSEC3()) {
-            addWildcards(zone_name, zone_data, rrset->getName());
-        }
-
-        addRdataSet(zone_name, zone_data, rrset, sig_rrset);
+    void operator()(std::string* filename) const {
+        delete filename;
     }
 };
 
-// A helper internal class for load().  make it non-copyable to avoid
-// accidental copy.
-//
-// The current internal implementation expects that both a normal
-// (non RRSIG) RRset and (when signed) its RRSIG are added at once.
-// Also in the current implementation, the input sequence of RRsets
-// are grouped with their owner name (so once a new owner name is encountered,
-// no subsequent RRset has the previous owner name), but the ordering
-// in the same group is not fixed.  So we hold all RRsets of the same
-// owner name in node_rrsets_ and node_rrsigsets_, and add the matching
-// pairs of RRsets to the zone when we see a new owner name.
-//
-// The caller is responsible for adding the RRsets of the last group
-// in the input sequence by explicitly calling flushNodeRRsets() at the
-// end.  It's cleaner and more robust if we let the destructor of this class
-// do it, but since we cannot guarantee the adding operation is exception free,
-// we don't choose that option to maintain the common expectation for
-// destructors.
-class InMemoryClient::Loader : boost::noncopyable {
-    typedef std::map<RRType, ConstRRsetPtr> NodeRRsets;
-    typedef NodeRRsets::value_type NodeRRsetsVal;
-public:
-    Loader(InMemoryClientImpl* client_impl, const Name& zone_name,
-           ZoneData& zone_data) :
-        client_impl_(client_impl), zone_name_(zone_name), zone_data_(zone_data)
-    {}
-    void addFromLoad(const ConstRRsetPtr& rrset) {
-        // If we see a new name, flush the temporary holders, adding the
-        // pairs of RRsets and RRSIGs of the previous name to the zone.
-        if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
-            getCurrentName() != rrset->getName()) {
-            flushNodeRRsets();
-        }
+} // end of unnamed namespace
 
-        // Store this RRset until it can be added to the zone.  The current
-        // implementation requires RRs of the same RRset should be added at
-        // once, so we check the "duplicate" here.
-        const bool is_rrsig = rrset->getType() == RRType::RRSIG();
-        NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
-        const RRType& rrtype = is_rrsig ?
-            getCoveredType(rrset) : rrset->getType();
-        if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
-            isc_throw(AddError,
-                      "Duplicate add of the same type of"
-                      << (is_rrsig ? " RRSIG" : "") << " RRset: "
-                      << rrset->getName() << "/" << rrtype);
-        }
-    }
-    void flushNodeRRsets() {
-        BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
-            // Identify the corresponding RRSIG for the RRset, if any.
-            // If found add both the RRset and its RRSIG at once.
-            ConstRRsetPtr sig_rrset;
-            NodeRRsets::iterator sig_it =
-                node_rrsigsets_.find(val.first);
-            if (sig_it != node_rrsigsets_.end()) {
-                sig_rrset = sig_it->second;
-                node_rrsigsets_.erase(sig_it);
-            }
-            client_impl_->add(val.second, sig_rrset, zone_name_, zone_data_);
-        }
-
-        // Right now, we don't accept RRSIG without covered RRsets (this
-        // should eventually allowed, but to do so we'll need to update the
-        // finder).
-        if (!node_rrsigsets_.empty()) {
-            isc_throw(AddError, "RRSIG is added without covered RRset for "
-                      << getCurrentName());
-        }
-
-        node_rrsets_.clear();
-        node_rrsigsets_.clear();
-    }
-private:
-    // A helper to identify the covered type of an RRSIG.
-    static RRType getCoveredType(const ConstRRsetPtr& sig_rrset) {
-        RdataIteratorPtr it = sig_rrset->getRdataIterator();
-        // Empty RRSIG shouldn't be passed either via a master file or another
-        // data source iterator, but it could still happen if the iterator
-        // has a bug.  We catch and reject such cases.
-        if (it->isLast()) {
-            isc_throw(isc::Unexpected,
-                      "Empty RRset is passed in-memory loader, name: "
-                      << sig_rrset->getName());
-        }
-        return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
-                typeCovered());
-    }
-    const Name& getCurrentName() const {
-        if (!node_rrsets_.empty()) {
-            return (node_rrsets_.begin()->second->getName());
-        }
-        assert(!node_rrsigsets_.empty());
-        return (node_rrsigsets_.begin()->second->getName());
-    }
+InMemoryClient::InMemoryClient(shared_ptr<ZoneTableSegment> ztable_segment,
+                               RRClass rrclass) :
+    ztable_segment_(ztable_segment),
+    rrclass_(rrclass),
+    zone_count_(0),
+    file_name_tree_(FileNameTree::create(
+        ztable_segment_->getMemorySegment(), false))
+{}
 
-private:
-    InMemoryClientImpl* client_impl_;
-    const Name& zone_name_;
-    ZoneData& zone_data_;
-    NodeRRsets node_rrsets_;
-    NodeRRsets node_rrsigsets_;
-};
+InMemoryClient::~InMemoryClient() {
+    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
+    FileNameDeleter deleter;
+    FileNameTree::destroy(mem_sgmt, file_name_tree_, deleter);
+}
 
 result::Result
-InMemoryClient::InMemoryClientImpl::load(
-    const Name& zone_name,
-    const string& filename,
-    boost::function<void(LoadCallback)> rrset_installer)
+InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
+                             const std::string& filename,
+                             ZoneData* zone_data)
 {
+    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
     SegmentObjectHolder<ZoneData, RRClass> holder(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zone_name), rrclass_);
-
-    Loader loader(this, zone_name, *holder.get());
-    rrset_installer(boost::bind(&Loader::addFromLoad, &loader, _1));
-    // Add any last RRsets that were left
-    loader.flushNodeRRsets();
-
-    const ZoneNode* origin_node = holder.get()->getOriginNode();
-    const RdataSet* set = origin_node->getData();
-    // If the zone is NSEC3-signed, check if it has NSEC3PARAM
-    if (holder.get()->isNSEC3Signed()) {
-        if (RdataSet::find(set, RRType::NSEC3PARAM()) == NULL) {
-            LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
-                arg(zone_name).arg(rrclass_);
-        }
-    }
-
-    // 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(set, RRType::SOA()) == NULL) {
-        isc_throw(EmptyZone,
-                  "Won't create an empty zone for: " << zone_name);
-    }
+        mem_sgmt, zone_data, rrclass_);
 
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
         arg(zone_name).arg(rrclass_);
@@ -614,7 +97,7 @@ InMemoryClient::InMemoryClientImpl::load(
     // Set the filename in file_name_tree_ now, so that getFileName()
     // can use it (during zone reloading).
     FileNameNode* node(NULL);
-    switch (file_name_tree_->insert(mem_sgmt_, zone_name, &node)) {
+    switch (file_name_tree_->insert(mem_sgmt, zone_name, &node)) {
     case FileNameTree::SUCCESS:
     case FileNameTree::ALREADYEXISTS:
         // These are OK
@@ -629,9 +112,10 @@ InMemoryClient::InMemoryClientImpl::load(
     const std::string* tstr = node->setData(new std::string(filename));
     delete tstr;
 
-    const ZoneTable::AddResult result(zone_table_->addZone(mem_sgmt_, rrclass_,
-                                                           zone_name,
-                                                           holder.release()));
+    ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
+    const ZoneTable::AddResult result(zone_table->addZone(mem_sgmt, rrclass_,
+                                                          zone_name,
+                                                          holder.release()));
     if (result.code == result::SUCCESS) {
         // Only increment the zone count if the zone doesn't already
         // exist.
@@ -639,52 +123,20 @@ InMemoryClient::InMemoryClientImpl::load(
     }
     // Destroy the old instance of the zone if there was any
     if (result.zone_data != NULL) {
-        ZoneData::destroy(mem_sgmt_, result.zone_data, rrclass_);
+        ZoneData::destroy(mem_sgmt, result.zone_data, rrclass_);
     }
 
     return (result.code);
 }
 
-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;
-    while ((rrset = iterator->getNextRRset()) != NULL) {
-        callback(rrset);
-    }
-}
-}
-
-InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
-                               RRClass rrclass) :
-    impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
-{}
-
-InMemoryClient::~InMemoryClient() {
-    delete impl_;
-}
-
 RRClass
 InMemoryClient::getClass() const {
-    return (impl_->rrclass_);
+    return (rrclass_);
 }
 
 unsigned int
 InMemoryClient::getZoneCount() const {
-    return (impl_->zone_count_);
+    return (zone_count_);
 }
 
 isc::datasrc::DataSourceClient::FindResult
@@ -692,7 +144,8 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
     LOG_DEBUG(logger, DBG_TRACE_DATA,
               DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
 
-    ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+    const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
+    const ZoneTable::FindResult result(zone_table->findZone(zone_name));
 
     ZoneFinderPtr finder;
     if (result.code != result::NOTFOUND) {
@@ -704,34 +157,37 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
 
 const ZoneData*
 InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
-    ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+    const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
+    const ZoneTable::FindResult result(zone_table->findZone(zone_name));
     return (result.zone_data);
 }
 
 result::Result
 InMemoryClient::load(const isc::dns::Name& zone_name,
-                     const std::string& filename) {
+                     const std::string& filename)
+{
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
         arg(filename);
 
-    return (impl_->load(zone_name, filename,
-                        boost::bind(masterLoadWrapper, filename.c_str(),
-                                    zone_name, getClass(), _1)));
+    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
+    ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
+                                       filename);
+    return (loadInternal(zone_name, filename, zone_data));
 }
 
 result::Result
-InMemoryClient::load(const isc::dns::Name& zone_name,
-                     ZoneIterator& iterator) {
-    return (impl_->load(zone_name, string(),
-                        boost::bind(generateRRsetFromIterator,
-                                    &iterator, _1)));
+InMemoryClient::load(const isc::dns::Name& zone_name, ZoneIterator& iterator) {
+    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
+    ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
+                                       iterator);
+    return (loadInternal(zone_name, string(), zone_data));
 }
 
 const std::string
 InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
     const FileNameNode* node(NULL);
-    const FileNameTree::Result result = impl_->file_name_tree_->find(zone_name,
-                                                                     &node);
+    const FileNameTree::Result result = file_name_tree_->find(zone_name,
+                                                              &node);
     if (result == FileNameTree::EXACTMATCH) {
         return (*node->getData());
     } else {
@@ -754,7 +210,7 @@ private:
     bool separate_rrs_;
     bool ready_;
 public:
-    MemoryIterator(const RRClass rrclass,
+    MemoryIterator(const RRClass& rrclass,
                    const ZoneTree& tree, const Name& origin,
                    bool separate_rrs) :
         rrclass_(rrclass),
@@ -853,7 +309,8 @@ public:
 
 ZoneIteratorPtr
 InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
-    ZoneTable::FindResult result(impl_->zone_table_->findZone(name));
+    const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
+    const ZoneTable::FindResult result(zone_table->findZone(name));
     if (result.code != result::SUCCESS) {
         isc_throw(DataSourceError, "No such zone: " + name.toText());
     }
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index c37ad53..3218c75 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -22,6 +22,8 @@
 #include <datasrc/memory/zone_table.h>
 #include <datasrc/memory/zone_data.h>
 
+#include <boost/shared_ptr.hpp>
+
 #include <string>
 
 namespace isc {
@@ -34,6 +36,8 @@ class RRsetList;
 namespace datasrc {
 namespace memory {
 
+class ZoneTableSegment;
+
 /// \brief A data source client that holds all necessary data in memory.
 ///
 /// The \c InMemoryClient class provides an access to a conceptual data
@@ -60,7 +64,7 @@ public:
     /// This constructor internally involves resource allocation, and if
     /// it fails, a corresponding standard exception will be thrown.
     /// It never throws an exception otherwise.
-    InMemoryClient(util::MemorySegment& mem_sgmt,
+    InMemoryClient(boost::shared_ptr<ZoneTableSegment> ztable_segment,
                    isc::dns::RRClass rrclass);
 
     /// The destructor.
@@ -139,40 +143,6 @@ public:
     /// zone from a file before.
     const std::string getFileName(const isc::dns::Name& zone_name) const;
 
-    /// \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 Zone is empty exception.
-    ///
-    /// This is thrown if we have an empty zone created as a result of
-    /// load().
-    struct EmptyZone : public InvalidParameter {
-        EmptyZone(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)
-        { }
-    };
-
     /// Returns a \c ZoneFinder result that best matches the given name.
     ///
     /// This derived version of the method never throws an exception.
@@ -210,14 +180,20 @@ public:
                      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_;
-
-    // A helper internal class used by load().  It maintains some intermediate
-    // states while loading RRs of the zone.
-    class Loader;
+    // Some type aliases
+    typedef DomainTree<std::string> FileNameTree;
+    typedef DomainTreeNode<std::string> FileNameNode;
+
+    // Common process for zone load. Registers filename internally and
+    // adds the ZoneData to the ZoneTable.
+    result::Result loadInternal(const isc::dns::Name& zone_name,
+                                const std::string& filename,
+                                ZoneData* zone_data);
+
+    boost::shared_ptr<ZoneTableSegment> ztable_segment_;
+    const isc::dns::RRClass rrclass_;
+    unsigned int zone_count_;
+    FileNameTree* file_name_tree_;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc
index f51b2f9..e7ed20c 100644
--- a/src/lib/datasrc/memory/treenode_rrset.cc
+++ b/src/lib/datasrc/memory/treenode_rrset.cc
@@ -342,7 +342,7 @@ TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const {
         // Same for the owner name.  Comparing the nodes also detect
         // the case where RR classes are different (see the method description
         // of the header for details).
-        if (node_ != other->node_ ) {
+        if (node_ != other->node_) {
             return (false);
         }
         // If one is constructed with a "real name" and the other isn't
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
new file mode 100644
index 0000000..d759901
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -0,0 +1,250 @@
+// 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 <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/logger.h>
+#include <datasrc/memory/segment_object_holder.h>
+
+#include <dns/rdataclass.h>
+#include <dns/rrset.h>
+#include <dns/masterload.h>
+
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <map>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+using detail::SegmentObjectHolder;
+
+namespace { // unnamed namespace
+
+// A functor type used for loading.
+typedef boost::function<void(isc::dns::ConstRRsetPtr)> LoadCallback;
+
+// A helper internal class for \c loadZoneData().  make it non-copyable
+// to avoid accidental copy.
+//
+// The current internal implementation expects that both a normal
+// (non RRSIG) RRset and (when signed) its RRSIG are added at once.
+// Also in the current implementation, the input sequence of RRsets
+// are grouped with their owner name (so once a new owner name is encountered,
+// no subsequent RRset has the previous owner name), but the ordering
+// in the same group is not fixed.  So we hold all RRsets of the same
+// owner name in node_rrsets_ and node_rrsigsets_, and add the matching
+// pairs of RRsets to the zone when we see a new owner name.
+//
+// The caller is responsible for adding the RRsets of the last group
+// in the input sequence by explicitly calling flushNodeRRsets() at the
+// end.  It's cleaner and more robust if we let the destructor of this class
+// do it, but since we cannot guarantee the adding operation is exception free,
+// we don't choose that option to maintain the common expectation for
+// destructors.
+class ZoneDataLoader : boost::noncopyable {
+public:
+    ZoneDataLoader(util::MemorySegment& mem_sgmt,
+                   const isc::dns::RRClass rrclass,
+                   const isc::dns::Name& zone_name, ZoneData& zone_data) :
+        updater_(mem_sgmt, rrclass, zone_name, zone_data)
+    {}
+
+    void addFromLoad(const isc::dns::ConstRRsetPtr& rrset);
+    void flushNodeRRsets();
+
+private:
+    typedef std::map<isc::dns::RRType, isc::dns::ConstRRsetPtr> NodeRRsets;
+    typedef NodeRRsets::value_type NodeRRsetsVal;
+
+    // A helper to identify the covered type of an RRSIG.
+    static isc::dns::RRType getCoveredType
+        (const isc::dns::ConstRRsetPtr& sig_rrset);
+    const isc::dns::Name& getCurrentName() const;
+
+private:
+    NodeRRsets node_rrsets_;
+    NodeRRsets node_rrsigsets_;
+    ZoneDataUpdater updater_;
+};
+
+void
+ZoneDataLoader::addFromLoad(const ConstRRsetPtr& rrset) {
+    // If we see a new name, flush the temporary holders, adding the
+    // pairs of RRsets and RRSIGs of the previous name to the zone.
+    if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
+        (getCurrentName() != rrset->getName())) {
+        flushNodeRRsets();
+    }
+
+    // Store this RRset until it can be added to the zone.  The current
+    // implementation requires RRs of the same RRset should be added at
+    // once, so we check the "duplicate" here.
+    const bool is_rrsig = rrset->getType() == RRType::RRSIG();
+    NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
+    const RRType& rrtype = is_rrsig ? getCoveredType(rrset) : rrset->getType();
+    if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
+        isc_throw(ZoneDataUpdater::AddError,
+                  "Duplicate add of the same type of"
+                  << (is_rrsig ? " RRSIG" : "") << " RRset: "
+                  << rrset->getName() << "/" << rrtype);
+    }
+
+    if (rrset->getRRsig()) {
+        addFromLoad(rrset->getRRsig());
+    }
+}
+
+void
+ZoneDataLoader::flushNodeRRsets() {
+    BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
+        // Identify the corresponding RRSIG for the RRset, if any.  If
+        // found add both the RRset and its RRSIG at once.
+        ConstRRsetPtr sig_rrset;
+        NodeRRsets::iterator sig_it = node_rrsigsets_.find(val.first);
+        if (sig_it != node_rrsigsets_.end()) {
+            sig_rrset = sig_it->second;
+            node_rrsigsets_.erase(sig_it);
+        }
+        updater_.add(val.second, sig_rrset);
+    }
+
+    // Right now, we don't accept RRSIG without covered RRsets (this
+    // should eventually allowed, but to do so we'll need to update the
+    // finder).
+    if (!node_rrsigsets_.empty()) {
+        isc_throw(ZoneDataUpdater::AddError,
+                  "RRSIG is added without covered RRset for "
+                  << getCurrentName());
+    }
+
+    node_rrsets_.clear();
+    node_rrsigsets_.clear();
+}
+
+RRType
+ZoneDataLoader::getCoveredType(const ConstRRsetPtr& sig_rrset) {
+    RdataIteratorPtr it = sig_rrset->getRdataIterator();
+    // Empty RRSIG shouldn't be passed either via a master file or
+    // another data source iterator, but it could still happen if the
+    // iterator has a bug.  We catch and reject such cases.
+    if (it->isLast()) {
+        isc_throw(isc::Unexpected,
+                  "Empty RRset is passed in-memory loader, name: "
+                  << sig_rrset->getName());
+    }
+    return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
+            typeCovered());
+}
+
+const Name&
+ZoneDataLoader::getCurrentName() const {
+    if (!node_rrsets_.empty()) {
+        return (node_rrsets_.begin()->second->getName());
+    }
+    assert(!node_rrsigsets_.empty());
+    return (node_rrsigsets_.begin()->second->getName());
+}
+
+ZoneData*
+loadZoneDataInternal(util::MemorySegment& mem_sgmt,
+                     const isc::dns::RRClass& rrclass,
+                     const Name& zone_name,
+                     boost::function<void(LoadCallback)> rrset_installer)
+{
+    SegmentObjectHolder<ZoneData, RRClass> holder(
+        mem_sgmt, ZoneData::create(mem_sgmt, zone_name), rrclass);
+
+    ZoneDataLoader loader(mem_sgmt, rrclass, zone_name, *holder.get());
+    rrset_installer(boost::bind(&ZoneDataLoader::addFromLoad, &loader, _1));
+    // Add any last RRsets that were left
+    loader.flushNodeRRsets();
+
+    const ZoneNode* origin_node = holder.get()->getOriginNode();
+    const RdataSet* rdataset = origin_node->getData();
+    // If the zone is NSEC3-signed, check if it has NSEC3PARAM
+    if (holder.get()->isNSEC3Signed()) {
+        if (RdataSet::find(rdataset, RRType::NSEC3PARAM()) == NULL) {
+            LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
+                arg(zone_name).arg(rrclass);
+        }
+    }
+
+    // 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);
+    }
+
+    return (holder.release());
+}
+
+// A wrapper for dns::masterLoad used by loadZoneData() 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 the iterator version of loadZoneData().
+void
+generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
+    ConstRRsetPtr rrset;
+    while ((rrset = iterator->getNextRRset()) != NULL) {
+        callback(rrset);
+    }
+}
+
+} // end of unnamed namespace
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+             const isc::dns::RRClass& rrclass,
+             const isc::dns::Name& zone_name,
+             const std::string& zone_file)
+{
+     return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+                                 boost::bind(masterLoadWrapper,
+                                             zone_file.c_str(),
+                                             zone_name, rrclass,
+                                             _1)));
+}
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+             const isc::dns::RRClass& rrclass,
+             const isc::dns::Name& zone_name,
+             ZoneIterator& iterator)
+{
+    return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+                                 boost::bind(generateRRsetFromIterator,
+                                             &iterator, _1)));
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
new file mode 100644
index 0000000..6f02fcb
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -0,0 +1,80 @@
+// 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 DATASRC_ZONE_DATA_LOADER_H
+#define DATASRC_ZONE_DATA_LOADER_H 1
+
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/iterator.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <util/memory_segment.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief Zone is empty exception.
+///
+/// This is thrown if an empty zone would be created during
+/// \c loadZoneData().
+struct EmptyZone : public InvalidParameter {
+    EmptyZone(const char* file, size_t line, const char* what) :
+        InvalidParameter(file, line, what)
+    {}
+};
+
+/// \brief Create and return a ZoneData instance populated from the
+/// \c zone_file.
+///
+/// Throws \c ZoneDataUpdater::AddError if invalid or inconsistent data
+/// is present in the \c zone_file. Throws \c isc::Unexpected if empty
+/// RRsets are passed by the master loader. Throws \c EmptyZone if an
+/// empty zone would be created due to the \c loadZoneData().
+///
+/// \param mem_sgmt The memory segment.
+/// \param rrclass The RRClass.
+/// \param zone_name The name of the zone that is being loaded.
+/// \param zone_file Filename which contains the zone data for \c zone_name.
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+                       const isc::dns::RRClass& rrclass,
+                       const isc::dns::Name& zone_name,
+                       const std::string& zone_file);
+
+/// \brief Create and return a ZoneData instance populated from the
+/// \c iterator.
+///
+/// Throws \c ZoneDataUpdater::AddError if invalid or inconsistent data
+/// is present in the \c zone_file. Throws \c isc::Unexpected if empty
+/// RRsets are passed by the zone iterator. Throws \c EmptyZone if an
+/// empty zone would be created due to the \c loadZoneData().
+///
+/// \param mem_sgmt The memory segment.
+/// \param rrclass The RRClass.
+/// \param zone_name The name of the zone that is being loaded.
+/// \param iterator Iterator that returns RRsets to load into the zone.
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+                       const isc::dns::RRClass& rrclass,
+                       const isc::dns::Name& zone_name,
+                       ZoneIterator& iterator);
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_ZONE_DATA_LOADER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
new file mode 100644
index 0000000..037eeb4
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -0,0 +1,347 @@
+// 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 <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/logger.h>
+#include <datasrc/zone.h>
+
+#include <dns/rdataclass.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+void
+ZoneDataUpdater::addWildcards(const Name& name) {
+    Name wname(name);
+    const unsigned int labels(wname.getLabelCount());
+    const unsigned int origin_labels(zone_name_.getLabelCount());
+    for (unsigned int l = labels;
+         l > origin_labels;
+         --l, wname = wname.split(1))
+    {
+        if (wname.isWildcard()) {
+            LOG_DEBUG(logger, DBG_TRACE_DATA,
+                      DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
+
+            // Ensure a separate level exists for the "wildcarding"
+            // name, and mark the node as "wild".
+            ZoneNode* node;
+            zone_data_.insertName(mem_sgmt_, wname.split(1), &node);
+            node->setFlag(ZoneData::WILDCARD_NODE);
+
+            // 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.
+            zone_data_.insertName(mem_sgmt_, wname, &node);
+        }
+    }
+}
+
+void
+ZoneDataUpdater::contextCheck(const AbstractRRset& rrset,
+                              const RdataSet* rdataset) 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()) {
+        for (const RdataSet* sp = rdataset; sp != NULL; sp = sp->getNext()) {
+            if (sp->type != RRType::NSEC()) {
+                LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
+                    arg(rrset.getName());
+                isc_throw(AddError,
+                          "CNAME can't be added with " << sp->type
+                          << " RRType for " << rrset.getName());
+            }
+        }
+    } else if ((rrset.getType() != RRType::NSEC()) &&
+               (RdataSet::find(rdataset, RRType::CNAME()) != NULL))
+    {
+        LOG_ERROR(logger,
+                  DATASRC_MEMORY_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() != zone_name_ &&
+        // Adding DNAME, NS already there
+        ((rrset.getType() == RRType::DNAME() &&
+          RdataSet::find(rdataset, RRType::NS()) != NULL) ||
+         // Adding NS, DNAME already there
+         (rrset.getType() == RRType::NS() &&
+          RdataSet::find(rdataset, RRType::DNAME()) != NULL)))
+    {
+        LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
+        isc_throw(AddError, "DNAME can't coexist with NS in non-apex domain: "
+                  << rrset.getName());
+    }
+}
+
+void
+ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
+    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_MEMORY_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");
+    }
+
+    // For RRSIGs, check consistency of the type covered.  We know the
+    // RRset isn't empty, so the following check is safe.
+    if (rrset->getType() == RRType::RRSIG()) {
+        RdataIteratorPtr rit = 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: "
+                          << rrset->toText());
+            }
+        }
+    }
+
+    const NameComparisonResult compare = zone_name_.compare(rrset->getName());
+    if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
+        compare.getRelation() != NameComparisonResult::EQUAL)
+    {
+        LOG_ERROR(logger,
+                  DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+            arg(zone_name_);
+        isc_throw(OutOfZone,
+                  "The name " << rrset->getName() <<
+                  " is not contained in zone " << zone_name_);
+    }
+
+    // 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) RFC6672 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_MEMORY_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_MEMORY_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() != zone_name_.getLabelCount() + 1))
+    {
+        LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).arg(rrset->getName());
+        isc_throw(AddError, "Invalid NSEC3 owner name: " <<
+                  rrset->getName() << "; zone: " << zone_name_);
+    }
+}
+
+const NSEC3Hash*
+ZoneDataUpdater::getNSEC3Hash() {
+    if (hash_ == NULL) {
+        NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+        // This should never be NULL in this codepath.
+        assert(nsec3_data != NULL);
+
+        hash_ = NSEC3Hash::create(nsec3_data->hashalg,
+                                  nsec3_data->iterations,
+                                  nsec3_data->getSaltData(),
+                                  nsec3_data->getSaltLen());
+    }
+
+    return (hash_);
+}
+
+template <typename T>
+void
+ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
+    // We know rrset has exactly one RDATA
+    const T& nsec3_rdata =
+        dynamic_cast<const T&>(
+            rrset->getRdataIterator()->getCurrent());
+
+    NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    if (nsec3_data == NULL) {
+        nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
+        zone_data_.setNSEC3Data(nsec3_data);
+        zone_data_.setSigned(true);
+    } else {
+        const NSEC3Hash* hash = getNSEC3Hash();
+        if (!hash->match(nsec3_rdata)) {
+            isc_throw(AddError,
+                      rrset->getType() << " with inconsistent parameters: "
+                      << rrset->toText());
+        }
+    }
+}
+
+void
+ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
+{
+    setupNSEC3<generic::NSEC3>(rrset);
+
+    NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+
+    ZoneNode* node;
+    nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
+    RdataSet* old_rdataset = node->setData(rdataset);
+    if (old_rdataset != NULL) {
+        RdataSet::destroy(mem_sgmt_, rrclass_, old_rdataset);
+    }
+}
+
+void
+ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
+                             const ConstRRsetPtr rrsig)
+{
+    if (rrset->getType() == RRType::NSEC3()) {
+        addNSEC3(rrset, rrsig);
+    } else {
+        ZoneNode* node;
+        zone_data_.insertName(mem_sgmt_, rrset->getName(), &node);
+
+        RdataSet* rdataset_head = 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, rdataset_head);
+
+        if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
+            isc_throw(AddError,
+                      "RRset of the type already exists: "
+                      << rrset->getName() << " (type: "
+                      << rrset->getType() << ")");
+        }
+
+        RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
+                                                  rrset, rrsig);
+        rdataset_new->next = rdataset_head;
+        node->setData(rdataset_new);
+
+        // 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() != zone_name_) {
+            node->setFlag(ZoneNode::FLAG_CALLBACK);
+            // If it is DNAME, we have a callback as well here
+        } else if (rrset->getType() == RRType::DNAME()) {
+            node->setFlag(ZoneNode::FLAG_CALLBACK);
+        }
+
+        // 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() == zone_name_) {
+            setupNSEC3<generic::NSEC3PARAM>(rrset);
+        } else if (rrset->getType() == RRType::NSEC()) {
+            // If it is NSEC signed zone, we mark the zone as signed
+            // (conceptually "signed" is a broader notion but our
+            // current zone finder implementation regards "signed" as
+            // "NSEC signed")
+            zone_data_.setSigned(true);
+        }
+    }
+}
+
+void
+ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
+                     const ConstRRsetPtr& sig_rrset)
+{
+    // Validate input.  This will cause an exception to be thrown if the
+    // input RRset is empty.
+    validate(rrset);
+    if (sig_rrset) {
+        validate(sig_rrset);
+    }
+
+    // OK, can add the RRset.
+    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
+        arg(rrset->getName()).arg(rrset->getType()).arg(zone_name_);
+
+    // Add wildcards possibly contained in the owner name to the domain
+    // tree.  This can only happen for the normal (non-NSEC3) tree.
+    // Note: this can throw an exception, breaking strong exception
+    // guarantee.  (see also the note for the call to contextCheck()
+    // above).
+    if (rrset->getType() != RRType::NSEC3()) {
+        addWildcards(rrset->getName());
+    }
+
+    addRdataSet(rrset, sig_rrset);
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
new file mode 100644
index 0000000..341d8ae
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -0,0 +1,180 @@
+// 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 DATASRC_ZONE_DATA_UPDATER_H
+#define DATASRC_ZONE_DATA_UPDATER_H 1
+
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/nsec3hash.h>
+#include <util/memory_segment.h>
+
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief A helper class to add records to a zone.
+///
+/// This class provides an \c add() method that can be used to add
+/// RRsets to a ZoneData instance. The RRsets are first validated for
+/// correctness and consistency, and their data is made into RdataSets
+/// which are added to the ZoneData for the zone.
+///
+/// The way to use this is to make a ZoneDataUpdater instance, and call
+/// add() on it as follows:
+///
+/// \code
+/// ZoneDataUpdater updater(mem_sgmt, rrclass, zone_origin_name, zone_data);
+/// ConstRRsetPtr rrset;
+/// updater.add(rrset, ConstRRsetPtr());
+/// \endcode
+///
+/// We enforce that instances are non-copyable as it's pointless to make
+/// copies.
+class ZoneDataUpdater : boost::noncopyable {
+public:
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    //@{
+
+    /// The constructor.
+    ///
+    /// \throw none
+    ///
+    /// \param mem_sgmt The memory segment used for the zone data.
+    /// \param rrclass The RRclass of the zone data.
+    /// \param zone_name The Name of the zone under which records will be
+    ///                  added.
+    //  \param zone_data The ZoneData object which is populated with
+    //                   record data.
+    ZoneDataUpdater(util::MemorySegment& mem_sgmt,
+                    isc::dns::RRClass rrclass,
+                    const isc::dns::Name& zone_name,
+                    ZoneData& zone_data) :
+       mem_sgmt_(mem_sgmt),
+       rrclass_(rrclass),
+       zone_name_(zone_name),
+       zone_data_(zone_data),
+       hash_(NULL)
+    {}
+
+    /// The destructor.
+    ~ZoneDataUpdater() {
+        delete hash_;
+    }
+
+    //@}
+
+    /// This is thrown if the provided RRset parameter passed to \c
+    /// add() 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)
+        {}
+    };
+
+    /// \brief Add an RRset to the zone.
+    ///
+    /// This is the core method of this class. It is used to add an
+    /// RRset to the ZoneData associated with this object. The RRset is
+    /// first validated for correctness and consistency with the rest of
+    /// the records in the zone, and then an RdataSet is created and
+    /// populated with the record data and added to the ZoneData for the
+    /// name in the RRset.
+    ///
+    /// This method throws an \c NullRRset exception (see above) if
+    /// \c rrset is empty. It throws \c AddError if any of a variety of
+    /// validation checks fail for the \c rrset and its associated
+    /// \c sig_rrset.
+    ///
+    /// \param rrset The RRset to be added.
+    /// \param sig_rrset An associated RRSIG RRset for the \c rrset. It
+    ///                  can be empty if there is no RRSIG for the \c rrset.
+    void add(const isc::dns::ConstRRsetPtr& rrset,
+             const isc::dns::ConstRRsetPtr& sig_rrset);
+
+private:
+    // 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 the zone finder,
+    // we must ensure that a node for the wildcarding level exists in the
+    // backend ZoneTree.
+    // 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(const isc::dns::Name& name);
+
+    // 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 isc::dns::AbstractRRset& rrset,
+                      const RdataSet* set) const;
+
+    // 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 validate(const isc::dns::ConstRRsetPtr rrset) const;
+
+    const isc::dns::NSEC3Hash* getNSEC3Hash();
+    template <typename T>
+    void setupNSEC3(const isc::dns::ConstRRsetPtr rrset);
+    void addNSEC3(const isc::dns::ConstRRsetPtr rrset,
+                  const isc::dns::ConstRRsetPtr rrsig);
+    void addRdataSet(const isc::dns::ConstRRsetPtr rrset,
+                     const isc::dns::ConstRRsetPtr rrsig);
+
+    util::MemorySegment& mem_sgmt_;
+    const isc::dns::RRClass rrclass_;
+    const isc::dns::Name& zone_name_;
+    ZoneData& zone_data_;
+    RdataEncoder encoder_;
+    const isc::dns::NSEC3Hash* hash_;
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_ZONE_DATA_UPDATER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/zone_table.cc b/src/lib/datasrc/memory/zone_table.cc
index 836b020..c0237f5 100644
--- a/src/lib/datasrc/memory/zone_table.cc
+++ b/src/lib/datasrc/memory/zone_table.cc
@@ -47,23 +47,22 @@ typedef boost::function<void(ZoneData*)> ZoneDataDeleterType;
 }
 
 ZoneTable*
-ZoneTable::create(util::MemorySegment& mem_sgmt, RRClass zone_class) {
+ZoneTable::create(util::MemorySegment& mem_sgmt, const RRClass& zone_class) {
     SegmentObjectHolder<ZoneTableTree, ZoneDataDeleterType> holder(
         mem_sgmt, ZoneTableTree::create(mem_sgmt),
         boost::bind(deleteZoneData, &mem_sgmt, _1, zone_class));
     void* p = mem_sgmt.allocate(sizeof(ZoneTable));
-    ZoneTable* zone_table = new(p) ZoneTable(holder.get());
+    ZoneTable* zone_table = new(p) ZoneTable(zone_class, holder.get());
     holder.release();
     return (zone_table);
 }
 
 void
-ZoneTable::destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable,
-                   RRClass zone_class)
+ZoneTable::destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable)
 {
     ZoneTableTree::destroy(mem_sgmt, ztable->zones_.get(),
                            boost::bind(deleteZoneData, &mem_sgmt, _1,
-                                       zone_class));
+                                       ztable->rrclass_));
     mem_sgmt.deallocate(ztable, sizeof(ZoneTable));
 }
 
diff --git a/src/lib/datasrc/memory/zone_table.h b/src/lib/datasrc/memory/zone_table.h
index 024558e..1b369b9 100644
--- a/src/lib/datasrc/memory/zone_table.h
+++ b/src/lib/datasrc/memory/zone_table.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATASRC_MEMORY_ZONE_TABLE_H
-#define __DATASRC_MEMORY_ZONE_TABLE_H 1
+#ifndef DATASRC_MEMORY_ZONE_TABLE_H
+#define DATASRC_MEMORY_ZONE_TABLE_H 1
 
 #include <util/memory_segment.h>
 
@@ -102,7 +102,9 @@ 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(ZoneTableTree* zones) : zones_(zones)
+    ZoneTable(const dns::RRClass& rrclass, ZoneTableTree* zones) :
+        rrclass_(rrclass),
+        zones_(zones)
     {}
 
 public:
@@ -119,7 +121,7 @@ public:
     /// \param zone_class The RR class of the zone.  It must be the RR class
     /// that is supposed to be associated to the zone table.
     static ZoneTable* create(util::MemorySegment& mem_sgmt,
-                             dns::RRClass zone_class);
+                             const dns::RRClass& zone_class);
 
     /// \brief Destruct and deallocate \c ZoneTable
     ///
@@ -135,8 +137,7 @@ public:
     /// \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,
-                        dns::RRClass zone_class);
+    static void destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable);
 
     /// Add a new zone to the \c ZoneTable.
     ///
@@ -185,12 +186,13 @@ public:
     FindResult findZone(const isc::dns::Name& name) const;
 
 private:
+    const dns::RRClass rrclass_;
     boost::interprocess::offset_ptr<ZoneTableTree> zones_;
 };
 }
 }
 }
-#endif  // __DATASRC_MEMORY_ZONE_TABLE_H
+#endif  // DATASRC_MEMORY_ZONE_TABLE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/memory/zone_table_segment.cc b/src/lib/datasrc/memory/zone_table_segment.cc
index 7a80e3c..50587c4 100644
--- a/src/lib/datasrc/memory/zone_table_segment.cc
+++ b/src/lib/datasrc/memory/zone_table_segment.cc
@@ -15,17 +15,20 @@
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/zone_table_segment_local.h>
 
+using namespace isc::dns;
+
 namespace isc {
 namespace datasrc {
 namespace memory {
 
 ZoneTableSegment*
-ZoneTableSegment::create(const isc::data::Element&) {
+ZoneTableSegment::create(const isc::data::Element&, const RRClass& rrclass) {
     /// FIXME: For now, we always return ZoneTableSegmentLocal. This
     /// should be updated eventually to parse the passed Element
     /// argument and construct a corresponding ZoneTableSegment
     /// implementation.
-    return (new ZoneTableSegmentLocal);
+
+    return (new ZoneTableSegmentLocal(rrclass));
 }
 
 void
diff --git a/src/lib/datasrc/memory/zone_table_segment.h b/src/lib/datasrc/memory/zone_table_segment.h
index 7fd1310..88e69f6 100644
--- a/src/lib/datasrc/memory/zone_table_segment.h
+++ b/src/lib/datasrc/memory/zone_table_segment.h
@@ -12,10 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ZONE_TABLE_SEGMENT_H__
-#define __ZONE_TABLE_SEGMENT_H__
+#ifndef ZONE_TABLE_SEGMENT_H
+#define ZONE_TABLE_SEGMENT_H
 
+#include <dns/rrclass.h>
 #include <datasrc/memory/zone_table.h>
+#include "load_action.h"
 #include <cc/data.h>
 #include <util/memory_segment.h>
 
@@ -24,8 +26,14 @@
 #include <stdlib.h>
 
 namespace isc {
+// Some forward declarations
+namespace dns {
+class Name;
+class RRClass;
+}
 namespace datasrc {
 namespace memory {
+class ZoneWriter;
 
 /// \brief Memory-management independent entry point that contains a
 /// pointer to a zone table in memory.
@@ -35,18 +43,21 @@ namespace memory {
 /// map from domain names to zone locators) in memory.
 struct ZoneTableHeader {
 public:
+    ZoneTableHeader(ZoneTable* zone_table) :
+        table_(zone_table)
+    {}
+
     /// \brief Returns a pointer to the underlying zone table.
     ZoneTable* getTable() {
-        return (table.get());
+        return (table_.get());
     }
 
     /// \brief const version of \c getTable().
     const ZoneTable* getTable() const {
-        return (table.get());
+        return (table_.get());
     }
-
 private:
-    boost::interprocess::offset_ptr<ZoneTable> table;
+    boost::interprocess::offset_ptr<ZoneTable> table_;
 };
 
 /// \brief Manages a ZoneTableHeader, an entry point into a table of
@@ -64,7 +75,7 @@ protected:
     /// An instance implementing this interface is expected to be
     /// created by the factory method (\c create()), so this constructor
     /// is protected.
-    ZoneTableSegment()
+    ZoneTableSegment(isc::dns::RRClass)
     {}
 public:
     /// \brief Destructor
@@ -92,7 +103,20 @@ public:
     /// \param config The configuration based on which a derived object
     ///               is returned.
     /// \return Returns a ZoneTableSegment object
-    static ZoneTableSegment* create(const isc::data::Element& config);
+    static ZoneTableSegment* create(const isc::data::Element& config,
+                                    const isc::dns::RRClass& rrclass);
+
+    /// \brief Temporary/Testing version of create.
+    ///
+    /// This exists as a temporary solution during the migration phase
+    /// towards using the ZoneTableSegment. It doesn't take a config,
+    /// but a memory segment instead. If you can, you should use the
+    /// other version, this one will be gone soon.
+    ///
+    /// \param segment The memory segment to use.
+    /// \return Returns a new ZoneTableSegment object.
+    /// \todo Remove this method.
+    static ZoneTableSegment* create(isc::util::MemorySegment& segment);
 
     /// \brief Destroy a ZoneTableSegment
     ///
@@ -101,10 +125,25 @@ public:
     ///
     /// \param segment The segment to destroy.
     static void destroy(ZoneTableSegment* segment);
+
+    /// \brief Create a zone write corresponding to this segment
+    ///
+    /// This creates a new write that can be used to update zones
+    /// inside this zone table segment.
+    ///
+    /// \param loadAction Callback to provide the actual data.
+    /// \param origin The origin of the zone to reload.
+    /// \param rrclass The class of the zone to reload.
+    /// \return New instance of a zone writer. The ownership is passed
+    ///     onto the caller and the caller needs to \c delete it when
+    ///     it's done with the writer.
+    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
+                                      const dns::Name& origin,
+                                      const dns::RRClass& rrclass) = 0;
 };
 
 } // namespace memory
 } // namespace datasrc
 } // namespace isc
 
-#endif // __ZONE_TABLE_SEGMENT_H__
+#endif // ZONE_TABLE_SEGMENT_H
diff --git a/src/lib/datasrc/memory/zone_table_segment_local.cc b/src/lib/datasrc/memory/zone_table_segment_local.cc
index 589c9af..fdaf678 100644
--- a/src/lib/datasrc/memory/zone_table_segment_local.cc
+++ b/src/lib/datasrc/memory/zone_table_segment_local.cc
@@ -13,13 +13,31 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/memory/zone_table_segment_local.h>
+#include "zone_writer_local.h"
 
+using namespace isc::dns;
 using namespace isc::util;
 
 namespace isc {
 namespace datasrc {
 namespace memory {
 
+ZoneTableSegmentLocal::ZoneTableSegmentLocal(const RRClass& rrclass) :
+    ZoneTableSegment(rrclass),
+    header_(ZoneTable::create(mem_sgmt_, rrclass))
+{
+}
+
+ZoneTableSegmentLocal::~ZoneTableSegmentLocal() {
+    // Explicitly clear the contained data, and check memory
+    // leak.  assert() (with abort on failure) may be too harsh, but
+    // it's probably better to find more leaks initially.  Once it's stabilized
+    // we should probably revisit it.
+
+    ZoneTable::destroy(mem_sgmt_, header_.getTable());
+    assert(mem_sgmt_.allMemoryDeallocated());
+}
+
 // After more methods' definitions are added here, it would be a good
 // idea to move getHeader() and getMemorySegment() definitions to the
 // header file.
@@ -38,6 +56,14 @@ ZoneTableSegmentLocal::getMemorySegment() {
      return (mem_sgmt_);
 }
 
+ZoneWriter*
+ZoneTableSegmentLocal::getZoneWriter(const LoadAction& load_action,
+                                     const dns::Name& name,
+                                     const dns::RRClass& rrclass)
+{
+    return (new ZoneWriterLocal(this, load_action, name, rrclass));
+}
+
 } // namespace memory
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/datasrc/memory/zone_table_segment_local.h b/src/lib/datasrc/memory/zone_table_segment_local.h
index de776a9..e08ca39 100644
--- a/src/lib/datasrc/memory/zone_table_segment_local.h
+++ b/src/lib/datasrc/memory/zone_table_segment_local.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ZONE_TABLE_SEGMENT_LOCAL_H__
-#define __ZONE_TABLE_SEGMENT_LOCAL_H__
+#ifndef ZONE_TABLE_SEGMENT_LOCAL_H
+#define ZONE_TABLE_SEGMENT_LOCAL_H
 
 #include <datasrc/memory/zone_table_segment.h>
 #include <util/memory_segment_local.h>
@@ -37,11 +37,10 @@ protected:
     /// Instances are expected to be created by the factory method
     /// (\c ZoneTableSegment::create()), so this constructor is
     /// protected.
-    ZoneTableSegmentLocal()
-    {}
+    ZoneTableSegmentLocal(const isc::dns::RRClass& rrclass);
 public:
     /// \brief Destructor
-    virtual ~ZoneTableSegmentLocal() {}
+    virtual ~ZoneTableSegmentLocal();
 
     /// \brief Return the ZoneTableHeader for the local zone table
     /// segment implementation.
@@ -54,13 +53,17 @@ public:
     /// implementation (a MemorySegmentLocal instance).
     virtual isc::util::MemorySegment& getMemorySegment();
 
+    /// \brief Concrete implementation of ZoneTableSegment::getZoneWriter
+    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
+                                      const dns::Name& origin,
+                                      const dns::RRClass& rrclass);
 private:
-    ZoneTableHeader header_;
     isc::util::MemorySegmentLocal mem_sgmt_;
+    ZoneTableHeader header_;
 };
 
 } // namespace memory
 } // namespace datasrc
 } // namespace isc
 
-#endif // __ZONE_TABLE_SEGMENT_LOCAL_H__
+#endif // ZONE_TABLE_SEGMENT_LOCAL_H
diff --git a/src/lib/datasrc/memory/zone_writer.h b/src/lib/datasrc/memory/zone_writer.h
new file mode 100644
index 0000000..0e8f285
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_writer.h
@@ -0,0 +1,92 @@
+// 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 MEM_ZONE_WRITER_H
+#define MEM_ZONE_WRITER_H
+
+#include "load_action.h"
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief Does an update to a zone.
+///
+/// This abstract base class represents the work of a reload of a zone.
+/// The work is divided into three stages -- load(), install() and cleanup().
+/// They should be called in this order for the effect to take place.
+///
+/// We divide them so the update of zone data can be done asynchronously,
+/// in a different thread. The install() operation is the only one that needs
+/// to be done in a critical section.
+///
+/// Each derived class implementation must provide the strong exception
+/// guarantee for each public method. That is, when any of the methods
+/// throws, the entire state should stay the same as before the call
+/// (how to achieve that may be implementation dependant).
+class ZoneWriter {
+public:
+    /// \brief Virtual destructor.
+    virtual ~ZoneWriter() {};
+
+    /// \brief Get the zone data into memory.
+    ///
+    /// This is the part that does the time-consuming loading into the memory.
+    /// This can be run in a separate thread, for example. It has no effect on
+    /// the data actually served, it only prepares them for future use.
+    ///
+    /// This is the first method you should call on the object. Never call it
+    /// multiple times.
+    ///
+    /// \note As this contains reading of files or other data sources, or with
+    ///     some other source of the data to load, it may throw quite anything.
+    ///     If it throws, do not call any other methods on the object and
+    ///     discard it.
+    /// \note After successful load(), you have to call cleanup() some time
+    ///     later.
+    /// \throw isc::InvalidOperation if called second time.
+    virtual void load() = 0;
+
+    /// \brief Put the changes to effect.
+    ///
+    /// This replaces the old version of zone with the one previously prepared
+    /// by load(). It takes ownership of the old zone data, if any.
+    ///
+    /// You may call it only after successful load() and at most once.
+    ///
+    /// The operation is expected to be fast and is meant to be used inside
+    /// a critical section.
+    ///
+    /// This may throw in rare cases, depending on the concrete implementation.
+    /// If it throws, you still need to call cleanup().
+    ///
+    /// \throw isc::InvalidOperation if called without previous load() or for
+    ///     the second time or cleanup() was called already.
+    virtual void install() = 0;
+
+    /// \brief Clean up resources.
+    ///
+    /// This releases all resources held by owned zone data. That means the
+    /// one loaded by load() in case install() was not called or was not
+    /// successful, or the one replaced in install().
+    ///
+    /// Generally, this should never throw.
+    virtual void cleanup() = 0;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory/zone_writer_local.cc b/src/lib/datasrc/memory/zone_writer_local.cc
new file mode 100644
index 0000000..0cd9587
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_writer_local.cc
@@ -0,0 +1,93 @@
+// 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 "zone_writer_local.h"
+#include "zone_data.h"
+#include "zone_table_segment_local.h"
+
+#include <memory>
+
+using std::auto_ptr;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+ZoneWriterLocal::ZoneWriterLocal(ZoneTableSegmentLocal* segment,
+                                 const LoadAction& load_action,
+                                 const dns::Name& origin,
+                                 const dns::RRClass& rrclass) :
+    segment_(segment),
+    load_action_(load_action),
+    origin_(origin),
+    rrclass_(rrclass),
+    zone_data_(NULL),
+    state_(ZW_UNUSED)
+{}
+
+ZoneWriterLocal::~ZoneWriterLocal() {
+    // Clean up everything there might be left if someone forgot, just
+    // in case.
+    cleanup();
+}
+
+void
+ZoneWriterLocal::load() {
+    if (state_ != ZW_UNUSED) {
+        isc_throw(isc::InvalidOperation, "Trying to load twice");
+    }
+
+    zone_data_ = load_action_(segment_->getMemorySegment());
+
+    if (zone_data_ == NULL) {
+        // Bug inside load_action_.
+        isc_throw(isc::InvalidOperation, "No data returned from load action");
+    }
+
+    state_ = ZW_LOADED;
+}
+
+void
+ZoneWriterLocal::install() {
+    if (state_ != ZW_LOADED) {
+        isc_throw(isc::InvalidOperation, "No data to install");
+    }
+
+
+    ZoneTable* table(segment_->getHeader().getTable());
+    if (table == NULL) {
+        isc_throw(isc::Unexpected, "No zone table present");
+    }
+    const ZoneTable::AddResult result(table->addZone(
+                                          segment_->getMemorySegment(),
+                                          rrclass_, origin_, zone_data_));
+
+    state_ = ZW_INSTALLED;
+    zone_data_ = result.zone_data;
+}
+
+void
+ZoneWriterLocal::cleanup() {
+    // We eat the data (if any) now.
+
+    if (zone_data_ != NULL) {
+        ZoneData::destroy(segment_->getMemorySegment(), zone_data_, rrclass_);
+        zone_data_ = NULL;
+        state_ = ZW_CLEANED;
+    }
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/memory/zone_writer_local.h b/src/lib/datasrc/memory/zone_writer_local.h
new file mode 100644
index 0000000..7231a57
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_writer_local.h
@@ -0,0 +1,95 @@
+// 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 MEM_ZONE_WRITER_LOCAL_H
+#define MEM_ZONE_WRITER_LOCAL_H
+
+#include "zone_writer.h"
+
+#include <dns/rrclass.h>
+#include <dns/name.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+class ZoneData;
+class ZoneTableSegmentLocal;
+
+/// \brief Writer implementation which loads data locally.
+///
+/// This implementation prepares a clean zone data and lets one callback
+/// to fill it and another to install it somewhere. The class does mostly
+/// nothing (and delegates the work to the callbacks), just stores little bit
+/// of state between the calls.
+class ZoneWriterLocal : public ZoneWriter {
+public:
+    /// \brief Constructor
+    ///
+    /// \param segment The zone table segment to store the zone into.
+    /// \param load_action The callback used to load data.
+    /// \param install_action The callback used to install the loaded zone.
+    /// \param rrclass The class of the zone.
+    ZoneWriterLocal(ZoneTableSegmentLocal* segment,
+                    const LoadAction& load_action, const dns::Name& name,
+                    const dns::RRClass& rrclass);
+
+    /// \brief Destructor
+    ~ZoneWriterLocal();
+
+    /// \brief Loads the data.
+    ///
+    /// This calls the load_action (passed to constructor) and stores the
+    /// data for future use.
+    ///
+    /// \throw isc::InvalidOperation if it is called the second time in
+    ///     lifetime of the object.
+    /// \throw Whatever the load_action throws, it is propagated up.
+    virtual void load();
+
+    /// \brief Installs the zone.
+    ///
+    /// It modifies the zone table accessible through the segment (passed to
+    /// constructor).
+    ///
+    /// \throw isc::InvalidOperation if it is called the second time in
+    ///     lifetime of the object or if load() was not called previously or if
+    ///     cleanup() was already called.
+    virtual void install();
+
+    /// \brief Clean up memory.
+    ///
+    /// Cleans up the memory used by load()ed zone if not yet installed, or
+    /// the old zone replaced by install().
+    virtual void cleanup();
+private:
+    ZoneTableSegmentLocal* segment_;
+    LoadAction load_action_;
+    dns::Name origin_;
+    dns::RRClass rrclass_;
+    ZoneData* zone_data_;
+    enum State {
+        ZW_UNUSED,
+        ZW_LOADED,
+        ZW_INSTALLED,
+        ZW_CLEANED
+    };
+    State state_;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
index be545d4..4e277e0 100644
--- a/src/lib/datasrc/memory_datasrc.h
+++ b/src/lib/datasrc/memory_datasrc.h
@@ -12,8 +12,8 @@
 // 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
+#ifndef MEMORY_DATA_SOURCE_H
+#define MEMORY_DATA_SOURCE_H 1
 
 #include <string>
 
@@ -360,7 +360,7 @@ extern "C" void destroyInstance(DataSourceClient* instance);
 
 }
 }
-#endif  // __DATA_SOURCE_MEMORY_H
+#endif  // MEMORY_DATA_SOURCE_H
 // Local Variables:
 // mode: c++
 // End:
diff --git a/src/lib/datasrc/rbnode_rrset.h b/src/lib/datasrc/rbnode_rrset.h
index 1c23e05..cbb1b71 100644
--- a/src/lib/datasrc/rbnode_rrset.h
+++ b/src/lib/datasrc/rbnode_rrset.h
@@ -12,8 +12,8 @@
 // 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
+#ifndef RBNODE_RRSET_H
+#define RBNODE_RRSET_H
 
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
@@ -227,4 +227,4 @@ private:
 }   // namespace datasrc
 }   // namespace isc
 
-#endif  // __RBNODE_RRSET_H
+#endif  // RBNODE_RRSET_H
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index eb971e8..d0efa0a 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -12,8 +12,8 @@
 // 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
+#ifndef RBTREE_H
+#define RBTREE_H 1
 
 //! \file datasrc/rbtree.h
 ///
@@ -1986,7 +1986,7 @@ RBTree<T>::dumpDotHelper(std::ostream& os, const RBNode<T>* node,
 }
 }
 
-#endif  // _RBTREE_H
+#endif  // RBTREE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/result.h b/src/lib/datasrc/result.h
index f7ca363..5a28d08 100644
--- a/src/lib/datasrc/result.h
+++ b/src/lib/datasrc/result.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DATASRC_RESULT_H
-#define __DATASRC_RESULT_H 1
+#ifndef DATASRC_RESULT_H
+#define DATASRC_RESULT_H 1
 
 namespace isc {
 namespace datasrc {
diff --git a/src/lib/datasrc/sqlite3_accessor.h b/src/lib/datasrc/sqlite3_accessor.h
index 3e44d5b..a8112d4 100644
--- a/src/lib/datasrc/sqlite3_accessor.h
+++ b/src/lib/datasrc/sqlite3_accessor.h
@@ -13,8 +13,8 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#ifndef __DATASRC_SQLITE3_ACCESSOR_H
-#define __DATASRC_SQLITE3_ACCESSOR_H
+#ifndef DATASRC_SQLITE3_ACCESSOR_H
+#define DATASRC_SQLITE3_ACCESSOR_H
 
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
@@ -291,7 +291,7 @@ extern "C" void destroyInstance(DataSourceClient* instance);
 }
 }
 
-#endif  // __DATASRC_SQLITE3_CONNECTION_H
+#endif  // DATASRC_SQLITE3_ACCESSOR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index d995d5c..d1ff852 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -12,14 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <util/memory_segment_local.h>
-
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
 #include <datasrc/iterator.h>
 #include <datasrc/data_source.h>
 #include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_writer.h>
 
 #include <dns/rrclass.h>
 #include <dns/rrttl.h>
@@ -27,15 +27,20 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/shared_ptr.hpp>
+
 #include <set>
 #include <fstream>
 
 using namespace isc::datasrc;
 using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::ZoneTableSegment;
 using isc::datasrc::memory::InMemoryZoneFinder;
 using namespace isc::data;
 using namespace isc::dns;
-using namespace boost;
+// don't import the entire boost namespace.  It will unexpectedly hide uintXX_t
+// for some systems.
+using boost::shared_ptr;
 using namespace std;
 
 namespace {
@@ -255,7 +260,9 @@ public:
             "   \"type\": \"test_type\","
             "   \"params\": [\"example.org\", \"example.com\", "
             "                \"noiter.org\", \"null.org\"]"
-            "}]"))
+            "}]")),
+        config_(Element::fromJSON("{}")),
+        ztable_segment_(ZoneTableSegment::create(*config_, rrclass_))
     {
         for (size_t i(0); i < ds_count; ++ i) {
             shared_ptr<MockDataSourceClient>
@@ -263,7 +270,7 @@ public:
             ds_.push_back(ds);
             ds_info_.push_back(ConfigurableClientList::DataSourceInfo(
                                    ds.get(), DataSourceClientContainerPtr(),
-                                   false, rrclass_, mem_sgmt_));
+                                   false, rrclass_, ztable_segment_));
         }
     }
 
@@ -283,13 +290,14 @@ public:
 
         // Create cache from the temporary data source, and push it to the
         // client list.
-        const shared_ptr<InMemoryClient> cache(new InMemoryClient(mem_sgmt_,
-                                                                  rrclass_));
+        const shared_ptr<InMemoryClient> cache(
+            new InMemoryClient(ztable_segment_, rrclass_));
         cache->load(zone, *mock_client.getIterator(zone, false));
 
         ConfigurableClientList::DataSourceInfo& dsrc_info =
                 list_->getDataSources()[index];
         dsrc_info.cache_ = cache;
+        dsrc_info.ztable_segment_ = ztable_segment_;
     }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
@@ -309,7 +317,7 @@ public:
                   result.life_keeper_);
         if (from_cache) {
             EXPECT_NE(shared_ptr<InMemoryZoneFinder>(),
-                      dynamic_pointer_cast<InMemoryZoneFinder>(
+                      boost::dynamic_pointer_cast<InMemoryZoneFinder>(
                           result.finder_)) << "Finder is not from cache";
             EXPECT_TRUE(NULL !=
                         dynamic_cast<InMemoryClient*>(result.dsrc_client_));
@@ -362,12 +370,12 @@ public:
                   shared_ptr<InMemoryClient>());
     }
     const RRClass rrclass_;
-    isc::util::MemorySegmentLocal mem_sgmt_;
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negative_result_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
     vector<ConfigurableClientList::DataSourceInfo> ds_info_;
-    const ConstElementPtr config_elem_, config_elem_zones_;
+    const ConstElementPtr config_elem_, config_elem_zones_, config_;
+    shared_ptr<ZoneTableSegment> ztable_segment_;
 };
 
 // Test the test itself
@@ -844,116 +852,169 @@ TEST_F(ListTest, BadMasterFile) {
                    true);
 }
 
+// This allows us to test two versions of the reloading code
+// (One by calling reload(), one by obtaining a ZoneWriter and
+// playing with that). Once we deprecate reload(), we should revert this
+// change and not use typed tests any more.
+template<class UpdateType>
+class ReloadTest : public ListTest {
+public:
+    ConfigurableClientList::ReloadResult doReload(const Name& origin);
+};
+
+// Version with calling reload()
+class ReloadUpdateType {};
+template<>
+ConfigurableClientList::ReloadResult
+ReloadTest<ReloadUpdateType>::doReload(const Name& origin) {
+    return (list_->reload(origin));
+};
+
+// Version with the ZoneWriter
+class WriterUpdateType {};
+template<>
+ConfigurableClientList::ReloadResult
+ReloadTest<WriterUpdateType>::doReload(const Name& origin) {
+    ConfigurableClientList::ZoneWriterPair
+        result(list_->getCachedZoneWriter(origin));
+    if (result.first == ConfigurableClientList::ZONE_SUCCESS) {
+        // Can't use ASSERT_NE here, it would want to return(), which
+        // it can't in non-void function.
+        if (result.second) {
+            result.second->load();
+            result.second->install();
+            result.second->cleanup();
+        } else {
+            ADD_FAILURE() << "getCachedZoneWriter returned ZONE_SUCCESS, "
+                "but the writer is NULL";
+        }
+    } else {
+        EXPECT_EQ(static_cast<memory::ZoneWriter*>(NULL),
+                  result.second.get());
+    }
+    return (result.first);
+}
+
+// Typedefs for the GTEST guts to make it work
+typedef ::testing::Types<ReloadUpdateType, WriterUpdateType> UpdateTypes;
+TYPED_TEST_CASE(ReloadTest, UpdateTypes);
+
 // Test we can reload a zone
-TEST_F(ListTest, reloadSuccess) {
-    list_->configure(config_elem_zones_, true);
+TYPED_TEST(ReloadTest, reloadSuccess) {
+    this->list_->configure(this->config_elem_zones_, true);
     const Name name("example.org");
-    prepareCache(0, name);
+    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,
-              list_->find(name).finder_->find(name, RRType::NS())->code);
+              this->list_->find(name).finder_->find(name, RRType::NS())->code);
     // Now reload the full zone. It should be there now.
-    EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
+    EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS, this->doReload(name));
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::NS())->code);
+              this->list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // The cache is not enabled. The load should be rejected.
-TEST_F(ListTest, reloadNotEnabled) {
-    list_->configure(config_elem_zones_, false);
+TYPED_TEST(ReloadTest, reloadNotEnabled) {
+    this->list_->configure(this->config_elem_zones_, false);
     const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the thing.
-    prepareCache(0, name);
+    this->prepareCache(0, name);
     // See the reloadSuccess test.  This should result in NXRRSET.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::NS())->code);
+              this->list_->find(name).finder_->find(name, RRType::NS())->code);
     // Now reload. It should reject it.
-    EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
+    EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, this->doReload(name));
     // Nothing changed here
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::NS())->code);
+              this->list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // Test several cases when the zone does not exist
-TEST_F(ListTest, reloadNoSuchZone) {
-    list_->configure(config_elem_zones_, true);
+TYPED_TEST(ReloadTest, reloadNoSuchZone) {
+    this->list_->configure(this->config_elem_zones_, true);
     const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the
     // reload method, as that one looks at the real state of things, not
     // at the configuration.
-    prepareCache(0, Name("example.com"));
+    this->prepareCache(0, Name("example.com"));
     // Not in the data sources
     EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
-              list_->reload(Name("example.cz")));
+              this->doReload(Name("exmaple.cz")));
     // Not cached
-    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND, list_->reload(name));
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND, this->doReload(name));
     // Partial match
     EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
-              list_->reload(Name("sub.example.com")));
+              this->doReload(Name("sub.example.com")));
     // Nothing changed here - these zones don't exist
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
-              list_->find(name).dsrc_client_);
+              this->list_->find(name).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
-              list_->find(Name("example.cz")).dsrc_client_);
+              this->list_->find(Name("example.cz")).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
-              list_->find(Name("sub.example.com"), true).dsrc_client_);
+              this->list_->find(Name("sub.example.com"), true).dsrc_client_);
     // Not reloaded, so NS shouldn't be visible yet.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(Name("example.com")).finder_->
+              this->list_->find(Name("example.com")).finder_->
               find(Name("example.com"), RRType::NS())->code);
 }
 
 // Check we gracefuly throw an exception when a zone disappeared in
 // the underlying data source when we want to reload it
-TEST_F(ListTest, reloadZoneGone) {
-    list_->configure(config_elem_, true);
+TYPED_TEST(ReloadTest, reloadZoneGone) {
+    this->list_->configure(this->config_elem_, true);
     const Name name("example.org");
     // We put in a cache for non-existant zone. This emulates being loaded
     // and then the zone disappearing. We prefill the cache, so we can check
     // it.
-    prepareCache(0, name);
+    this->prepareCache(0, name);
     // The (cached) zone contains zone's SOA
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
     // The zone is not there, so abort the reload.
-    EXPECT_THROW(list_->reload(name), DataSourceError);
+    EXPECT_THROW(this->doReload(name), DataSourceError);
     // The (cached) zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
 }
 
 // The underlying data source throws. Check we don't modify the state.
-TEST_F(ListTest, reloadZoneThrow) {
-    list_->configure(config_elem_zones_, true);
+TYPED_TEST(ReloadTest, reloadZoneThrow) {
+    this->list_->configure(this->config_elem_zones_, true);
     const Name name("noiter.org");
-    prepareCache(0, name);
+    this->prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
     // The iterator throws, so abort the reload.
-    EXPECT_THROW(list_->reload(name), isc::NotImplemented);
+    EXPECT_THROW(this->doReload(name), isc::NotImplemented);
     // The zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
 }
 
-TEST_F(ListTest, reloadNullIterator) {
-    list_->configure(config_elem_zones_, true);
+TYPED_TEST(ReloadTest, reloadNullIterator) {
+    this->list_->configure(this->config_elem_zones_, true);
     const Name name("null.org");
-    prepareCache(0, name);
+    this->prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
     // The iterator throws, so abort the reload.
-    EXPECT_THROW(list_->reload(name), isc::Unexpected);
+    EXPECT_THROW(this->doReload(name), isc::Unexpected);
     // The zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              this->list_->find(name).finder_->find(name,
+                                                    RRType::SOA())->code);
 }
 
 // Test we can reload the master files too (special-cased)
-TEST_F(ListTest, reloadMasterFile) {
+TYPED_TEST(ReloadTest, reloadMasterFile) {
     const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_DIR
         "/root.zone " TEST_DATA_BUILDDIR "/root.zone.copied";
     if (system(install_cmd) != 0) {
@@ -971,21 +1032,21 @@ TEST_F(ListTest, reloadMasterFile) {
         "       \".\": \"" TEST_DATA_BUILDDIR "/root.zone.copied\""
         "   }"
         "}]"));
-    list_->configure(elem, true);
+    this->list_->configure(elem, true);
     // Add a record that is not in the zone
     EXPECT_EQ(ZoneFinder::NXDOMAIN,
-              list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
-                                                   RRType::TXT())->code);
+              this->list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
+                                                         RRType::TXT())->code);
     ofstream f;
     f.open(TEST_DATA_BUILDDIR "/root.zone.copied", ios::out | ios::app);
     f << "nosuchdomain.\t\t3600\tIN\tTXT\ttest" << std::endl;
     f.close();
     // Do the reload.
-    EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(Name(".")));
+    EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS, this->doReload(Name(".")));
     // It is here now.
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
-                                                   RRType::TXT())->code);
+              this->list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
+                                                         RRType::TXT())->code);
 }
 
 }
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
index 37e9043..67e63b9 100644
--- a/src/lib/datasrc/tests/memory/Makefile.am
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -32,7 +32,9 @@ 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 += zone_table_segment_test.h
 run_unittests_SOURCES += zone_table_segment_unittest.cc
+run_unittests_SOURCES += zone_writer_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index c5b6c10..c1d2f30 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -29,21 +29,30 @@
 #include <datasrc/data_source.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/zone_data_loader.h>
 #include <datasrc/memory/memory_client.h>
 
 #include <testutils/dnsmessage_test.h>
 
 #include "memory_segment_test.h"
+#include "zone_table_segment_test.h"
 
 #include <gtest/gtest.h>
 
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+
 #include <new>                  // for bad_alloc
 
+using namespace isc::data;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc;
 using namespace isc::datasrc::memory;
 using namespace isc::testutils;
+using boost::shared_ptr;
+using std::vector;
 
 namespace {
 
@@ -86,8 +95,7 @@ private:
     MockIterator(const char** rrset_data_ptr, bool pass_empty_rrsig) :
         rrset_data_ptr_(rrset_data_ptr),
         pass_empty_rrsig_(pass_empty_rrsig)
-    {
-    }
+    {}
 
     const char** rrset_data_ptr_;
     // If true, emulate an unexpected bogus case where an RRSIG RRset is
@@ -123,23 +131,53 @@ public:
     }
 };
 
+class MockVectorIterator : public ZoneIterator {
+private:
+    MockVectorIterator(const vector<ConstRRsetPtr>& rrsets) :
+        rrsets_(rrsets),
+        counter_(0)
+    {}
+
+    const vector<ConstRRsetPtr> rrsets_;
+    int counter_;
+
+public:
+    virtual ConstRRsetPtr getNextRRset() {
+        if (counter_ >= rrsets_.size()) {
+             return (ConstRRsetPtr());
+        }
+
+        return (rrsets_[counter_++]);
+    }
+
+    virtual ConstRRsetPtr getSOA() const {
+        isc_throw(isc::NotImplemented, "Not implemented");
+    }
+
+    static ZoneIteratorPtr makeIterator(const vector<ConstRRsetPtr>& rrsets) {
+        return (ZoneIteratorPtr(new MockVectorIterator(rrsets)));
+    }
+};
+
 class MemoryClientTest : public ::testing::Test {
 protected:
     MemoryClientTest() : zclass_(RRClass::IN()),
-                         client_(new InMemoryClient(mem_sgmt_, zclass_))
+                         ztable_segment_(new test::ZoneTableSegmentTest(
+                             zclass_, mem_sgmt_)),
+                         client_(new InMemoryClient(ztable_segment_, zclass_))
     {}
     ~MemoryClientTest() {
-        if (client_ != NULL) {
-            delete client_;
-        }
+        delete client_;
     }
     void TearDown() {
         delete client_;
         client_ = NULL;
+        ztable_segment_.reset();
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
     }
     const RRClass zclass_;
     test::MemorySegmentTest mem_sgmt_;
+    shared_ptr<ZoneTableSegment> ztable_segment_;
     InMemoryClient* client_;
 };
 
@@ -187,7 +225,7 @@ TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
 
     EXPECT_THROW(client_->load(Name("."),
                                TEST_DATA_DIR "/empty.zone"),
-                 InMemoryClient::EmptyZone);
+                 EmptyZone);
 
     EXPECT_EQ(0, client_->getZoneCount());
 
@@ -241,13 +279,13 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                *MockIterator::makeIterator(
                                    rrset_data_separated)),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
 
     // Similar to the previous case, but with separated RRSIGs.
     EXPECT_THROW(client_->load(Name("example.org"),
                                *MockIterator::makeIterator(
                                    rrset_data_sigseparated)),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
 
     // Emulating bogus iterator implementation that passes empty RRSIGs.
     EXPECT_THROW(client_->load(Name("example.org"),
@@ -259,10 +297,22 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
     // Just to check that things get cleaned up
 
     for (int i = 1; i < 16; i++) {
+        SCOPED_TRACE("For throw count = " +
+                     boost::lexical_cast<std::string>(i));
         mem_sgmt_.setThrowCount(i);
-        EXPECT_THROW(client_->load(Name("example.org"),
-                                   TEST_DATA_DIR "/example.org.zone"),
-                     std::bad_alloc);
+        EXPECT_THROW({
+            shared_ptr<ZoneTableSegment> ztable_segment(
+                new test::ZoneTableSegmentTest(
+                    zclass_, mem_sgmt_));
+
+            // Include the InMemoryClient construction too here. Now,
+            // even allocations done from InMemoryClient constructor
+            // fail (due to MemorySegmentTest throwing) and we check for
+            // leaks when this happens.
+            InMemoryClient client2(ztable_segment, zclass_);
+            client2.load(Name("example.org"),
+                         TEST_DATA_DIR "/example.org.zone");
+        }, std::bad_alloc);
     }
     // Teardown checks for memory segment leaks
 }
@@ -383,7 +433,7 @@ TEST_F(MemoryClientTest, loadDuplicateType) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-duplicate-type-bad.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -392,7 +442,7 @@ TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-multiple-cname.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -401,7 +451,7 @@ TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-multiple-dname.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -410,7 +460,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-multiple-nsec3.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -419,7 +469,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-multiple-nsec3param.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -437,7 +487,7 @@ TEST_F(MemoryClientTest, loadWildcardNSThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-wildcard-ns.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -446,7 +496,7 @@ TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-wildcard-dname.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -455,7 +505,7 @@ TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-wildcard-nsec3.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -464,7 +514,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-nsec3-fewer-labels.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -473,7 +523,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-nsec3-more-labels.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -482,12 +532,12 @@ TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-cname-and-not-nsec-1.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
 
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-cname-and-not-nsec-2.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
 
     // Teardown checks for memory segment leaks
 }
@@ -513,7 +563,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-dname-ns-nonapex-1.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -522,7 +572,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-dname-ns-nonapex-2.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -532,7 +582,7 @@ TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
     EXPECT_THROW(client_->load(Name("example.org"),
                                TEST_DATA_DIR
                                "/example.org-rrsig-follows-nothing.zone"),
-                 InMemoryClient::AddError);
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
@@ -542,6 +592,33 @@ TEST_F(MemoryClientTest, loadRRSIGs) {
     EXPECT_EQ(1, client_->getZoneCount());
 }
 
+TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
+    vector<ConstRRsetPtr> rrsets_vec;
+
+    rrsets_vec.push_back(textToRRset("example.org. 3600 IN SOA "
+                                     "ns1.example.org. bugs.x.w.example.org. "
+                                     "2010012601 3600 300 3600000 1200",
+                                     zclass_, Name("example.org")));
+    RRsetPtr rrset(textToRRset("example.org. 3600 IN A 192.0.2.1\n"
+                               "example.org. 3600 IN A 192.0.2.2\n"));
+    RRsetPtr rrsig(textToRRset("example.org. 300 IN RRSIG "
+                               "A 5 3 3600 20000101000000 20000201000000 "
+                               "12345 example.org. FAKEFAKEFAKE"));
+    // textToRRset (correctly) consider this RDATA belongs to a different
+    // RRSIG, so we need to manually add it.
+    rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
+                                   "54321 example.org. FAKEFAKEFAKEFAKE"));
+    rrset->addRRsig(rrsig);
+
+    rrsets_vec.push_back(rrset);
+
+    EXPECT_THROW(
+        client_->load(Name("example.org"),
+                      *MockVectorIterator::makeIterator(rrsets_vec)),
+        ZoneDataUpdater::AddError);
+    // Teardown checks for memory segment leaks
+}
+
 TEST_F(MemoryClientTest, getZoneCount) {
     EXPECT_EQ(0, client_->getZoneCount());
     client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
@@ -631,6 +708,22 @@ TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
     EXPECT_THROW(iterator->getSOA(), isc::NotImplemented);
 }
 
+TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
+    vector<ConstRRsetPtr> rrsets_vec;
+    rrsets_vec.push_back(textToRRset("example.org. 3600 IN SOA "
+                                     "ns1.example.org. bugs.x.w.example.org. "
+                                     "2010012601 3600 300 3600000 1200",
+                                     zclass_, Name("example.org")));
+    rrsets_vec.push_back(RRsetPtr(new RRset(Name("example.org"), zclass_,
+                                            RRType::A(), RRTTL(3600))));
+
+    EXPECT_THROW(
+        client_->load(Name("example.org"),
+                      *MockVectorIterator::makeIterator(rrsets_vec)),
+        ZoneDataUpdater::AddError);
+    // Teardown checks for memory segment leaks
+}
+
 TEST_F(MemoryClientTest, findZoneData) {
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
@@ -682,15 +775,4 @@ TEST_F(MemoryClientTest, getJournalReaderNotImplemented) {
                  isc::NotImplemented);
 }
 
-// TODO (upon merge of #2268): Re-add (and modify not to need
-// InMemoryClient::add) the tests removed in
-// 7a628baa1a158b5837d6f383e10b30542d2ac59b. Maybe some of them
-// are really not needed.
-//
-// * MemoryClientTest::loadRRSIGsRdataMixedCoveredTypes
-// * MemoryClientTest::addRRsetToNonExistentZoneThrows
-// * MemoryClientTest::addOutOfZoneThrows
-// * MemoryClientTest::addNullRRsetThrows
-// * MemoryClientTest::addEmptyRRsetThrows
-// * MemoryClientTest::add
 }
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index a536bf5..4cd08c0 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -23,6 +23,7 @@
 #include "../../tests/faked_nsec3.h"
 
 #include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_updater.h>
 #include <datasrc/memory/rdata_serialization.h>
 #include <datasrc/data_source.h>
 #include <testutils/dnsmessage_test.h>
@@ -105,7 +106,8 @@ public:
         class_(RRClass::IN()),
         origin_("example.org"),
         zone_data_(ZoneData::create(mem_sgmt_, origin_)),
-        zone_finder_(*zone_data_, class_)
+        zone_finder_(*zone_data_, class_),
+        updater_(mem_sgmt_, class_, origin_, *zone_data_)
     {
         // Build test RRsets.  Below, we construct an RRset for
         // each textual RR(s) of zone_data, and assign it to the corresponding
@@ -190,130 +192,8 @@ public:
         ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
     }
 
-    // NSEC3-specific call for 'loading' data
-    void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
-        assert(rrset->getType() == RRType::NSEC3());
-
-        const generic::NSEC3& nsec3_rdata =
-             dynamic_cast<const generic::NSEC3&>(
-                  rrset->getRdataIterator()->getCurrent());
-
-        NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
-        if (nsec3_data == NULL) {
-             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
-             zone_data_->setNSEC3Data(nsec3_data);
-        } else {
-             const size_t salt_len = nsec3_data->getSaltLen();
-             const uint8_t* salt_data = nsec3_data->getSaltData();
-             const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
-
-             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
-                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
-                 (salt_data_2.size() != salt_len)) {
-                  isc_throw(isc::Unexpected,
-                            "NSEC3 with inconsistent parameters: " <<
-                            rrset->toText());
-             }
-
-             if ((salt_len > 0) &&
-                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
-                  isc_throw(isc::Unexpected,
-                            "NSEC3 with inconsistent parameters: " <<
-                            rrset->toText());
-             }
-        }
-
-        ZoneNode* node;
-        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
-
-        RdataSet* rdset = RdataSet::create(mem_sgmt_, encoder_,
-                                           rrset, ConstRRsetPtr());
-        RdataSet* old_rdset = node->setData(rdset);
-        if (old_rdset != NULL) {
-             RdataSet::destroy(mem_sgmt_, class_, old_rdset);
-        }
-        zone_data_->setSigned(true);
-    }
-
-    // simplified version of 'loading' data
-    void addZoneData(const ConstRRsetPtr rrset) {
-        ZoneNode* node = NULL;
-
-        if (rrset->getType() == RRType::NSEC3()) {
-            return (addZoneDataNSEC3(rrset));
-        } else if (rrset->getType() == RRType::NSEC()) {
-            zone_data_->setSigned(true);
-        }
-
-        zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
-
-        if (rrset->getType() == RRType::NS() &&
-            rrset->getName() != zone_data_->getOriginNode()->getName()) {
-            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
-        } else if (rrset->getType() == RRType::DNAME()) {
-            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
-        }
-
-        RdataSet* next_rds = node->getData();
-        RdataSet* rdataset =
-            RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
-        rdataset->next = next_rds;
-        node->setData(rdataset);
-
-        // find wildcard nodes in name (go through all of them in case there
-        // is a nonterminal one)
-        // Note that this method is pretty much equal to the 'real' loader;
-        // but less efficient
-        Name name(rrset->getName());
-        while (name.getLabelCount() > 1) {
-            if (name.isWildcard()) {
-                ZoneNode* wnode = NULL;
-                // add Wild node
-                zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
-                wnode->setFlag(ZoneData::WILDCARD_NODE);
-                // add wildcard name itself too
-                zone_data_->insertName(mem_sgmt_, name, &wnode);
-            }
-            name = name.split(1);
-        }
-
-        // 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());
-
-            NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
-            if (nsec3_data == NULL) {
-                nsec3_data = NSEC3Data::create(mem_sgmt_, param);
-                zone_data_->setNSEC3Data(nsec3_data);
-                zone_data_->setSigned(true);
-            } else {
-                size_t salt_len = nsec3_data->getSaltLen();
-                const uint8_t* salt_data = nsec3_data->getSaltData();
-                const vector<uint8_t>& salt_data_2 = param.getSalt();
-
-                if ((param.getHashalg() != nsec3_data->hashalg) ||
-                    (param.getIterations() != nsec3_data->iterations) ||
-                    (salt_data_2.size() != salt_len)) {
-                     isc_throw(isc::Unexpected,
-                               "NSEC3PARAM with inconsistent parameters: "
-                               << rrset->toText());
-                }
-
-                if ((salt_len > 0) &&
-                    (std::memcmp(&salt_data_2[0],
-                                 salt_data, salt_len) != 0)) {
-                     isc_throw(isc::Unexpected,
-                               "NSEC3PARAM with inconsistent parameters: "
-                               << rrset->toText());
-                }
-            }
-        }
+    void addToZoneData(const ConstRRsetPtr rrset) {
+        updater_.add(rrset, rrset->getRRsig());
     }
 
     // Some data to test with
@@ -323,7 +203,7 @@ public:
     MemorySegmentTest mem_sgmt_;
     memory::ZoneData* zone_data_;
     memory::InMemoryZoneFinder zone_finder_;
-    isc::datasrc::memory::RdataEncoder encoder_;
+    ZoneDataUpdater updater_;
 
     // Placeholder for storing RRsets to be checked with rrsetsCheck()
     vector<ConstRRsetPtr> actual_rrsets_;
@@ -538,7 +418,7 @@ TEST_F(InMemoryZoneFinderTest, constructor) {
 
 TEST_F(InMemoryZoneFinderTest, findCNAME) {
     // install CNAME RR
-    addZoneData(rr_cname_);
+    addToZoneData(rr_cname_);
 
     // Find A RR of the same.  Should match the CNAME
     findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
@@ -553,10 +433,10 @@ 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.
-    addZoneData(rr_child_ns_);
+    addToZoneData(rr_child_ns_);
     ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
         "cname.child.example.org. 300 IN CNAME target.child.example.org.");
-    addZoneData(rr_cname_under_cut_);
+    addToZoneData(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);
@@ -564,7 +444,7 @@ TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
 
 // Search under a DNAME record. It should return the DNAME
 TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
-    EXPECT_NO_THROW(addZoneData(rr_dname_));
+    EXPECT_NO_THROW(addToZoneData(rr_dname_));
     findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
              true, rr_dname_);
 }
@@ -572,8 +452,8 @@ TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
 // 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(addZoneData(rr_dname_));
-    EXPECT_NO_THROW(addZoneData(rr_dname_a_));
+    EXPECT_NO_THROW(addToZoneData(rr_dname_));
+    EXPECT_NO_THROW(addToZoneData(rr_dname_a_));
 
     const Name dname_name(rr_dname_->getName());
     findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
@@ -585,8 +465,8 @@ TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
 // 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) {
-    addZoneData(rr_child_ns_);
-    addZoneData(rr_child_dname_);
+    addToZoneData(rr_child_ns_);
+    addToZoneData(rr_child_dname_);
 
     Name lowName("below.dname.child.example.org.");
 
@@ -598,10 +478,10 @@ TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
 // Test adding child zones and zone cut handling
 TEST_F(InMemoryZoneFinderTest, delegationNS) {
     // add in-zone data
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_));
 
     // install a zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
 
     // below the zone cut
     findTest(Name("www.child.example.org"), RRType::A(),
@@ -618,7 +498,7 @@ TEST_F(InMemoryZoneFinderTest, delegationNS) {
     findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
 
     // unusual case of "nested delegation": the highest cut should be used.
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
     findTest(Name("www.grand.child.example.org"), RRType::A(),
              // note: !rr_grandchild_ns_
              ZoneFinder::DELEGATION, true, rr_child_ns_);
@@ -627,9 +507,9 @@ TEST_F(InMemoryZoneFinderTest, delegationNS) {
 TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
     // Similar setup to the previous one, but with DS RR at the delegation
     // point.
-    addZoneData(rr_ns_);
-    addZoneData(rr_child_ns_);
-    addZoneData(rr_child_ds_);
+    addToZoneData(rr_ns_);
+    addToZoneData(rr_child_ns_);
+    addToZoneData(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).
@@ -647,9 +527,9 @@ TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
 }
 
 TEST_F(InMemoryZoneFinderTest, findAny) {
-    EXPECT_NO_THROW(addZoneData(rr_a_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
-    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+    EXPECT_NO_THROW(addToZoneData(rr_a_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
 
     vector<ConstRRsetPtr> expected_sets;
 
@@ -668,7 +548,7 @@ TEST_F(InMemoryZoneFinderTest, findAny) {
     findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
 
     // add zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
 
     // zone cut
     findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
@@ -684,16 +564,16 @@ TEST_F(InMemoryZoneFinderTest, findAny) {
 TEST_F(InMemoryZoneFinderTest, glue) {
     // install zone data:
     // a zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
     // glue for this cut
-    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+    EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
     // a nested zone cut (unusual)
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
     // glue under the deeper zone cut
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
+    EXPECT_NO_THROW(addToZoneData(rr_grandchild_glue_));
     // glue 'at the' zone cut
-    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_ns_));
 
     // by default glue is hidden due to the zone cut
     findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
@@ -749,16 +629,16 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
     rr_a_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
                                 "A 5 3 3600 20120814220826 20120715220826 "
                                 "1234 example.com. FAKE"));
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
-    EXPECT_NO_THROW(addZoneData(rr_a_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
+    EXPECT_NO_THROW(addToZoneData(rr_ns_aaaa_));
+    EXPECT_NO_THROW(addToZoneData(rr_a_));
     if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
+        addToZoneData(rr_nsec3_);
         zone_data_->setSigned(true);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
+        addToZoneData(rr_nsec_);
         zone_data_->setSigned(true);
     }
 
@@ -805,7 +685,7 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
              expected_nsec, expected_flags, NULL, find_options);
 
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_ns_nsec_);
+        addToZoneData(rr_ns_nsec_);
         zone_data_->setSigned(true);
         if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
             expected_nsec = rr_ns_nsec_;
@@ -841,8 +721,8 @@ InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
     ConstRRsetPtr expected_nsec,
     ZoneFinder::FindResultFlags expected_flags)
 {
-    addZoneData(rr_emptywild_);
-    addZoneData(rr_under_wild_);
+    addToZoneData(rr_emptywild_);
+    addToZoneData(rr_under_wild_);
 
     // Sanity check: Should result in NXRRSET
     findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
@@ -854,10 +734,10 @@ InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
 
     // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
     // there are no sigs)
-    addZoneData(rr_nsec_);
-    addZoneData(rr_ent_nsec2_);
-    addZoneData(rr_ent_nsec3_);
-    addZoneData(rr_ent_nsec4_);
+    addToZoneData(rr_nsec_);
+    addToZoneData(rr_ent_nsec2_);
+    addToZoneData(rr_ent_nsec3_);
+    addToZoneData(rr_ent_nsec4_);
     zone_data_->setSigned(true);
 
     // Should result in NXRRSET, and RESULT_NSEC_SIGNED
@@ -915,14 +795,14 @@ InMemoryZoneFinderTest::emptyNodeCheck(
     for (int i = 0; names[i] != NULL; ++i) {
         ConstRRsetPtr rrset = textToRRset(string(names[i]) +
                                           " 300 IN A 192.0.2.1");
-        addZoneData(rrset);
+        addToZoneData(rrset);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
+        addToZoneData(rr_nsec3_);
         zone_data_->setSigned(true);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
+        addToZoneData(rr_nsec_);
         zone_data_->setSigned(true);
     }
 
@@ -989,15 +869,15 @@ InMemoryZoneFinderTest::wildcardCheck(
                                             "RRSIG CNAME " +
                                             string(rrsig_common)));
     }
-    addZoneData(rr_wild_);
-    addZoneData(rr_cnamewild_);
+    addToZoneData(rr_wild_);
+    addToZoneData(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) {
-        addZoneData(rr_nsec3_);
+        addToZoneData(rr_nsec3_);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
+        addToZoneData(rr_nsec_);
     }
 
     // Search at the parent. The parent will not have the A, but it will
@@ -1073,7 +953,7 @@ InMemoryZoneFinderTest::wildcardCheck(
                  wild_expected_flags, NULL, find_options, wild_ok);
     }
 
-    addZoneData(rr_under_wild_);
+    addToZoneData(rr_under_wild_);
     {
         SCOPED_TRACE("Search under non-wildcard");
         findTest(Name("bar.foo.wild.example.org"), RRType::A(),
@@ -1090,7 +970,7 @@ InMemoryZoneFinderTest::wildcardCheck(
     // 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) {
-        addZoneData(rr_wild_nsec_);
+        addToZoneData(rr_wild_nsec_);
         expected_wild_nsec = rr_wild_nsec_;
     }
     {
@@ -1127,8 +1007,8 @@ TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
  *     the wildcard defaults."
  */
 TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
-    addZoneData(rr_child_wild_);
-    addZoneData(rr_child_ns_);
+    addToZoneData(rr_child_wild_);
+    addToZoneData(rr_child_ns_);
 
     {
         SCOPED_TRACE("Looking under delegation point");
@@ -1149,12 +1029,12 @@ void
 InMemoryZoneFinderTest::anyWildcardCheck(
     ZoneFinder::FindResultFlags expected_flags)
 {
-    addZoneData(rr_wild_);
+    addToZoneData(rr_wild_);
     if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
+        addToZoneData(rr_nsec3_);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
+        addToZoneData(rr_nsec_);
     }
 
     vector<ConstRRsetPtr> expected_sets;
@@ -1206,12 +1086,12 @@ InMemoryZoneFinderTest::emptyWildcardCheck(
      *                 *
      *               wild
      */
-    addZoneData(rr_emptywild_);
+    addToZoneData(rr_emptywild_);
     if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
+        addToZoneData(rr_nsec3_);
     }
     if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
+        addToZoneData(rr_nsec_);
     }
 
     {
@@ -1263,7 +1143,7 @@ TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
 
 // Same as emptyWildcard, but with multiple * in the path.
 TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
-    addZoneData(rr_nested_emptywild_);
+    addToZoneData(rr_nested_emptywild_);
 
     {
         SCOPED_TRACE("Asking for the original record under wildcards");
@@ -1394,8 +1274,8 @@ InMemoryZoneFinderTest::doCancelWildcardCheck(
  * shouldn't be canceled isn't.
  */
 TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
+    addToZoneData(rr_wild_);
+    addToZoneData(rr_not_wild_);
 
     {
         SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
@@ -1405,7 +1285,7 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
     // 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.
-    addZoneData(rr_not_wild_another_);
+    addToZoneData(rr_not_wild_another_);
     {
         SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
         doCancelWildcardCheck();
@@ -1414,15 +1294,15 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
 
 // Same tests as cancelWildcard for NSEC3-signed zone
 TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
-    addZoneData(rr_nsec3_);
+    addToZoneData(rr_wild_);
+    addToZoneData(rr_not_wild_);
+    addToZoneData(rr_nsec3_);
 
     {
         SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
         doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
     }
-    addZoneData(rr_not_wild_another_);
+    addToZoneData(rr_not_wild_another_);
     {
         SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
         doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
@@ -1433,9 +1313,9 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
 // or without FIND_DNSSEC option.  NSEC should be returned only when the option
 // is given.
 TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
-    addZoneData(rr_nsec_);
+    addToZoneData(rr_wild_);
+    addToZoneData(rr_not_wild_);
+    addToZoneData(rr_nsec_);
 
     {
         SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
@@ -1443,7 +1323,7 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
                               ZoneFinder::FIND_DNSSEC);
         doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
     }
-    addZoneData(rr_not_wild_another_);
+    addToZoneData(rr_not_wild_another_);
     {
         SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
         doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
@@ -1464,7 +1344,7 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
                  DataSourceError);
 
     // Only having NSEC3PARAM isn't enough
-    addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
+    addToZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
                             "1 0 12 aabbccdd"));
     EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
                  DataSourceError);
@@ -1473,7 +1353,7 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
     // is guaranteed.
     const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
         string(nsec3_common);
-    addZoneData(textToRRset(ns1_nsec3_text));
+    addToZoneData(textToRRset(ns1_nsec3_text));
     EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
                  DataSourceError);
 }
@@ -1492,16 +1372,16 @@ public:
         // zzz.example.org:     hash=R5..
         const string apex_nsec3_text = string(apex_hash) + ".example.org." +
             string(nsec3_common);
-        addZoneData(textToRRset(apex_nsec3_text));
+        addToZoneData(textToRRset(apex_nsec3_text));
         const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
             string(nsec3_common);
-        addZoneData(textToRRset(ns1_nsec3_text));
+        addToZoneData(textToRRset(ns1_nsec3_text));
         const string w_nsec3_text = string(w_hash) + ".example.org." +
             string(nsec3_common);
-        addZoneData(textToRRset(w_nsec3_text));
+        addToZoneData(textToRRset(w_nsec3_text));
         const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
             string(nsec3_common);
-        addZoneData(textToRRset(zzz_nsec3_text));
+        addToZoneData(textToRRset(zzz_nsec3_text));
     }
 
 private:
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_test.h b/src/lib/datasrc/tests/memory/zone_table_segment_test.h
new file mode 100644
index 0000000..2078036
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_table_segment_test.h
@@ -0,0 +1,116 @@
+// 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 DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
+#define DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H 1
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_writer_local.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+// A special ZoneTableSegment that can be used for tests.  It can be
+// passed a MemorySegment that can be used later to test if all memory
+// was de-allocated on it.
+class ZoneTableSegmentTest : public ZoneTableSegment {
+public:
+    ZoneTableSegmentTest(isc::dns::RRClass rrclass,
+                         isc::util::MemorySegment& mem_sgmt) :
+        ZoneTableSegment(rrclass),
+        mem_sgmt_(mem_sgmt),
+        header_(ZoneTable::create(mem_sgmt_, rrclass))
+    {}
+
+    virtual ~ZoneTableSegmentTest() {
+        ZoneTable::destroy(mem_sgmt_, header_.getTable());
+    }
+
+    virtual ZoneTableHeader& getHeader() {
+        return (header_);
+    }
+
+    virtual const ZoneTableHeader& getHeader() const {
+        return (header_);
+    }
+
+    virtual isc::util::MemorySegment& getMemorySegment() {
+        return (mem_sgmt_);
+    }
+
+    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
+                                      const dns::Name& name,
+                                      const dns::RRClass& rrclass)
+    {
+        return (new Writer(this, load_action, name, rrclass));
+    }
+
+private:
+    isc::util::MemorySegment& mem_sgmt_;
+    ZoneTableHeader header_;
+
+    // A writer for this segment. The implementation is similar
+    // to ZoneWriterLocal, but all the error handling is stripped
+    // for simplicity. Also, we do everything inside the
+    // install(), for the same reason. We just need something
+    // inside the tests, not a full-blown implementation
+    // for background loading.
+    class Writer : public ZoneWriter {
+    public:
+        Writer(ZoneTableSegmentTest* segment, const LoadAction& load_action,
+               const dns::Name& name, const dns::RRClass& rrclass) :
+            segment_(segment),
+            load_action_(load_action),
+            name_(name),
+            rrclass_(rrclass)
+        {}
+
+        void load() {}
+
+        void install() {
+            ZoneTable* table(segment_->getHeader().getTable());
+            const ZoneTable::AddResult
+                result(table->addZone(segment_->getMemorySegment(), rrclass_,
+                                      name_,
+                                      load_action_(segment_->
+                                                   getMemorySegment())));
+            if (result.zone_data != NULL) {
+                ZoneData::destroy(segment_->getMemorySegment(),
+                                  result.zone_data, rrclass_);
+            }
+        }
+
+        virtual void cleanup() {}
+    private:
+        ZoneTableSegmentTest* segment_;
+        LoadAction load_action_;
+        dns::Name name_;
+        dns::RRClass rrclass_;
+    };
+};
+
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
index 6bdd737..ac114e2 100644
--- a/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
@@ -12,72 +12,86 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_writer_local.h>
+#include <datasrc/memory/zone_table_segment_local.h>
+#include <util/memory_segment_local.h>
+
 #include <gtest/gtest.h>
+#include <boost/scoped_ptr.hpp>
 
+using namespace isc::dns;
 using namespace isc::datasrc::memory;
 using namespace isc::data;
 using namespace isc::util;
 using namespace std;
+using boost::scoped_ptr;
 
 namespace {
 
 class ZoneTableSegmentTest : public ::testing::Test {
 protected:
     ZoneTableSegmentTest() :
-        config_(Element::fromJSON("{}")),
-        segment_(ZoneTableSegment::create((*config_.get())))
+        ztable_segment_(ZoneTableSegment::create(isc::data::NullElement(),
+                                                 RRClass::IN()))
     {}
 
-    ~ZoneTableSegmentTest() {
-        if (segment_ != NULL) {
-            ZoneTableSegment::destroy(segment_);
-        }
-    }
-
     void TearDown() {
-        // Catch any future leaks here.
-        const MemorySegment& mem_sgmt = segment_->getMemorySegment();
-        EXPECT_TRUE(mem_sgmt.allMemoryDeallocated());
-
-        ZoneTableSegment::destroy(segment_);
-        segment_ = NULL;
+        ZoneTableSegment::destroy(ztable_segment_);
+        ztable_segment_ = NULL;
     }
 
-    const ElementPtr config_;
-    ZoneTableSegment* segment_;
+    ZoneTableSegment* ztable_segment_;
 };
 
 
 TEST_F(ZoneTableSegmentTest, create) {
     // By default, a local zone table segment is created.
-    EXPECT_NE(static_cast<void*>(NULL), segment_);
+    EXPECT_NE(static_cast<void*>(NULL), ztable_segment_);
 }
 
 // Helper function to check const and non-const methods.
 template <typename TS, typename TH, typename TT>
 void
-testGetHeader(ZoneTableSegment* segment) {
-    TH& header = static_cast<TS*>(segment)->getHeader();
+testGetHeader(ZoneTableSegment* ztable_segment) {
+    TH& header = static_cast<TS*>(ztable_segment)->getHeader();
 
-    // The zone table is unset.
+    // The zone table must be set.
     TT* table = header.getTable();
-    EXPECT_EQ(static_cast<void*>(NULL), table);
+    EXPECT_NE(static_cast<void*>(NULL), table);
 }
 
 TEST_F(ZoneTableSegmentTest, getHeader) {
     // non-const version.
-    testGetHeader<ZoneTableSegment, ZoneTableHeader, ZoneTable>(segment_);
+    testGetHeader<ZoneTableSegment, ZoneTableHeader, ZoneTable>
+        (ztable_segment_);
 
     // const version.
     testGetHeader<const ZoneTableSegment, const ZoneTableHeader,
-                  const ZoneTable>(segment_);
+                  const ZoneTable>(ztable_segment_);
 }
 
 TEST_F(ZoneTableSegmentTest, getMemorySegment) {
     // This doesn't do anything fun except test the API.
-    MemorySegment& mem_sgmt = segment_->getMemorySegment();
-    EXPECT_TRUE(mem_sgmt.allMemoryDeallocated());
+    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
+    mem_sgmt.allMemoryDeallocated(); // use mem_sgmt
+}
+
+ZoneData*
+loadAction(MemorySegment&) {
+    // The function won't be called, so this is OK
+    return (NULL);
+}
+
+// Test we can get a writer.
+TEST_F(ZoneTableSegmentTest, getZoneWriter) {
+    scoped_ptr<ZoneWriter>
+        writer(ztable_segment_->getZoneWriter(loadAction, Name("example.org"),
+                                              RRClass::IN()));
+    // We have to get something
+    EXPECT_NE(static_cast<void*>(NULL), writer.get());
+    // And for now, it should be the local writer
+    EXPECT_NE(static_cast<void*>(NULL),
+              dynamic_cast<ZoneWriterLocal*>(writer.get()));
 }
 
 } // anonymous namespace
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
index 401d434..3c53a59 100644
--- a/src/lib/datasrc/tests/memory/zone_table_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include "memory_segment_test.h"
+
 #include <exceptions/exceptions.h>
 
 #include <util/memory_segment_local.h>
@@ -34,27 +36,6 @@ using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory::detail;
 
 namespace {
-// Memory segment specified for tests.  It normally behaves like a "local"
-// memory segment.  If "throw count" is set to non 0 via setThrowCount(),
-// it continues the normal behavior up to the specified number of calls to
-// allocate(), and throws an exception at the next call.
-class TestMemorySegment : public isc::util::MemorySegmentLocal {
-public:
-    TestMemorySegment() : throw_count_(0) {}
-    virtual void* allocate(size_t size) {
-        if (throw_count_ > 0) {
-            if (--throw_count_ == 0) {
-                throw std::bad_alloc();
-            }
-        }
-        return (isc::util::MemorySegmentLocal::allocate(size));
-    }
-    void setThrowCount(size_t count) { throw_count_ = count; }
-
-private:
-    size_t throw_count_;
-};
-
 class ZoneTableTest : public ::testing::Test {
 protected:
     ZoneTableTest() : zclass_(RRClass::IN()),
@@ -65,17 +46,17 @@ protected:
     {}
     ~ZoneTableTest() {
         if (zone_table != NULL) {
-            ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
+            ZoneTable::destroy(mem_sgmt_, zone_table);
         }
     }
     void TearDown() {
-        ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
+        ZoneTable::destroy(mem_sgmt_, zone_table);
         zone_table = NULL;
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
     }
     const RRClass zclass_;
     const Name zname1, zname2, zname3;
-    TestMemorySegment mem_sgmt_;
+    test::MemorySegmentTest mem_sgmt_;
     ZoneTable* zone_table;
 };
 
diff --git a/src/lib/datasrc/tests/memory/zone_writer_unittest.cc b/src/lib/datasrc/tests/memory/zone_writer_unittest.cc
new file mode 100644
index 0000000..13bcc3b
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_writer_unittest.cc
@@ -0,0 +1,240 @@
+// 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 <datasrc/memory/zone_writer_local.h>
+#include <datasrc/memory/zone_table_segment_local.h>
+#include <datasrc/memory/zone_data.h>
+
+#include <cc/data.h>
+#include <dns/rrclass.h>
+#include <dns/name.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
+
+using boost::scoped_ptr;
+using boost::bind;
+using isc::dns::RRClass;
+using isc::dns::Name;
+using namespace isc::datasrc::memory;
+
+namespace {
+
+class TestException {};
+
+class ZoneWriterLocalTest : public ::testing::Test {
+public:
+    ZoneWriterLocalTest() :
+        // FIXME: The NullElement probably isn't the best one, but we don't
+        // know how the config will look, so it just fills the argument
+        // (which is currently ignored)
+        segment_(ZoneTableSegment::create(isc::data::NullElement(),
+                                          RRClass::IN())),
+        writer_(new
+            ZoneWriterLocal(dynamic_cast<ZoneTableSegmentLocal*>(segment_.
+                                                                 get()),
+                            bind(&ZoneWriterLocalTest::loadAction, this, _1),
+                            Name("example.org"), RRClass::IN())),
+        load_called_(false),
+        load_throw_(false),
+        load_null_(false),
+        load_data_(false)
+    {}
+    void TearDown() {
+        // Release the writer
+        writer_.reset();
+    }
+protected:
+    scoped_ptr<ZoneTableSegment> segment_;
+    scoped_ptr<ZoneWriterLocal> writer_;
+    bool load_called_;
+    bool load_throw_;
+    bool load_null_;
+    bool load_data_;
+private:
+    ZoneData* loadAction(isc::util::MemorySegment& segment) {
+        // Make sure it is the correct segment passed. We know the
+        // exact instance, can compare pointers to them.
+        EXPECT_EQ(&segment_->getMemorySegment(), &segment);
+        // We got called
+        load_called_ = true;
+        if (load_throw_) {
+            throw TestException();
+        }
+
+        if (load_null_) {
+            // Be nasty to the caller and return NULL, which is forbidden
+            return (NULL);
+        }
+        ZoneData* data = ZoneData::create(segment, Name("example.org"));
+        if (load_data_) {
+            // Put something inside. The node itself should be enough for
+            // the tests.
+            ZoneNode* node(NULL);
+            data->insertName(segment, Name("subdomain.example.org"), &node);
+            EXPECT_NE(static_cast<ZoneNode*>(NULL), node);
+        }
+        return (data);
+    }
+};
+
+// We call it the way we are supposed to, check every callback is called in the
+// right moment.
+TEST_F(ZoneWriterLocalTest, correctCall) {
+    // Nothing called before we call it
+    EXPECT_FALSE(load_called_);
+
+    // Just the load gets called now
+    EXPECT_NO_THROW(writer_->load());
+    EXPECT_TRUE(load_called_);
+    load_called_ = false;
+
+    EXPECT_NO_THROW(writer_->install());
+    EXPECT_FALSE(load_called_);
+
+    // We don't check explicitly how this works, but call it to free memory. If
+    // everything is freed should be checked inside the TearDown.
+    EXPECT_NO_THROW(writer_->cleanup());
+}
+
+TEST_F(ZoneWriterLocalTest, loadTwice) {
+    // Load it the first time
+    EXPECT_NO_THROW(writer_->load());
+    EXPECT_TRUE(load_called_);
+    load_called_ = false;
+
+    // The second time, it should not be possible
+    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
+    EXPECT_FALSE(load_called_);
+
+    // The object should not be damaged, try installing and clearing now
+    EXPECT_NO_THROW(writer_->install());
+    EXPECT_FALSE(load_called_);
+
+    // We don't check explicitly how this works, but call it to free memory. If
+    // everything is freed should be checked inside the TearDown.
+    EXPECT_NO_THROW(writer_->cleanup());
+}
+
+// Try loading after call to install and call to cleanup. Both is
+// forbidden.
+TEST_F(ZoneWriterLocalTest, loadLater) {
+    // Load first, so we can install
+    EXPECT_NO_THROW(writer_->load());
+    EXPECT_NO_THROW(writer_->install());
+    // Reset so we see nothing is called now
+    load_called_ = false;
+
+    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
+    EXPECT_FALSE(load_called_);
+
+    // Cleanup and try loading again. Still shouldn't work.
+    EXPECT_NO_THROW(writer_->cleanup());
+
+    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
+    EXPECT_FALSE(load_called_);
+}
+
+// Try calling install at various bad times
+TEST_F(ZoneWriterLocalTest, invalidInstall) {
+    // Nothing loaded yet
+    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
+    EXPECT_FALSE(load_called_);
+
+    EXPECT_NO_THROW(writer_->load());
+    load_called_ = false;
+    // This install is OK
+    EXPECT_NO_THROW(writer_->install());
+    // But we can't call it second time now
+    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
+    EXPECT_FALSE(load_called_);
+}
+
+// We check we can clean without installing first and nothing bad
+// happens. We also misuse the testcase to check we can't install
+// after cleanup.
+TEST_F(ZoneWriterLocalTest, cleanWithoutInstall) {
+    EXPECT_NO_THROW(writer_->load());
+    EXPECT_NO_THROW(writer_->cleanup());
+
+    EXPECT_TRUE(load_called_);
+
+    // We cleaned up, no way to install now
+    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
+}
+
+// Test the case when load callback throws
+TEST_F(ZoneWriterLocalTest, loadThrows) {
+    load_throw_ = true;
+    EXPECT_THROW(writer_->load(), TestException);
+
+    // We can't install now
+    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
+    EXPECT_TRUE(load_called_);
+
+    // But we can cleanup
+    EXPECT_NO_THROW(writer_->cleanup());
+}
+
+// Check the strong exception guarantee - if it throws, nothing happened
+// to the content.
+TEST_F(ZoneWriterLocalTest, retry) {
+    // First attempt fails due to some exception.
+    load_throw_ = true;
+    EXPECT_THROW(writer_->load(), TestException);
+    // This one shall succeed.
+    load_called_ = load_throw_ = false;
+    // We want some data inside.
+    load_data_ = true;
+    EXPECT_NO_THROW(writer_->load());
+    // And this one will fail again. But the old data will survive.
+    load_data_ = false;
+    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
+
+    // The rest still works correctly
+    EXPECT_NO_THROW(writer_->install());
+    ZoneTable* const table(segment_->getHeader().getTable());
+    const ZoneTable::FindResult found(table->findZone(Name("example.org")));
+    ASSERT_EQ(isc::datasrc::result::SUCCESS, found.code);
+    // For some reason it doesn't seem to work by the ZoneNode typedef, using
+    // the full definition instead. At least on some compilers.
+    const isc::datasrc::memory::DomainTreeNode<RdataSet>* node;
+    EXPECT_EQ(isc::datasrc::memory::DomainTree<RdataSet>::EXACTMATCH,
+              found.zone_data->getZoneTree().
+              find(Name("subdomain.example.org"), &node));
+    EXPECT_NO_THROW(writer_->cleanup());
+}
+
+// Check the writer defends itsefl when load action returns NULL
+TEST_F(ZoneWriterLocalTest, loadNull) {
+    load_null_ = true;
+    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
+
+    // We can't install that
+    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
+
+    // It should be possible to clean up safely
+    EXPECT_NO_THROW(writer_->cleanup());
+}
+
+// Check the object cleans up in case we forget it.
+TEST_F(ZoneWriterLocalTest, autoCleanUp) {
+    // Load data and forget about it. It should get released
+    // when the writer itself is destroyed.
+    EXPECT_NO_THROW(writer_->load());
+}
+
+}
diff --git a/src/lib/datasrc/tests/test_client.h b/src/lib/datasrc/tests/test_client.h
index 2c692d3..1e35cd3 100644
--- a/src/lib/datasrc/tests/test_client.h
+++ b/src/lib/datasrc/tests/test_client.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TEST_DATA_SOURCE_CLIENT_H
-#define __TEST_DATA_SOURCE_CLIENT_H 1
+#ifndef TEST_DATA_SOURCE_CLIENT_H
+#define TEST_DATA_SOURCE_CLIENT_H 1
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
@@ -64,7 +64,7 @@ createSQLite3Client(dns::RRClass zclass, const dns::Name& zname,
 } // end of datasrc
 } // end of isc
 
-#endif  // __TEST_DATA_SOURCE_CLIENT_H
+#endif  // TEST_DATA_SOURCE_CLIENT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 14429ae..1a4cae2 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -14,14 +14,13 @@
 
 #include <exceptions/exceptions.h>
 
-#include <util/memory_segment_local.h>
-
 #include <dns/masterload.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
 #include <datasrc/zone.h>
 #include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
 
@@ -41,10 +40,12 @@
 using namespace std;
 using boost::shared_ptr;
 
+using namespace isc::data;
 using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::datasrc;
 using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::ZoneTableSegment;
 using namespace isc::testutils;
 
 namespace {
@@ -58,15 +59,17 @@ typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
 // This is the type used as the test parameter.  Note that this is
 // intentionally a plain old type (i.e. a function pointer), not a class;
 // otherwise it could cause initialization fiasco at the instantiation time.
-typedef DataSourceClientPtr (*ClientCreator)(MemorySegment&, RRClass,
-                                             const Name&);
+typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
 
 // Creator for the in-memory client to be tested
 DataSourceClientPtr
-createInMemoryClient(MemorySegment& mem_sgmt, RRClass zclass,
-                     const Name& zname)
+createInMemoryClient(RRClass zclass, const Name& zname)
 {
-    shared_ptr<InMemoryClient> client(new InMemoryClient(mem_sgmt, zclass));
+    const ElementPtr config(Element::fromJSON("{}"));
+    shared_ptr<ZoneTableSegment> ztable_segment(
+        ZoneTableSegment::create(*config, zclass));
+    shared_ptr<InMemoryClient> client(new InMemoryClient(ztable_segment,
+                                                         zclass));
     client->load(zname, TEST_ZONE_FILE);
 
     return (client);
@@ -78,7 +81,7 @@ addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
 }
 
 DataSourceClientPtr
-createSQLite3Client(MemorySegment&, RRClass zclass, const Name& zname) {
+createSQLite3Client(RRClass zclass, const Name& zname) {
     // We always begin with an empty template SQLite3 DB file and install
     // the zone data from the zone file to ensure both cases have the
     // same test data.
@@ -105,7 +108,7 @@ class ZoneFinderContextTest :
 {
 protected:
     ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
-        client_ = (*GetParam())(mem_sgmt_, qclass_, qzone_);
+        client_ = (*GetParam())(qclass_, qzone_);
         REQUESTED_A.push_back(RRType::A());
         REQUESTED_AAAA.push_back(RRType::AAAA());
         REQUESTED_BOTH.push_back(RRType::A());
@@ -116,7 +119,6 @@ protected:
         ASSERT_TRUE(finder_);
     }
 
-    MemorySegmentLocal mem_sgmt_;
     const RRClass qclass_;
     const Name qzone_;
     DataSourceClientPtr client_;
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 36a1cff..9572ed0 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ZONE_H
-#define __ZONE_H 1
+#ifndef ZONE_H
+#define ZONE_H 1
 
 #include <dns/name.h>
 #include <dns/rrset.h>
@@ -1065,7 +1065,7 @@ typedef boost::shared_ptr<ZoneJournalReader> ZoneJournalReaderPtr;
 } // end of datasrc
 } // end of isc
 
-#endif  // __ZONE_H
+#endif  // ZONE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/datasrc/zonetable.h b/src/lib/datasrc/zonetable.h
index 93a021c..911391c 100644
--- a/src/lib/datasrc/zonetable.h
+++ b/src/lib/datasrc/zonetable.h
@@ -12,8 +12,8 @@
 // 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
+#ifndef ZONETABLE_H
+#define ZONETABLE_H 1
 
 #include <util/memory_segment.h>
 
@@ -153,7 +153,7 @@ private:
 };
 }
 }
-#endif  // __ZONETABLE_H
+#endif  // ZONETABLE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 8cede9b..904bce3 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -18,19 +18,23 @@ CLEANFILES = *.gcno *.gcda
 
 lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
 libb10_dhcp___la_SOURCES  =
-libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
+libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
 libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
 libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
 libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
 libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
-libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
-libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
-libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
-libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
-libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
 libb10_dhcp___la_SOURCES += option.cc option.h
-libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
+libb10_dhcp___la_SOURCES += option_data_types.h
+libb10_dhcp___la_SOURCES += option_definition.cc option_definition.h
+libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
+libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
+libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
+libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
+libb10_dhcp___la_SOURCES += option6_int.h
+libb10_dhcp___la_SOURCES += option6_int_array.h
+libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
+libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
 
 libb10_dhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
 libb10_dhcp___la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
@@ -38,11 +42,14 @@ libb10_dhcp___la_LIBADD   = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 libb10_dhcp___la_LIBADD  += $(top_builddir)/src/lib/util/libb10-util.la
 libb10_dhcp___la_LDFLAGS  = -no-undefined -version-info 2:0:0
 
-libb10_dhcpsrv_la_SOURCES  = cfgmgr.cc cfgmgr.h
+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 += cfgmgr.cc cfgmgr.h
 libb10_dhcpsrv_la_SOURCES += duid.cc duid.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
+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
@@ -52,7 +59,8 @@ libb10_dhcpsrv_la_SOURCES += triplet.h
 
 libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
 libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libb10_dhcpsrv_la_LIBADD   = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_dhcpsrv_la_LIBADD   = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libb10_dhcpsrv_la_LIBADD  += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 libb10_dhcpsrv_la_LIBADD  += $(top_builddir)/src/lib/util/libb10-util.la
 libb10_dhcpsrv_la_LDFLAGS  = -no-undefined -version-info 2:0:0
 if HAVE_MYSQL
diff --git a/src/lib/dhcp/addr_utilities.cc b/src/lib/dhcp/addr_utilities.cc
index de1e8b4..6ac3f14 100644
--- a/src/lib/dhcp/addr_utilities.cc
+++ b/src/lib/dhcp/addr_utilities.cc
@@ -16,6 +16,7 @@
 #include <exceptions/exceptions.h>
 #include <dhcp/addr_utilities.h>
 
+using namespace isc;
 using namespace isc::asiolink;
 
 namespace {
@@ -45,10 +46,13 @@ const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
 /// @param len prefix length
 isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                             uint8_t len) {
-
-    uint8_t packed[V6ADDRESS_LEN];
+    if (len > 128) {
+        isc_throw(isc::BadValue,
+                  "Too large netmask. 0..128 is allowed in IPv6");
+    }
 
     // First we copy the whole address as 16 bytes.
+    uint8_t packed[V6ADDRESS_LEN];
     memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
 
     // If the length is divisible by 8, it is simple. We just zero out the host
@@ -86,11 +90,11 @@ isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& pref
 /// @param len netmask length (0-32)
 isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
                                             uint8_t len) {
-    uint32_t addr = prefix;
     if (len > 32) {
         isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
     }
 
+    uint32_t addr = prefix;
     return (IOAddress(addr & (~bitMask4[len])));
 }
 
@@ -103,11 +107,11 @@ isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& pref
 /// @param len netmask length (0-32)
 isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
                                            uint8_t len) {
-    uint32_t addr = prefix;
-    if (len>32) {
+    if (len > 32) {
         isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
     }
 
+    uint32_t addr = prefix;
     return (IOAddress(addr | bitMask4[len]));
 }
 
@@ -120,10 +124,13 @@ isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefi
 /// @param len netmask length (0-128)
 isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                            uint8_t len) {
-
-    uint8_t packed[V6ADDRESS_LEN];
+    if (len > 128) {
+        isc_throw(isc::BadValue,
+                  "Too large netmask. 0..128 is allowed in IPv6");
+    }
 
     // First we copy the whole address as 16 bytes.
+    uint8_t packed[V6ADDRESS_LEN];
     memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
 
     // if the length is divisible by 8, it is simple. We just fill the host part
diff --git a/src/lib/dhcp/addr_utilities.h b/src/lib/dhcp/addr_utilities.h
index 15532d0..a1d856c 100644
--- a/src/lib/dhcp/addr_utilities.h
+++ b/src/lib/dhcp/addr_utilities.h
@@ -12,6 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#ifndef ADDR_UTILITIES_H
+#define ADDR_UTILITIES_H
+
 #include <asiolink/io_address.h>
 
 namespace isc {
@@ -51,3 +54,5 @@ isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix
 
 };
 };
+
+#endif // ADDR_UTILITIES_H
diff --git a/src/lib/dhcp/alloc_engine.cc b/src/lib/dhcp/alloc_engine.cc
new file mode 100644
index 0000000..53ef7f3
--- /dev/null
+++ b/src/lib/dhcp/alloc_engine.cc
@@ -0,0 +1,276 @@
+// 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 <alloc_engine.h>
+#include <lease_mgr_factory.h>
+#include <string.h>
+
+#include <cstring>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+AllocEngine::IterativeAllocator::IterativeAllocator()
+    :Allocator() {
+}
+
+isc::asiolink::IOAddress
+AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& addr) {
+    uint8_t packed[V6ADDRESS_LEN];
+    int len;
+
+    // First we copy the whole address as 16 bytes.
+    if (addr.getFamily()==AF_INET) {
+        // IPv4
+        std::memcpy(packed, addr.getAddress().to_v4().to_bytes().data(), 4);
+        len = 4;
+    } else {
+        // IPv6
+        std::memcpy(packed, addr.getAddress().to_v6().to_bytes().data(), 16);
+        len = 16;
+    }
+
+    for (int i = len - 1; i >= 0; --i) {
+        ++packed[i];
+        if (packed[i] != 0) {
+            break;
+        }
+    }
+
+    return (IOAddress::from_bytes(addr.getFamily(), packed));
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
+                                             const DuidPtr&,
+                                             const IOAddress&) {
+
+    // Let's get the last allocated address. It is usually set correctly,
+    // but there are times when it won't be (like after removing a pool or
+    // perhaps restaring the server).
+    IOAddress last = subnet->getLastAllocated();
+
+    const Pool6Collection& pools = subnet->getPools();
+
+    if (pools.size() == 0) {
+        isc_throw(AllocFailed, "No pools defined in selected subnet");
+    }
+
+    // first we need to find a pool the last address belongs to.
+    Pool6Collection::const_iterator it;
+    for (it = pools.begin(); it != pools.end(); ++it) {
+        if ((*it)->inRange(last)) {
+            break;
+        }
+    }
+
+    // last one was bogus for one of several reasons:
+    // - we just booted up and that's the first address we're allocating
+    // - a subnet was removed or other reconfiguration just completed
+    // - perhaps allocation algorithm was changed
+    if (it == pools.end()) {
+        // ok to access first element directly. We checked that pools is non-empty
+        IOAddress next = pools[0]->getFirstAddress();
+        subnet->setLastAllocated(next);
+        return (next);
+    }
+
+    // Ok, we have a pool that the last address belonged to, let's use it.
+
+    IOAddress next = increaseAddress(last); // basically addr++
+    if ((*it)->inRange(next)) {
+        // the next one is in the pool as well, so we haven't hit pool boundary yet
+        subnet->setLastAllocated(next);
+        return (next);
+    }
+
+    // We hit pool boundary, let's try to jump to the next pool and try again
+    ++it;
+    if (it == pools.end()) {
+        // Really out of luck today. That was the last pool. Let's rewind
+        // to the beginning.
+        next = pools[0]->getFirstAddress();
+        subnet->setLastAllocated(next);
+        return (next);
+    }
+
+    // there is a next pool, let's try first adddress from it
+    next = (*it)->getFirstAddress();
+    subnet->setLastAllocated(next);
+    return (next);
+}
+
+AllocEngine::HashedAllocator::HashedAllocator()
+    :Allocator() {
+    isc_throw(NotImplemented, "Hashed allocator is not implemented");
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::HashedAllocator::pickAddress(const Subnet6Ptr&,
+                                             const DuidPtr&,
+                                             const IOAddress&) {
+    isc_throw(NotImplemented, "Hashed allocator is not implemented");
+}
+
+AllocEngine::RandomAllocator::RandomAllocator()
+    :Allocator() {
+    isc_throw(NotImplemented, "Random allocator is not implemented");
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::RandomAllocator::pickAddress(const Subnet6Ptr&,
+                                             const DuidPtr&,
+                                             const IOAddress&) {
+    isc_throw(NotImplemented, "Random allocator is not implemented");
+}
+
+
+AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
+    :attempts_(attempts) {
+    switch (engine_type) {
+    case ALLOC_ITERATIVE:
+        allocator_ = boost::shared_ptr<Allocator>(new IterativeAllocator());
+        break;
+    case ALLOC_HASHED:
+        allocator_ = boost::shared_ptr<Allocator>(new HashedAllocator());
+        break;
+    case ALLOC_RANDOM:
+        allocator_ = boost::shared_ptr<Allocator>(new RandomAllocator());
+        break;
+
+    default:
+        isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
+    }
+}
+
+Lease6Ptr
+AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
+                              const DuidPtr& duid,
+                              uint32_t iaid,
+                              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);
+    }
+
+    // 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 = createLease(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);
+            }
+        }
+    }
+
+    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);
+        // there's no existing lease for selected candidate, so it is
+        // free. Let's allocate it.
+        if (!existing) {
+            Lease6Ptr lease = createLease(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.
+        }
+
+        // continue trying allocation until we run out of attempts
+        // (or attempts are set to 0, which means infinite)
+        --i;
+    } while ( i || !attempts_);
+
+    isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
+              << " tries");
+}
+
+Lease6Ptr AllocEngine::createLease(const Subnet6Ptr& subnet,
+                                   const DuidPtr& duid,
+                                   uint32_t iaid,
+                                   const IOAddress& addr,
+                                   bool fake_allocation /*= false */ ) {
+
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid, iaid,
+                               subnet->getPreferred(), subnet->getValid(),
+                               subnet->getT1(), subnet->getT2(), subnet->getID()));
+
+    if (!fake_allocation) {
+        // That is a real (REQUEST) allocation
+        bool status = LeaseMgrFactory::instance().addLease(lease);
+
+        if (status) {
+
+            return (lease);
+        } else {
+            // One of many failures with LeaseMgr (e.g. lost connection to the
+            // database, database failed etc.). One notable case for that
+            // is that we are working in multi-process mode and we lost a race
+            // (some other process got that address first)
+            return (Lease6Ptr());
+        }
+    } else {
+        // That is only fake (SOLICIT without rapid-commit) allocation
+
+        // It is for advertise only. We should not insert the lease into LeaseMgr,
+        // but rather check that we could have inserted it.
+        Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(addr);
+        if (!existing) {
+            return (lease);
+        } else {
+            return (Lease6Ptr());
+        }
+    }
+}
+
+AllocEngine::~AllocEngine() {
+    // no need to delete allocator. smart_ptr will do the trick for us
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcp/alloc_engine.h b/src/lib/dhcp/alloc_engine.h
new file mode 100644
index 0000000..496703a
--- /dev/null
+++ b/src/lib/dhcp/alloc_engine.h
@@ -0,0 +1,228 @@
+// 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 ALLOC_ENGINE_H
+#define ALLOC_ENGINE_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <dhcp/duid.h>
+#include <dhcp/subnet.h>
+#include <asiolink/io_address.h>
+#include <dhcp/lease_mgr.h>
+
+namespace isc {
+namespace dhcp {
+
+/// An exception that is thrown when allocation module fails (e.g. due to
+/// lack of available addresses)
+class AllocFailed : public isc::Exception {
+public:
+
+    /// @brief constructor
+    ///
+    /// @param file name of the file, where exception occurred
+    /// @param line line of the file, where exception occurred
+    /// @param what text description of the issue that caused exception
+    AllocFailed(const char* file, size_t line, const char* what)
+        : isc::Exception(file, line, what) {}
+};
+
+/// @brief DHCPv4 and DHCPv6 allocation engine
+///
+/// This class represents DHCP allocation engine. It is responsible
+/// for picking subnets, choosing and allocating a lease, extending,
+/// renewing, releasing and possibly expiring leases.
+///
+/// @todo: Does not handle out of leases well
+/// @todo: Does not handle out of allocation attempts well
+class AllocEngine : public boost::noncopyable {
+protected:
+
+    /// @brief base class for all address/prefix allocation algorithms
+    ///
+    /// This is an abstract class that should not be used directly, but rather
+    /// specialized implementations should be used instead.
+    class Allocator {
+    public:
+
+        /// @brief picks one address out of available pools in a given subnet
+        ///
+        /// This method returns one address from the available pools in the
+        /// specified subnet. It should not check if the address is used or
+        /// reserved - AllocEngine will check that and will call pickAddress
+        /// again if necessary. The number of times this method is called will
+        /// increase as the number of available leases will decrease.
+        virtual isc::asiolink::IOAddress
+        pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                    const isc::asiolink::IOAddress& hint) = 0;
+
+        /// @brief virtual destructor
+        virtual ~Allocator() {
+        }
+    protected:
+    };
+
+    /// @brief Address/prefix allocator that iterates over all addresses
+    ///
+    /// This class implements iterative algorithm that returns all addresses in
+    /// a pool iteratively, one after another. Once the last address is reached,
+    /// it starts allocating from the beginning of the first pool (i.e. it loops
+    /// over).
+    class IterativeAllocator : public Allocator {
+    public:
+
+        /// @brief default constructor
+        ///
+        /// Does not do anything
+        IterativeAllocator();
+
+        /// @brief returns the next address from pools in a subnet
+        ///
+        /// @param subnet next address will be returned from pool of that subnet
+        /// @param duid Client's DUID (ignored)
+        /// @param hint client's hint (ignored)
+        /// @return the next address
+        virtual isc::asiolink::IOAddress
+            pickAddress(const Subnet6Ptr& subnet,
+                        const DuidPtr& duid,
+                        const isc::asiolink::IOAddress& hint);
+    private:
+
+        /// @brief returns an address by one
+        /// @param addr address to be increased
+        /// @return address increased by one
+        isc::asiolink::IOAddress increaseAddress(const isc::asiolink::IOAddress& addr);
+
+    };
+
+    /// @brief Address/prefix allocator that gets an address based on a hash
+    ///
+    /// @todo: This is a skeleton class for now and is missing implementation.
+    class HashedAllocator : public Allocator {
+    public:
+
+        /// @brief default constructor (does nothing)
+        HashedAllocator();
+
+        /// @brief returns an address based on hash calculated from client's DUID.
+        ///
+        /// @todo: Implement this method
+        ///
+        /// @param subnet an address will be picked from pool of that subnet
+        /// @param duid Client's DUID
+        /// @param hint a hint (last address that was picked)
+        /// @return selected address
+        virtual isc::asiolink::IOAddress pickAddress(const Subnet6Ptr& subnet,
+                                                     const DuidPtr& duid,
+                                                     const isc::asiolink::IOAddress& hint);
+    };
+
+    /// @brief Random allocator that picks address randomly
+    ///
+    /// @todo: This is a skeleton class for now and is missing implementation.
+    class RandomAllocator : public Allocator {
+    public:
+
+        /// @brief default constructor (does nothing)
+        RandomAllocator();
+
+        /// @brief returns an random address from pool of specified subnet
+        ///
+        /// @todo: Implement this method
+        ///
+        /// @param subnet an address will be picked from pool of that subnet
+        /// @param duid Client's DUID (ignored)
+        /// @param hint the last address that was picked (ignored)
+        /// @return a random address from the pool
+        virtual isc::asiolink::IOAddress
+        pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                    const isc::asiolink::IOAddress& hint);
+    };
+
+    public:
+
+    /// @brief specifies allocation type
+    typedef enum {
+        ALLOC_ITERATIVE, // iterative - one address after another
+        ALLOC_HASHED,    // hashed - client's DUID/client-id is hashed
+        ALLOC_RANDOM     // random - an address is randomly selected
+    } AllocType;
+
+
+    /// @brief Default constructor.
+    ///
+    /// Instantiates necessary services, required to run DHCPv6 server.
+    /// In particular, creates IfaceMgr that will be responsible for
+    /// network interaction. Will instantiate lease manager, and load
+    /// old or create new DUID.
+    ///
+    /// @param engine_type selects allocation algorithm
+    /// @param attempts number of attempts for each lease allocation before
+    ///        we give up (0 means unlimited)
+    AllocEngine(AllocType engine_type, unsigned int attempts);
+
+    /// @brief Allocates an IPv6 lease
+    ///
+    /// This method uses currently selected allocator to pick an address from
+    /// specified subnet, creates a lease for that address and then inserts
+    /// it into LeaseMgr (if this allocation is not fake).
+    ///
+    /// @param subnet subnet the allocation should come from
+    /// @param duid Client'd DUID
+    /// @param iaid iaid field from the IA_NA container that client sent
+    /// @param hint a hint that the client provided
+    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    ///        an address for SOLICIT that is not really allocated (true)
+    /// @return Allocated IPv6 lease (or NULL if allocation failed)
+    Lease6Ptr
+    allocateAddress6(const Subnet6Ptr& subnet,
+                     const DuidPtr& duid,
+                     uint32_t iaid,
+                     const isc::asiolink::IOAddress& hint,
+                     bool fake_allocation);
+
+    /// @brief Destructor. Used during DHCPv6 service shutdown.
+    virtual ~AllocEngine();
+private:
+
+    /// @brief creates a lease and inserts it in LeaseMgr if necessary
+    ///
+    /// Creates a lease based on specified parameters and tries to insert it
+    /// into the database. That may fail in some cases, i.e. when there is another
+    /// allocation process and we lost a race to a specific lease.
+    ///
+    /// @param subnet subnet the lease is allocated from
+    /// @param duid client's DUID
+    /// @param iaid IAID from the IA_NA container the client sent to us
+    /// @param addr an address that was selected and is confirmed to be available
+    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    ///        an address for SOLICIT that is not really allocated (true)
+    /// @return allocated lease (or NULL in the unlikely case of the lease just
+    ///        becomed unavailable)
+    Lease6Ptr createLease(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                          uint32_t iaid, const isc::asiolink::IOAddress& addr,
+                          bool fake_allocation = false);
+
+    /// @brief a pointer to currently used allocator
+    boost::shared_ptr<Allocator> allocator_;
+
+    /// @brief number of attempts before we give up lease allocation (0=unlimited)
+    unsigned int attempts_;
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif // ALLOC_ENGINE_H
diff --git a/src/lib/dhcp/cfgmgr.cc b/src/lib/dhcp/cfgmgr.cc
index d06544c..0e7c8f4 100644
--- a/src/lib/dhcp/cfgmgr.cc
+++ b/src/lib/dhcp/cfgmgr.cc
@@ -41,7 +41,7 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
     // configuration. Such requirement makes sense in IPv4, but not in IPv6.
     // The server does not need to have a global address (using just link-local
     // is ok for DHCPv6 server) from the pool it serves.
-    if (subnets6_.size() == 1) {
+    if ((subnets6_.size() == 1) && hint.getAddress().to_v6().is_link_local()) {
         return (subnets6_[0]);
     }
 
diff --git a/src/lib/dhcp/cfgmgr.h b/src/lib/dhcp/cfgmgr.h
index 2911d05..ea8125f 100644
--- a/src/lib/dhcp/cfgmgr.h
+++ b/src/lib/dhcp/cfgmgr.h
@@ -162,4 +162,4 @@ protected:
 } // namespace isc::dhcp
 } // namespace isc
 
-#endif
+#endif // CFGMGR_H
diff --git a/src/lib/dhcp/dhcp6.h b/src/lib/dhcp/dhcp6.h
index 15c306d..116019e 100644
--- a/src/lib/dhcp/dhcp6.h
+++ b/src/lib/dhcp/dhcp6.h
@@ -105,10 +105,11 @@ extern const int dhcpv6_type_name_max;
 
 /* DUID type definitions (RFC3315 section 9).
  */
-#define DUID_LLT        1
-#define DUID_EN         2
-#define DUID_LL         3
-#define DUID_UUID       4
+// see isc::dhcp::DUID::DUIDType enum in dhcp/duid.h
+// #define DUID_LLT        1
+// #define DUID_EN         2
+// #define DUID_LL         3
+// #define DUID_UUID       4
 
 // Define hardware types
 // Taken from http://www.iana.org/assignments/arp-parameters/
@@ -190,4 +191,4 @@ extern const int dhcpv6_type_name_max;
 #define IRT_DEFAULT     86400
 #define IRT_MINIMUM     600
 
-#endif
+#endif /* DHCP6_H */
diff --git a/src/lib/dhcp/duid.cc b/src/lib/dhcp/duid.cc
index db7ba25..01dcfe1 100644
--- a/src/lib/dhcp/duid.cc
+++ b/src/lib/dhcp/duid.cc
@@ -12,11 +12,13 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <vector>
 #include <exceptions/exceptions.h>
 #include <stdint.h>
 #include <util/io_utilities.h>
 #include <dhcp/duid.h>
+#include <vector>
+#include <sstream>
+#include <iomanip>
 
 namespace isc {
 namespace dhcp {
@@ -53,6 +55,21 @@ DUID::DUIDType DUID::getType() const {
     }
 }
 
+std::string DUID::toText() const {
+    std::stringstream tmp;
+    tmp << std::hex;
+    bool delim = false;
+    for (std::vector<uint8_t>::const_iterator it = duid_.begin();
+         it != duid_.end(); ++it) {
+        if (delim) {
+            tmp << ":";
+        }
+        tmp << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*it);
+        delim = true;
+    }
+    return (tmp.str());
+}
+
 bool DUID::operator == (const DUID& other) const {
     return (this->duid_ == other.duid_);
 }
diff --git a/src/lib/dhcp/duid.h b/src/lib/dhcp/duid.h
index 53257db..be575dd 100644
--- a/src/lib/dhcp/duid.h
+++ b/src/lib/dhcp/duid.h
@@ -12,11 +12,13 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#ifndef DUID_H
+#define DUID_H
+
+#include <asiolink/io_address.h>
+#include <vector>
 #include <stdint.h>
 #include <unistd.h>
-#include <vector>
-#include <asiolink/io_address.h>
-
 
 namespace isc {
 namespace dhcp {
@@ -59,17 +61,22 @@ class DUID {
     /// @brief returns DUID type
     DUIDType getType() const;
 
-    // compares two DUIDs
-    bool operator == (const DUID& other) const;
+    /// returns textual prepresentation (e.g. 00:01:02:03:ff)
+    std::string toText() const;
+
+    /// compares two DUIDs
+    bool operator==(const DUID& other) const;
 
-    // compares two DUIDs
-    bool operator != (const DUID& other) const;
+    /// compares two DUIDs
+    bool operator!=(const DUID& other) const;
 
  protected:
     /// the actual content of the DUID
     std::vector<uint8_t> duid_;
 };
 
+typedef boost::shared_ptr<DUID> DuidPtr;
+
 /// @brief Holds Client identifier or client IPv4 address
 ///
 /// This class is intended to be a generic IPv4 client identifier. It can hold
@@ -96,3 +103,5 @@ class ClientId : DUID {
 
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
+
+#endif /* DUID_H */
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index ecaa652..1c2a11c 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -247,6 +247,15 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
                 continue;
             }
 
+            // Bind link-local addresses only. Otherwise we bind several sockets
+            // on interfaces that have several global addresses. For examples
+            // with interface with 2 global addresses, we would bind 3 sockets
+            // (one for link-local and two for global). That would result in
+            // getting each message 3 times.
+            if (!addr->getAddress().to_v6().is_link_local()){
+                continue;
+            }
+
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
                 isc_throw(SocketConfigError, "failed to open unicast socket");
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index a7b9a78..1b15595 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -681,4 +681,4 @@ private:
 }; // namespace isc::dhcp
 }; // namespace isc
 
-#endif
+#endif // IFACE_MGR_H
diff --git a/src/lib/dhcp/lease_mgr.cc b/src/lib/dhcp/lease_mgr.cc
index 809c528..8fed916 100644
--- a/src/lib/dhcp/lease_mgr.cc
+++ b/src/lib/dhcp/lease_mgr.cc
@@ -13,16 +13,36 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <dhcp/lease_mgr.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <time.h>
 
 using namespace std;
 
 using namespace isc::dhcp;
 
-LeaseMgr::LeaseMgr(const LeaseMgr::ParameterMap& parameters)
-    : parameters_(parameters) {
-}
+Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
+               uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
+               uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
+    :type_(type), addr_(addr), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
+     preferred_lft_(preferred), valid_lft_(valid), t1_(t1), t2_(t2),
+     subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false),
+     fqdn_rev_(false) {
+    if (!duid) {
+        isc_throw(InvalidOperation, "DUID must be specified for a lease");
+    }
 
-LeaseMgr::~LeaseMgr() {
+    cltt_ = time(NULL);
 }
 
 std::string LeaseMgr::getParameter(const std::string& name) const {
@@ -76,3 +96,10 @@ Lease6::operator==(const Lease6& other) const {
         subnet_id_ == other.subnet_id_
         );
 }
+
+LeaseMgr::LeaseMgr(const LeaseMgr::ParameterMap& parameters)
+    : parameters_(parameters) {
+}
+
+LeaseMgr::~LeaseMgr() {
+}
diff --git a/src/lib/dhcp/lease_mgr.h b/src/lib/dhcp/lease_mgr.h
index 4b7c607..05eca4d 100644
--- a/src/lib/dhcp/lease_mgr.h
+++ b/src/lib/dhcp/lease_mgr.h
@@ -15,18 +15,21 @@
 #ifndef LEASE_MGR_H
 #define LEASE_MGR_H
 
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcp/option.h>
+#include <dhcp/subnet.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
 #include <fstream>
 #include <map>
 #include <string>
 #include <utility>
 #include <vector>
 
-#include <asiolink/io_address.h>
-#include <boost/shared_ptr.hpp>
-#include <dhcp/duid.h>
-#include <dhcp/option.h>
-#include <exceptions/exceptions.h>
-
 /// @file dhcp/lease_mgr.h
 /// @brief An abstract API for lease database
 ///
@@ -91,10 +94,6 @@ public:
         isc::Exception(file, line, what) {}
 };
 
-/// @brief specifies unique subnet identifier
-/// @todo: Move this to subnet.h once ticket #2237 is merged
-typedef uint32_t SubnetID;
-
 /// @brief Structure that holds a lease for IPv4 address
 ///
 /// For performance reasons it is a simple structure, not a class. If we chose
@@ -203,6 +202,10 @@ struct Lease6 {
         LEASE_IA_PD  /// the lease contains IPv6 prefix (for prefix delegation)
     } LeaseType;
 
+    Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
+           uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
+           uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);
+
     /// @brief specifies lease type (normal addr, temporary addr, prefix)
     LeaseType type_;
 
@@ -241,6 +244,8 @@ struct Lease6 {
     /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
     /// for the same IA, each must have consistent T1 and T2 values. Specified in
     /// seconds since cltt.
+    /// This value will also be useful for failover to calculate the next expected
+    /// client transmission time.
     uint32_t t1_;
 
     /// @brief T2 timer
@@ -330,21 +335,20 @@ typedef std::vector<Lease6Ptr> Lease6Collection;
 /// see the documentation of those classes for details.
 class LeaseMgr {
 public:
-
     /// Client Hardware address
     typedef std::vector<uint8_t> HWAddr;
 
     /// Database configuration parameter map
     typedef std::map<std::string, std::string> ParameterMap;
 
-    /// @brief The sole lease manager constructor
+    /// @brief Constructor
     ///
     /// @param parameters A data structure relating keywords and values
     ///        concerned with the database.
     LeaseMgr(const ParameterMap& parameters);
 
-    /// @brief Destructor (closes file)
-    virtual ~LeaseMgr();
+    /// @brief Destructor
+    ~LeaseMgr();
 
     /// @brief Adds an IPv4 lease.
     ///
@@ -542,10 +546,10 @@ public:
     /// As host reservation is outside of scope for 2012, support for hosts
     /// is currently postponed.
 
-protected:
     /// @brief returns value of the parameter
     std::string getParameter(const std::string& name) const;
 
+private:
     /// @brief list of parameters passed in dbconfig
     ///
     /// That will be mostly used for storing database name, username,
diff --git a/src/lib/dhcp/lease_mgr_factory.cc b/src/lib/dhcp/lease_mgr_factory.cc
index adc8ce0..08a04e4 100644
--- a/src/lib/dhcp/lease_mgr_factory.cc
+++ b/src/lib/dhcp/lease_mgr_factory.cc
@@ -28,6 +28,7 @@
 #include <exceptions/exceptions.h>
 #include <dhcp/lease_mgr_factory.h>
 
+#include <dhcp/memfile_lease_mgr.h>
 #ifdef HAVE_MYSQL
 #include <dhcp/mysql_lease_mgr.h>
 #endif
@@ -89,6 +90,10 @@ LeaseMgrFactory::create(const std::string& dbconfig) {
         return;
     }
 #endif
+    if (parameters[type] == string("memfile")) {
+        getLeaseMgrPtr().reset(new Memfile_LeaseMgr(parameters));
+        return;
+    }
 
     // Get here on no match
     isc_throw(InvalidType, "Database configuration parameter 'type' does "
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index 12e1bbd..99a3b91 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -23,6 +23,8 @@
 #include <dhcp/option.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option6_int_array.h>
 
 using namespace std;
 using namespace isc::dhcp;
@@ -34,6 +36,23 @@ std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
 // static array with factories for options
 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
 
+// Static container with DHCPv4 option definitions.
+OptionDefContainer LibDHCP::v4option_defs_;
+
+// Static container with DHCPv6 option definitions.
+OptionDefContainer LibDHCP::v6option_defs_;
+
+const OptionDefContainer&
+LibDHCP::getOptionDefs(Option::Universe u) {
+    switch (u) {
+    case Option::V4:
+        return (v4option_defs_);
+    case Option::V6:
+        return (v6option_defs_);
+    default:
+        isc_throw(isc::BadValue, "invalid universe " << u << " specified");
+    }
+}
 
 OptionPtr
 LibDHCP::optionFactory(Option::Universe u,
@@ -88,6 +107,11 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
                                               buf.begin() + offset,
                                               buf.begin() + offset + opt_len));
             break;
+        case D6O_ORO:
+            opt = OptionPtr(new Option6IntArray<uint16_t>(opt_type,
+                                                          buf.begin() + offset,
+                                                          buf.begin() + offset + opt_len));
+            break;
         default:
             opt = OptionPtr(new Option(Option::V6,
                                        opt_type,
@@ -201,3 +225,81 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
 
     return;
 }
+
+void
+LibDHCP::initStdOptionDefs(Option::Universe u) {
+    switch (u) {
+    case Option::V4:
+        initStdOptionDefs4();
+        break;
+    case Option::V6:
+        initStdOptionDefs6();
+        break;
+    default:
+        isc_throw(isc::BadValue, "invalid universe " << u << " specified");
+    }
+}
+
+void
+LibDHCP::initStdOptionDefs4() {
+    isc_throw(isc::NotImplemented, "initStdOptionDefs4 is not implemented");
+}
+
+void
+LibDHCP::initStdOptionDefs6() {
+    v6option_defs_.clear();
+
+    struct OptionParams {
+        std::string name;
+        uint16_t code;
+        OptionDefinition::DataType type;
+        bool array;
+    };
+    OptionParams params[] = {
+        { "CLIENTID", D6O_CLIENTID, OptionDefinition::BINARY_TYPE, false },
+        { "SERVERID", D6O_SERVERID, OptionDefinition::BINARY_TYPE, false },
+        { "IA_NA", D6O_IA_NA, OptionDefinition::RECORD_TYPE, false },
+        { "IAADDR", D6O_IAADDR, OptionDefinition::RECORD_TYPE, false },
+        { "ORO", D6O_ORO, OptionDefinition::UINT16_TYPE, true },
+        { "ELAPSED_TIME", D6O_ELAPSED_TIME, OptionDefinition::UINT16_TYPE, false },
+        { "STATUS_CODE", D6O_STATUS_CODE, OptionDefinition::RECORD_TYPE, false },
+        { "RAPID_COMMIT", D6O_RAPID_COMMIT, OptionDefinition::EMPTY_TYPE, false },
+        { "DNS_SERVERS", D6O_NAME_SERVERS, OptionDefinition::IPV6_ADDRESS_TYPE, true }
+    };
+    const int params_size = sizeof(params) / sizeof(params[0]);
+
+    for (int i = 0; i < params_size; ++i) {
+        OptionDefinitionPtr definition(new OptionDefinition(params[i].name,
+                                                            params[i].code,
+                                                            params[i].type,
+                                                            params[i].array));
+        switch(params[i].code) {
+        case D6O_IA_NA:
+            for (int j = 0; j < 3; ++j) {
+                definition->addRecordField(OptionDefinition::UINT32_TYPE);
+            }
+            break;
+        case D6O_IAADDR:
+            definition->addRecordField(OptionDefinition::IPV6_ADDRESS_TYPE);
+            definition->addRecordField(OptionDefinition::UINT32_TYPE);
+            definition->addRecordField(OptionDefinition::UINT32_TYPE);
+            break;
+        case D6O_STATUS_CODE:
+            definition->addRecordField(OptionDefinition::UINT16_TYPE);
+            definition->addRecordField(OptionDefinition::STRING_TYPE);
+            break;
+        default:
+            // The default case is intentionally left empty
+            // as it does not need any processing.
+            ;
+        }
+        try {
+            definition->validate();
+        } catch (const Exception& ex) {
+            isc_throw(isc::Unexpected, "internal server error: invalid definition of standard"
+                      << " DHCPv6 option (with code " << params[i].code << "): "
+                      << ex.what());
+        }
+        v6option_defs_.push_back(definition);
+    }
+}
diff --git a/src/lib/dhcp/libdhcp++.dox b/src/lib/dhcp/libdhcp++.dox
new file mode 100644
index 0000000..013b6f2
--- /dev/null
+++ b/src/lib/dhcp/libdhcp++.dox
@@ -0,0 +1,79 @@
+/**
+ at page libdhcp libdhcp++
+
+ at section libdhcpIntro Libdhcp++ Library Introduction
+
+libdhcp++ is an all-purpose DHCP-manipulation library, written in
+C++. It offers packet parsing and assembly, DHCPv4 and DHCPv6
+options parsing and ssembly, interface detection (currently on
+Linux systems only) and socket operations. It is a generic purpose library that
+can be used by server, client, relay, performance tools and other DHCP-related
+tools. For server specific library, see \ref libdhcpsrv. Please do not
+add any server-specific code to libdhcp++ and use \ref libdhcpsrv instead.
+
+The following classes for packet manipulation are implemented:
+
+- isc::dhcp::Pkt4 - represents DHCPv4 packet.
+- isc::dhcp::Pkt6 - represents DHCPv6 packet.
+
+There are two pointer types defined: Pkt4Ptr and Pkt6Ptr. They are
+smart pointer and are using boost::shared_ptr. There are not const
+versions defined, as we assume that hooks can modify any aspect of
+the packet at almost any stage of processing.
+
+Both packets use collection of Option objects to represent DHCPv4
+and DHCPv6 options. The base class -- Option -- can be used to
+represent generic option that contains collection of
+bytes. Depending on if the option is instantiated as v4 or v6
+option, it will adjust its header (DHCPv4 options use 1 octet for
+type and 1 octet for length, while DHCPv6 options use 2 bytes for
+each).
+
+There are many specialized classes that are intended to handle options with
+specific content:
+- isc::dhcp::Option4AddrLst -- DHCPv4 option, contains one or more IPv4 addresses;
+- isc::dhcp::Option6AddrLst -- DHCPv6 option, contains one or more IPv6 addresses;
+- isc::dhcp::Option6IAAddr -- DHCPv6 option, represents IAADDR_OPTION (an option that
+                    contains IPv6 address with extra parameters);
+- isc::dhcp::Option6IA -- DHCPv6 option used to store IA_NA and its suboptions.
+
+All options can store sub-options (i.e. options that are stored within option
+rather than in a message directly). This functionality is commonly used in
+DHCPv6, but is rarely used in DHCPv4. isc::dhcp::Option::addOption(),
+isc::dhcp::Option::delOption(), isc::dhcp::Option::getOption() can be used
+for that purpose.
+
+ at section libdhcpIfaceMgr Interface Manager
+
+Interface Manager (or IfaceMgr) is an abstraction layer about low-level
+network operations. In particlar, it provides information about existing
+network interfaces See isc::dhcp::IfaceMgr::Iface class and
+isc::dhcp::IfaceMgr::detectIfaces() and isc::dhcp::IfaceMgr::getIface().
+
+Currently there is interface detection is implemented in Linux only. There
+are plans to implement such support for other OSes, but they remain low
+priority for now.
+
+Generic parts of the code are isc::dhcp::IfaceMgr class in
+src/lib/dhcp/iface_mgr.cc file. OS-specific code is located in separate
+files, e.g. iface_mgr_linux.cc. Such separation should be maintained when
+additional code will be developed.
+
+For systems that interface detection is not supported on, there is a stub
+mechanism implemented. It assumes that interface name is read from a text
+file. This is a temporary solution and will be removed as soon as proper
+interface detection is implemented. It is not going to be developed further.
+To use this feature, store interfaces.txt file. It uses a simple syntax.
+Each line represents an interface name, followed by IPv4 or IPv6 address
+that follows it. This is usually link-local IPv6 address that the server
+should bind to. In theory this mechanism also supports IPv4, but it was
+never tested. The code currently supports only a single interface defined
+that way.
+
+Another useful methods are dedicated to transmission
+(isc::dhcp::IfaceMgr::send(), 2 overloads) and reception
+(isc::dhcp::IfaceMgr::receive4() and isc::dhcp::IfaceMgr::receive6()).
+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 53405b4..b848ad3 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// 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
@@ -15,9 +15,10 @@
 #ifndef LIBDHCP_H_
 #define LIBDHCP_H_
 
-#include <iostream>
-#include <util/buffer.h>
+#include <dhcp/option_definition.h>
 #include <dhcp/pkt6.h>
+#include <util/buffer.h>
+#include <iostream>
 
 namespace isc {
 namespace dhcp {
@@ -29,6 +30,12 @@ public:
     /// Map of factory functions.
     typedef std::map<unsigned short, Option::Factory*>  FactoryMap;
 
+    /// @brief Return collection of option definitions.
+    ///
+    /// @param u universe of the options (V4 or V6).
+    /// @return collection of option definitions.
+    static const OptionDefContainer& getOptionDefs(Option::Universe u);
+
     /// @brief Factory function to create instance of option.
     ///
     /// Factory method creates instance of specified option. The option
@@ -104,12 +111,54 @@ public:
     static void OptionFactoryRegister(Option::Universe u,
                                       uint16_t type,
                                       Option::Factory * factory);
-protected:
+
+    /// Initialize standard DHCP options (V4 or V6).
+    ///
+    /// The method creates option definitions for all options
+    /// (DHCPv4 or DHCPv6 depending on universe specified).
+    /// Currently DHCPv4 option definitions initialization is not
+    /// implemented thus this function will throw isc::NotImplemented
+    /// if V4 universe is specified.
+    ///
+    /// @param u universe
+    /// @throw isc::Unexpected if internal error occured during option
+    /// definitions creation.
+    /// @throw std::bad_alloc if system went out of memory.
+    /// @throw isc::NotImplemented when V4 universe specified.
+    static void initStdOptionDefs(Option::Universe u);
+
+private:
+
+    /// Initialize standard DHCPv4 option definitions.
+    ///
+    /// The method creates option definitions for all DHCPv4 options.
+    /// Currently this function is not implemented.
+    ///
+    /// @todo implemend this function.
+    ///
+    /// @throw isc::NotImplemeneted
+    static void initStdOptionDefs4();
+
+    /// Initialize standard DHCPv6 option definitions.
+    ///
+    /// The method creates option definitions for all DHCPv6 options.
+    ///
+    /// @throw isc::Unexpected if internal error occured during option
+    /// definitions creation.
+    /// @throw std::bad_alloc if system went out of memory.
+    static void initStdOptionDefs6();
+
     /// pointers to factories that produce DHCPv6 options
     static FactoryMap v4factories_;
 
     /// pointers to factories that produce DHCPv6 options
     static FactoryMap v6factories_;
+
+    /// Container with DHCPv4 option definitions.
+    static OptionDefContainer v4option_defs_;
+
+    /// Container with DHCPv6 option definitions.
+    static OptionDefContainer v6option_defs_;
 };
 
 }
diff --git a/src/lib/dhcp/libdhcsrv.dox b/src/lib/dhcp/libdhcsrv.dox
new file mode 100644
index 0000000..bb4a8ec
--- /dev/null
+++ b/src/lib/dhcp/libdhcsrv.dox
@@ -0,0 +1,86 @@
+/**
+ @page libdhcpsrv libdhcpsrv - Server DHCP library
+
+This library contains code useful for DHCPv4 and DHCPv6 server operations, like
+Lease Manager that stores leases information, configuration manager that stores
+configuration etc. The code here is server specific. For generic (useful in
+server, client, relay and other tools like perfdhcp) code, please see
+\ref libdhcp.
+
+This library contains several crucial elements of the DHCP server operation:
+
+- isc::dhcp::LeaseMgr - Lease Manager is a name for database backend that stores
+  leases.
+- isc::dhcp::CfgMgr - Configuration Manager that holds DHCP specific
+  configuration information (subnets, pools, options, timer values etc.) in
+  easy to use format.
+- AllocEngine - allocation engine that handles new requestes and allocates new
+  leases.
+
+ at section leasemgr Lease Manager
+
+LeaseMgr provides a common, unified abstract API for all database backends. All
+backends are derived from the base class isc::dhcp::LeaseMgr. Currently the
+only available backend is MySQL (see \ref isc::dhcp::MySqlLeaseMgr).
+
+ at section cfgmgr Configuration Manager
+
+Configuration Manager (\ref isc::dhcp::CfgMgr) stores configuration information
+necessary for DHCPv4 and DHCPv6 server operation. In particular, it stores
+subnets (\ref isc::dhcp::Subnet4 and \ref isc::dhcp::Subnet6) together with
+their pools (\ref isc::dhcp::Pool4 and \ref isc::dhcp::Pool6), options and
+other information specified by the used in BIND10 configuration.
+
+ at section allocengine Allocation Engine
+
+Allocation Engine (\ref isc::dhcp::AllocEngine) is what its name say - an engine
+that handles allocation of new leases. It takes parameters that the client
+provided (client-id, DUID, subnet, a hint if the user provided one, etc.) and
+then attempts to allocate a lease.
+
+There is no single best soluction to the address assignment problem. Server
+is expected to pick an address from its available pools is currently not used.
+There are many possible algorithms that can do that, each with its own advantages
+and drawbacks. This allocation engine must provide robust operation is radically
+different scenarios, so there address selection problem was abstracted into
+separate module, called allocator. Its sole purpose is to pick an address from
+a pool. Allocation engine will then check if the picked address is free and if
+it is not, then will ask allocator to pick again.
+
+At lease 3 allocators will be implemented:
+
+- Iterative - it iterates over all addresses in available pools, one
+by one. The advantages of this approach are speed (typically it only needs to
+increase last address), the guarantee to cover all addresses and predictability.
+This allocator behaves very good in case of nearing depletion. Even when pools
+are almost completely allocated, it still will be able to allocate outstanding
+leases efficiently. Predictability can also be considered a serious flaw in
+some environments, as prediction of the next address is trivial and can be
+leveraged by an attacker. Another drawback of this allocator is that it does
+not attempt to give the same address to returning clients (clients that released
+or expired their leases and are requesting a new lease will likely to get a 
+different lease). This allocator is implemented in \ref isc::dhcp::AllocEngine::IterativeAllocator.
+
+- Hashed - ISC-DHCP uses hash of the client-id or DUID to determine, which
+address is tried first. If that address is not available, the result is hashed
+again. That procedure is repeated until available address is found or there
+are no more addresses left. The benefit of that approach is that it provides
+a relative lease stability, so returning old clients are likely to get the same
+address again. The drawbacks are increased computation cost, as each iteration
+requires use of a hashing function. That is especially difficult when the 
+pools are almost depleted. It also may be difficult to guarantee that the
+repeated hashing will iterate over all available addresses in all pools. Flawed
+hash algorithm can go into cycles that iterate over only part of the addresses.
+It is difficult to detect such issues as only some initial seed (client-id
+or DUID) values may trigger short cycles. This allocator is currently not
+implemented.
+
+- Random - Another possible approach to address selection is randomization. This
+allocator can pick an address randomly from the configured pool. The benefit
+of this approach is that it is easy to implement and makes attacks based on
+address prediction more difficult. The drawback of this approach is that
+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/dhcp/memfile_lease_mgr.cc b/src/lib/dhcp/memfile_lease_mgr.cc
new file mode 100644
index 0000000..1424b39
--- /dev/null
+++ b/src/lib/dhcp/memfile_lease_mgr.cc
@@ -0,0 +1,132 @@
+// 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 <iostream>
+
+#include <dhcp/memfile_lease_mgr.h>
+
+using namespace isc::dhcp;
+
+Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
+    : LeaseMgr(parameters) {
+    std::cout << "Warning: Using memfile database backend. It is usable for" << std::endl;
+    std::cout << "Warning: limited testing only. File support not implemented yet." << std::endl;
+    std::cout << "Warning: Leases will be lost after restart." << std::endl;
+}
+
+Memfile_LeaseMgr::~Memfile_LeaseMgr() {
+}
+
+bool Memfile_LeaseMgr::addLease(const Lease4Ptr&) {
+    return (false);
+}
+
+bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
+    if (getLease6(lease->addr_)) {
+        // there is a lease with specified address already
+        return (false);
+    }
+    storage6_.insert(lease);
+    return (true);
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&) const {
+    return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
+    return (Lease4Collection());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&,
+                                      SubnetID) const {
+    return (Lease4Ptr());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr&,
+                                      SubnetID) const {
+    return (Lease4Ptr());
+}
+
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId&,
+                                      SubnetID) const {
+    return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
+    return (Lease4Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
+    Lease6Storage::iterator l = storage6_.find(addr);
+    if (l == storage6_.end()) {
+        return (Lease6Ptr());
+    } else {
+        return (*l);
+    }
+}
+
+Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& , uint32_t ) const {
+    return (Lease6Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
+                                      SubnetID subnet_id) const {
+    /// @todo: Slow, naive implementation. Write it using additional indexes
+    for (Lease6Storage::iterator l = storage6_.begin(); l != storage6_.end(); ++l) {
+        if ( (*((*l)->duid_) == duid) &&
+             ( (*l)->iaid_ == iaid) &&
+             ( (*l)->subnet_id_ == subnet_id)) {
+            return (*l);
+        }
+    }
+    return (Lease6Ptr());
+}
+
+void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& ) {
+}
+
+void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& ) {
+
+}
+
+bool Memfile_LeaseMgr::deleteLease4(const isc::asiolink::IOAddress&) {
+    return (false);
+}
+
+bool Memfile_LeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
+    Lease6Storage::iterator l = storage6_.find(addr);
+    if (l == storage6_.end()) {
+        // no such lease
+        return (false);
+    } else {
+        storage6_.erase(l);
+        return (true);
+    }
+}
+
+std::string Memfile_LeaseMgr::getDescription() const {
+    return (std::string("This is a dummy memfile backend implementation.\n"
+                        "It does not offer any useful lease management and its only\n"
+                        "purpose is to test abstract lease manager API."));
+}
+
+void
+Memfile_LeaseMgr::commit() {
+}
+
+void
+Memfile_LeaseMgr::rollback() {
+}
diff --git a/src/lib/dhcp/memfile_lease_mgr.h b/src/lib/dhcp/memfile_lease_mgr.h
new file mode 100644
index 0000000..e3f415d
--- /dev/null
+++ b/src/lib/dhcp/memfile_lease_mgr.h
@@ -0,0 +1,241 @@
+// 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 MEMFILE_LEASE_MGR_H
+#define MEMFILE_LEASE_MGR_H
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/indexed_by.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/member.hpp>
+
+#include <dhcp/lease_mgr.h>
+
+namespace isc {
+namespace dhcp {
+
+// This is a concrete implementation of a Lease database.
+//
+// It is for testing purposes only. It is NOT a production code.
+//
+// It does not do anything useful now, and is used for abstract LeaseMgr
+// class testing. It may later evolve into more useful backend if the
+// need arises. We can reuse code from memfile benchmark. See code in
+// tests/tools/dhcp-ubench/memfile_bench.{cc|h}
+class Memfile_LeaseMgr : public LeaseMgr {
+public:
+
+    /// @brief The sole lease manager constructor
+    ///
+    /// dbconfig is a generic way of passing parameters. Parameters
+    /// are passed in the "name=value" format, separated by spaces.
+    /// Values may be enclosed in double quotes, if needed.
+    ///
+    /// @param parameters A data structure relating keywords and values
+    ///        concerned with the database.
+    Memfile_LeaseMgr(const ParameterMap& parameters);
+
+    /// @brief Destructor (closes file)
+    virtual ~Memfile_LeaseMgr();
+
+    /// @brief Adds an IPv4 lease.
+    ///
+    /// @todo Not implemented yet
+    /// @param lease lease to be added
+    virtual bool addLease(const Lease4Ptr& lease);
+
+    /// @brief Adds an IPv6 lease.
+    ///
+    /// @param lease lease to be added
+    virtual bool addLease(const Lease6Ptr& lease);
+
+    /// @brief Returns existing IPv4 lease for specified IPv4 address.
+    ///
+    /// @todo Not implemented yet
+    /// @param addr address of the searched lease
+    ///
+    /// @return a collection of leases
+    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
+
+    /// @brief Returns existing IPv4 lease for specific address and subnet
+    ///
+    /// @todo Not implemented yet
+    /// @param addr address of the searched lease
+    /// @param subnet_id ID of the subnet the lease must belong to
+    ///
+    /// @return smart pointer to the lease (or NULL if a lease is not found)
+    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
+                                SubnetID subnet_id) const;
+
+    /// @brief Returns existing IPv4 leases for specified hardware address.
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// Although in the usual case there will be only one lease, for mobile
+    /// clients or clients with multiple static/fixed/reserved leases there
+    /// can be more than one. Thus return type is a container, not a single
+    /// pointer.
+    ///
+    /// @param hwaddr hardware address of the client
+    ///
+    /// @return lease collection
+    virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
+
+    /// @brief Returns existing IPv4 leases for specified hardware address
+    ///        and a subnet
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// There can be at most one lease for a given HW address in a single
+    /// pool, so this method with either return a single lease or NULL.
+    ///
+    /// @param hwaddr hardware address of the client
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    ///
+    /// @return a pointer to the lease (or NULL if a lease is not found)
+    virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+                                SubnetID subnet_id) const;
+
+    /// @brief Returns existing IPv4 lease for specified client-id
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param clientid client identifier
+    virtual Lease4Collection getLease4(const ClientId& clientid) const;
+
+    /// @brief Returns existing IPv4 lease for specified client-id
+    ///
+    /// There can be at most one lease for a given HW address in a single
+    /// pool, so this method with either return a single lease or NULL.
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param clientid client identifier
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    ///
+    /// @return a pointer to the lease (or NULL if a lease is not found)
+    virtual Lease4Ptr getLease4(const ClientId& clientid,
+                                SubnetID subnet_id) const;
+
+    /// @brief Returns existing IPv6 lease for a given IPv6 address.
+    ///
+    /// @param addr address of the searched lease
+    ///
+    /// @return smart pointer to the lease (or NULL if a lease is not found)
+    Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
+
+    /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param duid client DUID
+    /// @param iaid IA identifier
+    ///
+    /// @return collection of IPv6 leases
+    Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
+
+    /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param duid client DUID
+    /// @param iaid IA identifier
+    /// @param subnet_id identifier of the subnet the lease must belong to
+    ///
+    /// @return smart pointer to the lease (or NULL if a lease is not found)
+    Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
+
+    /// @brief Updates IPv4 lease.
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param lease4 The lease to be updated.
+    ///
+    /// If no such lease is present, an exception will be thrown.
+    void updateLease4(const Lease4Ptr& lease4);
+
+    /// @brief Updates IPv4 lease.
+    ///
+    /// @todo Not implemented yet
+    ///
+    /// @param lease4 The lease to be updated.
+    ///
+    /// If no such lease is present, an exception will be thrown.
+    void updateLease6(const Lease6Ptr& lease6);
+
+    /// @brief Deletes a lease.
+    ///
+    /// @param addr IPv4 address of the lease to be deleted.
+    ///
+    /// @return true if deletion was successful, false if no such lease exists
+    virtual bool deleteLease4(const isc::asiolink::IOAddress& addr);
+
+    /// @brief Deletes a lease.
+    ///
+    /// @param addr IPv4 address of the lease to be deleted.
+    ///
+    /// @return true if deletion was successful, false if no such lease exists
+    bool deleteLease6(const isc::asiolink::IOAddress& addr);
+
+    /// @brief Returns backend name.
+    ///
+    /// Each backend have specific name, e.g. "mysql" or "sqlite".
+    std::string getName() const { return ("memfile"); }
+
+    /// @brief Returns description of the backend.
+    ///
+    /// This description may be multiline text that describes the backend.
+    std::string getDescription() const;
+
+    /// @brief Returns backend version.
+    virtual std::pair<uint32_t, uint32_t> getVersion() const {
+        return (std::make_pair(1, 0));
+    }
+
+    /// @brief Commit Transactions
+    ///
+    /// Commits all pending database operations.  On databases that don't
+    /// support transactions, this is a no-op.
+    virtual void commit();
+
+    /// @brief Rollback Transactions
+    ///
+    /// Rolls back all pending database operations.  On databases that don't
+    /// support transactions, this is a no-op.
+    virtual void rollback();
+
+    using LeaseMgr::getParameter;
+
+protected:
+
+    typedef boost::multi_index_container< // this is a multi-index container...
+    Lease6Ptr, // it will hold shared_ptr to leases6
+        boost::multi_index::indexed_by< // and will be sorted by
+            // IPv6 address that are unique. That particular key is a member
+            // of the Lease6 structure, is of type IOAddress and can be accessed
+            // by doing &Lease6::addr_
+            boost::multi_index::ordered_unique< 
+                boost::multi_index::member<Lease6, isc::asiolink::IOAddress, &Lease6::addr_> 
+            >
+        >
+    > Lease6Storage; // Let the whole contraption be called Lease6Storage.
+
+    Lease6Storage storage6_;
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // MEMFILE_LEASE_MGR_HSE4
+
diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h
index 3bedc6d..01a8a4b 100644
--- a/src/lib/dhcp/option4_addrlst.h
+++ b/src/lib/dhcp/option4_addrlst.h
@@ -20,6 +20,7 @@
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_array.hpp>
+#include <asiolink/io_address.h>
 #include <util/buffer.h>
 #include <dhcp/option.h>
 
diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc
index 65be711..beba75f 100644
--- a/src/lib/dhcp/option6_ia.cc
+++ b/src/lib/dhcp/option6_ia.cc
@@ -29,7 +29,7 @@ namespace isc {
 namespace dhcp {
 
 Option6IA::Option6IA(uint16_t type, uint32_t iaid)
-    :Option(Option::V6, type), iaid_(iaid) {
+    :Option(Option::V6, type), iaid_(iaid), t1_(0), t2_(0) {
 }
 
 Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h
new file mode 100644
index 0000000..5fd5c19
--- /dev/null
+++ b/src/lib/dhcp/option6_int.h
@@ -0,0 +1,189 @@
+// 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 OPTION6_INT_H_
+#define OPTION6_INT_H_
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <util/io_utilities.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with single value.
+/// This value is of integer type and can be any of the following:
+/// - uint8_t,
+/// - uint16_t,
+/// - uint32_t,
+/// - int8_t,
+/// - int16_t,
+/// - int32_t.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6Int: public Option {
+
+public:
+    /// @brief Constructor.
+    ///
+    /// @param type option type.
+    /// @param value option value.
+    ///
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6Int(uint16_t type, T value)
+        : Option(Option::V6, type), value_(value) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+    }
+
+    /// @brief Constructor.
+    ///
+    /// This constructor creates option from a buffer. This construtor
+    /// may throw exception if \ref unpack function throws during buffer
+    /// parsing.
+    ///
+    /// @param type option type.
+    /// @param begin iterator to first byte of option data.
+    /// @param end iterator to end of option data (first byte after option end).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6Int(uint16_t type, OptionBufferConstIter begin,
+               OptionBufferConstIter end)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(begin, end);
+    }
+
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf buffer (option will be stored here)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    void pack(isc::util::OutputBuffer& buf) {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        // Depending on the data type length we use different utility functions
+        // writeUint16 or writeUint32 which write the data in the network byte
+        // order to the provided buffer. The same functions can be safely used
+        // for either unsiged or signed integers so there is not need to create
+        // special cases for intX_t types.
+        switch (OptionDataTypes<T>::len) {
+        case 1:
+            buf.writeUint8(value_);
+            break;
+        case 2:
+            buf.writeUint16(value_);
+            break;
+        case 4:
+            buf.writeUint32(value_);
+            break;
+        default:
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        LibDHCP::packOptions6(buf, options_);
+    }
+
+    /// @brief Parses received buffer
+    ///
+    /// Parses received buffer and returns offset to the first unused byte after
+    /// parsed option.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    ///
+    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
+    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+        if (distance(begin, end) < sizeof(T)) {
+            isc_throw(OutOfRange, "Option " << getType() << " truncated");
+        }
+        // @todo consider what to do if buffer is longer than data type.
+
+        // Depending on the data type length we use different utility functions
+        // readUint16 or readUint32 which read the data laid in the network byte
+        // order from the provided buffer. The same functions can be safely used
+        // for either unsiged or signed integers so there is not need to create
+        // special cases for intX_t types.
+        int data_size_len = OptionDataTypes<T>::len;
+        switch (data_size_len) {
+        case 1:
+            value_ = *begin;
+            break;
+        case 2:
+            value_ = isc::util::readUint16(&(*begin));
+            break;
+        case 4:
+            value_ = isc::util::readUint32(&(*begin));
+            break;
+        default:
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        // Use local variable to set a new value for this iterator.
+        // When using OptionDataTypes<T>::len directly some versions
+        // of clang complain about unresolved reference to
+        // OptionDataTypes structure during linking.
+        begin += data_size_len;
+        LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
+    }
+
+    /// @brief Set option value.
+    ///
+    /// @param value new option value.
+    void setValue(T value) { value_ = value; }
+
+    /// @brief Return option value.
+    ///
+    /// @return option value.
+    T getValue() const { return value_; }
+
+    /// @brief returns complete length of option
+    ///
+    /// Returns length of this option, including option header and suboptions
+    ///
+    /// @return length of this option
+    virtual uint16_t len() {
+        uint16_t length = OPTION6_HDR_LEN + sizeof(T);
+        // length of all suboptions
+        for (Option::OptionCollection::iterator it = options_.begin();
+             it != options_.end();
+             ++it) {
+            length += (*it).second->len();
+        }
+        return (length);
+    }
+
+private:
+
+    T value_;  ///< Value conveyed by the option.
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_H_ */
diff --git a/src/lib/dhcp/option6_int_array.h b/src/lib/dhcp/option6_int_array.h
new file mode 100644
index 0000000..57aad1e
--- /dev/null
+++ b/src/lib/dhcp/option6_int_array.h
@@ -0,0 +1,228 @@
+// 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 OPTION6_INT_ARRAY_H_
+#define OPTION6_INT_ARRAY_H_
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <util/io_utilities.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with array of
+/// integer values. The type of the elements in the array can be
+/// any of the following:
+/// - uint8_t,
+/// - uint16_t,
+/// - uint32_t,
+/// - int8_t,
+/// - int16_t,
+/// - int32_t.
+///
+/// @warning Since this option may convey variable number of integer
+/// values, sub-options are should not be added in this option as
+/// there is no way to distinguish them from other data. The API will
+/// allow addition of sub-options but they will be ignored during
+/// packing and unpacking option data.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6IntArray: public Option {
+
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Creates option with empty values vector.
+    ///
+    /// @param type option type.
+    ///
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type)
+        : Option(Option::V6, type),
+          values_(0) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+    }
+
+    /// @brief Constructor.
+    ///
+    /// @param type option type.
+    /// @param buf buffer with option data (must not be empty).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is empty or its length
+    /// is not multiple of size of the data type in bytes.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type, const OptionBuffer& buf)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(buf.begin(), buf.end());
+    }
+
+    /// @brief Constructor.
+    ///
+    /// This constructor creates option from a buffer. This construtor
+    /// may throw exception if \ref unpack function throws during buffer
+    /// parsing.
+    ///
+    /// @param type option type.
+    /// @param begin iterator to first byte of option data.
+    /// @param end iterator to end of option data (first byte after option end).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is empty or its length
+    /// is not multiple of size of the data type in bytes.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type, OptionBufferConstIter begin,
+                    OptionBufferConstIter end)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(begin, end);
+    }
+
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf buffer (option will be stored here)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    void pack(isc::util::OutputBuffer& buf) {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        for (int i = 0; i < values_.size(); ++i) {
+            // Depending on the data type length we use different utility functions
+            // writeUint16 or writeUint32 which write the data in the network byte
+            // order to the provided buffer. The same functions can be safely used
+            // for either unsiged or signed integers so there is not need to create
+            // special cases for intX_t types.
+            switch (OptionDataTypes<T>::len) {
+            case 1:
+                buf.writeUint8(values_[i]);
+                break;
+            case 2:
+                buf.writeUint16(values_[i]);
+                break;
+            case 4:
+                buf.writeUint32(values_[i]);
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-integer type");
+            }
+        }
+        // We don't pack sub-options here because we have array-type option.
+        // We don't allow sub-options in array-type options as there is no
+        // way to distinguish them from the data fields on option reception.
+    }
+
+    /// @brief Parses received buffer
+    ///
+    /// Parses received buffer and returns offset to the first unused byte after
+    /// parsed option.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+        if (distance(begin, end) == 0) {
+            isc_throw(OutOfRange, "option " << getType() << " empty");
+        }
+        if (distance(begin, end) % sizeof(T) != 0) {
+            isc_throw(OutOfRange, "option " << getType() << " truncated");
+        }
+        // @todo consider what to do if buffer is longer than data type.
+
+        values_.clear();
+        while (begin != end) {
+            // Depending on the data type length we use different utility functions
+            // readUint16 or readUint32 which read the data laid in the network byte
+            // order from the provided buffer. The same functions can be safely used
+            // for either unsiged or signed integers so there is not need to create
+            // special cases for intX_t types.
+            int data_size_len = OptionDataTypes<T>::len;
+            switch (data_size_len) {
+            case 1:
+                values_.push_back(*begin);
+                break;
+            case 2:
+                values_.push_back(isc::util::readUint16(&(*begin)));
+                break;
+            case 4:
+                values_.push_back(isc::util::readUint32(&(*begin)));
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-integer type");
+            }
+            // Use local variable to set a new value for this iterator.
+            // When using OptionDataTypes<T>::len directly some versions
+            // of clang complain about unresolved reference to
+            // OptionDataTypes structure during linking.
+            begin += data_size_len;
+        }
+        // We do not unpack sub-options here because we have array-type option.
+        // Such option have variable number of data fields, thus there is no
+        // way to assess where sub-options start.
+    }
+
+    /// @brief Return collection of option values.
+    ///
+    /// @return collection of values.
+    const std::vector<T>& getValues() const { return (values_); }
+
+    /// @brief Set option values.
+    ///
+    /// @param values collection of values to be set for option.
+    void setValues(const std::vector<T>& values) { values_ = values; }
+
+    /// @brief returns complete length of option
+    ///
+    /// Returns length of this option, including option header and suboptions
+    ///
+    /// @return length of this option
+    virtual uint16_t len() {
+        uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
+        // length of all suboptions
+        for (Option::OptionCollection::iterator it = options_.begin();
+             it != options_.end();
+             ++it) {
+            length += (*it).second->len();
+        }
+        return (length);
+    }
+
+private:
+
+    std::vector<T> values_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_ARRAY_H_ */
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
new file mode 100644
index 0000000..4e8d8a6
--- /dev/null
+++ b/src/lib/dhcp/option_data_types.h
@@ -0,0 +1,89 @@
+// 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 OPTION_DATA_TYPES_H_
+#define OPTION_DATA_TYPES_H_
+
+#include <exceptions/exceptions.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception to be thrown when invalid type specified as template parameter.
+class InvalidDataType : public Exception {
+public:
+    InvalidDataType(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Trait class for integer data types supported in DHCP option definitions.
+///
+/// This is useful to check whether the type specified as template parameter
+/// is supported by classes like Option6Int, Option6IntArray and some template
+/// factory functions in OptionDefinition class.
+template<typename T>
+struct OptionDataTypes {
+    static const bool valid = false;
+    static const int len = 0;
+};
+
+/// int8_t type is supported.
+template<>
+struct OptionDataTypes<int8_t> {
+    static const bool valid = true;
+    static const int len = 1;
+};
+
+/// int16_t type is supported.
+template<>
+struct OptionDataTypes<int16_t> {
+    static const bool valid = true;
+    static const int len = 2;
+};
+
+/// int32_t type is supported.
+template<>
+struct OptionDataTypes<int32_t> {
+    static const bool valid = true;
+    static const int len = 4;
+};
+
+/// uint8_t type is supported.
+template<>
+struct OptionDataTypes<uint8_t> {
+    static const bool valid = true;
+    static const int len = 1;
+};
+
+/// uint16_t type is supported.
+template<>
+struct OptionDataTypes<uint16_t> {
+    static const bool valid = true;
+    static const int len = 2;
+};
+
+/// uint32_t type is supported.
+template<>
+struct OptionDataTypes<uint32_t> {
+    static const bool valid = true;
+    static const int len = 4;
+};
+
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_DATA_TYPES_H_ */
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
new file mode 100644
index 0000000..87b3216
--- /dev/null
+++ b/src/lib/dhcp/option_definition.cc
@@ -0,0 +1,257 @@
+// 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 <dhcp/dhcp6.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+
+using namespace std;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+OptionDefinition::DataTypeUtil::DataTypeUtil() {
+    data_types_["empty"] = EMPTY_TYPE;
+    data_types_["binary"] = BINARY_TYPE;
+    data_types_["boolean"] = BOOLEAN_TYPE;
+    data_types_["int8"] = INT8_TYPE;
+    data_types_["int16"] = INT16_TYPE;
+    data_types_["int32"] = INT32_TYPE;
+    data_types_["uint8"] = UINT8_TYPE;
+    data_types_["uint16"] = UINT16_TYPE;
+    data_types_["uint32"] = UINT32_TYPE;
+    data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
+    data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
+    data_types_["string"] = STRING_TYPE;
+    data_types_["fqdn"] = FQDN_TYPE;
+    data_types_["record"] = RECORD_TYPE;
+}
+
+OptionDefinition::DataType
+OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
+    std::map<std::string, DataType>::const_iterator data_type_it =
+        data_types_.find(data_type);
+    if (data_type_it != data_types_.end()) {
+        return (data_type_it->second);
+    }
+    return UNKNOWN_TYPE;
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                 const uint16_t code,
+                                 const std::string& type,
+                                 const bool array_type /* = false */)
+    : name_(name),
+      code_(code),
+      type_(UNKNOWN_TYPE),
+      array_type_(array_type) {
+    // Data type is held as enum value by this class.
+    // Use the provided option type string to get the
+    // corresponding enum value.
+    type_ = DataTypeUtil::instance().getDataType(type);
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                   const uint16_t code,
+                                   const DataType type,
+                                   const bool array_type /* = false */)
+    : name_(name),
+      code_(code),
+      type_(type),
+      array_type_(array_type) {
+}
+
+void
+OptionDefinition::addRecordField(const std::string& data_type_name) {
+    DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
+    addRecordField(data_type);
+}
+
+void
+OptionDefinition::addRecordField(const DataType data_type) {
+    if (type_ != RECORD_TYPE) {
+        isc_throw(isc::InvalidOperation, "'record' option type must be used"
+                  " to add data fields to the record");
+    }
+    if (data_type >= UNKNOWN_TYPE) {
+        isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
+    }
+    record_fields_.push_back(data_type);
+}
+
+Option::Factory*
+OptionDefinition::getFactory() const {
+    validate();
+
+    // @todo This function must be extended to return more factory
+    // functions that create instances of more specialized options.
+    // This requires us to first implement those more specialized
+    // options that will be derived from Option class.
+    if (type_ == BINARY_TYPE) {
+        return (factoryGeneric);
+    } else if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
+        return (factoryAddrList6);
+    } else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
+        return (factoryAddrList4);
+    } else if (type_ == EMPTY_TYPE) {
+        return (factoryEmpty);
+    } else if (code_ == D6O_IA_NA && haveIA6Format()) {
+        return (factoryIA6);
+    } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
+        return (factoryIAAddr6);
+    } else if (type_ == UINT8_TYPE) {
+        if (array_type_) {
+            return (factoryGeneric);
+        } else {
+            return (factoryInteger<uint8_t>);
+        }
+    } else if (type_ == UINT16_TYPE) {
+        if (array_type_) {
+            return (factoryIntegerArray<uint16_t>);
+        } else {
+            return (factoryInteger<uint16_t>);
+        }
+    } else if (type_ == UINT32_TYPE) {
+        if (array_type_) {
+            return (factoryIntegerArray<uint32_t>);
+        } else {
+            return (factoryInteger<uint32_t>);
+        }
+    }
+    // Factory generic returns instance of Option class. However, once we
+    // implement CustomOption class we may want to return factory function
+    // that will create instance of CustomOption rather than Option.
+    // CustomOption will allow to access particular data fields within the
+    // option rather than raw data buffer.
+    return (factoryGeneric);
+}
+
+void
+OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
+                                      const Option::Universe actual_universe) {
+    if (expected_universe != actual_universe) {
+        isc_throw(isc::BadValue, "invalid universe specified for the option");
+    }
+}
+
+void
+OptionDefinition::validate() const {
+    // Option name must not be empty.
+    if (name_.empty()) {
+        isc_throw(isc::BadValue, "option name must not be empty");
+    }
+    // Option name must not contain spaces.
+    if (name_.find(" ") != string::npos) {
+        isc_throw(isc::BadValue, "option name must not contain spaces");
+    }
+    // Unsupported option types are not allowed.
+    if (type_ >= UNKNOWN_TYPE) {
+        isc_throw(isc::OutOfRange, "option type value " << type_
+                  << " is out of range");
+    }
+}
+
+bool
+OptionDefinition::haveIAx6Format(OptionDefinition::DataType first_type) const {
+   return (haveType(RECORD_TYPE) &&
+           record_fields_.size() == 3 &&
+           record_fields_[0] == first_type &&
+           record_fields_[1] == UINT32_TYPE &&
+           record_fields_[2] == UINT32_TYPE);
+}
+
+bool
+OptionDefinition::haveIA6Format() const {
+    // Expect that IA_NA option format is defined as record.
+    // Although it consists of 3 elements of the same (uint32)
+    // type it can't be defined as array of uint32 elements because
+    // arrays do not impose limitations on number of elements in
+    // the array while this limitation is needed for IA_NA - need
+    // exactly 3 elements.
+    return (haveIAx6Format(UINT32_TYPE));
+}
+
+bool
+OptionDefinition::haveIAAddr6Format() const {
+    return (haveIAx6Format(IPV6_ADDRESS_TYPE));
+}
+
+OptionPtr
+OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
+                                   const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V4);
+    boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, buf.begin(),
+                                                                buf.begin() + buf.size()));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
+                                   const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, buf.begin(),
+                                                                buf.begin() + buf.size()));
+    return (option);
+}
+
+
+OptionPtr
+OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    if (buf.size() > 0) {
+        isc_throw(isc::BadValue, "input option buffer must be empty"
+                  " when creating empty option instance");
+    }
+    OptionPtr option(new Option(u, type));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    OptionPtr option(new Option(u, type, buf));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryIA6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    if (buf.size() != Option6IA::OPTION6_IA_LEN) {
+        isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
+                  << Option6IA::OPTION6_IA_LEN << " bytes");
+    }
+    boost::shared_ptr<Option6IA> option(new Option6IA(type, buf.begin(),
+                                                      buf.begin() + buf.size()));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    if (buf.size() != Option6IAAddr::OPTION6_IAADDR_LEN) {
+        isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
+                  << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
+    }
+    boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, buf.begin(),
+                                                      buf.begin() + buf.size()));
+    return (option);
+}
+
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
new file mode 100644
index 0000000..166765f
--- /dev/null
+++ b/src/lib/dhcp/option_definition.h
@@ -0,0 +1,464 @@
+// 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 OPTION_DEFINITION_H_
+#define OPTION_DEFINITION_H_
+
+#include <dhcp/option_data_types.h>
+#include <dhcp/option.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Forward declaration to OptionDefinition.
+class OptionDefinition;
+
+/// @brief Pointer to option definition object.
+typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;
+
+/// @brief Forward declaration to Option6Int.
+///
+/// This forward declaration is needed to access Option6Int class
+/// without having to include option6_int.h header. This is because
+/// this header includes libdhcp++.h and this causes circular
+/// inclusion between libdhcp++.h, option_definition.h and
+/// option6_int.h.
+template<typename T>
+class Option6Int;
+
+/// @brief Forward declaration to Option6IntArray.
+///
+/// This forward declaration is needed to access Option6IntArray class
+/// without having to include option6_int_array.h header. This is because
+/// this header includes libdhcp++.h and this causes circular
+/// inclusion between libdhcp++.h, option_definition.h and
+/// option6_int_array.h.
+template<typename T>
+class Option6IntArray;
+
+/// @brief Base class representing a DHCP option definition.
+///
+/// This is a base class representing a DHCP option definition, which describes
+/// the format of the option. In particular, it defines:
+/// - option name,
+/// - option code,
+/// - data fields order and their types,
+/// - sub options space that the particular option encapsulates.
+///
+/// The option type specifies the data type(s) which an option conveys.  If
+/// this is a single value the option type points to the data type of the
+/// value. For example, DHCPv6 option 8 comprises a two-byte option code, a
+/// two-byte option length and two-byte field that carries a uint16 value
+/// (RFC 3315 - http://ietf.org/rfc/rfc3315.txt).  In such a case, the option
+/// type is defined as "uint16".
+///
+/// When the option has a more complex structure, the option type may be
+/// defined as "array", "record" or even "array of records".
+///
+/// Array types should be used when the option contains multiple contiguous
+/// data values of the same type laid. For example, DHCPv6 option 6 includes
+/// multiple fields holding uint16 codes of requested DHCPv6 options (RFC 3315).
+/// Such an option can be represented with this class by setting the option
+/// type to "uint16" and the array indicator (array_type) to true.  The number
+/// of elements in the array is effectively unlimited (although it is actually
+/// limited by the maximal DHCPv6 option length).
+///
+/// Should the option comprise data fields of different types, the "record"
+/// option type is used. In such cases the data field types within the record
+/// are specified using \ref OptioDefinition::addRecordField.
+///
+/// When the OptionDefinition object has been sucessfully created, it can be
+/// queried to return the appropriate option factory function for the specified
+/// specified option format. There are a number of "standard" factory functions
+/// that cover well known (common) formats.  If the particular format does not
+/// match any common format the generic factory function is returned.
+///
+/// The following data type strings are supported:
+/// - "empty" (option does not contain data fields)
+/// - "boolean"
+/// - "int8"
+/// - "int16"
+/// - "int32"
+/// - "uint8"
+/// - "uint16"
+/// - "uint32"
+/// - "ipv4-address" (IPv4 Address)
+/// - "ipv6-address" (IPV6 Address)
+/// - "string"
+/// - "fqdn" (fully qualified name)
+/// - "record" (set of data fields of different types)
+///
+/// @todo Extend the comment to describe "generic factories".
+/// @todo Extend this class to use custom namespaces.
+/// @todo Extend this class with more factory functions.
+class OptionDefinition {
+public:
+
+    /// Data types of DHCP option fields.
+    enum DataType {
+        EMPTY_TYPE,
+        BINARY_TYPE,
+        BOOLEAN_TYPE,
+        INT8_TYPE,
+        INT16_TYPE,
+        INT32_TYPE,
+        UINT8_TYPE,
+        UINT16_TYPE,
+        UINT32_TYPE,
+        IPV4_ADDRESS_TYPE,
+        IPV6_ADDRESS_TYPE,
+        STRING_TYPE,
+        FQDN_TYPE,
+        RECORD_TYPE,
+        UNKNOWN_TYPE
+    };
+
+    /// List of fields within the record.
+    typedef std::vector<DataType> RecordFieldsCollection;
+    /// Const iterator for record data fields.
+    typedef std::vector<DataType>::const_iterator RecordFieldsConstIter;
+
+private:
+
+    /// @brief Utility class for operations on DataTypes.
+    ///
+    /// This class is implemented as the singleton because the list of
+    /// supported data types need only be loaded only once into memory as it
+    /// can persist for all option definitions.
+    ///
+    /// @todo This class can be extended to return the string value
+    /// representing the data type from the enum value.
+    class DataTypeUtil {
+    public:
+
+        /// @brief Return the sole instance of this class.
+        ///
+        /// @return instance of this class.
+        static DataTypeUtil& instance() {
+            static DataTypeUtil instance;
+            return (instance);
+        }
+
+        /// @brief Convert type given as string value to option data type.
+        ///
+        /// @param data_type_name data type string.
+        ///
+        /// @return option data type.
+        DataType getDataType(const std::string& data_type_name);
+
+    private:
+        /// @brief Private constructor.
+        ///
+        /// Constructor initializes the internal data structures, e.g.
+        /// mapping between data type name and the corresponding enum.
+        /// This constructor is private to ensure that exactly one
+        /// instance of this class can be created using \ref instance
+        /// function.
+        DataTypeUtil();
+
+        /// Map of data types, maps name of the type to enum value.
+        std::map<std::string, DataType> data_types_;
+    };
+
+public:
+    /// @brief Constructor.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @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);
+
+    /// @brief Constructor.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @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 DataType type,
+                     const bool array_type = false);
+
+    /// @brief Adds data field to the record.
+    ///
+    /// @param data_type_name name of the data type for the field.
+    ///
+    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
+    /// @throw isc::BadValue if specified invalid data type.
+    void addRecordField(const std::string& data_type_name);
+
+    /// @brief Adds data field to the record.
+    ///
+    /// @param data_type data type for the field.
+    ///
+    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
+    /// @throw isc::BadValue if specified invalid data type.
+    void addRecordField(const DataType data_type);
+
+    /// @brief Return array type indicator.
+    ///
+    /// The method returns the bool value to indicate whether the option is a
+    /// a single value or an array of values.
+    ///
+    /// @return true if option comprises an array of values.
+    bool getArrayType() const { return (array_type_); }
+
+    /// @brief Return option code.
+    ///
+    /// @return option code.
+    uint16_t getCode() const { return (code_); }
+
+    /// @brief Return factory function for the given definition.
+    ///
+    /// @throw isc::OutOfRange if \ref validate returns it.
+    /// @throw isc::BadValue if \ref validate returns it.
+    /// @return pointer to a factory function.
+    Option::Factory* getFactory() const;
+
+    /// @brief Return option name.
+    ///
+    /// @return option name.
+    const std::string& getName() const { return (name_); }
+
+    /// @brief Return list of record fields.
+    ///
+    /// @return list of record fields.
+    const RecordFieldsCollection& getRecordFields() const { return (record_fields_); }
+
+    /// @brief Return option data type.
+    ///
+    /// @return option data type.
+    DataType getType() const { return (type_); };
+
+    /// @brief Check if the option definition is valid.
+    ///
+    /// @throw isc::OutOfRange if invalid option type was specified.
+    /// @throw isc::BadValue if invalid option name was specified,
+    /// e.g. empty or containing spaces.
+    void validate() const;
+
+    /// @brief Check if specified format is IA_NA option format.
+    ///
+    /// @return true if specified format is IA_NA option format.
+    bool haveIA6Format() const;
+
+    /// @brief Check if specified format is IAADDR option format.
+    ///
+    /// @return true if specified format is IAADDR option format.
+    bool haveIAAddr6Format() const;
+
+    /// @brief Factory to create option with address list.
+    ///
+    /// @param u universe (must be V4).
+    /// @param type option type.
+    /// @param buf option buffer with a list of IPv4 addresses.
+    ///
+    /// @throw isc::OutOfRange if length of the provided option buffer
+    /// is not multiple of IPV4 address length.
+    static OptionPtr factoryAddrList4(Option::Universe u, uint16_t type,
+                                      const OptionBuffer& buf);
+
+    /// @brief Factory to create option with address list.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer with a list of IPv6 addresses.
+    ///
+    /// @throw isc::OutOfaRange if length of provided option buffer
+    /// is not multiple of IPV6 address length.
+    static OptionPtr factoryAddrList6(Option::Universe u, uint16_t type,
+                                      const OptionBuffer& buf);
+
+    /// @brief Empty option factory.
+    ///
+    /// @param u universe (V6 or V4).
+    /// @param type option type.
+    /// @param buf option buffer (must be empty).
+    static OptionPtr factoryEmpty(Option::Universe u, uint16_t type,
+                                  const OptionBuffer& buf);
+
+    /// @brief Factory to create generic option.
+    ///
+    /// @param u universe (V6 or V4).
+    /// @param type option type.
+    /// @param buf option buffer.
+    static OptionPtr factoryGeneric(Option::Universe u, uint16_t type,
+                                    const OptionBuffer& buf);
+
+    /// @brief Factory for IA-type of option.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer.
+    ///
+    /// @throw isc::OutOfRange if provided option buffer is too short or
+    /// too long. Expected size is 12 bytes.
+    /// @throw isc::BadValue if specified universe value is not V6.
+    static OptionPtr factoryIA6(Option::Universe u, uint16_t type,
+                                const OptionBuffer& buf);
+
+    /// @brief Factory for IAADDR-type of option.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer.
+    ///
+    /// @throw isc::OutOfRange if provided option buffer is too short or
+    /// too long. Expected size is 24 bytes.
+    /// @throw isc::BadValue if specified universe value is not V6.
+    static OptionPtr factoryIAAddr6(Option::Universe u, uint16_t type,
+                                const OptionBuffer& buf);
+
+    /// @brief Factory function to create option with integer value.
+    ///
+    /// @param type option type.
+    /// @param buf option buffer.
+    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+    ///
+    /// @throw isc::OutOfRange if provided option buffer length is invalid.
+    template<typename T>
+    static OptionPtr factoryInteger(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+        if (buf.size() > sizeof(T)) {
+            isc_throw(isc::OutOfRange, "provided option buffer is too large, expected: "
+                      << sizeof(T) << " bytes");
+        }
+        OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.end()));
+        return (option);
+    }
+
+    /// @brief Factory function to create option with array of integer values.
+    ///
+    /// @param type option type.
+    /// @param buf option buffer.
+    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+    ///
+    /// @throw isc::OutOfRange if provided option buffer length is invalid.
+    template<typename T>
+    static OptionPtr factoryIntegerArray(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+        if (buf.size() == 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be greater than zero");
+        } else if (buf.size() % OptionDataTypes<T>::len != 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be multiple of "
+                      << OptionDataTypes<T>::len << " bytes");
+        }
+        OptionPtr option(new Option6IntArray<T>(type, buf.begin(), buf.end()));
+        return (option);
+    }
+
+private:
+
+    /// @brief Check if specified option format is a record with 3 fields
+    /// where first one is custom, and two others are uint32.
+    ///
+    /// This is a helper function for functions that detect IA_NA and IAAddr
+    /// option formats.
+    ///
+    /// @param first_type type of the first data field.
+    ///
+    /// @return true if actual option format matches expected format.
+    bool haveIAx6Format(const OptionDefinition::DataType first_type) const;
+
+    /// @brief Check if specified type matches option definition type.
+    ///
+    /// @return true if specified type matches option definition type.
+    inline bool haveType(const DataType type) const {
+        return (type == type_);
+    }
+
+    /// @brief Sanity check universe value.
+    ///
+    /// @param expected_universe expected universe value.
+    /// @param actual_universe actual universe value.
+    ///
+    /// @throw isc::BadValue if expected universe and actual universe don't match.
+   static inline void sanityCheckUniverse(const Option::Universe expected_universe,
+                                          const Option::Universe actual_universe); 
+
+    /// Option name.
+    std::string name_;
+    /// Option code.
+    uint16_t code_;
+    /// Option data type.
+    DataType type_;
+    /// Indicates wheter option is a single value or array.
+    bool array_type_;
+    /// Collection of data fields within the record.
+    RecordFieldsCollection record_fields_;
+};
+
+
+/// @brief Multi index container for DHCP option definitions.
+///
+/// This container allows to search for DHCP option definition
+/// using two indexes:
+/// - sequenced: used to access elements in the order they have
+/// been added to the container
+/// - option code: used to search defintions of options
+/// with a specified option code (aka option type).
+/// Note that this container can hold multiple options with the
+/// same code. For this reason, the latter index can be used to
+/// obtain a range of options for a particular option code.
+/// 
+/// @todo: need an index to search options using option space name
+/// once option spaces are implemented.
+typedef boost::multi_index_container<
+    // Container comprises elements of OptionDefinition type.
+    OptionDefinitionPtr,
+    // Here we start enumerating various indexes.
+    boost::multi_index::indexed_by<
+        // Sequenced index allows accessing elements in the same way
+        // as elements in std::list. Sequenced is an index #0.
+        boost::multi_index::sequenced<>,
+        // Start definition of index #1.
+        boost::multi_index::hashed_non_unique<
+            // Use option type as the index key. The type is held
+            // in OptionDefinition object so we have to call
+            // OptionDefinition::getCode to retrieve this key
+            // for each element. The option code is non-unique so
+            // multiple elements with the same option code can
+            // be returned by this index.
+            boost::multi_index::const_mem_fun<
+                OptionDefinition,
+                uint16_t,
+                &OptionDefinition::getCode
+            >
+        >
+    >
+> OptionDefContainer;
+
+/// Type of the index #1 - option type.
+typedef OptionDefContainer::nth_index<1>::type OptionDefContainerTypeIndex;
+/// Pair of iterators to represent the range of options definitions
+///  having the same option type value. The first element in this pair
+///  represents the begining of the range, the second element
+///  represents the end.
+typedef std::pair<OptionDefContainerTypeIndex::const_iterator,
+                  OptionDefContainerTypeIndex::const_iterator> OptionDefContainerTypeRange;
+
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/pool.h b/src/lib/dhcp/pool.h
index 46f6578..dd68fdd 100644
--- a/src/lib/dhcp/pool.h
+++ b/src/lib/dhcp/pool.h
@@ -141,6 +141,7 @@ public:
 
     /// @brief the constructor for Pool6 "min-max" style definition
     ///
+    /// @param type type of the pool (IA, TA or PD)
     /// @param first the first address in a pool
     /// @param last the last address in a pool
     Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
@@ -148,6 +149,7 @@ public:
 
     /// @brief the constructor for Pool6 "prefix/len" style definition
     ///
+    /// @param type type of the pool (IA, TA or PD)
     /// @param prefix specifies prefix of the pool
     /// @param prefix_len specifies length of the prefix of the pool
     Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
diff --git a/src/lib/dhcp/subnet.cc b/src/lib/dhcp/subnet.cc
index d0c4cb3..28f2391 100644
--- a/src/lib/dhcp/subnet.cc
+++ b/src/lib/dhcp/subnet.cc
@@ -15,7 +15,7 @@
 #include <dhcp/addr_utilities.h>
 #include <asiolink/io_address.h>
 #include <dhcp/subnet.h>
-#include <dhcp/pool.h>
+#include <sstream>
 
 using namespace isc::asiolink;
 
@@ -27,7 +27,8 @@ Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
                const Triplet<uint32_t>& t2,
                const Triplet<uint32_t>& valid_lifetime)
     :id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
-     t2_(t2), valid_(valid_lifetime) {
+     t2_(t2), valid_(valid_lifetime),
+     last_allocated_(lastAddrInPrefix(prefix, len)) {
     if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
          (prefix.getFamily() == AF_INET && len > 32) ) {
         isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
@@ -41,6 +42,23 @@ bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
     return ((first <= addr) && (addr <= last));
 }
 
+void
+Subnet::addOption(OptionPtr& option, bool persistent /* = false */) {
+    validateOption(option);
+    options_.push_back(OptionDescriptor(option, persistent));
+}
+
+void
+Subnet::delOptions() {
+    options_.clear();
+}
+
+std::string Subnet::toText() const {
+    std::stringstream tmp;
+    tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
+    return (tmp.str());
+}
+
 Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
                  const Triplet<uint32_t>& t1,
                  const Triplet<uint32_t>& t2,
@@ -85,6 +103,31 @@ Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("
     return (candidate);
 }
 
+void
+Subnet4::validateOption(const OptionPtr& option) const {
+    if (!option) {
+        isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
+    } else if (option->getUniverse() != Option::V4) {
+        isc_throw(isc::BadValue, "expected V4 option to be added to the subnet");
+    }
+}
+
+bool Subnet4::inPool(const isc::asiolink::IOAddress& addr) const {
+
+    // Let's start with checking if it even belongs to that subnet.
+    if (!inRange(addr)) {
+        return (false);
+    }
+
+    for (Pool4Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+        if ((*pool)->inRange(addr)) {
+            return (true);
+        }
+    }
+    // there's no pool that address belongs to
+    return (false);
+}
+
 Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
                  const Triplet<uint32_t>& t1,
                  const Triplet<uint32_t>& t2,
@@ -131,5 +174,30 @@ Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("
     return (candidate);
 }
 
+void
+Subnet6::validateOption(const OptionPtr& option) const {
+    if (!option) {
+        isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
+    } else if (option->getUniverse() != Option::V6) {
+        isc_throw(isc::BadValue, "expected V6 option to be added to the subnet");
+    }
+}
+
+bool Subnet6::inPool(const isc::asiolink::IOAddress& addr) const {
+
+    // Let's start with checking if it even belongs to that subnet.
+    if (!inRange(addr)) {
+        return (false);
+    }
+
+    for (Pool6Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+        if ((*pool)->inRange(addr)) {
+            return (true);
+        }
+    }
+    // there's no pool that address belongs to
+    return (false);
+}
+
 } // end of isc::dhcp namespace
 } // end of isc namespace
diff --git a/src/lib/dhcp/subnet.h b/src/lib/dhcp/subnet.h
index 7e4e0b7..00b3375 100644
--- a/src/lib/dhcp/subnet.h
+++ b/src/lib/dhcp/subnet.h
@@ -15,10 +15,16 @@
 #ifndef SUBNET_H
 #define SUBNET_H
 
-#include <boost/shared_ptr.hpp>
 #include <asiolink/io_address.h>
 #include <dhcp/pool.h>
 #include <dhcp/triplet.h>
+#include <dhcp/option.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
 
 namespace isc {
 namespace dhcp {
@@ -30,14 +36,200 @@ namespace dhcp {
 /// attached to it. In most cases all devices attached to a single link can
 /// share the same parameters. Therefore Subnet holds several values that are
 /// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
-/// leased addresses lifetime (valid-lifetime).
+/// leased addresses lifetime (valid-lifetime). It also holds the set
+/// of DHCP option instances configured for the subnet. These options are
+/// included in DHCP messages being sent to clients which are connected
+/// to the particular subnet.
 ///
 /// @todo: Implement support for options here
+
+
+/// @brief Unique indentifier for a subnet (both v4 and v6)
+typedef uint32_t SubnetID;
+
 class Subnet {
 public:
+
+    /// @brief Option descriptor.
+    ///
+    /// Option descriptor holds information about option configured for
+    /// a particular subnet. This information comprises the actual option
+    /// instance and information whether this option is sent to DHCP client
+    /// only on request (persistent = false) or always (persistent = true).
+    struct OptionDescriptor {
+        /// Option instance.
+        OptionPtr option;
+        /// Persistent flag, if true option is always sent to the client,
+        /// if false option is sent to the client on request.
+        bool persistent;
+
+        /// @brief Constructor.
+        ///
+        /// @param opt option
+        /// @param persist if true option is always sent.
+        OptionDescriptor(OptionPtr& opt, bool persist)
+            : option(opt), persistent(persist) {};
+    };
+
+    /// @brief Extractor class to extract key with another key.
+    ///
+    /// This class solves the problem of accessing index key values
+    /// that are stored in objects nested in other objects.
+    /// Each OptionDescriptor structure contains the OptionPtr object.
+    /// The value retured by one of its accessors (getType) is used
+    /// as an indexing value in the multi_index_container defined below.
+    /// There is no easy way to mark that value returned by Option::getType
+    /// should be an index of this multi_index_container. There are standard
+    /// key extractors such as 'member' or 'mem_fun' but they are not
+    /// sufficient here. The former can be used to mark that member of
+    /// the structure that is held in the container should be used as an
+    /// indexing value. The latter can be used if the indexing value is
+    /// a product of the class being held in the container. In this complex
+    /// scenario when the indexing value is a product of the function that
+    /// is wrapped by the structure, this new extractor template has to be
+    /// defined. The template class provides a 'chain' of two extractors
+    /// to access the value returned by nested object and to use it as
+    /// indexing value.
+    /// For some more examples of complex keys see:
+    /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
+    ///
+    /// @tparam KeyExtractor1 extractor used to access data in
+    /// OptionDescriptor::option
+    /// @tparam KeyExtractor2 extractor used to access
+    /// OptionDescriptor::option member.
+    template<typename KeyExtractor1, typename KeyExtractor2>
+    class KeyFromKey {
+    public:
+        typedef typename KeyExtractor1::result_type result_type;
+
+        /// @brief Constructor.
+        KeyFromKey()
+            : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
+
+        /// @brief Extract key with another key.
+        ///
+        /// @param arg the key value.
+        ///
+        /// @tparam key value type.
+        template<typename T>
+        result_type operator() (T& arg) const {
+            return (key1_(key2_(arg)));
+        }
+    private:
+        KeyExtractor1 key1_; ///< key 1.
+        KeyExtractor2 key2_; ///< key 2.
+    };
+
+    /// @brief Multi index container for DHCP option descriptors.
+    ///
+    /// This container comprises three indexes to access option
+    /// descriptors:
+    /// - sequenced index: used to access elements in the order they
+    /// have been added to the container,
+    /// - option type index: used to search option descriptors containing
+    /// options with specific option code (aka option type).
+    /// - persistency flag index: used to search option descriptors with
+    /// 'persistent' flag set to true.
+    ///
+    /// This container is the equivalent of three separate STL containers:
+    /// - std::list of all options,
+    /// - std::multimap of options with option code used as a multimap key,
+    /// - std::multimap of option descriptors with option persistency flag
+    /// used as a multimap key.
+    /// The major advantage of this container over 3 separate STL containers
+    /// is automatic synchronization of all indexes when elements are added,
+    /// removed or modified in the container. With separate containers,
+    /// the synchronization would have to be guaranteed by the Subnet class
+    /// code. This would increase code complexity and presumably it would
+    /// be much harder to add new search criteria (indexes).
+    ///
+    /// @todo we may want to search for options using option spaces when
+    /// they are implemented.
+    ///
+    /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
+    typedef boost::multi_index_container<
+        // Container comprises elements of OptionDescriptor type.
+        OptionDescriptor,
+        // Here we start enumerating various indexes.
+        boost::multi_index::indexed_by<
+            // Sequenced index allows accessing elements in the same way
+            // as elements in std::list.
+            // Sequenced is an index #0.
+            boost::multi_index::sequenced<>,
+            // Start definition of index #1.
+            boost::multi_index::hashed_non_unique<
+                // KeyFromKey is the index key extractor that allows accessing
+                // option type being held by the OptionPtr through
+                // OptionDescriptor structure.
+                KeyFromKey<
+                    // Use option type as the index key. The type is held
+                    // in OptionPtr object so we have to call Option::getType
+                    // to retrieve this key for each element.
+                    boost::multi_index::mem_fun<
+                        Option,
+                        uint16_t,
+                        &Option::getType
+                    >,
+                    // Indicate that OptionPtr is a member of
+                    // OptionDescriptor structure.
+                    boost::multi_index::member<
+                        OptionDescriptor,
+                        OptionPtr,
+                        &OptionDescriptor::option
+                    >
+                 >
+            >,
+            // Start definition of index #2.
+            // Use 'persistent' struct member as a key.
+            boost::multi_index::hashed_non_unique<
+                boost::multi_index::member<
+                    OptionDescriptor,
+                    bool,
+                    &OptionDescriptor::persistent
+                >
+            >
+        >
+    > OptionContainer;
+
+    /// Type of the index #1 - option type.
+    typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
+    /// Pair of iterators to represent the range of options having the
+    /// same option type value. The first element in this pair represents
+    /// the begining of the range, the second element represents the end.
+    typedef std::pair<OptionContainerTypeIndex::const_iterator,
+                      OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
+    /// Type of the index #2 - option persistency flag.
+    typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
+
     /// @brief checks if specified address is in range
     bool inRange(const isc::asiolink::IOAddress& addr) const;
 
+    /// @brief Add new option instance to the collection.
+    ///
+    /// @param option option instance.
+    /// @param persistent if true, send an option regardless if client
+    /// requested it or not.
+    ///
+    /// @throw isc::BadValue if invalid option provided.
+    void addOption(OptionPtr& option, bool persistent = false);
+
+    /// @brief Delete all options configured for the subnet.
+    void delOptions();
+
+    /// @brief checks if the specified address is in pools
+    ///
+    /// Note the difference between inSubnet() and inPool(). For a given
+    /// subnet (e.g. 2001::/64) there may be one or more pools defined
+    /// that may or may not cover entire subnet, e.g. pool 2001::1-2001::10).
+    /// inPool() returning true implies inSubnet(), but the reverse implication
+    /// is not always true. For the given example, 2001::1234:abcd would return
+    /// true for inSubnet(), but false for inPool() check.
+    ///
+    /// @param addr this address will be checked if it belongs to any pools in
+    ///        that subnet
+    /// @return true if the address is in any of the pools
+    virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
+
     /// @brief return valid-lifetime for addresses in that prefix
     Triplet<uint32_t> getValid() const {
         return (valid_);
@@ -53,6 +245,57 @@ public:
         return (t2_);
     }
 
+    /// @brief Return a collection of options.
+    ///
+    /// @return reference to collection of options configured for a subnet.
+    /// The returned reference is valid as long as the Subnet object which
+    /// returned it still exists.
+    const OptionContainer& getOptions() const {
+        return (options_);
+    }
+
+    /// @brief returns the last address that was tried from this pool
+    ///
+    /// This method returns the last address that was attempted to be allocated
+    /// from this subnet. This is used as helper information for the next
+    /// iteration of the allocation algorithm.
+    ///
+    /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+    ///        AllocEngine::IterativeAllocator and keep the data there
+    ///
+    /// @return address that was last tried from this pool
+    isc::asiolink::IOAddress getLastAllocated() const {
+        return (last_allocated_);
+    }
+
+    /// @brief sets the last address that was tried from this pool
+    ///
+    /// This method sets the last address that was attempted to be allocated
+    /// from this subnet. This is used as helper information for the next
+    /// iteration of the allocation algorithm.
+    ///
+    /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+    ///        AllocEngine::IterativeAllocator and keep the data there
+    void setLastAllocated(const isc::asiolink::IOAddress& addr) {
+        last_allocated_ = addr;
+    }
+
+    /// @brief returns unique ID for that subnet
+    /// @return unique ID for that subnet
+    SubnetID getID() const { return (id_); }
+
+    /// @brief returns subnet parameters (prefix and prefix length)
+    ///
+    /// @return (prefix, prefix length) pair
+    std::pair<isc::asiolink::IOAddress, uint8_t> get() const {
+        return (std::make_pair(prefix_, prefix_len_));
+    }
+
+    /// @brief returns textual representation of the subnet (e.g. "2001:db8::/64")
+    ///
+    /// @return textual representation
+    virtual std::string toText() const;
+
 protected:
     /// @brief protected constructor
     //
@@ -63,19 +306,30 @@ protected:
            const Triplet<uint32_t>& t2,
            const Triplet<uint32_t>& valid_lifetime);
 
+    /// @brief virtual destructor
+    ///
+    /// A virtual destructor is needed because other classes
+    /// derive from this class.
+    virtual ~Subnet() { };
+
     /// @brief returns the next unique Subnet-ID
     ///
     /// @return the next unique Subnet-ID
-    static uint32_t getNextID() {
-        static uint32_t id = 0;
+    static SubnetID getNextID() {
+        static SubnetID id = 0;
         return (id++);
     }
 
+    /// @brief Check if option is valid and can be added to a subnet.
+    ///
+    /// @param option option to be validated.
+    virtual void validateOption(const OptionPtr& option) const = 0;
+
     /// @brief subnet-id
     ///
     /// Subnet-id is a unique value that can be used to find or identify
     /// a Subnet4 or Subnet6.
-    uint32_t id_;
+    SubnetID id_;
 
     /// @brief a prefix of the subnet
     isc::asiolink::IOAddress prefix_;
@@ -91,6 +345,20 @@ protected:
 
     /// @brief a tripet (min/default/max) holding allowed valid lifetime values
     Triplet<uint32_t> valid_;
+
+    /// @brief a collection of DHCP options configured for a subnet.
+    OptionContainer options_;
+
+    /// @brief last allocated address
+    ///
+    /// This is the last allocated address that was previously allocated from
+    /// this particular subnet. Some allocation algorithms (e.g. iterative) use
+    /// that value, others do not. It should be noted that although the value
+    /// is usually correct, there are cases when it is invalid, e.g. after
+    /// removing a pool, restarting or changing allocation algorithms. For
+    /// that purpose it should be only considered a help that should not be
+    /// fully trusted.
+    isc::asiolink::IOAddress last_allocated_;
 };
 
 /// @brief A configuration holder for IPv4 subnet.
@@ -124,15 +392,30 @@ public:
 
     /// @brief returns all pools
     ///
-    /// The reference is only valid as long as the object that
-    /// returned it.
+    /// The reference is only valid as long as the object that returned it.
     ///
     /// @return a collection of all pools
     const Pool4Collection& getPools() const {
         return pools_;
     }
 
+    /// @brief checks if the specified address is in pools
+    ///
+    /// See the description in \ref Subnet::inPool().
+    ///
+    /// @param addr this address will be checked if it belongs to any pools in that subnet
+    /// @return true if the address is in any of the pools
+    bool inPool(const isc::asiolink::IOAddress& addr) const;
+
 protected:
+
+    /// @brief Check if option is valid and can be added to a subnet.
+    ///
+    /// @param option option to be validated.
+    ///
+    /// @throw isc::BadValue if provided option is invalid.
+    virtual void validateOption(const OptionPtr& option) const;
+
     /// @brief collection of pools in that list
     Pool4Collection pools_;
 };
@@ -192,7 +475,23 @@ public:
         return pools_;
     }
 
+    /// @brief checks if the specified address is in pools
+    ///
+    /// See the description in \ref Subnet::inPool().
+    ///
+    /// @param addr this address will be checked if it belongs to any pools in that subnet
+    /// @return true if the address is in any of the pools
+    bool inPool(const isc::asiolink::IOAddress& addr) const;
+
 protected:
+
+    /// @brief Check if option is valid and can be added to a subnet.
+    ///
+    /// @param option option to be validated.
+    ///
+    /// @throw isc::BadValue if provided option is invalid.
+    virtual void validateOption(const OptionPtr& option) const;
+
     /// @brief collection of pools in that list
     Pool6Collection pools_;
 
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 99548f6..bf5e2e7 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -33,8 +33,11 @@ libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
 libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
 libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
-libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
 libdhcp___unittests_SOURCES += option6_ia_unittest.cc
+libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
+libdhcp___unittests_SOURCES += option6_int_array_unittest.cc
+libdhcp___unittests_SOURCES += option6_int_unittest.cc
+libdhcp___unittests_SOURCES += option_definition_unittest.cc
 libdhcp___unittests_SOURCES += option_unittest.cc
 libdhcp___unittests_SOURCES += pkt4_unittest.cc
 libdhcp___unittests_SOURCES += pkt6_unittest.cc
@@ -46,10 +49,12 @@ libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
 
 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 += duid_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
diff --git a/src/lib/dhcp/tests/alloc_engine_unittest.cc b/src/lib/dhcp/tests/alloc_engine_unittest.cc
new file mode 100644
index 0000000..d4290a3
--- /dev/null
+++ b/src/lib/dhcp/tests/alloc_engine_unittest.cc
@@ -0,0 +1,341 @@
+// 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 <config.h>
+#include <asiolink/io_address.h>
+#include <dhcp/lease_mgr.h>
+#include <dhcp/lease_mgr_factory.h>
+#include <dhcp/duid.h>
+#include <dhcp/alloc_engine.h>
+#include <dhcp/cfgmgr.h>
+#include <dhcp/memfile_lease_mgr.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <iostream>
+#include <sstream>
+#include <map>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace {
+
+class NakedAllocEngine : public AllocEngine {
+public:
+    NakedAllocEngine(AllocEngine::AllocType engine_type, unsigned int attempts)
+        :AllocEngine(engine_type, attempts) {
+    }
+    using AllocEngine::Allocator;
+    using AllocEngine::IterativeAllocator;
+};
+
+// empty class for now, but may be extended once Addr6 becomes bigger
+class AllocEngineTest : public ::testing::Test {
+public:
+    AllocEngineTest() {
+        duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+        iaid_ = 42;
+
+        // instantiate cfg_mgr
+        CfgMgr& cfg_mgr = CfgMgr::instance();
+
+        subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+        pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::10"),
+                                   IOAddress("2001:db8:1::20")));
+        subnet_->addPool6(pool_);
+        cfg_mgr.addSubnet6(subnet_);
+
+        factory_.create("type=memfile");
+    }
+
+    void checkLease6(const Lease6Ptr& lease) {
+        // that is belongs to the right subnet
+        EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+        EXPECT_TRUE(subnet_->inRange(lease->addr_));
+        EXPECT_TRUE(subnet_->inPool(lease->addr_));
+
+        // that it have proper parameters
+        EXPECT_EQ(iaid_, lease->iaid_);
+        EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
+        EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
+        EXPECT_EQ(subnet_->getT1(), lease->t1_);
+        EXPECT_EQ(subnet_->getT2(), lease->t2_);
+        EXPECT_EQ(0, lease->prefixlen_); // this is IA_NA, not IA_PD
+        EXPECT_TRUE(false == lease->fqdn_fwd_);
+        EXPECT_TRUE(false == lease->fqdn_rev_);
+        EXPECT_TRUE(*lease->duid_ == *duid_);
+        // @todo: check cltt
+     }
+
+    ~AllocEngineTest() {
+        factory_.destroy();
+    }
+
+    DuidPtr duid_;
+    uint32_t iaid_;
+    Subnet6Ptr subnet_;
+    Pool6Ptr pool_;
+    LeaseMgrFactory factory_;
+};
+
+// This test checks if the Allocation Engine can be instantiated and that it
+// parses parameters string properly.
+TEST_F(AllocEngineTest, constructor) {
+    AllocEngine* x = NULL;
+
+    // Hashed and random allocators are not supported yet
+    ASSERT_THROW(x = new AllocEngine(AllocEngine::ALLOC_HASHED, 5), NotImplemented);
+    ASSERT_THROW(x = new AllocEngine(AllocEngine::ALLOC_RANDOM, 5), NotImplemented);
+
+    ASSERT_NO_THROW(x = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
+
+    delete x;
+}
+
+/// @todo: This method is taken from mysql_lease_mgr_utilities.cc from ticket
+/// #2342. Get rid of one instance once the code is merged
+void
+detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
+    EXPECT_EQ(first->type_, second->type_);
+
+    // Compare address strings - odd things happen when they are different
+    // as the EXPECT_EQ appears to call the operator uint32_t() function,
+    // which causes an exception to be thrown for IPv6 addresses.
+    EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
+    EXPECT_EQ(first->prefixlen_, second->prefixlen_);
+    EXPECT_EQ(first->iaid_, second->iaid_);
+    EXPECT_TRUE(*first->duid_ == *second->duid_);
+    EXPECT_EQ(first->preferred_lft_, second->preferred_lft_);
+    EXPECT_EQ(first->valid_lft_, second->valid_lft_);
+    EXPECT_EQ(first->cltt_, second->cltt_);
+    EXPECT_EQ(first->subnet_id_, second->subnet_id_);
+}
+
+
+// This test checks if the simple allocation can succeed
+TEST_F(AllocEngineTest, simpleAlloc) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
+                                               false);
+
+    // check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // do all checks on the lease
+    checkLease6(lease);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease6(lease, from_mgr);
+}
+
+// This test checks if the fake allocation (for SOLICIT) can succeed
+TEST_F(AllocEngineTest, fakeAlloc) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
+                                               true);
+
+    // check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // do all checks on the lease
+    checkLease6(lease);
+
+    // Check that the lease is NOT in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+    ASSERT_FALSE(from_mgr);
+}
+
+// This test checks if the allocation with a hint that is valid (in range,
+// in pool and free) can succeed
+TEST_F(AllocEngineTest, allocWithValidHint) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+                                               IOAddress("2001:db8:1::15"),
+                                               false);
+
+    // check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // we should get what we asked for
+    EXPECT_EQ(lease->addr_.toText(), "2001:db8:1::15");
+
+    // do all checks on the lease
+    checkLease6(lease);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease6(lease, from_mgr);
+}
+
+// This test checks if the allocation with a hint that is in range,
+// in pool, but is currently used) can succeed
+TEST_F(AllocEngineTest, allocWithUsedHint) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // let's create a lease and put it in the LeaseMgr
+    DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
+    Lease6Ptr used(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1f"),
+                              duid2, 1, 2, 3, 4, 5, subnet_->getID()));
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+    // another client comes in and request an address that is in pool, but
+    // unfortunately it is used already. The same address must not be allocated
+    // twice.
+    Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+                                               IOAddress("2001:db8:1::1f"),
+                                               false);
+    // check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // allocated address must be different
+    EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
+
+    // we should NOT get what we asked for, because it is used already
+    EXPECT_TRUE(lease->addr_.toText() != "2001:db8:1::1f");
+
+    // do all checks on the lease
+    checkLease6(lease);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease6(lease, from_mgr);
+}
+
+// This test checks if the allocation with a hint that is out the blue
+// can succeed. The invalid hint should be ignored completely.
+TEST_F(AllocEngineTest, allocBogusHint) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // Client would like to get a 3000::abc lease, which does not belong to any
+    // supported lease. Allocation engine should ignore it and carry on
+    // with the normal allocation
+    Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+                                               IOAddress("3000::abc"),
+                                               false);
+    // check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // we should NOT get what we asked for, because it is used already
+    EXPECT_TRUE(lease->addr_.toText() != "3000::abc");
+
+    // do all checks on the lease
+    checkLease6(lease);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease6(lease, from_mgr);
+}
+
+// This test verifies that the allocator picks addresses that belong to the
+// pool
+TEST_F(AllocEngineTest, IterativeAllocator) {
+    NakedAllocEngine::Allocator* alloc = new NakedAllocEngine::IterativeAllocator();
+
+    for (int i = 0; i < 1000; ++i) {
+        IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
+
+        EXPECT_TRUE(subnet_->inPool(candidate));
+    }
+
+    delete alloc;
+}
+
+
+// This test verifies that the iterative allocator really walks over all addresses
+// in all pools in specified subnet. It also must not pick the same address twice
+// unless it runs out of pool space and must start over.
+TEST_F(AllocEngineTest, IterativeAllocator_manyPools) {
+    NakedAllocEngine::IterativeAllocator* alloc = new NakedAllocEngine::IterativeAllocator();
+
+    // let's start from 2, as there is 2001:db8:1::10 - 2001:db8:1::20 pool already.
+    for (int i = 2; i < 10; ++i) {
+        stringstream min, max;
+
+        min << "2001:db8:1::" << hex << i*16 + 1;
+        max << "2001:db8:1::" << hex << i*16 + 9;
+
+        Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, IOAddress(min.str()),
+                                IOAddress(max.str())));
+        // cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
+        subnet_->addPool6(pool);
+    }
+
+    int total = 17 + 8*9; // first pool (::10 - ::20) has 17 addresses in it,
+                          // there are 8 extra pools with 9 addresses in each.
+
+    // Let's keep picked addresses here and check their uniqueness.
+    std::map<IOAddress, int> generated_addrs;
+    int cnt = 0;
+    while (++cnt) {
+        IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
+        EXPECT_TRUE(subnet_->inPool(candidate));
+
+        // One way to easily verify that the iterative allocator really works is
+        // to uncomment the following line and observe its output that it
+        // covers all defined subnets.
+        // cout << candidate.toText() << endl;
+
+        if (generated_addrs.find(candidate) == generated_addrs.end()) {
+            // we haven't had this
+            generated_addrs[candidate] = 0;
+        } else {
+            // we have seen this address before. That should mean that we
+            // iterated over all addresses.
+            if (generated_addrs.size() == total) {
+                // we have exactly the number of address in all pools
+                break;
+            }
+            ADD_FAILURE() << "Too many or not enough unique addresses generated.";
+            break;
+        }
+
+        if ( cnt>total ) {
+            ADD_FAILURE() << "Too many unique addresses generated.";
+            break;
+        }
+    }
+
+    delete alloc;
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
index 462ca9e..5cc6345 100644
--- a/src/lib/dhcp/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcp/tests/cfgmgr_unittest.cc
@@ -32,13 +32,22 @@ using boost::scoped_ptr;
 
 namespace {
 
+class CfgMgrTest : public ::testing::Test {
+public:
+    CfgMgrTest() {
+    }
+
+    ~CfgMgrTest() {
+        CfgMgr::instance().deleteSubnets6();
+    }
+};
+
+
 // This test verifies if the configuration manager is able to hold and return
 // valid leases
-TEST(CfgMgrTest, subnet4) {
+TEST_F(CfgMgrTest, subnet4) {
     CfgMgr& cfg_mgr = CfgMgr::instance();
 
-    ASSERT_TRUE(&cfg_mgr != 0);
-
     Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
     Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
     Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
@@ -66,10 +75,9 @@ TEST(CfgMgrTest, subnet4) {
 
 // This test verifies if the configuration manager is able to hold and return
 // valid leases
-TEST(CfgMgrTest, subnet6) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
 
-    ASSERT_TRUE(&cfg_mgr != 0);
+TEST_F(CfgMgrTest, subnet6) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
 
     Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
     Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
@@ -81,7 +89,11 @@ TEST(CfgMgrTest, subnet6) {
     cfg_mgr.addSubnet6(subnet1);
 
     // Now we have only one subnet, any request will be served from it
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8::1")));
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1")));
+
+    // If we have only a single subnet and the request came from a local
+    // address, let's use that subnet
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef")));
 
     cfg_mgr.addSubnet6(subnet2);
     cfg_mgr.addSubnet6(subnet3);
diff --git a/src/lib/dhcp/tests/duid_unittest.cc b/src/lib/dhcp/tests/duid_unittest.cc
index aaf6d91..435d2d2 100644
--- a/src/lib/dhcp/tests/duid_unittest.cc
+++ b/src/lib/dhcp/tests/duid_unittest.cc
@@ -166,4 +166,12 @@ TEST(ClientIdTest, operators) {
     EXPECT_TRUE(*id1 != *id3);
 }
 
+// Test checks if the toText() returns valid texual representation
+TEST(ClientIdTest, toText) {
+    uint8_t data1[] = {0, 1, 2, 3, 4, 0xff, 0xfe};
+
+    DUID duid(data1, sizeof(data1));
+    EXPECT_EQ("00:01:02:03:04:ff:fe", duid.toText());
+}
+
 } // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/lease_mgr_unittest.cc b/src/lib/dhcp/tests/lease_mgr_unittest.cc
index 897301a..64ce9b1 100644
--- a/src/lib/dhcp/tests/lease_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/lease_mgr_unittest.cc
@@ -25,12 +25,9 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 
-// This is a concrete implementation of a Lease database.
-// It does not do anything useful now, and is used for abstract LeaseMgr
-// class testing. It may later evolve into more useful backend if the
-// need arises. We can reuse code from memfile benchmark. See code in
-// tests/tools/dhcp-ubench/memfile_bench.{cc|h}
-class Memfile_LeaseMgr : public LeaseMgr {
+// This is a concrete implementation of a Lease database.  It does not do
+// anything useful and is used for abstract LeaseMgr class testing.
+class ConcreteLeaseMgr : public LeaseMgr {
 public:
 
     /// @brief The sole lease manager constructor
@@ -41,35 +38,46 @@ public:
     ///
     /// @param parameters A data structure relating keywords and values
     ///        concerned with the database.
-    Memfile_LeaseMgr(const LeaseMgr::ParameterMap& parameters);
+    ConcreteLeaseMgr(const LeaseMgr::ParameterMap& parameters)
+        : LeaseMgr(parameters)
+    {}
 
-    /// @brief Destructor (closes file)
-    virtual ~Memfile_LeaseMgr();
+    /// @brief Destructor
+    virtual ~ConcreteLeaseMgr()
+    {}
 
     /// @brief Adds an IPv4 lease.
     ///
     /// @param lease lease to be added
-    virtual bool addLease(const Lease4Ptr& lease);
+    virtual bool addLease(const Lease4Ptr&) {
+        return (false);
+    }
 
     /// @brief Adds an IPv6 lease.
     ///
     /// @param lease lease to be added
-    virtual bool addLease(const Lease6Ptr& lease);
+    virtual bool addLease(const Lease6Ptr&) {
+        return (false);
+    }
 
     /// @brief Returns existing IPv4 lease for specified IPv4 address.
     ///
     /// @param addr address of the searched lease
     ///
-    /// @return a collection of leases
-    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
+    /// @return smart pointer to the lease (or NULL if a lease is not found)
+    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&) const {
+        return (Lease4Ptr());
+    }
 
     /// @brief Returns existing IPv4 lease for specific address and subnet
     /// @param addr address of the searched lease
     /// @param subnet_id ID of the subnet the lease must belong to
     ///
     /// @return smart pointer to the lease (or NULL if a lease is not found)
-    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
-                                SubnetID subnet_id) const;
+    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&,
+                                SubnetID) const {
+        return (Lease4Ptr());
+    }
 
     /// @brief Returns existing IPv4 leases for specified hardware address.
     ///
@@ -81,7 +89,9 @@ public:
     /// @param hwaddr hardware address of the client
     ///
     /// @return lease collection
-    virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
+    virtual Lease4Collection getLease4(const HWAddr&) const {
+        return (Lease4Collection());
+    }
 
     /// @brief Returns existing IPv4 leases for specified hardware address
     ///        and a subnet
@@ -93,13 +103,18 @@ public:
     /// @param subnet_id identifier of the subnet that lease must belong to
     ///
     /// @return a pointer to the lease (or NULL if a lease is not found)
-    virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
-                                SubnetID subnet_id) const;
+    virtual Lease4Ptr getLease4(const HWAddr&, SubnetID) const {
+        return (Lease4Ptr());
+    }
 
     /// @brief Returns existing IPv4 lease for specified client-id
     ///
     /// @param clientid client identifier
-    virtual Lease4Collection getLease4(const ClientId& clientid) const;
+    ///
+    /// @return lease collection
+    virtual Lease4Collection getLease4(const ClientId&) const {
+        return (Lease4Collection());
+    }
 
     /// @brief Returns existing IPv4 lease for specified client-id
     ///
@@ -110,15 +125,18 @@ public:
     /// @param subnet_id identifier of the subnet that lease must belong to
     ///
     /// @return a pointer to the lease (or NULL if a lease is not found)
-    virtual Lease4Ptr getLease4(const ClientId& clientid,
-                                SubnetID subnet_id) const;
+    virtual Lease4Ptr getLease4(const ClientId&, SubnetID) const {
+        return (Lease4Ptr());
+    }
 
     /// @brief Returns existing IPv6 lease for a given IPv6 address.
     ///
     /// @param addr address of the searched lease
     ///
     /// @return smart pointer to the lease (or NULL if a lease is not found)
-    Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
+    Lease6Ptr getLease6(const isc::asiolink::IOAddress&) const {
+        return (Lease6Ptr());
+    }
 
     /// @brief Returns existing IPv6 lease for a given DUID+IA combination
     ///
@@ -126,7 +144,9 @@ public:
     /// @param iaid IA identifier
     ///
     /// @return collection of IPv6 leases
-    Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
+    Lease6Collection getLease6(const DUID&, uint32_t) const {
+        return (Lease6Collection());
+    }
 
     /// @brief Returns existing IPv6 lease for a given DUID+IA combination
     ///
@@ -135,45 +155,55 @@ public:
     /// @param subnet_id identifier of the subnet the lease must belong to
     ///
     /// @return smart pointer to the lease (or NULL if a lease is not found)
-    Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
+    Lease6Ptr getLease6(const DUID&, uint32_t, SubnetID) const {
+        return (Lease6Ptr());
+    }
 
     /// @brief Updates IPv4 lease.
     ///
     /// @param lease4 The lease to be updated.
     ///
     /// If no such lease is present, an exception will be thrown.
-    void updateLease4(const Lease4Ptr& lease4);
+    void updateLease4(const Lease4Ptr&) {}
 
     /// @brief Updates IPv4 lease.
     ///
     /// @param lease4 The lease to be updated.
     ///
     /// If no such lease is present, an exception will be thrown.
-    void updateLease6(const Lease6Ptr& lease6);
+    void updateLease6(const Lease6Ptr&) {}
 
     /// @brief Deletes a lease.
     ///
     /// @param addr IPv4 address of the lease to be deleted.
     ///
     /// @return true if deletion was successful, false if no such lease exists
-    bool deleteLease4(const isc::asiolink::IOAddress& addr);
+    bool deleteLease4(const isc::asiolink::IOAddress&) {
+        return (false);
+    }
 
     /// @brief Deletes a lease.
     ///
     /// @param addr IPv4 address of the lease to be deleted.
     ///
     /// @return true if deletion was successful, false if no such lease exists
-    bool deleteLease6(const isc::asiolink::IOAddress& addr);
+    bool deleteLease6(const isc::asiolink::IOAddress&) {
+        return (false);
+    }
 
     /// @brief Returns backend name.
     ///
     /// Each backend have specific name, e.g. "mysql" or "sqlite".
-    std::string getName() const { return "memfile"; }
+    std::string getName() const {
+        return (std::string("concrete"));
+    }
 
     /// @brief Returns description of the backend.
     ///
     /// This description may be multiline text that describes the backend.
-    std::string getDescription() const;
+    std::string getDescription() const {
+        return (std::string("This is a dummy concrete backend implementation."));
+    }
 
     /// @brief Returns backend version.
     std::pair<uint32_t, uint32_t> getVersion() const {
@@ -187,91 +217,8 @@ public:
     /// @brief Rollback transactions
     void rollback() {
     }
-
-    using LeaseMgr::getParameter;
-
-protected:
-
-
 };
 
-Memfile_LeaseMgr::Memfile_LeaseMgr(const LeaseMgr::ParameterMap& parameters)
-    : LeaseMgr(parameters) {
-}
-
-Memfile_LeaseMgr::~Memfile_LeaseMgr() {
-}
-
-bool Memfile_LeaseMgr::addLease(const boost::shared_ptr<isc::dhcp::Lease4>&) {
-    return (false);
-}
-
-bool Memfile_LeaseMgr::addLease(const boost::shared_ptr<isc::dhcp::Lease6>&) {
-    return (false);
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&) const {
-    return (Lease4Ptr());
-}
-
-Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
-    return (Lease4Collection());
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress & ,
-                                      SubnetID) const {
-    return (Lease4Ptr());
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr&,
-                                      SubnetID) const {
-    return (Lease4Ptr());
-}
-
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId&,
-                                      SubnetID) const {
-    return (Lease4Ptr());
-}
-
-Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
-    return (Lease4Collection());
-}
-
-Lease6Ptr Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress&) const {
-    return (Lease6Ptr());
-}
-
-Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& , uint32_t ) const {
-    return (Lease6Collection());
-}
-
-Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID&, uint32_t,
-                                      SubnetID) const {
-    return (Lease6Ptr());
-}
-
-void Memfile_LeaseMgr::updateLease4(const Lease4Ptr&) {
-}
-
-void Memfile_LeaseMgr::updateLease6(const Lease6Ptr&) {
-
-}
-
-bool Memfile_LeaseMgr::deleteLease4(const isc::asiolink::IOAddress&) {
-    return (false);
-}
-
-bool Memfile_LeaseMgr::deleteLease6(const isc::asiolink::IOAddress&) {
-    return (false);
-}
-
-std::string Memfile_LeaseMgr::getDescription() const {
-    return (string("This is a dummy memfile backend implementation.\n"
-                   "It does not offer any useful lease management and its only\n"
-                   "purpose is to test abstract lease manager API."));
-}
-
 namespace {
 // empty class for now, but may be extended once Addr6 becomes bigger
 class LeaseMgrTest : public ::testing::Test {
@@ -287,7 +234,7 @@ TEST_F(LeaseMgrTest, getParameter) {
     LeaseMgr::ParameterMap pmap;
     pmap[std::string("param1")] = std::string("value1");
     pmap[std::string("param2")] = std::string("value2");
-    Memfile_LeaseMgr leasemgr(pmap);
+    ConcreteLeaseMgr leasemgr(pmap);
 
     EXPECT_EQ("value1", leasemgr.getParameter("param1"));
     EXPECT_EQ("value2", leasemgr.getParameter("param2"));
@@ -295,10 +242,39 @@ TEST_F(LeaseMgrTest, getParameter) {
 }
 
 // There's no point in calling any other methods in LeaseMgr, as they
-// are purely virtual, so we would only call Memfile_LeaseMgr methods.
-// Those methods are just stubs that does not return anything.
-// It seems likely that we will need to extend the memfile code for
-// allocation engine tests, so we may implement tests that call
-// Memfile_LeaseMgr methods then.
+// are purely virtual, so we would only call ConcreteLeaseMgr methods.
+// Those methods are just stubs that do not return anything.
 
+// Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
+// This test checks if the Lease6 structure can be instantiated correctly
+TEST(Lease6, Lease6Constructor) {
+
+    IOAddress addr("2001:db8:1::456");
+
+    uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+    DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+    uint32_t iaid = 7; // just a number
+
+    SubnetID subnet_id = 8; // just another number
+
+    Lease6Ptr x(new Lease6(Lease6::LEASE_IA_NA, addr,
+                           duid, iaid, 100, 200, 50, 80,
+                           subnet_id));
+
+    EXPECT_TRUE(x->addr_ == addr);
+    EXPECT_TRUE(*x->duid_ == *duid);
+    EXPECT_TRUE(x->iaid_ == iaid);
+    EXPECT_TRUE(x->subnet_id_ == subnet_id);
+    EXPECT_TRUE(x->type_ == Lease6::LEASE_IA_NA);
+    EXPECT_TRUE(x->preferred_lft_ == 100);
+    EXPECT_TRUE(x->valid_lft_ == 200);
+    EXPECT_TRUE(x->t1_ == 50);
+    EXPECT_TRUE(x->t2_ == 80);
+
+    // Lease6 must be instantiated with a DUID, not with NULL pointer
+    EXPECT_THROW(new Lease6(Lease6::LEASE_IA_NA, addr,
+                            DuidPtr(), iaid, 100, 200, 50, 80,
+                            subnet_id), InvalidOperation);
+}
 }; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index d17eb65..0c9dc89 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -21,6 +21,11 @@
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/libdhcp++.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option6_addrlst.h>
 #include "config.h"
 
 using namespace std;
@@ -46,6 +51,57 @@ public:
         Option* option = new Option(u, type, buf);
         return OptionPtr(option);
     }
+
+    /// @brief Test option option definition.
+    ///
+    /// This function tests if option definition for standard
+    /// option has been initialized correctly.
+    ///
+    /// @param code option code.
+    /// @param bug buffer to be used to create option instance.
+    /// @param expected_type type of the option created by the
+    /// factory function returned by the option definition.
+    static void testInitOptionDefs6(const uint16_t code,
+                             const OptionBuffer& buf,
+                             const std::type_info& expected_type) {
+        // Initialize stdandard options definitions. They are held
+        // in the static container throughout the program.
+        LibDHCP::initStdOptionDefs(Option::V6);
+        // Get all option definitions, we will use them to extract
+        // the definition for a particular option code.
+        OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
+        // Get the container index #1. This one allows for searching
+        // option definitions using option code.
+        const OptionDefContainerTypeIndex& idx = options.get<1>();
+        // Get 'all' option definitions for a particular option code.
+        // For standard options we expect that the range returned
+        // will contain single option as their codes are unique.
+        OptionDefContainerTypeRange range = idx.equal_range(code);
+        ASSERT_EQ(1, std::distance(range.first, range.second));
+        // If we have single option definition returned, the
+        // first iterator holds it.
+        OptionDefinitionPtr def = *(range.first);
+        // It should not happen that option definition is NULL but
+        // let's make sure (test should take things like that into
+        // account).
+        ASSERT_TRUE(def);
+        // Check that option definition is valid.
+        ASSERT_NO_THROW(def->validate());
+        // Get the factory function for the particular option
+        // definition. We will use this factory function to
+        // create option instance.
+        Option::Factory* factory = NULL;
+        ASSERT_NO_THROW(factory = def->getFactory());
+        OptionPtr option;
+        // Create the option.
+        ASSERT_NO_THROW(option = factory(Option::V6, code, buf));
+        // Make sure it is not NULL.
+        ASSERT_TRUE(option);
+        // And the actual object type is the one that we expect.
+        // Note that for many options there are dedicated classes
+        // derived from Option class to represent them.
+        EXPECT_TRUE(typeid(*option) == expected_type);
+    }
 };
 
 static const uint8_t packed[] = {
@@ -311,4 +367,30 @@ TEST(LibDhcpTest, unpackOptions4) {
     EXPECT_TRUE(x == options.end()); // option 2 not found
 }
 
+// Test that definitions of standard options have been initialized
+// correctly.
+// @todo Only limited number of option definitions are now created
+// This test have to be extended once all option definitions are
+// created.
+TEST(LibDhcpTest, initStdOptionDefs) {
+    LibDhcpTest::testInitOptionDefs6(D6O_CLIENTID, OptionBuffer(14, 1),
+                                     typeid(Option));
+    LibDhcpTest::testInitOptionDefs6(D6O_SERVERID, OptionBuffer(14, 1),
+                                     typeid(Option));
+    LibDhcpTest::testInitOptionDefs6(D6O_IA_NA, OptionBuffer(12, 1),
+                                     typeid(Option6IA));
+    LibDhcpTest::testInitOptionDefs6(D6O_IAADDR, OptionBuffer(24, 1),
+                                     typeid(Option6IAAddr));
+    LibDhcpTest::testInitOptionDefs6(D6O_ORO, OptionBuffer(10, 1),
+                                     typeid(Option6IntArray<uint16_t>));
+    LibDhcpTest::testInitOptionDefs6(D6O_ELAPSED_TIME, OptionBuffer(2, 1),
+                                     typeid(Option6Int<uint16_t>));
+    LibDhcpTest::testInitOptionDefs6(D6O_STATUS_CODE, OptionBuffer(10, 1),
+                                     typeid(Option));
+    LibDhcpTest::testInitOptionDefs6(D6O_RAPID_COMMIT, OptionBuffer(),
+                                     typeid(Option));
+    LibDhcpTest::testInitOptionDefs6(D6O_NAME_SERVERS, OptionBuffer(32, 1),
+                                     typeid(Option6AddrLst));
+}
+
 }
diff --git a/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc
new file mode 100644
index 0000000..c625a16
--- /dev/null
+++ b/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc
@@ -0,0 +1,130 @@
+// 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 <config.h>
+#include <iostream>
+#include <sstream>
+#include <gtest/gtest.h>
+#include <asiolink/io_address.h>
+
+#include <dhcp/lease_mgr.h>
+#include <dhcp/duid.h>
+#include <dhcp/memfile_lease_mgr.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class MemfileLeaseMgrTest : public ::testing::Test {
+public:
+    MemfileLeaseMgrTest() {
+    }
+};
+
+// This test checks if the LeaseMgr can be instantiated and that it
+// parses parameters string properly.
+TEST_F(MemfileLeaseMgrTest, constructor) {
+
+    const LeaseMgr::ParameterMap pmap;  // Empty parameter map
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+    ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+}
+
+// There's no point in calling any other methods in LeaseMgr, as they
+// are purely virtual, so we would only call Memfile_LeaseMgr methods.
+// Those methods are just stubs that does not return anything.
+// It seems likely that we will need to extend the memfile code for
+// allocation engine tests, so we may implement tests that call
+// Memfile_LeaseMgr methods then.
+
+TEST_F(MemfileLeaseMgrTest, addGetDelete) {
+    const LeaseMgr::ParameterMap pmap;  // Empty parameter map
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+
+    IOAddress addr("2001:db8:1::456");
+
+    uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+    DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+    uint32_t iaid = 7; // just a number
+
+    SubnetID subnet_id = 8; // just another number
+
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr,
+                               duid, iaid, 100, 200, 50, 80,
+                               subnet_id));
+
+    EXPECT_TRUE(lease_mgr->addLease(lease));
+
+    // should not be allowed to add a second lease with the same address
+    EXPECT_FALSE(lease_mgr->addLease(lease));
+
+    Lease6Ptr x = lease_mgr->getLease6(IOAddress("2001:db8:1::234"));
+    EXPECT_EQ(Lease6Ptr(), x);
+
+    x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
+    ASSERT_TRUE(x);
+
+    EXPECT_EQ(x->addr_.toText(), addr.toText());
+    EXPECT_TRUE(*x->duid_ == *duid);
+    EXPECT_EQ(x->iaid_, iaid);
+    EXPECT_EQ(x->subnet_id_, subnet_id);
+
+    // These are not important from lease management perspective, but
+    // let's check them anyway.
+    EXPECT_EQ(x->type_, Lease6::LEASE_IA_NA);
+    EXPECT_EQ(x->preferred_lft_, 100);
+    EXPECT_EQ(x->valid_lft_, 200);
+    EXPECT_EQ(x->t1_, 50);
+    EXPECT_EQ(x->t2_, 80);
+
+    // Test getLease6(duid, iaid, subnet_id) - positive case
+    Lease6Ptr y = lease_mgr->getLease6(*duid, iaid, subnet_id);
+    ASSERT_TRUE(y);
+    EXPECT_TRUE(*y->duid_ == *duid);
+    EXPECT_EQ(y->iaid_, iaid);
+    EXPECT_EQ(y->addr_.toText(), addr.toText());
+
+    // Test getLease6(duid, iaid, subnet_id) - wrong iaid
+    uint32_t invalid_iaid = 9; // no such iaid
+    y = lease_mgr->getLease6(*duid, invalid_iaid, subnet_id);
+    EXPECT_FALSE(y);
+
+    uint32_t invalid_subnet_id = 999;
+    y = lease_mgr->getLease6(*duid, iaid, invalid_subnet_id);
+    EXPECT_FALSE(y);
+
+    // truncated duid
+    DuidPtr invalid_duid(new DUID(llt, sizeof(llt) - 1));
+    y = lease_mgr->getLease6(*invalid_duid, iaid, subnet_id);
+    EXPECT_FALSE(y);
+
+    // should return false - there's no such address
+    EXPECT_FALSE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::789")));
+
+    // this one should succeed
+    EXPECT_TRUE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::456")));
+
+    // after the lease is deleted, it should really be gone
+    x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
+    EXPECT_EQ(Lease6Ptr(), x);
+}
+
+// TODO: Write more memfile tests
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/option6_int_array_unittest.cc b/src/lib/dhcp/tests/option6_int_array_unittest.cc
new file mode 100644
index 0000000..581d4e1
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_int_array_unittest.cc
@@ -0,0 +1,420 @@
+// 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 <config.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Option6IntArray test class.
+class Option6IntArrayTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    ///
+    /// Initializes the option buffer with some data.
+    Option6IntArrayTest(): buf_(255), out_buf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
+    }
+
+    /// @brief Test parsing buffer into array of int8_t or uint8_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int8_t or uint8_t type is used.
+    ///
+    /// @tparam T int8_t or uint8_t.
+    template<typename T>
+    void bufferToIntTest8() {
+        // Create option that conveys array of multiple uint8_t or int8_t values.
+        // In fact there is no need to use this template class for array
+        // of uint8_t values because Option class is sufficient - it
+        // returns the buffer which is actually the array of uint8_t.
+        // However, since we allow using uint8_t types with this template
+        // class we have to test it here.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 10;
+        const uint16_t opt_code = 80;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Provided buffer is not empty so it should not throw exception.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return the collection of int8_t or uint8_t values that
+        // we can match with the buffer we used to create the option.
+        std::vector<T> values = opt->getValues();
+        // We need to copy values from the buffer to apply sign if signed
+        // type is used.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; ++i) {
+            // Values have been read from the buffer in network
+            // byte order. We put them back in the same order here.
+            reference_values.push_back(static_cast<T>(buf_[i]));
+        }
+
+        // Compare the values against the reference buffer.
+        ASSERT_EQ(opt_len, values.size());
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
+                               + opt_len, values.begin()));
+
+        // test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 10 bytes.
+        EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 10 bytes for data and 4 bytes for header.
+        ASSERT_EQ(14, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(10, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+    /// @brief Test parsing buffer into array of int16_t or uint16_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int16_t or uint16_t type is used.
+    ///
+    /// @tparam T int16_t or uint16_t.
+    template<typename T>
+    void bufferToIntTest16() {
+        // Create option that conveys array of multiple uint16_t or int16_t values.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 20;
+        const uint16_t opt_code = 81;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Constructor throws exception if provided buffer's length is not
+        // multiple of 2-bytes.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 5),
+            isc::OutOfRange
+        );
+
+        // Now the buffer length is correct.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return vector of uint16_t values which should be
+        // constructed from the buffer we provided.
+        std::vector<T> values = opt->getValues();
+        ASSERT_EQ(opt_len, values.size() * sizeof(T));
+        // Create reference values from the buffer so as we can
+        // simply compare two vectors.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; i += 2) {
+            reference_values.push_back((buf_[i] << 8) |
+                                       buf_[i + 1]);
+        }
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+                               values.begin()));
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 20 bytes.
+        EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 20 bytes for data and 4 bytes for header.
+        ASSERT_EQ(24, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(20, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+    /// @brief Test parsing buffer into array of int32_t or uint32_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int32_t or uint32_t type is used.
+    ///
+    /// @tparam T int32_t or uint32_t.
+    template<typename T>
+    void bufferToIntTest32() {
+        // Create option that conveys array of multiple uint16_t values.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 40;
+        const uint16_t opt_code = 82;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Constructor throws exception if provided buffer's length is not
+        // multiple of 4-bytes.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 9),
+            isc::OutOfRange
+        );
+
+        // Now the buffer length is correct.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return vector of uint32_t values which should be
+        // constructed from the buffer we provided.
+        std::vector<T> values = opt->getValues();
+        ASSERT_EQ(opt_len, values.size() * sizeof(T));
+        // Create reference values from the buffer so as we can
+        // simply compare two vectors.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; i += 4) {
+            reference_values.push_back((buf_[i] << 24) |
+                                       (buf_[i + 1] << 16 & 0x00FF0000) |
+                                       (buf_[i + 2] << 8 & 0xFF00) |
+                                       (buf_[i + 3] & 0xFF));
+        }
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+                               values.begin()));
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 40 bytes.
+        EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 40 bytes for data and 4 bytes for header.
+        ASSERT_EQ(44, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(40, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+
+    OptionBuffer buf_;     ///< Option buffer
+    OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned values. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(Option6IntArrayTest, useInvalidType) {
+    const uint16_t opt_code = 80;
+    EXPECT_THROW(
+        boost::scoped_ptr<
+            Option6IntArray<bool> >(new Option6IntArray<bool>(opt_code, OptionBuffer(5))),
+        InvalidDataType
+    );
+
+    EXPECT_THROW(
+        boost::scoped_ptr<
+            Option6IntArray<int64_t> >(new Option6IntArray<int64_t>(opt_code,
+                                                                    OptionBuffer(10))),
+        InvalidDataType
+    );
+
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint8) {
+    bufferToIntTest8<uint8_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt8) {
+    bufferToIntTest8<int8_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint16) {
+    bufferToIntTest16<uint16_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt16) {
+    bufferToIntTest16<int16_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint32) {
+    bufferToIntTest32<uint32_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt32) {
+    bufferToIntTest32<int32_t>();
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint8) {
+    const uint16_t opt_code = 100;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint8_t> > opt(new Option6IntArray<uint8_t>(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()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt8) {
+    const uint16_t opt_code = 100;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int8_t> > opt(new Option6IntArray<int8_t>(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()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint16) {
+    const uint16_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint16_t> > opt(new Option6IntArray<uint16_t>(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()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt16) {
+    const uint16_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int16_t> > opt(new Option6IntArray<int16_t>(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()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint32) {
+    const uint32_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint32_t> > opt(new Option6IntArray<uint32_t>(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()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt32) {
+    const uint32_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int32_t> > opt(new Option6IntArray<int32_t>(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);
+
+    // 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()));
+}
+
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option6_int_unittest.cc b/src/lib/dhcp/tests/option6_int_unittest.cc
new file mode 100644
index 0000000..3d39a1a
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_int_unittest.cc
@@ -0,0 +1,413 @@
+// 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 <config.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Option6Int test class.
+class Option6IntTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    ///
+    /// Initializes the option buffer with some data.
+    Option6IntTest(): buf_(255), out_buf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
+    }
+
+    /// @brief Basic test for int8 and uint8 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int8_t or uint8_t type is used.
+    ///
+    /// @tparam T int8_t or uint8_t.
+    template<typename T>
+    void basicTest8() {
+        // Create option that conveys single 8 bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with this value.
+        buf_[0] = 0xa1;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_PREFERENCE,
+                                                                      buf_.begin(),
+                                                                      buf_.end()))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+        // Option should return the same value that we initialized the first
+        // byte of the buffer with.
+        EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
+
+        // test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 1 byte.
+        EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+        // The total length is 1 byte for data and 4 bytes for header.
+        EXPECT_EQ(5, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_PREFERENCE, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(1, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1, out.readUint8() );
+    }
+
+    /// @brief Basic test for int16 and uint16 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int16_t or uint16_t type is used.
+    ///
+    /// @tparam T int16_t or uint16_t.
+    template<typename T>
+    void basicTest16() {
+        // Create option that conveys single 16-bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with uint16_t value.
+        buf_[0] = 0xa1;
+        buf_[1] = 0xa2;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_ELAPSED_TIME,
+                                                                      buf_.begin(),
+                                                                      buf_.end()))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+        // Option should return the value equal to the contents of first
+        // and second byte of the buffer.
+        EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 2 bytes.
+        EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+        // The total length is 2 byte for data and 4 bytes for header.
+        EXPECT_EQ(6, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(2, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1a2, out.readUint16() );
+    }
+
+    /// @brief Basic test for int32 and uint32 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int32_t or uint32_t type is used.
+    ///
+    /// @tparam T int32_t or uint32_t.
+    template<typename T>
+    void basicTest32() {
+        // Create option that conveys single 32-bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with 32-bit integer value.
+        buf_[0] = 0xa1;
+        buf_[1] = 0xa2;
+        buf_[2] = 0xa3;
+        buf_[3] = 0xa4;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+                        opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_CLT_TIME,
+                                                                                  buf_.begin(),
+                                                                                  buf_.end()))
+                        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+        // Option should return the value equal to the value made of
+        // first 4 bytes of the buffer.
+        EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 4 bytes.
+        EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+        // The total length is 4 bytes for data and 4 bytes for header.
+        EXPECT_EQ(8, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_CLT_TIME, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(4, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1a2a3a4, out.readUint32());
+    }
+
+    OptionBuffer buf_;     ///< Option buffer
+    OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned value. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(Option6IntTest, useInvalidType) {
+    EXPECT_THROW(
+        boost::scoped_ptr<Option6Int<bool> >(new Option6Int<bool>(D6O_ELAPSED_TIME, 10)),
+        InvalidDataType
+    );
+
+    EXPECT_THROW(
+        boost::scoped_ptr<Option6Int<int64_t> >(new Option6Int<int64_t>(D6O_ELAPSED_TIME, 10)),
+        InvalidDataType
+    );
+
+}
+
+TEST_F(Option6IntTest, basicUint8) {
+    basicTest8<uint8_t>();
+}
+
+TEST_F(Option6IntTest, basicUint16) {
+    basicTest16<uint16_t>();
+}
+
+TEST_F(Option6IntTest, basicUint32) {
+    basicTest32<uint32_t>();
+}
+
+TEST_F(Option6IntTest, basicInt8) {
+    basicTest8<int8_t>();
+}
+
+TEST_F(Option6IntTest, basicInt16) {
+    basicTest16<int16_t>();
+}
+
+TEST_F(Option6IntTest, basicInt32) {
+    basicTest32<int32_t>();
+}
+
+TEST_F(Option6IntTest, setValueUint8) {
+    boost::shared_ptr<Option6Int<uint8_t> > opt(new Option6Int<uint8_t>(D6O_PREFERENCE, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(111);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(111, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueInt8) {
+    boost::shared_ptr<Option6Int<int8_t> > opt(new Option6Int<int8_t>(D6O_PREFERENCE, -123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-123, opt->getValue());
+    // Override the value.
+    opt->setValue(-111);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-111, opt->getValue());
+}
+
+
+TEST_F(Option6IntTest, setValueUint16) {
+    boost::shared_ptr<Option6Int<uint16_t> > opt(new Option6Int<uint16_t>(D6O_ELAPSED_TIME, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(0x0102);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(0x0102, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueInt16) {
+    boost::shared_ptr<Option6Int<int16_t> > opt(new Option6Int<int16_t>(D6O_ELAPSED_TIME, -16500));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-16500, opt->getValue());
+    // Override the value.
+    opt->setValue(-20100);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-20100, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueUint32) {
+    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(D6O_CLT_TIME, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(0x01020304);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(0x01020304, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueint32) {
+    boost::shared_ptr<Option6Int<int32_t> > opt(new Option6Int<int32_t>(D6O_CLT_TIME, -120100));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-120100, opt->getValue());
+    // Override the value.
+    opt->setValue(-125000);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-125000, opt->getValue());
+}
+
+TEST_F(Option6IntTest, packSuboptions) {
+    // option code is really uint16_t, but using uint8_t
+    // for easier conversion to uint8_t array.
+    uint8_t opt_code = 80;
+
+    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(opt_code, 0x01020304));
+    OptionPtr sub1(new Option(Option::V6, 0xcafe));
+
+    boost::shared_ptr<Option6IAAddr> addr1(
+        new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
+
+    opt->addOption(sub1);
+    opt->addOption(addr1);
+
+    ASSERT_EQ(28, addr1->len());
+    ASSERT_EQ(4, sub1->len());
+    ASSERT_EQ(40, opt->len());
+
+    uint8_t expected[] = {
+        0, opt_code, // type
+        0, 36, // length
+        0x01, 0x02, 0x03, 0x04, // uint32_t value
+
+        // iaaddr suboption
+        D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+        0, 24, // len
+        0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+        0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+        0, 0, 0x50, 0, // preferred-lifetime
+        0, 0, 0x70, 0, // valid-lifetime
+
+        // suboption
+        0xca, 0xfe, // type
+        0, 0 // len
+    };
+
+    // Create on-wire format of option and suboptions.
+    opt->pack(out_buf_);
+    // Compare the on-wire data with the reference buffer.
+    ASSERT_EQ(40, out_buf_.getLength());
+    EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
+}
+
+
+TEST_F(Option6IntTest, unpackSuboptions) {
+    // option code is really uint16_t, but using uint8_t
+    // for easier conversion to uint8_t array.
+    const uint8_t opt_code = 80;
+    // Prepare reference data.
+    uint8_t expected[] = {
+        0, opt_code, // type
+        0, 34, // length
+        0x01, 0x02, // uint16_t value
+
+        // iaaddr suboption
+        D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+        0, 24, // len
+        0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+        0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+        0, 0, 0x50, 0, // preferred-lifetime
+        0, 0, 0x70, 0, // valid-lifetime
+
+        // suboption
+        0xca, 0xfe, // type
+        0, 0 // len
+    };
+    ASSERT_EQ(38, sizeof(expected));
+
+    memcpy(&buf_[0], expected, sizeof(expected));
+
+    boost::shared_ptr<Option6Int<uint16_t> > opt;
+    EXPECT_NO_THROW(
+        opt = boost::shared_ptr<
+            Option6Int<uint16_t> >(new Option6Int<uint16_t>(opt_code, buf_.begin() + 4,
+                                                            buf_.begin() + sizeof(expected)));
+    );
+    ASSERT_TRUE(opt);
+
+    EXPECT_EQ(opt_code, opt->getType());
+    EXPECT_EQ(0x0102, opt->getValue());
+
+    // Checks for address option
+    OptionPtr subopt = opt->getOption(D6O_IAADDR);
+    ASSERT_TRUE(subopt);
+    boost::shared_ptr<Option6IAAddr> addr(boost::dynamic_pointer_cast<Option6IAAddr>(subopt));
+    ASSERT_TRUE(addr);
+
+    EXPECT_EQ(D6O_IAADDR, addr->getType());
+    EXPECT_EQ(28, addr->len());
+    EXPECT_EQ(0x5000, addr->getPreferred());
+    EXPECT_EQ(0x7000, addr->getValid());
+    EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
+
+    // Checks for dummy option
+    subopt = opt->getOption(0xcafe);
+    ASSERT_TRUE(subopt); // should be non-NULL
+
+    EXPECT_EQ(0xcafe, subopt->getType());
+    EXPECT_EQ(4, subopt->len());
+    // There should be no data at all
+    EXPECT_EQ(0, subopt->getData().size());
+
+    // Try to get non-existent option.
+    subopt = opt->getOption(1);
+    // Expecting NULL which means that option does not exist.
+    ASSERT_FALSE(subopt);
+}
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
new file mode 100644
index 0000000..7e92680
--- /dev/null
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -0,0 +1,660 @@
+// 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 <config.h>
+
+#include <exceptions/exceptions.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option_definition.h>
+
+#include <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/pointer_cast.hpp>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+namespace {
+
+/// @brief OptionDefinition test class.
+///
+/// This class does not do anything useful but we keep
+/// it around for the future.
+class OptionDefinitionTest : public ::testing::Test {
+public:
+    // @brief Constructor.
+    OptionDefinitionTest() { }
+};
+
+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");
+    EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
+    EXPECT_EQ(1, opt_def1.getCode());
+    EXPECT_EQ(OptionDefinition::STRING_TYPE,  opt_def1.getType());
+    EXPECT_FALSE(opt_def1.getArrayType());
+    EXPECT_NO_THROW(opt_def1.validate());
+
+    // Specify the option data type as an enum value.
+    OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
+                              OptionDefinition::EMPTY_TYPE);
+    EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
+    EXPECT_EQ(14, opt_def2.getCode());
+    EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
+    EXPECT_FALSE(opt_def2.getArrayType());
+    EXPECT_NO_THROW(opt_def1.validate());
+
+    // Check if it is possible to set that option is an array.
+    OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
+                              OptionDefinition::IPV6_ADDRESS_TYPE,
+                              true);
+    EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
+    EXPECT_EQ(27, opt_def3.getCode());
+    EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, opt_def3.getType());
+    EXPECT_TRUE(opt_def3.getArrayType());
+    EXPECT_NO_THROW(opt_def3.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::UNKNOWN_TYPE + 10,
+                                  OptionDefinition::STRING_TYPE);
+    );
+}
+
+TEST_F(OptionDefinitionTest, addRecordField) {
+    // We can only add fields to record if the option type has been
+    // specified as 'record'. We try all other types but 'record'
+    // here and expect exception to be thrown.
+    for (int i = 0; i < OptionDefinition::UNKNOWN_TYPE; ++i) {
+        // Do not try for 'record' type because this is the only
+        // type for which adding record will succeed.
+        if (i == OptionDefinition::RECORD_TYPE) {
+            continue;
+        }
+        OptionDefinition opt_def("OPTION_IAADDR", 5,
+                                 static_cast<OptionDefinition::DataType>(i));
+        EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
+    }
+
+    // Positive scenario starts here.
+    OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
+    EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
+    EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
+    // It should not matter if we specify field type by its name or using enum.
+    EXPECT_NO_THROW(opt_def.addRecordField(OptionDefinition::UINT32_TYPE));
+
+    // Check what we have actually added.
+    OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
+    ASSERT_EQ(3, fields.size());
+    EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, fields[0]);
+    EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[1]);
+    EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[2]);
+
+    // Let's try some more negative scenarios: use invalid data types.
+    EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
+    OptionDefinition::DataType invalid_type =
+        static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE + 10);
+    EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, validate) {
+    // Not supported option type string is not allowed.
+    OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
+    EXPECT_THROW(opt_def1.validate(), isc::OutOfRange);
+
+    // Not supported option type enum value is not allowed.
+    OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OptionDefinition::UNKNOWN_TYPE);
+    EXPECT_THROW(opt_def2.validate(), isc::OutOfRange);
+
+    OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
+                              static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE
+                                                                      + 2));
+    EXPECT_THROW(opt_def3.validate(), isc::OutOfRange);
+    
+    // Empty option name is not allowed.
+    OptionDefinition opt_def4("", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def4.validate(), isc::BadValue);
+
+    // Option name must not contain spaces.
+    OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def5.validate(), isc::BadValue);
+
+    OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def6.validate(), isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, factoryAddrList6) {
+    OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
+                             "ipv6-address", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create a list of some V6 addresses.
+    std::vector<asiolink::IOAddress> addrs;
+    addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
+    addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
+    addrs.push_back(asiolink::IOAddress("::1"));
+    addrs.push_back(asiolink::IOAddress("::2"));
+
+    // Write addresses to the buffer.
+    OptionBuffer buf(addrs.size() * asiolink::V6ADDRESS_LEN);
+    for (int i = 0; i < addrs.size(); ++i) {
+        asio::ip::address_v6::bytes_type addr_bytes =
+            addrs[i].getAddress().to_v6().to_bytes();
+        ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
+        std::copy(addr_bytes.begin(), addr_bytes.end(),
+                  buf.begin() + i * asiolink::V6ADDRESS_LEN);
+    }
+    // Create DHCPv6 option from this buffer. Once option is created it is
+    // supposed to have internal list of addresses that it parses out from
+    // the provided buffer.
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_NIS_SERVERS, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
+    boost::shared_ptr<Option6AddrLst> option_cast_v6 =
+        boost::static_pointer_cast<Option6AddrLst>(option_v6);
+    ASSERT_TRUE(option_cast_v6);
+    // Get the list of parsed addresses from the option object.
+    std::vector<asiolink::IOAddress> addrs_returned =
+        option_cast_v6->getAddresses();
+    // The list of addresses must exactly match addresses that we
+    // stored in the buffer to create the option from it.
+    EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
+
+    // The provided buffer's length must be a multiple of V6 address length.
+    // Let's extend the buffer by one byte so as this condition is not
+    // fulfilled anymore.
+    buf.insert(buf.end(), 1, 1);
+    // It should throw exception then.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_NIS_SERVERS, buf),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryAddrList4) {
+    OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
+                             "ipv4-address", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create a list of some V6 addresses.
+    std::vector<asiolink::IOAddress> addrs;
+    addrs.push_back(asiolink::IOAddress("192.168.0.1"));
+    addrs.push_back(asiolink::IOAddress("172.16.1.1"));
+    addrs.push_back(asiolink::IOAddress("127.0.0.1"));
+    addrs.push_back(asiolink::IOAddress("213.41.23.12"));
+
+    // Write addresses to the buffer.
+    OptionBuffer buf(addrs.size() * asiolink::V4ADDRESS_LEN);
+    for (int i = 0; i < addrs.size(); ++i) {
+        asio::ip::address_v4::bytes_type addr_bytes =
+            addrs[i].getAddress().to_v4().to_bytes();
+        ASSERT_EQ(asiolink::V4ADDRESS_LEN, addr_bytes.size());
+        std::copy(addr_bytes.begin(), addr_bytes.end(),
+                  buf.begin() + i * asiolink::V4ADDRESS_LEN);
+    }
+    // Create DHCPv6 option from this buffer. Once option is created it is
+    // supposed to have internal list of addresses that it parses out from
+    // the provided buffer.
+    OptionPtr option_v4;
+    ASSERT_NO_THROW(
+        option_v4 = factory(Option::V4, DHO_NAME_SERVERS, buf)
+    );
+    ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
+    // Get the list of parsed addresses from the option object.
+    boost::shared_ptr<Option4AddrLst> option_cast_v4 =
+        boost::static_pointer_cast<Option4AddrLst>(option_v4);
+    std::vector<asiolink::IOAddress> addrs_returned =
+        option_cast_v4->getAddresses();
+    // The list of addresses must exactly match addresses that we
+    // stored in the buffer to create the option from it.
+    EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
+
+    // The provided buffer's length must be a multiple of V4 address length.
+    // Let's extend the buffer by one byte so as this condition is not
+    // fulfilled anymore.
+    buf.insert(buf.end(), 1, 1);
+    // It should throw exception then.
+    EXPECT_THROW(factory(Option::V4, DHO_NIS_SERVERS, buf), isc::OutOfRange);
+}
+
+TEST_F(OptionDefinitionTest, factoryEmpty) {
+    OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create option instance and provide empty buffer as expected.
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
+    // Expect 'empty' DHCPv6 option.
+    EXPECT_EQ(Option::V6, option_v6->getUniverse());
+    EXPECT_EQ(4, option_v6->getHeaderLen());
+    EXPECT_EQ(0, option_v6->getData().size());
+
+    // Repeat the same test scenario for DHCPv4 option.
+    EXPECT_THROW(factory(Option::V4, 214, OptionBuffer(2)),isc::BadValue);
+
+    OptionPtr option_v4;
+    ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, OptionBuffer()));
+    // Expect 'empty' DHCPv4 option.
+    EXPECT_EQ(Option::V4, option_v4->getUniverse());
+    EXPECT_EQ(2, option_v4->getHeaderLen());
+    EXPECT_EQ(0, option_v4->getData().size());
+
+    // This factory produces empty option (consisting of option type
+    // and length). Attempt to provide some data in the buffer should
+    // result in exception.
+    EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, factoryBinary) {
+    // Binary option is the one that is represented by the generic
+    // Option class. In fact all options can be represented by this
+    // class but for some of them it is just natural. The SERVERID
+    // option consists of the option code, length and binary data so
+    // this one was picked for this test.
+    OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Prepare some dummy data (serverid): 0, 1, 2 etc.
+    OptionBuffer buf(14);
+    for (int i = 0; i < 14; ++i) {
+        buf[i] = i;
+    }
+    // Create option instance with the factory function.
+    // If the OptionDefinition code works properly than
+    // object of the type Option should be returned.
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_SERVERID, buf);
+    );
+    // Expect base option type returned.
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
+    // Sanity check on universe, length and size. These are
+    // the basic parameters identifying any option.
+    EXPECT_EQ(Option::V6, option_v6->getUniverse());
+    EXPECT_EQ(4, option_v6->getHeaderLen());
+    ASSERT_EQ(buf.size(), option_v6->getData().size());
+
+    // Get the server id data from the option and compare
+    // against reference buffer. They are expected to match.
+    EXPECT_TRUE(std::equal(option_v6->getData().begin(),
+                           option_v6->getData().end(),
+                           buf.begin()));
+
+    // Repeat the same test scenario for DHCPv4 option.
+    OptionPtr option_v4;
+    ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, buf));
+    // Expect 'empty' DHCPv4 option.
+    EXPECT_EQ(Option::V4, option_v4->getUniverse());
+    EXPECT_EQ(2, option_v4->getHeaderLen());
+    ASSERT_EQ(buf.size(), option_v4->getData().size());
+
+    EXPECT_TRUE(std::equal(option_v6->getData().begin(),
+                           option_v6->getData().end(),
+                           buf.begin()));
+}
+
+TEST_F(OptionDefinitionTest, factoryIA6) {
+    // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
+    const int option6_ia_len = 12;
+
+    // Get the factory function pointer.
+    OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", true);
+    // Each data field is uint32.
+    for (int i = 0; i < 3; ++i) {
+        EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
+    }
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Check the positive scenario.
+    OptionBuffer buf(12);
+    for (int i = 0; i < buf.size(); ++i) {
+        buf[i] = i;
+    }
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IA_NA, buf));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IA));
+    boost::shared_ptr<Option6IA> option_cast_v6 =
+        boost::static_pointer_cast<Option6IA>(option_v6);
+    EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
+    EXPECT_EQ(0x04050607, option_cast_v6->getT1());
+    EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
+
+    // This should work for DHCPv6 only, try passing invalid universe value.
+    EXPECT_THROW(
+        factory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
+        isc::BadValue
+    );
+    // The length of the buffer must be 12 bytes.
+    // Check too short buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
+        isc::OutOfRange
+     );
+    // Check too long buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len + 1)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryIAAddr6) {
+    // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
+    // valid-lifetime fields (each 4 bytes long).
+    const int option6_iaaddr_len = 24;
+
+    OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
+    ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
+    ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+    ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Check the positive scenario.
+    OptionPtr option_v6;
+    asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
+    OptionBuffer buf(asiolink::V6ADDRESS_LEN);
+    ASSERT_TRUE(addr_v6.getAddress().is_v6());
+    asio::ip::address_v6::bytes_type addr_bytes =
+        addr_v6.getAddress().to_v6().to_bytes();
+    ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
+    std::copy(addr_bytes.begin(), addr_bytes.end(), buf.begin());
+
+    for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
+        buf.push_back(i);
+    }
+    ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IAADDR, buf));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
+    boost::shared_ptr<Option6IAAddr> option_cast_v6 =
+        boost::static_pointer_cast<Option6IAAddr>(option_v6);
+    EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
+    EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
+    EXPECT_EQ(0x04050607, option_cast_v6->getValid());
+
+    // This should work for DHCPv6 only, try passing invalid universe value.
+    EXPECT_THROW(
+        factory(Option::V4, D6O_IAADDR, OptionBuffer(option6_iaaddr_len)),
+        isc::BadValue
+    );
+    // The length of the buffer must be 12 bytes.
+    // Check too short buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
+        isc::OutOfRange
+     );
+    // Check too long buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len + 1)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
+    // The template function factoryInteger<> accepts integer values only
+    // as template typename. Here we try passing different type and
+    // see if it rejects it.
+    EXPECT_THROW(
+        OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
+        isc::dhcp::InvalidDataType
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryUint8) {
+    OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Try to use correct buffer length = 1 byte.
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+    EXPECT_EQ(1, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(3)),
+        isc::OutOfRange
+    );
+
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint16) {
+    OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Try to use correct buffer length = 2 bytes.
+    OptionBuffer buf;
+    buf.push_back(1);
+    buf.push_back(2);
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+    EXPECT_EQ(0x0102, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(3)),
+        isc::OutOfRange
+    );
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint32) {
+    OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    OptionBuffer buf;
+    buf.push_back(1);
+    buf.push_back(2);
+    buf.push_back(3);
+    buf.push_back(4);
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+    EXPECT_EQ(0x01020304, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint16Array) {
+    // Let's define some dummy option.
+    const uint16_t opt_code = 79;
+    OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x112233.
+    OptionBuffer buf(6);
+    for (int i = 0; i < 6; ++i) {
+        buf[i] = i / 2;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = factory(Option::V6, opt_code, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
+    boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    std::vector<uint16_t> values = option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
+        uint16_t expected = (i << 8) | i;
+        EXPECT_EQ(expected, values[i]);
+    }
+
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryUint32Array) {
+    // Let's define some dummy option.
+    const uint16_t opt_code = 80;
+
+    OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x111122223333.
+    OptionBuffer buf(12);
+    for (int i = 0; i < buf.size(); ++i) {
+        buf[i] = i / 4;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = factory(Option::V6, opt_code, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
+    boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    std::vector<uint32_t> values = option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
+        uint32_t expected = 0x01010101 * i;
+        EXPECT_EQ(expected, values[i]);
+    }
+
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, recognizeFormat) {
+    // IA_NA option format.
+    OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
+    for (int i = 0; i < 3; ++i) {
+        opt_def1.addRecordField("uint32");
+    }
+    EXPECT_TRUE(opt_def1.haveIA6Format());
+    // Create non-matching format to check that this function does not
+    // return 'true' all the time.
+    OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
+    EXPECT_FALSE(opt_def2.haveIA6Format());
+
+    // IAADDR option format.
+    OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
+    opt_def3.addRecordField("ipv6-address");
+    opt_def3.addRecordField("uint32");
+    opt_def3.addRecordField("uint32");
+    EXPECT_TRUE(opt_def3.haveIAAddr6Format());
+    // Create non-matching format to check that this function does not
+    // return 'true' all the time.
+    OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
+    EXPECT_FALSE(opt_def4.haveIAAddr6Format());
+}
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc
index 63d4289..e596278 100644
--- a/src/lib/dhcp/tests/pool_unittest.cc
+++ b/src/lib/dhcp/tests/pool_unittest.cc
@@ -179,4 +179,3 @@ TEST(Pool6Test, unique_id) {
 }
 
 }; // end of anonymous namespace
-
diff --git a/src/lib/dhcp/tests/subnet_unittest.cc b/src/lib/dhcp/tests/subnet_unittest.cc
index 6c26106..0d9c546 100644
--- a/src/lib/dhcp/tests/subnet_unittest.cc
+++ b/src/lib/dhcp/tests/subnet_unittest.cc
@@ -15,6 +15,7 @@
 
 #include <config.h>
 #include <dhcp/subnet.h>
+#include <dhcp/option.h>
 #include <exceptions/exceptions.h>
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
@@ -104,6 +105,72 @@ TEST(Subnet4Test, Subnet4_Pool4_checks) {
     EXPECT_THROW(subnet->addPool4(pool3), BadValue);
 }
 
+TEST(Subnet4Test, addInvalidOption) {
+    // Create the V4 subnet.
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
+
+    // Some dummy option code.
+    uint16_t code = 100;
+    // Create option with invalid universe (V6 instead of V4).
+    // Attempt to add this option should result in exception.
+    OptionPtr option1(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+    EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+
+    // Create NULL pointer option. Attempt to add NULL option
+    // should result in exception.
+    OptionPtr option2;
+    ASSERT_FALSE(option2);
+    EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+}
+
+// This test verifies that inRange() and inPool() methods work properly.
+TEST(Subnet4Test, inRangeinPool) {
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.0.0"), 8, 1, 2, 3));
+
+    // this one is in subnet
+    Pool4Ptr pool1(new Pool4(IOAddress("192.2.0.0"), 16));
+    subnet->addPool4(pool1);
+
+    // 192.1.1.1 belongs to the subnet...
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.1.1.1")));
+
+    // ... but it does not belong to any pool within
+    EXPECT_FALSE(subnet->inPool(IOAddress("192.1.1.1")));
+
+    // the last address that is in range, but out of pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.1.255.255")));
+    EXPECT_FALSE(subnet->inPool(IOAddress("192.1.255.255")));
+
+    // the first address that is in range, in pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.0.0")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("192.2.0.0")));
+
+    // let's try something in the middle as well
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.3.4")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("192.2.3.4")));
+
+    // the last address that is in range, in pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.255.255")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("192.2.255.255")));
+
+    // the first address that is in range, but out of pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("192.3.0.0")));
+    EXPECT_FALSE(subnet->inPool(IOAddress("192.3.0.0")));
+}
+
+// This test checks if the toText() method returns text representation
+TEST(Subnet4Test, toText) {
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
+    EXPECT_EQ("192.0.2.0/24", subnet->toText());
+}
+
+// This test checks if the get() method returns proper parameters
+TEST(Subnet4Test, get) {
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 28, 1, 2, 3));
+    EXPECT_EQ("192.0.2.0", subnet->get().first.toText());
+    EXPECT_EQ(28, subnet->get().second);
+}
+
 // Tests for Subnet6
 
 TEST(Subnet6Test, constructor) {
@@ -161,7 +228,6 @@ TEST(Subnet6Test, Pool6InSubnet6) {
     mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
 
     EXPECT_EQ(mypool, pool3);
-
 }
 
 TEST(Subnet6Test, Subnet6_Pool6_checks) {
@@ -187,4 +253,195 @@ TEST(Subnet6Test, Subnet6_Pool6_checks) {
     EXPECT_THROW(subnet->addPool6(pool4), BadValue);
 }
 
+TEST(Subnet6Test, addOptions) {
+    // Create as subnet to add options to it.
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    // Differentiate options by their codes (100-109)
+    for (uint16_t code = 100; code < 110; ++code) {
+        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+        ASSERT_NO_THROW(subnet->addOption(option));
+    }
+
+    // Get options from the Subnet and check if all 10 are there.
+    Subnet::OptionContainer options = subnet->getOptions();
+    ASSERT_EQ(10, options.size());
+
+    // Validate codes of added options.
+    uint16_t expected_code = 100;
+    for (Subnet::OptionContainer::const_iterator option_desc = options.begin();
+         option_desc != options.end(); ++option_desc) {
+        ASSERT_TRUE(option_desc->option);
+        EXPECT_EQ(expected_code, option_desc->option->getType());
+        ++expected_code;
+    }
+
+    subnet->delOptions();
+
+    options = subnet->getOptions();
+    EXPECT_EQ(0, options.size());
+}
+
+TEST(Subnet6Test, addNonUniqueOptions) {
+    // Create as subnet to add options to it.
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    // Create a set of options with non-unique codes.
+    for (int i = 0;  i < 2; ++i) {
+        // In the inner loop we create options with unique codes (100-109).
+        for (uint16_t code = 100; code < 110; ++code) {
+            OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+            ASSERT_NO_THROW(subnet->addOption(option));
+        }
+    }
+
+    // Sanity check that all options are there.
+    Subnet::OptionContainer options = subnet->getOptions();
+    ASSERT_EQ(20, options.size());
+
+    // Use container index #1 to get the options by their codes.
+    Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+    // Look for the codes 100-109.
+    for (uint16_t code = 100; code < 110; ++ code) {
+        // For each code we should get two instances of options.
+        std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+                  Subnet::OptionContainerTypeIndex::const_iterator> range =
+            idx.equal_range(code);
+        // Distance between iterators indicates how many options
+        // have been retured for the particular code.
+        ASSERT_EQ(2, distance(range.first, range.second));
+        // Check that returned options actually have the expected option code.
+        for (Subnet::OptionContainerTypeIndex::const_iterator option_desc = range.first;
+             option_desc != range.second; ++option_desc) {
+            ASSERT_TRUE(option_desc->option);
+            EXPECT_EQ(code, option_desc->option->getType());
+        }
+    }
+
+    // Let's try to find some non-exiting option.
+    const uint16_t non_existing_code = 150;
+    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+              Subnet::OptionContainerTypeIndex::const_iterator> range =
+        idx.equal_range(non_existing_code);
+    // Empty set is expected.
+    EXPECT_EQ(0, distance(range.first, range.second));
+
+    subnet->delOptions();
+
+    options = subnet->getOptions();
+    EXPECT_EQ(0, options.size());
+}
+
+TEST(Subnet6Test, addInvalidOption) {
+    // Create as subnet to add options to it.
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    // Some dummy option code.
+    uint16_t code = 100;
+    // Create option with invalid universe (V4 instead of V6).
+    // Attempt to add this option should result in exception.
+    OptionPtr option1(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
+    EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+
+    // Create NULL pointer option. Attempt to add NULL option
+    // should result in exception.
+    OptionPtr option2;
+    ASSERT_FALSE(option2);
+    EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+}
+
+TEST(Subnet6Test, addPersistentOption) {
+    // Create as subnet to add options to it.
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    // Add 10 options to the subnet with option codes 100 - 109.
+    for (uint16_t code = 100; code < 110; ++code) {
+        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+        // We create 10 options and want some of them to be flagged
+        // persistent and some non-persistent. Persistent options are
+        // those that server sends to clients regardless if they ask
+        // for them or not. We pick 3 out of 10 options and mark them
+        // non-persistent and 7 other options persistent.
+        // Code values: 102, 105 and 108 are divisable by 3
+        // and options with these codes will be flagged non-persistent.
+        // Options with other codes will be flagged persistent.
+        bool persistent = (code % 3) ? true : false;
+        ASSERT_NO_THROW(subnet->addOption(option, persistent));
+    }
+
+    // Get added options from the subnet.
+    Subnet::OptionContainer options = subnet->getOptions();
+
+    // options.get<2> returns reference to container index #2. This
+    // index is used to access options by the 'persistent' flag.
+    Subnet::OptionContainerPersistIndex& idx = options.get<2>();
+
+    // Get all persistent options.
+    std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
+              Subnet::OptionContainerPersistIndex::const_iterator> range_persistent =
+        idx.equal_range(true);
+    // 3 out of 10 options have been flagged persistent.
+    ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
+
+    // Get all non-persistent options.
+    std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
+              Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
+        idx.equal_range(false);
+    // 7 out of 10 options have been flagged persistent.
+    ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
+
+    subnet->delOptions();
+
+    options = subnet->getOptions();
+    EXPECT_EQ(0, options.size());
+}
+
+// This test verifies that inRange() and inPool() methods work properly.
+TEST(Subnet6Test, inRangeinPool) {
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
+
+    // this one is in subnet
+    Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::10"),
+                             IOAddress("2001:db8::20")));
+    subnet->addPool6(pool1);
+
+    // 192.1.1.1 belongs to the subnet...
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::1")));
+    // ... but it does not belong to any pool within
+    EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::1")));
+
+    // the last address that is in range, but out of pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::f")));
+    EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::f")));
+
+    // the first address that is in range, in pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::10")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::10")));
+
+    // let's try something in the middle as well
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::18")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::18")));
+
+    // the last address that is in range, in pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::20")));
+    EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::20")));
+
+    // the first address that is in range, but out of pool
+    EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::21")));
+    EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::21")));
+}
+
+// This test checks if the toText() method returns text representation
+TEST(Subnet6Test, toText) {
+    Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
+    EXPECT_EQ("2001:db8::/32", subnet.toText());
+}
+
+// This test checks if the get() method returns proper parameters
+TEST(Subnet6Test, get) {
+    Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
+    EXPECT_EQ("2001:db8::", subnet.get().first.toText());
+    EXPECT_EQ(32, subnet.get().second);
+}
+
 };
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 977854d..e81ef76 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -93,8 +93,10 @@ libb10_dns___la_LDFLAGS = -no-undefined -version-info 2:0:0
 libb10_dns___la_SOURCES =
 libb10_dns___la_SOURCES += edns.h edns.cc
 libb10_dns___la_SOURCES += exceptions.h exceptions.cc
+libb10_dns___la_SOURCES += master_lexer_inputsource.h master_lexer_inputsource.cc
 libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
 libb10_dns___la_SOURCES += masterload.h masterload.cc
+libb10_dns___la_SOURCES += master_lexer.h master_lexer.cc
 libb10_dns___la_SOURCES += message.h message.cc
 libb10_dns___la_SOURCES += messagerenderer.h messagerenderer.cc
 libb10_dns___la_SOURCES += name.h name.cc
@@ -145,6 +147,8 @@ libdns___include_HEADERS = \
 	exceptions.h \
 	labelsequence.h \
 	message.h \
+	master_lexer.h \
+	masterload.h \
 	messagerenderer.h \
 	name.h \
 	question.h \
diff --git a/src/lib/dns/benchmarks/message_renderer_bench.cc b/src/lib/dns/benchmarks/message_renderer_bench.cc
index abf3192..f5b3e38 100644
--- a/src/lib/dns/benchmarks/message_renderer_bench.cc
+++ b/src/lib/dns/benchmarks/message_renderer_bench.cc
@@ -145,7 +145,6 @@ main(int argc, char* argv[]) {
         }
     }
     argc -= optind;
-    argv += optind;
     if (argc != 0) {
         usage();
     }
diff --git a/src/lib/dns/benchmarks/oldmessagerenderer.h b/src/lib/dns/benchmarks/oldmessagerenderer.h
index d408081..acbd757 100644
--- a/src/lib/dns/benchmarks/oldmessagerenderer.h
+++ b/src/lib/dns/benchmarks/oldmessagerenderer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __OLDMESSAGERENDERER_H
-#define __OLDMESSAGERENDERER_H 1
+#ifndef OLDMESSAGERENDERER_H
+#define OLDMESSAGERENDERER_H 1
 
 //
 // This is a copy of an older version of MessageRenderer class.  It is kept
@@ -49,7 +49,7 @@ private:
 };
 }
 }
-#endif // __OLDMESSAGERENDERER_H
+#endif // OLDMESSAGERENDERER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/character_string.h b/src/lib/dns/character_string.h
index 7961274..2a68778 100644
--- a/src/lib/dns/character_string.h
+++ b/src/lib/dns/character_string.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CHARACTER_STRING_H
-#define __CHARACTER_STRING_H
+#ifndef CHARACTER_STRING_H
+#define CHARACTER_STRING_H
 
 #include <string>
 #include <exceptions/exceptions.h>
@@ -54,4 +54,4 @@ namespace characterstr {
 } // namespace dns
 } // namespace isc
 
-#endif // __CHARACTER_STRING_H
+#endif // CHARACTER_STRING_H
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index a7bc4c4..dcd552f 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __EDNS_H
-#define __EDNS_H 1
+#ifndef EDNS_H
+#define EDNS_H 1
 
 #include <stdint.h>
 
@@ -438,7 +438,7 @@ EDNS* createEDNSFromRR(const Name& name, const RRClass& rrclass,
 std::ostream& operator<<(std::ostream& os, const EDNS& edns);
 }
 }
-#endif  // __EDNS_H
+#endif  // EDNS_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/exceptions.h b/src/lib/dns/exceptions.h
index bd696a5..070b152 100644
--- a/src/lib/dns/exceptions.h
+++ b/src/lib/dns/exceptions.h
@@ -17,8 +17,8 @@
 // style for the header guide (e.g. module-name_file-name_H) throughout the
 // package.
 
-#ifndef __DNS_EXCEPTIONS_H
-#define __DNS_EXCEPTIONS_H 1
+#ifndef DNS_EXCEPTIONS_H
+#define DNS_EXCEPTIONS_H 1
 
 #include <exceptions/exceptions.h>
 
@@ -52,7 +52,7 @@ public:
 };
 }
 }
-#endif  // __DNS_EXCEPTIONS_H
+#endif  // DNS_EXCEPTIONS_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index f3cd5df..e51dfc5 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -74,7 +74,7 @@ def import_classheader(class_txt, type_txt, type_code, file):
     # for each CLASS_n/TYPE_m.h
     rdata_header = open(file, 'r')
     content = ''
-    guard_macro = '__' + class_txt.upper() + '_' + type_txt.upper()
+    guard_macro = class_txt.upper() + '_' + type_txt.upper()
     guard_macro += '_' + type_code + '_H'
     for line in rdata_header.readlines():
         if re.match('// BEGIN_HEADER_GUARD', line):
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
index 3f6a03a..6c97454 100644
--- a/src/lib/dns/labelsequence.h
+++ b/src/lib/dns/labelsequence.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LABELSEQUENCE_H
-#define __LABELSEQUENCE_H 1
+#ifndef LABELSEQUENCE_H
+#define LABELSEQUENCE_H 1
 
 #include <dns/name.h>
 #include <util/buffer.h>
diff --git a/src/lib/dns/master_lexer.cc b/src/lib/dns/master_lexer.cc
new file mode 100644
index 0000000..c9c5528
--- /dev/null
+++ b/src/lib/dns/master_lexer.cc
@@ -0,0 +1,119 @@
+// 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/master_lexer.h>
+#include <dns/master_lexer_inputsource.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dns {
+
+namespace {
+typedef boost::shared_ptr<master_lexer_internal::InputSource> InputSourcePtr;
+}
+using namespace master_lexer_internal;
+
+struct MasterLexer::MasterLexerImpl {
+    MasterLexerImpl() : token_(Token::NOT_STARTED) {}
+
+    std::vector<InputSourcePtr> sources_;
+    Token token_;
+};
+
+MasterLexer::MasterLexer() : impl_(new MasterLexerImpl) {
+}
+
+MasterLexer::~MasterLexer() {
+    delete impl_;
+}
+
+bool
+MasterLexer::pushSource(const char* filename, std::string* error) {
+    if (filename == NULL) {
+        isc_throw(InvalidParameter,
+                  "NULL filename for MasterLexer::pushSource");
+    }
+    try {
+        impl_->sources_.push_back(InputSourcePtr(new InputSource(filename)));
+    } catch (const InputSource::OpenError& ex) {
+        if (error != NULL) {
+            *error = ex.what();
+        }
+        return (false);
+    }
+
+    return (true);
+}
+
+void
+MasterLexer::pushSource(std::istream& input) {
+    impl_->sources_.push_back(InputSourcePtr(new InputSource(input)));
+}
+
+void
+MasterLexer::popSource() {
+    if (impl_->sources_.empty()) {
+        isc_throw(InvalidOperation,
+                  "MasterLexer::popSource on an empty source");
+    }
+    impl_->sources_.pop_back();
+}
+
+std::string
+MasterLexer::getSourceName() const {
+    if (impl_->sources_.empty()) {
+        return (std::string());
+    }
+    return (impl_->sources_.back()->getName());
+}
+
+size_t
+MasterLexer::getSourceLine() const {
+    if (impl_->sources_.empty()) {
+        return (0);
+    }
+    return (impl_->sources_.back()->getCurrentLine());
+}
+
+namespace {
+const char* const error_text[] = {
+    "lexer not started",        // NOT_STARTED
+    "unbalanced parentheses",   // UNBALANCED_PAREN
+    "unexpected end of input",  // UNEXPECTED_END
+    "unbalanced quotes"         // UNBALANCED_QUOTES
+};
+const size_t error_text_max_count = sizeof(error_text) / sizeof(error_text[0]);
+}
+
+std::string
+MasterLexer::Token::getErrorText() const {
+    if (type_ != ERROR) {
+        isc_throw(InvalidOperation,
+                  "Token::getErrorText() for non error type");
+    }
+
+    // The class integrity ensures the following:
+    assert(val_.error_code_ < error_text_max_count);
+    return (error_text[val_.error_code_]);
+}
+
+} // end of namespace dns
+} // end of namespace isc
diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h
new file mode 100644
index 0000000..da6bb5d
--- /dev/null
+++ b/src/lib/dns/master_lexer.h
@@ -0,0 +1,379 @@
+// 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 MASTER_LEXER_H
+#define MASTER_LEXER_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <istream>
+#include <string>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dns {
+
+/// \brief Tokenizer for parsing DNS master files.
+///
+/// The \c MasterLexer class provides tokenize interfaces for parsing DNS
+/// master files.  It understands some special rules of master files as
+/// defined in RFC 1035, such as comments, character escaping, and multi-line
+/// data, and provides the user application with the actual data in a
+/// more convenient form such as a std::string object.
+///
+/// In order to support the $INCLUDE notation, this class is designed to be
+/// able to operate on multiple files or input streams in the nested way.
+/// The \c pushSource() and \c popSource() methods correspond to the push
+/// and pop operations.
+///
+/// While this class is public, it is less likely to be used by normal
+/// applications; it's mainly expected to be used within this library,
+/// specifically by the \c MasterLoader class and \c Rdata implementation
+/// classes.
+///
+/// \note The error handling policy of this class is slightly different from
+/// that of other classes of this library.  We generally throw an exception
+/// for an invalid input, whether it's more likely to be a program error or
+/// a "user error", which means an invalid input that comes from outside of
+/// the library.  But, this class returns an error code for some certain
+/// types of user errors instead of throwing an exception.  Such cases include
+/// a syntax error identified by the lexer or a misspelled file name that
+/// causes a system error at the time of open.  This is based on the assumption
+/// that the main user of this class is a parser of master files, where
+/// we want to give an option to ignore some non fatal errors and continue
+/// the parsing.  This will be useful if it just performs overall error
+/// checks on a master file.  When the (immediate) caller needs to do explicit
+/// error handling, exceptions are not that a useful tool for error reporting
+/// because we cannot separate the normal and error cases anyway, which would
+/// be one major advantage when we use exceptions.  And, exceptions are
+/// generally more expensive, either when it happens or just by being able
+/// to handle with \c try and \c catch (depending on the underlying
+/// implementation of the exception handling).  For these reasons, some of
+/// this class does not throw for an error that would be reported as an
+/// exception in other classes.
+class MasterLexer {
+public:
+    class Token;       // we define it separately for better readability
+
+    /// \brief The constructor.
+    ///
+    /// \throw std::bad_alloc Internal resource allocation fails (rare case).
+    MasterLexer();
+
+    /// \brief The destructor.
+    ///
+    /// It internally closes any remaining input sources.
+    ~MasterLexer();
+
+    /// \brief Open a file and make it the current input source of MasterLexer.
+    ///
+    /// The opened file can be explicitly closed by the \c popSource() method;
+    /// if \c popSource() is not called within the lifetime of the
+    /// \c MasterLexer, it will be closed in the destructor.
+    ///
+    /// In the case possible system errors in opening the file (most likely
+    /// because of specifying a non-existent or unreadable file), it returns
+    /// false, and if the optional \c error parameter is non NULL, it will be
+    /// set to a description of the error (any existing content of the string
+    /// will be discarded).  If opening the file succeeds, the given
+    /// \c error parameter will be intact.
+    ///
+    /// Note that this method has two styles of error reporting: one by
+    /// returning \c false (and setting \c error optionally) and the other
+    /// by throwing an exception.  See the note for the class description
+    /// about the distinction.
+    ///
+    /// \throw InvalidParameter filename is NULL
+    /// \param filename A non NULL string specifying a master file
+    /// \param error If non null, a placeholder to set error description in
+    /// case of failure.
+    ///
+    /// \return true if pushing the file succeeds; false otherwise.
+    bool pushSource(const char* filename, std::string* error = NULL);
+
+    /// \brief Make the given stream the current input source of MasterLexer.
+    ///
+    /// The caller still holds the ownership of the passed stream; it's the
+    /// caller's responsibility to keep it valid as long as it's used in
+    /// \c MasterLexer or to release any resource for the stream after that.
+    /// The caller can explicitly tell \c MasterLexer to stop using the
+    /// stream by calling the \c popSource() method.
+    ///
+    /// \param input An input stream object that produces textual
+    /// representation of DNS RRs.
+    void pushSource(std::istream& input);
+
+    /// \brief Stop using the most recently opened input source (file or
+    /// stream).
+    ///
+    /// If it's a file, the previously opened file will be closed internally.
+    /// If it's a stream, \c MasterLexer will simply stop using
+    /// the stream; the caller can assume it will be never used in
+    /// \c MasterLexer thereafter.
+    ///
+    /// This method must not be called when there is no source pushed for
+    /// \c MasterLexer.  This method is otherwise exception free.
+    ///
+    /// \throw isc::InvalidOperation Called with no pushed source.
+    void popSource();
+
+    /// \brief Return the name of the current input source name.
+    ///
+    /// If it's a file, it will be the C string given at the corresponding
+    /// \c pushSource() call, that is, its filename.  If it's a stream, it will
+    /// be formatted as \c "stream-%p" where \c %p is hex representation
+    /// of the address of the stream object.
+    ///
+    /// If there is no opened source at the time of the call, this method
+    /// returns an empty string.
+    ///
+    /// \throw std::bad_alloc Resource allocation failed for string
+    /// construction (rare case)
+    ///
+    /// \return A string representation of the current source (see the
+    /// description)
+    std::string getSourceName() const;
+
+    /// \brief Return the input source line number.
+    ///
+    /// If there is an opened source, the return value will be a non-0
+    /// integer indicating the line number of the current source where
+    /// the \c MasterLexer is currently working.  The expected usage of
+    /// this value is to print a helpful error message when parsing fails
+    /// by specifically identifying the position of the error.
+    ///
+    /// If there is no opened source at the time of the call, this method
+    /// returns 0.
+    ///
+    /// \throw None
+    ///
+    /// \return The current line number of the source (see the description)
+    size_t getSourceLine() const;
+
+private:
+    struct MasterLexerImpl;
+    MasterLexerImpl* impl_;
+};
+
+/// \brief Tokens for \c MasterLexer
+///
+/// This is a simple value-class encapsulating a type of a lexer token and
+/// (if it has a value) its value.  Essentially, the class provides
+/// constructors corresponding to different types of tokens, and corresponding
+/// getter methods.  The type and value are fixed at the time of construction
+/// and will never be modified throughout the lifetime of the object.
+/// The getter methods are still provided to maximize the safety; an
+/// application cannot refer to a value that is invalid for the type of token.
+///
+/// This class is intentionally implemented as copyable and assignable
+/// (using the default version of copy constructor and assignment operator),
+/// but it's mainly for internal implementation convenience.  Applications will
+/// simply refer to Token object as a reference via the \c MasterLexer class.
+class MasterLexer::Token {
+public:
+    /// \brief Enumeration for token types
+    ///
+    /// \note At the time of initial implementation, all numeric tokens
+    /// that would be extracted from \c MasterLexer should be represented
+    /// as an unsigned 32-bit integer.  If we see the need for larger integers
+    /// or negative numbers, we can then extend the token types.
+    enum Type {
+        END_OF_LINE, ///< End of line detected (if asked for detecting it)
+        END_OF_FILE, ///< End of file detected (if asked for detecting it)
+        INITIAL_WS,  ///< White spaces at the beginning of a line
+        NOVALUE_TYPE_MAX = INITIAL_WS, ///< Max integer corresponding to
+                                       /// no-value (type only) types.
+                                       /// Mainly for internal use.
+        STRING, ///< A single string
+        QSTRING, ///< A single string quoted by double-quotes (").
+        NUMBER,  ///< A decimal number (unsigned 32-bit)
+        ERROR    ///< Error detected in getting a token
+    };
+
+    /// \brief Enumeration for lexer error codes
+    enum ErrorCode {
+        NOT_STARTED, ///< The lexer is just initialized and has no token
+        UNBALANCED_PAREN,       ///< Unbalanced parentheses detected
+        UNEXPECTED_END, ///< The lexer reaches the end of line or file
+                       /// unexpectedly
+        UNBALANCED_QUOTES,      ///< Unbalanced quotations detected
+        MAX_ERROR_CODE ///< Max integer corresponding to valid error codes.
+                       /// (excluding this one). Mainly for internal use.
+    };
+
+    /// \brief A simple representation of a range of a string.
+    ///
+    /// This is a straightforward pair of the start pointer of a string
+    /// and its length.  The \c STRING and \c QSTRING types of tokens
+    /// will be primarily represented in this form.
+    ///
+    /// Any character can be stored in the valid range of the region.
+    /// In particular, there can be a nul character (\0) in the middle of
+    /// the region.  On the other hand, it is not ensured that the string
+    /// is nul-terminated.  So the usual string manipulation API may not work
+    /// as expected.
+    struct StringRegion {
+        const char* beg;        ///< The start address of the string
+        size_t len;             ///< The length of the string in bytes
+    };
+
+    /// \brief Constructor for non-value type of token.
+    ///
+    /// \throw InvalidParameter A value type token is specified.
+    /// \param type The type of the token.  It must indicate a non-value
+    /// type (not larger than \c NOVALUE_TYPE_MAX).
+    explicit Token(Type type) : type_(type) {
+        if (type > NOVALUE_TYPE_MAX) {
+            isc_throw(InvalidParameter, "Token per-type constructor "
+                      "called with invalid type: " << type);
+        }
+    }
+
+    /// \brief Constructor for string and quoted-string types of token.
+    ///
+    /// The optional \c quoted parameter specifies whether it's a quoted or
+    /// non quoted string.
+    ///
+    /// The string is specified as a pair of a pointer to the start address
+    /// and its length.  Any character can be contained in any position of
+    /// the valid range (see \c StringRegion).
+    ///
+    /// When it's a quoted string, the quotation marks must be excluded
+    /// from the specified range.
+    ///
+    /// \param str_beg The start address of the string
+    /// \param str_len The size of the string in bytes
+    /// \param quoted true if it's a quoted string; false otherwise.
+    Token(const char* str_beg, size_t str_len, bool quoted = false) :
+        type_(quoted ? QSTRING : STRING)
+    {
+        val_.str_region_.beg = str_beg;
+        val_.str_region_.len = str_len;
+    }
+
+    /// \brief Constructor for number type of token.
+    ///
+    /// \brief number An unsigned 32-bit integer corresponding to the token
+    /// value.
+    explicit Token(uint32_t number) : type_(NUMBER) {
+        val_.number_ = number;
+    }
+
+    /// \brief Constructor for error type of token.
+    ///
+    /// \throw InvalidParameter Invalid error code value is specified.
+    /// \brief error_code A pre-defined constant of \c ErrorCode.
+    explicit Token(ErrorCode error_code) : type_(ERROR) {
+        if (!(error_code < MAX_ERROR_CODE)) {
+            isc_throw(InvalidParameter, "Invalid master lexer error code: "
+                      << error_code);
+        }
+        val_.error_code_ = error_code;
+    }
+
+    /// \brief Return the token type.
+    ///
+    /// \throw none
+    Type getType() const { return (type_); }
+
+    /// \brief Return the value of a string-variant token.
+    ///
+    /// \throw InvalidOperation Called on a non string-variant types of token.
+    /// \return A reference to \c StringRegion corresponding to the string
+    ///         token value.
+    const StringRegion& getStringRegion() const {
+        if (type_ != STRING && type_ != QSTRING) {
+            isc_throw(InvalidOperation,
+                      "Token::getStringRegion() for non string-variant type");
+        }
+        return (val_.str_region_);
+    }
+
+    /// \brief Return the value of a string-variant token as a string object.
+    ///
+    /// Note that the underlying string may contain a nul (\0) character
+    /// in the middle.  The returned string object will contain all characters
+    /// of the valid range of the underlying string.  So some string
+    /// operations such as c_str() may not work as expected.
+    ///
+    /// \throw InvalidOperation Called on a non string-variant types of token.
+    /// \throw std::bad_alloc Resource allocation failure in constructing the
+    ///                       string object.
+    /// \return A std::string object corresponding to the string token value.
+    std::string getString() const {
+        if (type_ != STRING && type_ != QSTRING) {
+            isc_throw(InvalidOperation,
+                      "Token::getString() for non string-variant type");
+        }
+        return (std::string(val_.str_region_.beg,
+                            val_.str_region_.beg + val_.str_region_.len));
+    }
+
+    /// \brief Return the value of a string-variant token as a string object.
+    ///
+    /// \throw InvalidOperation Called on a non number type of token.
+    /// \return The integer corresponding to the number token value.
+    uint32_t getNumber() const {
+        if (type_ != NUMBER) {
+            isc_throw(InvalidOperation,
+                      "Token::getNumber() for non number type");
+        }
+        return (val_.number_);
+    }
+
+    /// \brief Return the error code of a error type token.
+    ///
+    /// \throw InvalidOperation Called on a non error type of token.
+    /// \return The error code of the token.
+    ErrorCode getErrorCode() const {
+        if (type_ != ERROR) {
+            isc_throw(InvalidOperation,
+                      "Token::getErrorCode() for non error type");
+        }
+        return (val_.error_code_);
+    };
+
+    /// \brief Return a textual description of the error of a error type token.
+    ///
+    /// The returned string would be useful to produce a log message when
+    /// a zone file parser encounters an error.
+    ///
+    /// \throw InvalidOperation Called on a non error type of token.
+    /// \throw std::bad_alloc Resource allocation failure in constructing the
+    ///                       string object.
+    /// \return A string object that describes the meaning of the error.
+    std::string getErrorText() const;
+
+private:
+    Type type_;    // this is not const so the class can be assignable
+
+    // We use a union to represent different types of token values via the
+    // unified Token class.  The class integrity should ensure valid operation
+    // on the union; getter methods should only refer to the member set at
+    // the construction.
+    union {
+        StringRegion str_region_;
+        uint32_t number_;
+        ErrorCode error_code_;
+    } val_;
+};
+
+} // namespace dns
+} // namespace isc
+#endif  // MASTER_LEXER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/master_lexer_inputsource.cc b/src/lib/dns/master_lexer_inputsource.cc
new file mode 100644
index 0000000..effe163
--- /dev/null
+++ b/src/lib/dns/master_lexer_inputsource.cc
@@ -0,0 +1,158 @@
+// 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 <dns/master_lexer_inputsource.h>
+
+#include <cerrno>
+#include <cstring>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+namespace { // unnamed namespace
+
+std::string
+createStreamName(const std::istream& input_stream) {
+     std::stringstream ss;
+     ss << "stream-" << &input_stream;
+     return (ss.str());
+}
+
+} // end of unnamed namespace
+
+// Explicit definition of class static constant.  The value is given in the
+// declaration so it's not needed here.
+const int InputSource::END_OF_STREAM;
+
+InputSource::InputSource(std::istream& input_stream) :
+    at_eof_(false),
+    line_(1),
+    saved_line_(line_),
+    buffer_pos_(0),
+    name_(createStreamName(input_stream)),
+    input_(input_stream)
+{}
+
+InputSource::InputSource(const char* filename) :
+    at_eof_(false),
+    line_(1),
+    saved_line_(line_),
+    buffer_pos_(0),
+    name_(filename),
+    input_(file_stream_)
+{
+    errno = 0;
+    file_stream_.open(filename);
+    if (file_stream_.fail()) {
+        std::string error_txt("Error opening the input source file: ");
+        error_txt += filename;
+        if (errno != 0) {
+            error_txt += "; possible cause: ";
+            error_txt += std::strerror(errno);
+        }
+        isc_throw(OpenError, error_txt);
+    }
+}
+
+InputSource::~InputSource()
+{
+    if (file_stream_.is_open()) {
+        file_stream_.close();
+    }
+}
+
+int
+InputSource::getChar() {
+    if (buffer_pos_ == buffer_.size()) {
+        // We may have reached EOF at the last call to
+        // getChar(). at_eof_ will be set then. We then simply return
+        // early.
+        if (at_eof_) {
+            return (END_OF_STREAM);
+        }
+        // We are not yet at EOF. Read from the stream.
+        const int c = input_.get();
+        // Have we reached EOF now? If so, set at_eof_ and return early,
+        // but don't modify buffer_pos_ (which should still be equal to
+        // the size of buffer_).
+        if (input_.eof()) {
+            at_eof_ = true;
+            return (END_OF_STREAM);
+        }
+        // This has to come after the .eof() check as some
+        // implementations seem to check the eofbit also in .fail().
+        if (input_.fail()) {
+            isc_throw(ReadError,
+                      "Error reading from the input stream: " << getName());
+        }
+        buffer_.push_back(c);
+    }
+
+    const int c = buffer_[buffer_pos_];
+    ++buffer_pos_;
+    if (c == '\n') {
+        ++line_;
+    }
+
+    return (c);
+}
+
+void
+InputSource::ungetChar() {
+    if (at_eof_) {
+        at_eof_ = false;
+    } else if (buffer_pos_ == 0) {
+        isc_throw(UngetBeforeBeginning,
+                  "Cannot skip before the start of buffer");
+    } else {
+        --buffer_pos_;
+        if (buffer_[buffer_pos_] == '\n') {
+            --line_;
+        }
+    }
+}
+
+void
+InputSource::ungetAll() {
+    buffer_pos_ = 0;
+    line_ = saved_line_;
+    at_eof_ = false;
+}
+
+void
+InputSource::saveLine() {
+    saved_line_ = line_;
+}
+
+void
+InputSource::compact() {
+    if (buffer_pos_ == buffer_.size()) {
+        buffer_.clear();
+    } else {
+        buffer_.erase(buffer_.begin(), buffer_.begin() + buffer_pos_);
+    }
+
+    buffer_pos_ = 0;
+}
+
+void
+InputSource::mark() {
+    saveLine();
+    compact();
+}
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/master_lexer_inputsource.h b/src/lib/dns/master_lexer_inputsource.h
new file mode 100644
index 0000000..8feffa2
--- /dev/null
+++ b/src/lib/dns/master_lexer_inputsource.h
@@ -0,0 +1,167 @@
+// 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 DNS_INPUTSOURCE_H
+#define DNS_INPUTSOURCE_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+/// \brief An input source that is used internally by MasterLexer.
+///
+/// This is a helper internal class for MasterLexer, and represents
+/// state of a single source of the entire zone data to be
+/// parsed. Normally this means the master zone file, but MasterLexer
+/// can have multiple InputSources if $INCLUDE is used. The source can
+/// also be generic input stream (std::istream).
+///
+/// This class is not meant for public use. We also enforce that
+/// instances are non-copyable.
+class InputSource : boost::noncopyable {
+public:
+    /// \brief Returned by getChar() when end of stream is reached.
+    ///
+    /// \note C++ allows a static const class member of an integral type to
+    /// be used without explicit definition as long as its address isn't
+    /// required.  But, since this is a public member variable and we cannot
+    /// assume how it's used, we give a definition in the implementation.
+    static const int END_OF_STREAM = -1;
+
+    /// \brief Exception thrown when ungetChar() is made to go before
+    /// the start of buffer.
+    struct UngetBeforeBeginning : public OutOfRange {
+        UngetBeforeBeginning(const char* file, size_t line, const char* what) :
+            OutOfRange(file, line, what)
+        {}
+    };
+
+    /// \brief Exception thrown when we fail to read from the input
+    /// stream or file.
+    struct ReadError : public Unexpected {
+        ReadError(const char* file, size_t line, const char* what) :
+            Unexpected(file, line, what)
+        {}
+    };
+
+    /// \brief Exception thrown when we fail to open the input file.
+    struct OpenError : public Unexpected {
+        OpenError(const char* file, size_t line, const char* what) :
+            Unexpected(file, line, what)
+        {}
+    };
+
+    /// \brief Constructor which takes an input stream. The stream is
+    /// read-from, but it is not closed.
+    explicit InputSource(std::istream& input_stream);
+
+    /// \brief Constructor which takes a filename to read from. The
+    /// associated file stream is managed internally.
+    ///
+    /// \throws OpenError when opening the input file fails.
+    explicit InputSource(const char* filename);
+
+    /// \brief Destructor
+    ~InputSource();
+
+    /// \brief Returns a name for the InputSource. Typically this is the
+    /// filename, but if the InputSource was constructed for an
+    /// \c std::istream, it returns a name in the format "stream-%p".
+    const std::string& getName() const {
+        return (name_);
+    }
+
+    /// \brief Returns if the input source is at end of file.
+    bool atEOF() const {
+        return (at_eof_);
+    }
+
+    /// \brief Returns the current line number being read.
+    size_t getCurrentLine() const {
+        return (line_);
+    }
+
+    /// \brief Saves the current line being read. Later, when
+    /// \c ungetAll() is called, it skips back to the last-saved line.
+    ///
+    /// TODO: Please make this method private if it is unused after the
+    /// MasterLexer implementation is complete (and only \c mark() is
+    /// used instead).
+    void saveLine();
+
+    /// Removes buffered content before the current location in the
+    /// \c InputSource. It's not possible to \c ungetChar() after this,
+    /// unless we read more data using \c getChar().
+    ///
+    /// TODO: Please make this method private if it is unused after the
+    /// MasterLexer implementation is complete (and only \c mark() is
+    /// used instead).
+    void compact();
+
+    /// Calls \c saveLine() and \c compact() in sequence.
+    void mark();
+
+    /// \brief Returns a single character from the input source. If end
+    /// of file is reached, \c END_OF_STREAM is returned.
+    ///
+    /// \throws ReadError when reading from the input stream or file
+    /// fails.
+    int getChar();
+
+    /// \brief Skips backward a single character in the input
+    /// source. The last-read character is unget.
+    ///
+    /// \throws UngetBeforeBeginning if we go backwards past the start
+    /// of reading, or backwards past the last time compact() was
+    /// called.
+    void ungetChar();
+
+    /// Forgets what was read, and skips back to the position where
+    /// \c compact() was last called. If \c compact() was not called, it
+    /// skips back to where reading started. If \c saveLine() was called
+    /// previously, it sets the current line number to the line number
+    /// saved.
+    void ungetAll();
+
+private:
+    bool at_eof_;
+    size_t line_;
+    size_t saved_line_;
+
+    std::vector<char> buffer_;
+    size_t buffer_pos_;
+
+    const std::string name_;
+    std::ifstream file_stream_;
+    std::istream& input_;
+};
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
+
+#endif  // DNS_INPUTSOURCE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/masterload.h b/src/lib/dns/masterload.h
index e252285..44b3d62 100644
--- a/src/lib/dns/masterload.h
+++ b/src/lib/dns/masterload.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MASTERLOAD_H
-#define __MASTERLOAD_H 1
+#ifndef MASTERLOAD_H
+#define MASTERLOAD_H 1
 
 #include <iosfwd>
 
@@ -244,7 +244,7 @@ void masterLoad(std::istream& input, const Name& origin,
 //@}
 }
 
-#endif  // __MASTERLOAD_H
+#endif  // MASTERLOAD_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h
index 85754ac..8aaaa48 100644
--- a/src/lib/dns/message.h
+++ b/src/lib/dns/message.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_H
-#define __MESSAGE_H 1
+#ifndef MESSAGE_H
+#define MESSAGE_H 1
 
 #include <stdint.h>
 
@@ -687,7 +687,7 @@ typedef boost::shared_ptr<const Message> ConstMessagePtr;
 std::ostream& operator<<(std::ostream& os, const Message& message);
 }
 }
-#endif  // __MESSAGE_H
+#endif  // MESSAGE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/messagerenderer.h b/src/lib/dns/messagerenderer.h
index 4816ad5..092d6de 100644
--- a/src/lib/dns/messagerenderer.h
+++ b/src/lib/dns/messagerenderer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGERENDERER_H
-#define __MESSAGERENDERER_H 1
+#ifndef MESSAGERENDERER_H
+#define MESSAGERENDERER_H 1
 
 #include <util/buffer.h>
 
@@ -397,7 +397,7 @@ private:
 };
 }
 }
-#endif // __MESSAGERENDERER_H
+#endif // MESSAGERENDERER_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index 5ea339d..079033a 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -123,15 +123,18 @@ typedef enum {
     ft_ordinary,                // parsing an ordinary label
     ft_initialescape,           // just found '\'
     ft_escape,                  // begin of handling a '\'-escaped sequence
-    ft_escdecimal,              // parsing a '\DDD' octet.
-
-    // Unused at this moment.  We'll revisit this when we support master file
-    // parser where @ is used to mean an origin name.
-    ft_at
+    ft_escdecimal               // parsing a '\DDD' octet.
 } ft_state;
-}
 
-Name::Name(const std::string &namestring, bool downcase) {
+// The parser of name from a string. It is a template, because
+// some parameters are used with two different types, while others
+// are private type aliases.
+template<class Iterator, class Offsets, class Data>
+void
+stringParse(Iterator s, Iterator send, bool downcase, Offsets& offsets,
+            Data& ndata)
+{
+    const Iterator orig_s(s);
     //
     // Initialize things to make the compiler happy; they're not required.
     //
@@ -142,17 +145,14 @@ Name::Name(const std::string &namestring, bool downcase) {
     //
     // Set up the state machine.
     //
-    std::string::const_iterator s = namestring.begin();
-    std::string::const_iterator send = namestring.end();
     bool done = false;
     bool is_root = false;
+    const bool empty = s == send;
     ft_state state = ft_init;
 
-    NameOffsets offsets;
+    // Prepare the output buffers.
     offsets.reserve(Name::MAX_LABELS);
     offsets.push_back(0);
-
-    NameString ndata;
     ndata.reserve(Name::MAX_WIRE);
 
     // should we refactor this code using, e.g, the state pattern?  Probably
@@ -171,7 +171,8 @@ Name::Name(const std::string &namestring, bool downcase) {
             if (c == '.') {
                 if (s != send) {
                     isc_throw(EmptyLabel,
-                              "non terminating empty label in " << namestring);
+                              "non terminating empty label in " <<
+                              string(orig_s, send));
                 }
                 is_root = true;
             } else if (c == '@' && s == send) {
@@ -200,7 +201,7 @@ Name::Name(const std::string &namestring, bool downcase) {
             if (c == '.') {
                 if (count == 0) {
                     isc_throw(EmptyLabel,
-                              "duplicate period in " << namestring);
+                              "duplicate period in " << string(orig_s, send));
                 }
                 ndata.at(offsets.back()) = count;
                 offsets.push_back(ndata.size());
@@ -212,9 +213,9 @@ Name::Name(const std::string &namestring, bool downcase) {
             } else if (c == '\\') {
                 state = ft_escape;
             } else {
-                if (++count > MAX_LABELLEN) {
+                if (++count > Name::MAX_LABELLEN) {
                     isc_throw(TooLongLabel,
-                              "label is too long in " << namestring);
+                              "label is too long in " << string(orig_s, send));
                 }
                 ndata.push_back(downcase ? maptolower[c] : c);
             }
@@ -224,15 +225,15 @@ Name::Name(const std::string &namestring, bool downcase) {
                 // This looks like a bitstring label, which was deprecated.
                 // Intentionally drop it.
                 isc_throw(BadLabelType,
-                          "invalid label type in " << namestring);
+                          "invalid label type in " << string(orig_s, send));
             }
             state = ft_escape;
             // FALLTHROUGH
         case ft_escape:
             if (!isdigit(c & 0xff)) {
-                if (++count > MAX_LABELLEN) {
+                if (++count > Name::MAX_LABELLEN) {
                     isc_throw(TooLongLabel,
-                              "label is too long in " << namestring);
+                              "label is too long in " << string(orig_s, send));
                 }
                 ndata.push_back(downcase ? maptolower[c] : c);
                 state = ft_ordinary;
@@ -246,7 +247,7 @@ Name::Name(const std::string &namestring, bool downcase) {
             if (!isdigit(c & 0xff)) {
                 isc_throw(BadEscape,
                           "mixture of escaped digit and non-digit in "
-                          << namestring);
+                          << string(orig_s, send));
             }
             value *= 10;
             value += digitvalue[c];
@@ -255,11 +256,11 @@ Name::Name(const std::string &namestring, bool downcase) {
                 if (value > 255) {
                     isc_throw(BadEscape,
                               "escaped decimal is too large in "
-                              << namestring);
+                              << string(orig_s, send));
                 }
-                if (++count > MAX_LABELLEN) {
+                if (++count > Name::MAX_LABELLEN) {
                     isc_throw(TooLongLabel,
-                              "label is too long in " << namestring);
+                              "label is too long in " << string(orig_s, send));
                 }
                 ndata.push_back(downcase ? maptolower[value] : value);
                 state = ft_ordinary;
@@ -274,13 +275,14 @@ Name::Name(const std::string &namestring, bool downcase) {
     if (!done) {                // no trailing '.' was found.
         if (ndata.size() == Name::MAX_WIRE) {
             isc_throw(TooLongName,
-                      "name is too long for termination in " << namestring);
+                      "name is too long for termination in " <<
+                      string(orig_s, send));
         }
         assert(s == send);
-        if (state != ft_ordinary && state != ft_at) {
+        if (state != ft_ordinary) {
             isc_throw(IncompleteName,
                       "incomplete textual name in " <<
-                      (namestring.empty() ? "<empty>" : namestring));
+                      (empty ? "<empty>" : string(orig_s, send)));
         }
         if (state == ft_ordinary) {
             assert(count != 0);
@@ -291,12 +293,93 @@ Name::Name(const std::string &namestring, bool downcase) {
             ndata.push_back('\0');
         }
     }
+}
+
+}
+
+Name::Name(const std::string &namestring, bool downcase) {
+    // Prepare inputs for the parser
+    const std::string::const_iterator s = namestring.begin();
+    const std::string::const_iterator send = namestring.end();
+
+    // Prepare outputs
+    NameOffsets offsets;
+    NameString ndata;
+
+    // To the parsing
+    stringParse(s, send, downcase, offsets, ndata);
+
+    // And get the output
+    labelcount_ = offsets.size();
+    assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS);
+    ndata_.assign(ndata.data(), ndata.size());
+    length_ = ndata_.size();
+    offsets_.assign(offsets.begin(), offsets.end());
+}
+
+Name::Name(const char* namedata, size_t data_len, const Name* origin,
+           bool downcase)
+{
+    // Check validity of data
+    if (namedata == NULL || data_len == 0) {
+        isc_throw(isc::InvalidParameter,
+                  "No data provided to Name constructor");
+    }
+    // If the last character is not a dot, it is a relative to origin.
+    // It is safe to check now, we know there's at least one character.
+    const bool absolute = (namedata[data_len - 1] == '.');
+    // If we are not absolute, we need the origin to complete the name.
+    if (!absolute && origin == NULL) {
+        isc_throw(MissingNameOrigin,
+                  "No origin available and name is relative");
+    }
+    // Prepare inputs for the parser
+    const char* end = namedata + data_len;
+
+    // Prepare outputs
+    NameOffsets offsets;
+    NameString ndata;
+
+    // Do the actual parsing
+    stringParse(namedata, end, downcase, offsets, ndata);
 
+    // Get the output
     labelcount_ = offsets.size();
     assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS);
     ndata_.assign(ndata.data(), ndata.size());
     length_ = ndata_.size();
     offsets_.assign(offsets.begin(), offsets.end());
+
+    if (!absolute) {
+        // Now, extend the data with the ones from origin. But eat the
+        // last label (the empty one).
+
+        // Drop the last character of the data (the \0) and append a copy of
+        // the origin's data
+        ndata_.erase(ndata_.end() - 1);
+        ndata_.append(origin->ndata_);
+
+        // Do a similar thing with offsets. However, we need to move them
+        // so they point after the prefix we parsed before.
+        size_t offset = offsets_.back();
+        offsets_.pop_back();
+        size_t offset_count = offsets_.size();
+        offsets_.insert(offsets_.end(), origin->offsets_.begin(),
+                        origin->offsets_.end());
+        for (NameOffsets::iterator it(offsets_.begin() + offset_count);
+             it != offsets_.end(); ++it) {
+            *it += offset;
+        }
+
+        // Adjust sizes.
+        length_ = ndata_.size();
+        labelcount_ = offsets_.size();
+
+        // And check the sizes are OK.
+        if (labelcount_ > Name::MAX_LABELS || length_ > Name::MAX_WIRE) {
+            isc_throw(TooLongName, "Combined name is too long");
+        }
+    }
 }
 
 namespace {
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h
index 261caee..02c868f 100644
--- a/src/lib/dns/name.h
+++ b/src/lib/dns/name.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NAME_H
-#define __NAME_H 1
+#ifndef NAME_H
+#define NAME_H 1
 
 #include <stdint.h>
 
@@ -105,6 +105,17 @@ public:
         NameParserException(file, line, what) {}
 };
 
+/// \brief Thrown when origin is NULL and is needed.
+///
+/// The exception is thrown when the Name constructor for master file
+/// is used, the provided data is relative and the origin parameter is
+/// set to NULL.
+class MissingNameOrigin : public NameParserException {
+public:
+    MissingNameOrigin(const char* file, size_t line, const char* what) :
+        NameParserException(file, line, what) {}
+};
+
 ///
 /// This is a supplemental class used only as a return value of
 /// Name::compare() and LabelSequence::compare().
@@ -261,6 +272,37 @@ public:
     /// \param namestr A string representation of the name to be constructed.
     /// \param downcase Whether to convert upper case alphabets to lower case.
     explicit Name(const std::string& namestr, bool downcase = false);
+
+    /// \brief Constructor for master file parser
+    ///
+    /// This acts similar to the above. But the data is passed as raw C-string
+    /// instead of wrapped-up C++ std::string.
+    ///
+    /// Also, when the origin is non-NULL and the name_data is not ending with
+    /// a dot, it is considered relative and the origin is appended to it.
+    ///
+    /// If the name_data is equal to "@", the content of origin is copied.
+    ///
+    /// \param name_data The raw data of the name.
+    /// \param data_len How many bytes in name_data is valid and considered
+    ///     part of the name.
+    /// \param origin If non-NULL, it is taken as the origin to complete
+    ///     relative names.
+    /// \param downcase Whether to convert upper case letters to lower case.
+    /// \throw NameParserException or any of its descendants in case the
+    ///     input data is invalid.
+    /// \throw isc::InvalidParameter In case name_data is NULL or data_len is
+    ///     0.
+    /// \throw std::bad_alloc In case allocation fails.
+    /// \note This constructor is specially designed for the use of master
+    ///     file parser. It mimics the behaviour of names in the master file
+    ///     and accepts raw data. It is not recommended to be used by anything
+    ///     else.
+    /// \todo Should we make it private and the parser a friend, to hide the
+    ///     constructor?
+    Name(const char* name_data, size_t data_len, const Name* origin,
+         bool downcase = false);
+
     /// Constructor from wire-format %data.
     ///
     /// The \c buffer parameter normally stores a complete DNS message
@@ -724,7 +766,7 @@ operator<<(std::ostream& os, const Name& name);
 
 }
 }
-#endif // __NAME_H
+#endif // NAME_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/name_internal.h b/src/lib/dns/name_internal.h
index 8595df1..d60ee7a 100644
--- a/src/lib/dns/name_internal.h
+++ b/src/lib/dns/name_internal.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NAME_INTERNAL_H
-#define __NAME_INTERNAL_H 1
+#ifndef NAME_INTERNAL_H
+#define NAME_INTERNAL_H 1
 
 // This is effectively a "private" namespace for the Name class implementation,
 // but exposed publicly so the definitions in it can be shared with other
@@ -36,7 +36,7 @@ extern const uint8_t maptolower[];
 } // end of name
 } // end of dns
 } // end of isc
-#endif // __NAME_INTERNAL_H
+#endif // NAME_INTERNAL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/nsec3hash.h b/src/lib/dns/nsec3hash.h
index e082ee8..f1ca1a3 100644
--- a/src/lib/dns/nsec3hash.h
+++ b/src/lib/dns/nsec3hash.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSEC3HASH_H
-#define __NSEC3HASH_H 1
+#ifndef NSEC3HASH_H
+#define NSEC3HASH_H 1
 
 #include <string>
 #include <vector>
@@ -276,7 +276,7 @@ void setNSEC3HashCreator(const NSEC3HashCreator* new_creator);
 
 }
 }
-#endif  // __NSEC3HASH_H
+#endif  // NSEC3HASH_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/opcode.h b/src/lib/dns/opcode.h
index dd88062..8e93877 100644
--- a/src/lib/dns/opcode.h
+++ b/src/lib/dns/opcode.h
@@ -18,8 +18,8 @@
 
 #include <ostream>
 
-#ifndef __OPCODE_H
-#define __OPCODE_H 1
+#ifndef OPCODE_H
+#define OPCODE_H 1
 
 namespace isc {
 namespace dns {
diff --git a/src/lib/dns/python/edns_python.h b/src/lib/dns/python/edns_python.h
index 30d92ab..2106b22 100644
--- a/src/lib/dns/python/edns_python.h
+++ b/src/lib/dns/python/edns_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_EDNS_H
-#define __PYTHON_EDNS_H 1
+#ifndef PYTHON_EDNS_H
+#define PYTHON_EDNS_H 1
 
 #include <Python.h>
 
@@ -57,7 +57,7 @@ const EDNS& PyEDNS_ToEDNS(const PyObject* edns_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_EDNS_H
+#endif // PYTHON_EDNS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/message_python.h b/src/lib/dns/python/message_python.h
index be23890..f3c1488 100644
--- a/src/lib/dns/python/message_python.h
+++ b/src/lib/dns/python/message_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_MESSAGE_H
-#define __PYTHON_MESSAGE_H 1
+#ifndef PYTHON_MESSAGE_H
+#define PYTHON_MESSAGE_H 1
 
 #include <Python.h>
 
@@ -33,7 +33,7 @@ extern PyTypeObject message_type;
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_MESSAGE_H
+#endif // PYTHON_MESSAGE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/messagerenderer_python.h b/src/lib/dns/python/messagerenderer_python.h
index ea9a940..f6ea922 100644
--- a/src/lib/dns/python/messagerenderer_python.h
+++ b/src/lib/dns/python/messagerenderer_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_MESSAGERENDERER_H
-#define __PYTHON_MESSAGERENDERER_H 1
+#ifndef PYTHON_MESSAGERENDERER_H
+#define PYTHON_MESSAGERENDERER_H 1
 
 #include <Python.h>
 
@@ -50,7 +50,7 @@ MessageRenderer& PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_o
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_MESSAGERENDERER_H
+#endif // PYTHON_MESSAGERENDERER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/name_python.h b/src/lib/dns/python/name_python.h
index 86d7fd0..d18c0d9 100644
--- a/src/lib/dns/python/name_python.h
+++ b/src/lib/dns/python/name_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_NAME_H
-#define __PYTHON_NAME_H 1
+#ifndef PYTHON_NAME_H
+#define PYTHON_NAME_H 1
 
 #include <Python.h>
 
@@ -74,7 +74,7 @@ const Name& PyName_ToName(const PyObject* name_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_NAME_H
+#endif // PYTHON_NAME_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/nsec3hash_python.h b/src/lib/dns/python/nsec3hash_python.h
index fa9b9b6..51a5fde 100644
--- a/src/lib/dns/python/nsec3hash_python.h
+++ b/src/lib/dns/python/nsec3hash_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_NSEC3HASH_H
-#define __PYTHON_NSEC3HASH_H 1
+#ifndef PYTHON_NSEC3HASH_H
+#define PYTHON_NSEC3HASH_H 1
 
 #include <Python.h>
 
@@ -40,7 +40,7 @@ bool initModulePart_NSEC3Hash(PyObject* mod);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_NSEC3HASH_H
+#endif // PYTHON_NSEC3HASH_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/opcode_python.h b/src/lib/dns/python/opcode_python.h
index d0aec15..6e9967e 100644
--- a/src/lib/dns/python/opcode_python.h
+++ b/src/lib/dns/python/opcode_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_OPCODE_H
-#define __PYTHON_OPCODE_H 1
+#ifndef PYTHON_OPCODE_H
+#define PYTHON_OPCODE_H 1
 
 #include <Python.h>
 
@@ -57,7 +57,7 @@ const Opcode& PyOpcode_ToOpcode(const PyObject* opcode_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_OPCODE_H
+#endif // PYTHON_OPCODE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h
index 3cc69c4..5ca1cd8 100644
--- a/src/lib/dns/python/pydnspp_common.h
+++ b/src/lib/dns/python/pydnspp_common.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LIBDNS_PYTHON_COMMON_H
-#define __LIBDNS_PYTHON_COMMON_H 1
+#ifndef LIBDNS_PYTHON_COMMON_H
+#define LIBDNS_PYTHON_COMMON_H 1
 
 #include <Python.h>
 
@@ -106,7 +106,7 @@ convertToPyHash(HashvalType val) {
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __LIBDNS_PYTHON_COMMON_H
+#endif // LIBDNS_PYTHON_COMMON_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/pydnspp_towire.h b/src/lib/dns/python/pydnspp_towire.h
index e987a29..7ad70cd 100644
--- a/src/lib/dns/python/pydnspp_towire.h
+++ b/src/lib/dns/python/pydnspp_towire.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LIBDNS_PYTHON_TOWIRE_H
-#define __LIBDNS_PYTHON_TOWIRE_H 1
+#ifndef LIBDNS_PYTHON_TOWIRE_H
+#define LIBDNS_PYTHON_TOWIRE_H 1
 
 #include <Python.h>
 
@@ -120,7 +120,7 @@ toWireWrapper(const PYSTRUCT* const self, PyObject* args) {
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __LIBDNS_PYTHON_TOWIRE_H
+#endif // LIBDNS_PYTHON_TOWIRE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/question_python.h b/src/lib/dns/python/question_python.h
index f5d78b1..99b37c7 100644
--- a/src/lib/dns/python/question_python.h
+++ b/src/lib/dns/python/question_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_QUESTION_H
-#define __PYTHON_QUESTION_H 1
+#ifndef PYTHON_QUESTION_H
+#define PYTHON_QUESTION_H 1
 
 #include <Python.h>
 
@@ -59,7 +59,7 @@ const Question& PyQuestion_ToQuestion(const PyObject* question_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_QUESTION_H
+#endif // PYTHON_QUESTION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rcode_python.h b/src/lib/dns/python/rcode_python.h
index a149406..704821a 100644
--- a/src/lib/dns/python/rcode_python.h
+++ b/src/lib/dns/python/rcode_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RCODE_H
-#define __PYTHON_RCODE_H 1
+#ifndef PYTHON_RCODE_H
+#define PYTHON_RCODE_H 1
 
 #include <Python.h>
 
@@ -57,7 +57,7 @@ const Rcode& PyRcode_ToRcode(const PyObject* rcode_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RCODE_H
+#endif // PYTHON_RCODE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rdata_python.h b/src/lib/dns/python/rdata_python.h
index c7ddd57..6fa6631 100644
--- a/src/lib/dns/python/rdata_python.h
+++ b/src/lib/dns/python/rdata_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RDATA_H
-#define __PYTHON_RDATA_H 1
+#ifndef PYTHON_RDATA_H
+#define PYTHON_RDATA_H 1
 
 #include <Python.h>
 
@@ -61,7 +61,7 @@ const isc::dns::rdata::Rdata& PyRdata_ToRdata(const PyObject* rdata_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RDATA_H
+#endif // PYTHON_RDATA_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rrclass_python.h b/src/lib/dns/python/rrclass_python.h
index f58bba6..df5ca70 100644
--- a/src/lib/dns/python/rrclass_python.h
+++ b/src/lib/dns/python/rrclass_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RRCLASS_H
-#define __PYTHON_RRCLASS_H 1
+#ifndef PYTHON_RRCLASS_H
+#define PYTHON_RRCLASS_H 1
 
 #include <Python.h>
 
@@ -61,7 +61,7 @@ const RRClass& PyRRClass_ToRRClass(const PyObject* rrclass_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RRCLASS_H
+#endif // PYTHON_RRCLASS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rrset_python.h b/src/lib/dns/python/rrset_python.h
index 2435397..9faac95 100644
--- a/src/lib/dns/python/rrset_python.h
+++ b/src/lib/dns/python/rrset_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RRSET_H
-#define __PYTHON_RRSET_H 1
+#ifndef PYTHON_RRSET_H
+#define PYTHON_RRSET_H 1
 
 #include <Python.h>
 
@@ -71,7 +71,7 @@ RRsetPtr PyRRset_ToRRsetPtr(PyObject* rrset_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RRSET_H
+#endif // PYTHON_RRSET_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rrttl_python.h b/src/lib/dns/python/rrttl_python.h
index 9dbc982..9ad904f 100644
--- a/src/lib/dns/python/rrttl_python.h
+++ b/src/lib/dns/python/rrttl_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RRTTL_H
-#define __PYTHON_RRTTL_H 1
+#ifndef PYTHON_RRTTL_H
+#define PYTHON_RRTTL_H 1
 
 #include <Python.h>
 
@@ -60,7 +60,7 @@ const RRTTL& PyRRTTL_ToRRTTL(const PyObject* rrttl_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RRTTL_H
+#endif // PYTHON_RRTTL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/rrtype_python.h b/src/lib/dns/python/rrtype_python.h
index 596598e..3595952 100644
--- a/src/lib/dns/python/rrtype_python.h
+++ b/src/lib/dns/python/rrtype_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_RRTYPE_H
-#define __PYTHON_RRTYPE_H 1
+#ifndef PYTHON_RRTYPE_H
+#define PYTHON_RRTYPE_H 1
 
 #include <Python.h>
 
@@ -61,7 +61,7 @@ const RRType& PyRRType_ToRRType(const PyObject* rrtype_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_RRTYPE_H
+#endif // PYTHON_RRTYPE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/serial_python.h b/src/lib/dns/python/serial_python.h
index 48b5199..9a495be 100644
--- a/src/lib/dns/python/serial_python.h
+++ b/src/lib/dns/python/serial_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_SERIAL_H
-#define __PYTHON_SERIAL_H 1
+#ifndef PYTHON_SERIAL_H
+#define PYTHON_SERIAL_H 1
 
 #include <Python.h>
 
@@ -57,7 +57,7 @@ const Serial& PySerial_ToSerial(const PyObject* Serial_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_SERIAL_H
+#endif // PYTHON_SERIAL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/tsig_python.h b/src/lib/dns/python/tsig_python.h
index e4e9fff..0bd57d7 100644
--- a/src/lib/dns/python/tsig_python.h
+++ b/src/lib/dns/python/tsig_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_TSIGCONTEXT_H
-#define __PYTHON_TSIGCONTEXT_H 1
+#ifndef PYTHON_TSIGCONTEXT_H
+#define PYTHON_TSIGCONTEXT_H 1
 
 #include <Python.h>
 
@@ -52,7 +52,7 @@ TSIGContext& PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_TSIGCONTEXT_H
+#endif // PYTHON_TSIGCONTEXT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/tsig_rdata_python.h b/src/lib/dns/python/tsig_rdata_python.h
index a84d9e8..85dd366 100644
--- a/src/lib/dns/python/tsig_rdata_python.h
+++ b/src/lib/dns/python/tsig_rdata_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_TSIG_H
-#define __PYTHON_TSIG_H 1
+#ifndef PYTHON_TSIG_H
+#define PYTHON_TSIG_H 1
 
 #include <Python.h>
 
@@ -61,7 +61,7 @@ const rdata::any::TSIG& PyTSIG_ToTSIG(const PyObject* tsig_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_TSIG_H
+#endif // PYTHON_TSIG_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/tsigerror_python.h b/src/lib/dns/python/tsigerror_python.h
index 0b5b630..6258ab3 100644
--- a/src/lib/dns/python/tsigerror_python.h
+++ b/src/lib/dns/python/tsigerror_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_TSIGERROR_H
-#define __PYTHON_TSIGERROR_H 1
+#ifndef PYTHON_TSIGERROR_H
+#define PYTHON_TSIGERROR_H 1
 
 #include <Python.h>
 
@@ -37,7 +37,7 @@ PyObject* createTSIGErrorObject(const TSIGError& source);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_TSIGERROR_H
+#endif // PYTHON_TSIGERROR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/tsigkey_python.h b/src/lib/dns/python/tsigkey_python.h
index 6c3d2e3..ec09e2c 100644
--- a/src/lib/dns/python/tsigkey_python.h
+++ b/src/lib/dns/python/tsigkey_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_TSIGKEY_H
-#define __PYTHON_TSIGKEY_H 1
+#ifndef PYTHON_TSIGKEY_H
+#define PYTHON_TSIGKEY_H 1
 
 #include <Python.h>
 
@@ -68,7 +68,7 @@ const TSIGKeyRing& PyTSIGKeyRing_ToTSIGKeyRing(const PyObject* tsigkeyring_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_TSIGKEY_H
+#endif // PYTHON_TSIGKEY_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/python/tsigrecord_python.h b/src/lib/dns/python/tsigrecord_python.h
index d6252e1..ec505f7 100644
--- a/src/lib/dns/python/tsigrecord_python.h
+++ b/src/lib/dns/python/tsigrecord_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_TSIGRECORD_H
-#define __PYTHON_TSIGRECORD_H 1
+#ifndef PYTHON_TSIGRECORD_H
+#define PYTHON_TSIGRECORD_H 1
 
 #include <Python.h>
 
@@ -58,7 +58,7 @@ const TSIGRecord& PyTSIGRecord_ToTSIGRecord(PyObject* tsigrecord_obj);
 } // namespace python
 } // namespace dns
 } // namespace isc
-#endif // __PYTHON_TSIGRECORD_H
+#endif // PYTHON_TSIGRECORD_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h
index 5d2783b..4b5b233 100644
--- a/src/lib/dns/question.h
+++ b/src/lib/dns/question.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __QUESTION_H
-#define __QUESTION_H 1
+#ifndef QUESTION_H
+#define QUESTION_H 1
 
 #include <iostream>
 #include <string>
@@ -288,7 +288,7 @@ private:
 std::ostream& operator<<(std::ostream& os, const Question& question);
 } // end of namespace dns
 } // end of namespace isc
-#endif  // __QUESTION_H
+#endif  // QUESTION_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rcode.h b/src/lib/dns/rcode.h
index 0c63285..f294615 100644
--- a/src/lib/dns/rcode.h
+++ b/src/lib/dns/rcode.h
@@ -18,8 +18,8 @@
 
 #include <ostream>
 
-#ifndef __RCODE_H
-#define __RCODE_H 1
+#ifndef RCODE_H
+#define RCODE_H 1
 
 namespace isc {
 namespace dns {
diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h
index afcf4b3..f77ea6e 100644
--- a/src/lib/dns/rdata.h
+++ b/src/lib/dns/rdata.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RDATA_H
-#define __RDATA_H 1
+#ifndef RDATA_H
+#define RDATA_H 1
 
 #include <stdint.h>
 
@@ -509,7 +509,7 @@ int compareNames(const Name& n1, const Name& n2);
 } // end of namespace "rdata"
 }
 }
-#endif  // __RDATA_H
+#endif  // RDATA_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rdata/generic/detail/ds_like.h b/src/lib/dns/rdata/generic/detail/ds_like.h
index b5a35cd..333de4c 100644
--- a/src/lib/dns/rdata/generic/detail/ds_like.h
+++ b/src/lib/dns/rdata/generic/detail/ds_like.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __DS_LIKE_H
-#define __DS_LIKE_H 1
+#ifndef DS_LIKE_H
+#define DS_LIKE_H 1
 
 #include <stdint.h>
 
@@ -218,7 +218,7 @@ private:
 }
 }
 }
-#endif //  __DS_LIKE_H
+#endif //  DS_LIKE_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rdata/generic/detail/nsec3param_common.h b/src/lib/dns/rdata/generic/detail/nsec3param_common.h
index 515777b..1891fae 100644
--- a/src/lib/dns/rdata/generic/detail/nsec3param_common.h
+++ b/src/lib/dns/rdata/generic/detail/nsec3param_common.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSEC3PARAM_COMMON_H
-#define __NSEC3PARAM_COMMON_H 1
+#ifndef NSEC3PARAM_COMMON_H
+#define NSEC3PARAM_COMMON_H 1
 
 #include <util/buffer.h>
 
@@ -127,7 +127,7 @@ ParseNSEC3ParamResult parseNSEC3ParamWire(const char* const rrtype_name,
 }
 }
 
-#endif  // __NSEC3PARAM_COMMON_H
+#endif  // NSEC3PARAM_COMMON_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/rdata/generic/detail/nsec_bitmap.h b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
index 85cae2e..0b2102f 100644
--- a/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
+++ b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSECBITMAP_H
-#define __NSECBITMAP_H 1
+#ifndef NSECBITMAP_H
+#define NSECBITMAP_H 1
 
 #include <stdint.h>
 
@@ -100,7 +100,7 @@ void bitmapsToText(const std::vector<uint8_t>& typebits,
 }
 }
 
-#endif  // __NSECBITMAP_H
+#endif  // NSECBITMAP_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/rdata/generic/detail/txt_like.h b/src/lib/dns/rdata/generic/detail/txt_like.h
index a0ab7ac..fdab6bf 100644
--- a/src/lib/dns/rdata/generic/detail/txt_like.h
+++ b/src/lib/dns/rdata/generic/detail/txt_like.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TXT_LIKE_H
-#define __TXT_LIKE_H 1
+#ifndef TXT_LIKE_H
+#define TXT_LIKE_H 1
 
 #include <stdint.h>
 
@@ -217,7 +217,7 @@ private:
 // END_RDATA_NAMESPACE
 // END_ISC_NAMESPACE
 
-#endif //  __TXT_LIKE_H
+#endif //  TXT_LIKE_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rdatafields.h b/src/lib/dns/rdatafields.h
index 16880f0..efdc453 100644
--- a/src/lib/dns/rdatafields.h
+++ b/src/lib/dns/rdatafields.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RDATAFIELDS_H
-#define __RDATAFIELDS_H 1
+#ifndef RDATAFIELDS_H
+#define RDATAFIELDS_H 1
 
 #include <stdint.h>
 
@@ -420,7 +420,7 @@ private:
 }
 }
 }
-#endif  // __RDATAFIELDS_H
+#endif  // RDATAFIELDS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index 80035d8..70d6b78 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRCLASS_H
-#define __RRCLASS_H 1
+#ifndef RRCLASS_H
+#define RRCLASS_H 1
 
 #include <stdint.h>
 
@@ -283,7 +283,7 @@ std::ostream&
 operator<<(std::ostream& os, const RRClass& rrclass);
 }
 }
-#endif  // __RRCLASS_H
+#endif  // RRCLASS_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h
index ae41b5f..b1ca225 100644
--- a/src/lib/dns/rrparamregistry.h
+++ b/src/lib/dns/rrparamregistry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRPARAMREGISTRY_H
-#define __RRPARAMREGISTRY_H 1
+#ifndef RRPARAMREGISTRY_H
+#define RRPARAMREGISTRY_H 1
 
 #include <string>
 
@@ -506,7 +506,7 @@ private:
 
 }
 }
-#endif  // __RRPARAMREGISTRY_H
+#endif  // RRPARAMREGISTRY_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index 17a02cd..7ea01d0 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -64,8 +64,12 @@ AbstractRRset::toText() const {
         it->next();
     } while (!it->isLast());
 
+    if (getRRsig()) {
+        s += getRRsig()->toText();
+    }
+
     return (s);
-}   
+}
 
 namespace {
 template <typename T>
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index 7019f93..9c1715b 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRSET_H
-#define __RRSET_H 1
+#ifndef RRSET_H
+#define RRSET_H 1
 
 #include <iostream>
 #include <string>
@@ -267,6 +267,9 @@ public:
     /// the resulting string with a trailing newline character.
     /// (following the BIND9 convention)
     ///
+    /// If any RRSIGs are associated with the RRset, they are also
+    /// appended to the returned string.
+    ///
     /// If the class is not ANY or NONE, the RRset must contain some RDATA;
     /// otherwise, an exception of class \c EmptyRRset will be thrown.
     /// If resource allocation fails, a corresponding standard exception
@@ -293,6 +296,8 @@ public:
     /// RRset would cause truncation, and handles the case appropriately
     /// (this is a TODO item, and not implemented in this version).
     ///
+    /// If any RRSIGs are associated with the RRset, they are also rendered.
+    ///
     /// Note: perhaps we may want to add more arguments to convey optional
     /// information such as an "rrset-order" policy or how to handle truncation
     /// case.  This is a TODO item.
@@ -929,7 +934,7 @@ private:
 std::ostream& operator<<(std::ostream& os, const AbstractRRset& rrset);
 } // end of namespace dns
 } // end of namespace isc
-#endif  // __RRSET_H
+#endif  // RRSET_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h
index bf23295..62bf886 100644
--- a/src/lib/dns/rrttl.h
+++ b/src/lib/dns/rrttl.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRTTL_H
-#define __RRTTL_H 1
+#ifndef RRTTL_H
+#define RRTTL_H 1
 
 #include <stdint.h>
 
@@ -255,7 +255,7 @@ std::ostream&
 operator<<(std::ostream& os, const RRTTL& rrttl);
 }
 }
-#endif  // __RRTTL_H
+#endif  // RRTTL_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h
index dad1b2b..273a486 100644
--- a/src/lib/dns/rrtype-placeholder.h
+++ b/src/lib/dns/rrtype-placeholder.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RRTYPE_H
-#define __RRTYPE_H 1
+#ifndef RRTYPE_H
+#define RRTYPE_H 1
 
 #include <stdint.h>
 
@@ -235,11 +235,11 @@ public:
     ///
     /// \param other the \c RRType object to compare against.
     /// \return true if the two RRTypes are not equal; otherwise false.
-    bool nequals(const RRType& other) const 
+    bool nequals(const RRType& other) const
     { return (typecode_ != other.typecode_); }
     /// \brief Same as \c nequals().
     bool operator!=(const RRType& other) const { return (nequals(other)); }
- 
+
     /// \brief Less-than comparison for RRType against \c other
     ///
     /// We define the less-than relationship based on their type codes;
@@ -317,8 +317,8 @@ std::ostream&
 operator<<(std::ostream& os, const RRType& rrtype);
 }
 }
-#endif  // __RRTYPE_H
+#endif  // RRTYPE_H
 
-// Local Variables: 
+// Local Variables:
 // mode: c++
-// End: 
+// End:
diff --git a/src/lib/dns/serial.h b/src/lib/dns/serial.h
index 3549860..678fb22 100644
--- a/src/lib/dns/serial.h
+++ b/src/lib/dns/serial.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SERIAL_H
-#define __SERIAL_H 1
+#ifndef SERIAL_H
+#define SERIAL_H 1
 
 #include <stdint.h>
 #include <iostream>
@@ -152,4 +152,4 @@ std::ostream& operator<<(std::ostream& os, const Serial& serial);
 } // end namespace dns
 } // end namespace isc
 
-#endif // __SERIAL_H
+#endif // SERIAL_H
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index e8cbe10..d5adc21 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -4,7 +4,7 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
-AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(abs_top_srcdir)/src/lib/dns/tests/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dns/tests/testdata\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
@@ -22,8 +22,11 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES = unittest_util.h unittest_util.cc
 run_unittests_SOURCES += edns_unittest.cc
+run_unittests_SOURCES += master_lexer_inputsource_unittest.cc
 run_unittests_SOURCES += labelsequence_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
+run_unittests_SOURCES += master_lexer_token_unittest.cc
+run_unittests_SOURCES += master_lexer_unittest.cc
 run_unittests_SOURCES += name_unittest.cc
 run_unittests_SOURCES += nsec3hash_unittest.cc
 run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
diff --git a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
new file mode 100644
index 0000000..db0cbec
--- /dev/null
+++ b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
@@ -0,0 +1,325 @@
+// 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 <dns/master_lexer_inputsource.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <string.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::master_lexer_internal;
+
+namespace {
+
+class InputSourceTest : public ::testing::Test {
+protected:
+    InputSourceTest() :
+        str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"),
+        str_length_(strlen(str_)),
+        iss_(str_),
+        source_(iss_)
+    {}
+
+    const char* str_;
+    const size_t str_length_;
+    stringstream iss_;
+    InputSource source_;
+};
+
+// Test the default return values set during InputSource construction.
+TEST_F(InputSourceTest, defaults) {
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+// getName() on file and stream sources
+TEST_F(InputSourceTest, getName) {
+    EXPECT_EQ(0, source_.getName().find("stream-"));
+
+    // Use some file; doesn't really matter what.
+    InputSource source2(TEST_DATA_SRCDIR "/masterload.txt");
+    EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", source2.getName());
+}
+
+TEST_F(InputSourceTest, nonExistentFile) {
+    EXPECT_THROW({
+        InputSource source(TEST_DATA_SRCDIR "/does-not-exist");
+    }, InputSource::OpenError);
+}
+
+// getChar() should return characters from the input stream in
+// sequence. ungetChar() should skip backwards.
+void
+checkGetAndUngetChar(InputSource& source,
+                     const char* str, const size_t str_length)
+{
+    for (size_t i = 0; i < str_length; ++i) {
+        EXPECT_EQ(str[i], source.getChar());
+        EXPECT_FALSE(source.atEOF());
+    }
+
+    // At this point, we still have not reached EOF.
+    EXPECT_FALSE(source.atEOF());
+
+    // This should cause EOF to be set.
+    EXPECT_EQ(InputSource::END_OF_STREAM, source.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source.atEOF());
+
+    // Now, let's go backwards. This should cause the EOF to be set to
+    // false.
+    source.ungetChar();
+
+    // Now, EOF should be false.
+    EXPECT_FALSE(source.atEOF());
+
+    // This should cause EOF to be set again.
+    EXPECT_EQ(InputSource::END_OF_STREAM, source.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source.atEOF());
+
+    // Now, let's go backwards in a loop. Start by skipping the EOF.
+    source.ungetChar();
+
+    for (size_t i = 0; i < str_length; ++i) {
+        const size_t index = str_length - 1 - i;
+        // Skip one character.
+        source.ungetChar();
+        EXPECT_EQ(str[index], source.getChar());
+        // Skip the character we received again.
+        source.ungetChar();
+    }
+
+    // Skipping past the start of buffer should throw.
+    EXPECT_THROW(source.ungetChar(), InputSource::UngetBeforeBeginning);
+}
+
+TEST_F(InputSourceTest, stream) {
+    checkGetAndUngetChar(source_, str_, str_length_);
+}
+
+TEST_F(InputSourceTest, file) {
+    std::ifstream fs(TEST_DATA_SRCDIR "/masterload.txt");
+    const std::string str((std::istreambuf_iterator<char>(fs)),
+                          std::istreambuf_iterator<char>());
+    fs.close();
+
+    InputSource source(TEST_DATA_SRCDIR "/masterload.txt");
+    checkGetAndUngetChar(source, str.c_str(), str.size());
+}
+
+// ungetAll() should skip back to the place where the InputSource
+// started at construction, or the last saved start of line.
+TEST_F(InputSourceTest, ungetAll) {
+    while (!source_.atEOF()) {
+        source_.getChar();
+    }
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    source_.ungetAll();
+
+    // Now we are back to where we started.
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+TEST_F(InputSourceTest, compact) {
+    // Compact at the start
+    source_.compact();
+
+    // Ungetting here must throw.
+    EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+    for (size_t i = 0; i < str_length_; ++i) {
+        EXPECT_EQ(str_[i], source_.getChar());
+        EXPECT_FALSE(source_.atEOF());
+    }
+
+    // At this point, we still have not reached EOF.
+    EXPECT_FALSE(source_.atEOF());
+
+    // This should cause EOF to be set.
+    EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    // Compact again
+    source_.compact();
+
+    // We are still at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    // Skip the EOF.
+    source_.ungetChar();
+
+    // Ungetting here must throw.
+    EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+    EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+    EXPECT_TRUE(source_.atEOF());
+}
+
+TEST_F(InputSourceTest, markDuring) {
+    // First, skip to line 2.
+    while (!source_.atEOF() &&
+           (source_.getCurrentLine() != 2)) {
+        source_.getChar();
+    }
+    EXPECT_FALSE(source_.atEOF());
+    EXPECT_EQ(2, source_.getCurrentLine());
+
+    // Now, unget a couple of characters. This should cause the
+    // buffer_pos_ to be not equal to the size of the buffer.
+    source_.ungetChar();
+    source_.ungetChar();
+
+    // Now "mark" the source, meaning that we save line number and also
+    // compact the internal buffer at this stage.
+    source_.mark();
+
+    // Ungetting here must throw.
+    EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+    for (size_t i = 13; i < str_length_; ++i) {
+        EXPECT_EQ(str_[i], source_.getChar());
+        EXPECT_FALSE(source_.atEOF());
+    }
+
+    // At this point, we still have not reached EOF.
+    EXPECT_FALSE(source_.atEOF());
+
+    // This should cause EOF to be set.
+    EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source_.atEOF());
+
+    // Now, ungetAll() and check where it goes back.
+    source_.ungetAll();
+
+    // Ungetting here must throw.
+    EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+    for (size_t i = 13; i < str_length_; ++i) {
+        EXPECT_EQ(str_[i], source_.getChar());
+        EXPECT_FALSE(source_.atEOF());
+    }
+
+    // At this point, we still have not reached EOF.
+    EXPECT_FALSE(source_.atEOF());
+
+    // This should cause EOF to be set.
+    EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source_.atEOF());
+}
+
+// Test line counters.
+TEST_F(InputSourceTest, lines) {
+    size_t line = 1;
+    while (!source_.atEOF()) {
+        if (source_.getChar() == '\n') {
+            ++line;
+        }
+        EXPECT_EQ(line, source_.getCurrentLine());
+    }
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    // Go backwards 2 characters, skipping the last EOF and '\n'.
+    source_.ungetChar();
+    source_.ungetChar();
+
+    EXPECT_FALSE(source_.atEOF());
+    EXPECT_EQ(3, source_.getCurrentLine());
+
+    source_.ungetAll();
+
+    // Now we are back to where we started.
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+
+    // Now check that line numbers are decremented properly (as much as
+    // possible using the available API).
+    while (!source_.atEOF()) {
+        source_.getChar();
+    }
+    line = source_.getCurrentLine();
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, line);
+
+    EXPECT_THROW({
+        while (true) {
+            source_.ungetChar();
+            EXPECT_TRUE(((line == source_.getCurrentLine()) ||
+                         ((line - 1) == source_.getCurrentLine())));
+            line = source_.getCurrentLine();
+        }
+    }, InputSource::UngetBeforeBeginning);
+
+    // Now we are back to where we started.
+    EXPECT_EQ(1, source_.getCurrentLine());
+}
+
+// ungetAll() after saveLine() should skip back to the last-saved place.
+TEST_F(InputSourceTest, saveLine) {
+    // First, skip to line 2.
+    while (!source_.atEOF() &&
+           (source_.getCurrentLine() != 2)) {
+        source_.getChar();
+    }
+    EXPECT_FALSE(source_.atEOF());
+    EXPECT_EQ(2, source_.getCurrentLine());
+
+    // Now, save the line.
+    source_.saveLine();
+
+    // Now, go to EOF
+    while (!source_.atEOF()) {
+        source_.getChar();
+    }
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    // Now, ungetAll() and check where it goes back.
+    source_.ungetAll();
+
+    // Now we are back to where we last-saved.
+    EXPECT_EQ(2, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/master_lexer_token_unittest.cc b/src/lib/dns/tests/master_lexer_token_unittest.cc
new file mode 100644
index 0000000..a63b9ca
--- /dev/null
+++ b/src/lib/dns/tests/master_lexer_token_unittest.cc
@@ -0,0 +1,156 @@
+// 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/master_lexer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+using namespace isc::dns;
+
+namespace {
+
+const char TEST_STRING[] = "string token";
+// This excludes the ending \0 character
+const size_t TEST_STRING_LEN = sizeof(TEST_STRING) - 1;
+
+class MasterLexerTokenTest : public ::testing::Test {
+protected:
+    MasterLexerTokenTest() :
+        token_eof(MasterLexer::Token::END_OF_FILE),
+        token_str(TEST_STRING, TEST_STRING_LEN),
+        token_num(42),
+        token_err(MasterLexer::Token::UNEXPECTED_END)
+    {}
+
+    const MasterLexer::Token token_eof; // an example of non-value type token
+    const MasterLexer::Token token_str;
+    const MasterLexer::Token token_num;
+    const MasterLexer::Token token_err;
+};
+
+
+TEST_F(MasterLexerTokenTest, strings) {
+    // basic construction and getter checks
+    EXPECT_EQ(MasterLexer::Token::STRING, token_str.getType());
+    EXPECT_EQ(std::string("string token"), token_str.getString());
+    const MasterLexer::Token::StringRegion str_region =
+        token_str.getStringRegion();
+    EXPECT_EQ(TEST_STRING, str_region.beg);
+    EXPECT_EQ(TEST_STRING_LEN, str_region.len);
+
+    // Even if the stored string contains a nul character (in this case,
+    // it happens to be at the end of the string, but could be in the middle),
+    // getString() should return a string object containing the nul.
+    std::string expected_str("string token");
+    expected_str.push_back('\0');
+    EXPECT_EQ(expected_str,
+              MasterLexer::Token(TEST_STRING, TEST_STRING_LEN + 1).getString());
+
+    // Construct type of qstring
+    EXPECT_EQ(MasterLexer::Token::QSTRING,
+              MasterLexer::Token(TEST_STRING, sizeof(TEST_STRING), true).
+              getType());
+    // if we explicitly set 'quoted' to false, it should be normal string
+    EXPECT_EQ(MasterLexer::Token::STRING,
+              MasterLexer::Token(TEST_STRING, sizeof(TEST_STRING), false).
+              getType());
+
+    // getString/StringRegion() aren't allowed for non string(-variant) types
+    EXPECT_THROW(token_eof.getString(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getString(), isc::InvalidOperation);
+    EXPECT_THROW(token_eof.getStringRegion(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getStringRegion(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, numbers) {
+    EXPECT_EQ(42, token_num.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token_num.getType());
+
+    // It's copyable and assignable.
+    MasterLexer::Token token(token_num);
+    EXPECT_EQ(42, token.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token.getType());
+
+    token = token_num;
+    EXPECT_EQ(42, token.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token.getType());
+
+    // it's okay to replace it with a different type of token
+    token = token_eof;
+    EXPECT_EQ(MasterLexer::Token::END_OF_FILE, token.getType());
+
+    // Possible max value
+    token = MasterLexer::Token(0xffffffff);
+    EXPECT_EQ(4294967295u, token.getNumber());
+
+    // getNumber() isn't allowed for non number types
+    EXPECT_THROW(token_eof.getNumber(), isc::InvalidOperation);
+    EXPECT_THROW(token_str.getNumber(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, novalues) {
+    // Just checking we can construct them and getType() returns correct value.
+    EXPECT_EQ(MasterLexer::Token::END_OF_FILE, token_eof.getType());
+    EXPECT_EQ(MasterLexer::Token::END_OF_LINE,
+              MasterLexer::Token(MasterLexer::Token::END_OF_LINE).getType());
+    EXPECT_EQ(MasterLexer::Token::INITIAL_WS,
+              MasterLexer::Token(MasterLexer::Token::INITIAL_WS).getType());
+
+    // Special types of tokens cannot have value-based types
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::STRING),
+                 isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::QSTRING),
+                 isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::NUMBER),
+                 isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::ERROR),
+                 isc::InvalidParameter);
+}
+
+TEST_F(MasterLexerTokenTest, errors) {
+    EXPECT_EQ(MasterLexer::Token::ERROR, token_err.getType());
+    EXPECT_EQ(MasterLexer::Token::UNEXPECTED_END, token_err.getErrorCode());
+    EXPECT_EQ("unexpected end of input", token_err.getErrorText());
+    EXPECT_EQ("lexer not started",
+              MasterLexer::Token(MasterLexer::Token::NOT_STARTED).
+              getErrorText());
+    EXPECT_EQ("unbalanced parentheses",
+              MasterLexer::Token(MasterLexer::Token::UNBALANCED_PAREN).
+              getErrorText());
+    EXPECT_EQ("unbalanced quotes",
+              MasterLexer::Token(MasterLexer::Token::UNBALANCED_QUOTES).
+              getErrorText());
+
+    // getErrorCode/Text() isn't allowed for non number types
+    EXPECT_THROW(token_num.getErrorCode(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getErrorText(), isc::InvalidOperation);
+
+    // Only the pre-defined error code is accepted.  Hardcoding '4' (max code
+    // + 1) is intentional; it'd be actually better if we notice it when we
+    // update the enum list (which shouldn't happen too often).
+    EXPECT_THROW(MasterLexer::Token(MasterLexer::Token::ErrorCode(4)),
+                 isc::InvalidParameter);
+
+    // Check the coexistence of "from number" and "from error-code"
+    // constructors won't cause confusion.
+    EXPECT_EQ(MasterLexer::Token::NUMBER,
+              MasterLexer::Token(static_cast<uint32_t>(
+                                     MasterLexer::Token::NOT_STARTED)).
+              getType());
+}
+}
diff --git a/src/lib/dns/tests/master_lexer_unittest.cc b/src/lib/dns/tests/master_lexer_unittest.cc
new file mode 100644
index 0000000..93fead7
--- /dev/null
+++ b/src/lib/dns/tests/master_lexer_unittest.cc
@@ -0,0 +1,127 @@
+// 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/master_lexer.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <sstream>
+
+using namespace isc::dns;
+using std::string;
+using std::stringstream;
+using boost::lexical_cast;
+
+namespace {
+
+class MasterLexerTest : public ::testing::Test {
+protected:
+    MasterLexerTest() :
+        expected_stream_name("stream-" + lexical_cast<string>(&ss))
+    {}
+
+    MasterLexer lexer;
+    stringstream ss;
+    const string expected_stream_name;
+};
+
+// Commonly used check case where the input sources stack is empty.
+void
+checkEmptySource(const MasterLexer& lexer) {
+    EXPECT_TRUE(lexer.getSourceName().empty());
+    EXPECT_EQ(0, lexer.getSourceLine());
+}
+
+TEST_F(MasterLexerTest, preOpen) {
+    // Initially sources stack is empty.
+    checkEmptySource(lexer);
+}
+
+TEST_F(MasterLexerTest, pushStream) {
+    lexer.pushSource(ss);
+    EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+
+    // From the point of view of this test, we only have to check (though
+    // indirectly) getSourceLine calls InputSource::getCurrentLine.  It should
+    // return 1 initially.
+    EXPECT_EQ(1, lexer.getSourceLine());
+
+    // By popping it the stack will be empty again.
+    lexer.popSource();
+    checkEmptySource(lexer);
+}
+
+TEST_F(MasterLexerTest, pushFile) {
+    // We use zone file (-like) data, but in this test that actually doesn't
+    // matter.
+    EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
+    EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
+    EXPECT_EQ(1, lexer.getSourceLine());
+
+    lexer.popSource();
+    checkEmptySource(lexer);
+
+    // If we give a non NULL string pointer, its content will be intact
+    // if pushSource succeeds.
+    std::string error_txt = "dummy";
+    EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
+                                 &error_txt));
+    EXPECT_EQ("dummy", error_txt);
+}
+
+TEST_F(MasterLexerTest, pushBadFileName) {
+    EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
+}
+
+TEST_F(MasterLexerTest, pushFileFail) {
+    // The file to be pushed doesn't exist.  pushSource() fails and
+    // some non empty error string should be set.
+    std::string error_txt;
+    EXPECT_TRUE(error_txt.empty());
+    EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
+    EXPECT_FALSE(error_txt.empty());
+
+    // It's safe to pass NULL error_txt (either explicitly or implicitly as
+    // the default)
+    EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
+    EXPECT_FALSE(lexer.pushSource("no-such-file"));
+}
+
+TEST_F(MasterLexerTest, nestedPush) {
+    lexer.pushSource(ss);
+    EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+
+    // We can push another source without popping the previous one.
+    lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
+    EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
+
+    // popSource() works on the "topmost" (last-pushed) source
+    lexer.popSource();
+    EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+
+    lexer.popSource();
+    EXPECT_TRUE(lexer.getSourceName().empty());
+}
+
+TEST_F(MasterLexerTest, invalidPop) {
+    // popSource() cannot be called if the sources stack is empty.
+    EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
+}
+
+}
diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc
index c327bdc..10d1e55 100644
--- a/src/lib/dns/tests/name_unittest.cc
+++ b/src/lib/dns/tests/name_unittest.cc
@@ -40,6 +40,22 @@ using namespace isc::util;
 const size_t Name::MAX_WIRE;
 const size_t Name::MAX_LABELS;
 
+// This is a name of maximum allowed number of labels
+const char* max_labels_str = "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 40
+                             "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 80
+                             "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 120
+                             "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 160
+                             "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 200
+                             "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 240
+                             "0.1.2.3.4.5.6";
+// This is a name of maximum allowed length
+const char* max_len_str = "123456789.123456789.123456789.123456789.123456789."
+                          "123456789.123456789.123456789.123456789.123456789."
+                          "123456789.123456789.123456789.123456789.123456789."
+                          "123456789.123456789.123456789.123456789.123456789."
+                          "123456789.123456789.123456789.123456789.123456789."
+                          "123";
+
 namespace {
 class NameTest : public ::testing::Test {
 protected:
@@ -47,6 +63,8 @@ protected:
                  example_name_upper("WWW.EXAMPLE.COM"),
                  small_name("aaa.example.com"),
                  large_name("zzz.example.com"),
+                 origin_name("example.com."),
+                 origin_name_upper("EXAMPLE.COM"),
                  buffer_actual(0), buffer_expected(0)
     {}
 
@@ -54,6 +72,8 @@ protected:
     Name example_name_upper;    // this will be modified and cannot be const
     const Name small_name;
     const Name large_name;
+    const Name origin_name;
+    const Name origin_name_upper;
     OutputBuffer buffer_actual, buffer_expected;
 
     //
@@ -137,6 +157,11 @@ checkBadTextName(const string& txt) {
     // NameParserException.
     EXPECT_THROW(Name(txt, false), ExceptionType);
     EXPECT_THROW(Name(txt, false), NameParserException);
+    // The same is thrown when constructing by the master-file constructor
+    EXPECT_THROW(Name(txt.c_str(), txt.length(), &Name::ROOT_NAME()),
+                 ExceptionType);
+    EXPECT_THROW(Name(txt.c_str(), txt.length(), &Name::ROOT_NAME()),
+                 NameParserException);
 }
 
 TEST_F(NameTest, fromText) {
@@ -201,27 +226,99 @@ TEST_F(NameTest, fromText) {
                                   "123456789.123456789.123456789.123456789."
                                   "123456789.1234");
     // This is a possible longest name and should be accepted
-    EXPECT_NO_THROW(Name("123456789.123456789.123456789.123456789.123456789."
-                         "123456789.123456789.123456789.123456789.123456789."
-                         "123456789.123456789.123456789.123456789.123456789."
-                         "123456789.123456789.123456789.123456789.123456789."
-                         "123456789.123456789.123456789.123456789.123456789."
-                         "123"));
+    EXPECT_NO_THROW(Name(string(max_len_str)));
     // \DDD must consist of 3 digits.
     checkBadTextName<IncompleteName>("\\12");
 
     // a name with the max number of labels.  should be constructed without
     // an error, and its length should be the max value.
-    Name maxlabels = Name("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 40
-                          "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 80
-                          "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 120
-                          "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 160
-                          "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 200
-                          "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 240
-                          "0.1.2.3.4.5.6.");
+    Name maxlabels = Name(string(max_labels_str));
     EXPECT_EQ(Name::MAX_LABELS, maxlabels.getLabelCount());
 }
 
+// on the rest while we prepare it.
+// Check the @ syntax is accepted and it just copies the origin.
+TEST_F(NameTest, copyOrigin) {
+    EXPECT_EQ(origin_name, Name("@", 1, &origin_name));
+    // The downcase works on the origin too. But only when we provide it.
+    EXPECT_EQ(origin_name, Name("@", 1, &origin_name_upper, true));
+    EXPECT_EQ(origin_name_upper, Name("@", 1, &origin_name_upper, true));
+    // If we don't provide the origin, it throws
+    EXPECT_THROW(Name("@", 1, NULL), MissingNameOrigin);
+}
+
+// Test the master-file constructor does not append the origin when the
+// provided name is absolute
+TEST_F(NameTest, dontAppendOrigin) {
+    EXPECT_EQ(example_name, Name("www.example.com.", 16, &origin_name));
+    // The downcase works (only if provided, though)
+    EXPECT_EQ(example_name, Name("WWW.EXAMPLE.COM.", 16, &origin_name, true));
+    EXPECT_EQ(example_name_upper, Name("WWW.EXAMPLE.COM.", 16, &origin_name));
+    // And it does not require the origin to be provided
+    EXPECT_NO_THROW(Name("www.example.com.", 16, NULL));
+}
+
+// Test the master-file constructor properly appends the origin when
+// the provided name is relative.
+TEST_F(NameTest, appendOrigin) {
+    EXPECT_EQ(example_name, Name("www", 3, &origin_name));
+    // Check the downcase works (if provided)
+    EXPECT_EQ(example_name, Name("WWW", 3, &origin_name, true));
+    EXPECT_EQ(example_name, Name("WWW", 3, &origin_name_upper, true));
+    EXPECT_EQ(example_name_upper, Name("WWW", 3, &origin_name_upper));
+    // Check we can prepend more than one label
+    EXPECT_EQ(Name("a.b.c.d.example.com."), Name("a.b.c.d", 7, &origin_name));
+    // When the name is relative, we throw.
+    EXPECT_THROW(Name("www", 3, NULL), MissingNameOrigin);
+}
+
+// When we don't provide the data, it throws
+TEST_F(NameTest, noDataProvided) {
+    EXPECT_THROW(Name(NULL, 10, NULL), isc::InvalidParameter);
+    EXPECT_THROW(Name(NULL, 10, &origin_name), isc::InvalidParameter);
+    EXPECT_THROW(Name("www", 0, NULL), isc::InvalidParameter);
+    EXPECT_THROW(Name("www", 0, &origin_name), isc::InvalidParameter);
+}
+
+// When we combine the first part and the origin together, the resulting name
+// is too long. It should throw. Other test checks this is valid when alone
+// (without the origin appended).
+TEST_F(NameTest, combinedTooLong) {
+    EXPECT_THROW(Name(max_len_str, strlen(max_len_str), &origin_name),
+                 TooLongName);
+    EXPECT_THROW(Name(max_labels_str, strlen(max_labels_str), &origin_name),
+                 TooLongName);
+    // Appending the root should be OK
+    EXPECT_NO_THROW(Name(max_len_str, strlen(max_len_str),
+                         &Name::ROOT_NAME()));
+    EXPECT_NO_THROW(Name(max_labels_str, strlen(max_labels_str),
+                         &Name::ROOT_NAME()));
+}
+
+// Test the handling of @ in the name. If it is alone, it is the origin (when
+// it exists) or the root. If it is somewhere else, it has no special meaning.
+TEST_F(NameTest, atSign) {
+    // If it is alone, it is the origin
+    EXPECT_EQ(origin_name, Name("@", 1, &origin_name));
+    EXPECT_THROW(Name("@", 1, NULL), MissingNameOrigin);
+    EXPECT_EQ(Name::ROOT_NAME(), Name("@"));
+
+    // It is not alone. It is taken verbatim. We check the name converted
+    // back to the textual form, since checking it agains other name object
+    // may be wrong -- if we create it wrong the same way as the tested
+    // object.
+    EXPECT_EQ("\\@.", Name("@.").toText());
+    EXPECT_EQ("\\@.", Name("@.", 2, NULL).toText());
+    EXPECT_EQ("\\@something.", Name("@something").toText());
+    EXPECT_EQ("something\\@.", Name("something@").toText());
+    EXPECT_EQ("\\@x.example.com.", Name("@x", 2, &origin_name).toText());
+    EXPECT_EQ("x\\@.example.com.", Name("x@", 2, &origin_name).toText());
+
+    // An escaped at-sign isn't active
+    EXPECT_EQ("\\@.", Name("\\@").toText());
+    EXPECT_EQ("\\@.example.com.", Name("\\@", 2, &origin_name).toText());
+}
+
 TEST_F(NameTest, fromWire) {
     //
     // test cases derived from BIND9 tests.
@@ -520,7 +617,6 @@ TEST_F(NameTest, downcase) {
     // confirm the calling object is actually modified
     example_name_upper.downcase();
     compareInWireFormat(example_name_upper, example_name);
-    
 }
 
 TEST_F(NameTest, at) {
diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h
index 1bc0fa4..f593609 100644
--- a/src/lib/dns/tests/rdata_unittest.h
+++ b/src/lib/dns/tests/rdata_unittest.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RDATA_UNITTEST_H
-#define __RDATA_UNITTEST_H 1
+#ifndef RDATA_UNITTEST_H
+#define RDATA_UNITTEST_H 1
 
 #include <util/buffer.h>
 #include <dns/messagerenderer.h>
@@ -44,7 +44,7 @@ protected:
 }
 }
 }
-#endif // __RDATA_UNITTEST_H
+#endif // RDATA_UNITTEST_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index 5596bcb..725eea7 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -359,4 +359,12 @@ TEST_F(RRsetRRSIGTest, getRRsigDataCount) {
     rrset_a->removeRRsig();
     EXPECT_EQ(0, rrset_a->getRRsigDataCount());
 }
+
+TEST_F(RRsetRRSIGTest, toText) {
+    // toText() should also return the associated RRSIG.
+    EXPECT_EQ("test.example.com. 3600 IN AAAA 2001:db8::1234\n"
+              "test.example.com. 3600 IN RRSIG AAAA 5 3 7200 "
+              "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n",
+              rrset_aaaa->toText());
+}
 }
diff --git a/src/lib/dns/tests/unittest_util.h b/src/lib/dns/tests/unittest_util.h
index ebb514d..f50df14 100644
--- a/src/lib/dns/tests/unittest_util.h
+++ b/src/lib/dns/tests/unittest_util.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UNITTEST_UTIL_H
-#define __UNITTEST_UTIL_H 1
+#ifndef UNITTEST_UTIL_H
+#define UNITTEST_UTIL_H 1
 
 #include <vector>
 #include <string>
@@ -111,7 +111,7 @@ public:
 
 };
 }
-#endif // __UNITTEST_UTIL_H
+#endif // UNITTEST_UTIL_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
index 9ccc580..a7ec011 100644
--- a/src/lib/dns/tsig.h
+++ b/src/lib/dns/tsig.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TSIG_H
-#define __TSIG_H 1
+#ifndef TSIG_H
+#define TSIG_H 1
 
 #include <boost/noncopyable.hpp>
 
@@ -433,7 +433,7 @@ private:
 }
 }
 
-#endif  // __TSIG_H
+#endif  // TSIG_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/tsigerror.h b/src/lib/dns/tsigerror.h
index 8efd3ae..5b8056d 100644
--- a/src/lib/dns/tsigerror.h
+++ b/src/lib/dns/tsigerror.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TSIGERROR_H
-#define __TSIGERROR_H 1
+#ifndef TSIGERROR_H
+#define TSIGERROR_H 1
 
 #include <ostream>
 #include <string>
@@ -331,7 +331,7 @@ std::ostream& operator<<(std::ostream& os, const TSIGError& tsig_error);
 }
 }
 
-#endif  // __TSIGERROR_H
+#endif  // TSIGERROR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index 6081dd3..1bbd3fe 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TSIGKEY_H
-#define __TSIGKEY_H 1
+#ifndef TSIGKEY_H
+#define TSIGKEY_H 1
 
 #include <cryptolink/cryptolink.h>
 
@@ -353,7 +353,7 @@ private:
 }
 }
 
-#endif  // __TSIGKEY_H
+#endif  // TSIGKEY_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/dns/tsigrecord.h b/src/lib/dns/tsigrecord.h
index 03de746..b5e8de3 100644
--- a/src/lib/dns/tsigrecord.h
+++ b/src/lib/dns/tsigrecord.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TSIGRECORD_H
-#define __TSIGRECORD_H 1
+#ifndef TSIGRECORD_H
+#define TSIGRECORD_H 1
 
 #include <ostream>
 #include <string>
@@ -301,7 +301,7 @@ std::ostream& operator<<(std::ostream& os, const TSIGRecord& record);
 }
 }
 
-#endif  // __TSIGRECORD_H
+#endif  // TSIGRECORD_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/exceptions/exceptions.h b/src/lib/exceptions/exceptions.h
index 010fd39..d7e270d 100644
--- a/src/lib/exceptions/exceptions.h
+++ b/src/lib/exceptions/exceptions.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __EXCEPTIONS_H
-#define __EXCEPTIONS_H 1
+#ifndef EXCEPTIONS_H
+#define EXCEPTIONS_H 1
 
 #include <stdexcept>
 #include <string>
@@ -230,7 +230,7 @@ public:
     } while (1)
 
 }
-#endif // __EXCEPTIONS_H
+#endif // EXCEPTIONS_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index ef62b2f..7bff8bd 100644
--- a/src/lib/log/compiler/message.cc
+++ b/src/lib/log/compiler/message.cc
@@ -122,7 +122,7 @@ currentTime() {
 /// \brief Create Header Sentinel
 ///
 /// Given the name of a file, create an \#ifdef sentinel name.  The name is
-/// __<name>_<ext>, where <name> is the name of the file, and <ext>
+/// <name>_<ext>, where <name> is the name of the file, and <ext>
 /// is the extension less the leading period.  The sentinel will be upper-case.
 ///
 /// \param file Filename object representing the file.
@@ -134,7 +134,7 @@ sentinel(Filename& file) {
 
     string name = file.name();
     string ext = file.extension();
-    string sentinel_text = "__" + name + "_" + ext.substr(1);
+    string sentinel_text = name + "_" + ext.substr(1);
     isc::util::str::uppercase(sentinel_text);
     return (sentinel_text);
 }
diff --git a/src/lib/log/dummylog.h b/src/lib/log/dummylog.h
index ef5af13..6f6ae97 100644
--- a/src/lib/log/dummylog.h
+++ b/src/lib/log/dummylog.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_DUMMYLOG_H
-#define _ISC_DUMMYLOG_H 1
+#ifndef ISC_DUMMYLOG_H
+#define ISC_DUMMYLOG_H 1
 
 #include <string>
 
@@ -58,4 +58,4 @@ void dlog(const std::string& message, bool error_flag=false);
 }
 }
 
-#endif // _ISC_DUMMYLOG_H
+#endif // ISC_DUMMYLOG_H
diff --git a/src/lib/log/log_dbglevels.h b/src/lib/log/log_dbglevels.h
index d713714..a459bed 100644
--- a/src/lib/log/log_dbglevels.h
+++ b/src/lib/log/log_dbglevels.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOG_DBGLVLS_H
-#define __LOG_DBGLVLS_H
+#ifndef LOG_DBGLVLS_H
+#define LOG_DBGLVLS_H
 
 /// \file
 ///
@@ -90,4 +90,4 @@ const int DBGLVL_TRACE_DETAIL_DATA = 55;
 
 }   // Anonymous namespace
 
-#endif // __LOG_DBGLVLS_H
+#endif // LOG_DBGLVLS_H
diff --git a/src/lib/log/log_formatter.h b/src/lib/log/log_formatter.h
index eebdb1a..8cb34c7 100644
--- a/src/lib/log/log_formatter.h
+++ b/src/lib/log/log_formatter.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOG_FORMATTER_H
-#define __LOG_FORMMATER_H
+#ifndef LOG_FORMATTER_H
+#define LOG_FORMATTER_H
 
 #include <cstddef>
 #include <string>
diff --git a/src/lib/log/log_messages.h b/src/lib/log/log_messages.h
index 10e1501..2b70553 100644
--- a/src/lib/log/log_messages.h
+++ b/src/lib/log/log_messages.h
@@ -1,7 +1,7 @@
 // File created from log_messages.mes on Thu Jul  7 15:32:06 2011
 
-#ifndef __LOG_MESSAGES_H
-#define __LOG_MESSAGES_H
+#ifndef LOG_MESSAGES_H
+#define LOG_MESSAGES_H
 
 #include <log/message_types.h>
 
@@ -32,4 +32,4 @@ extern const isc::log::MessageID LOG_WRITE_ERROR;
 } // namespace log
 } // namespace isc
 
-#endif // __LOG_MESSAGES_H
+#endif // LOG_MESSAGES_H
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 6405488..e3ba163 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_H
-#define __LOGGER_H
+#ifndef LOGGER_H
+#define LOGGER_H
 
 #include <cassert>
 #include <cstdlib>
@@ -33,9 +33,9 @@ namespace log {
 /// \page LoggingApi Logging API
 /// \section LoggingApiOverview Overview
 /// BIND 10 logging uses the concepts of the widely-used Java logging
-/// package log4j (http://logging.apache.log/log4j), albeit implemented 
+/// package log4j (http://logging.apache.log/log4j), albeit implemented
 /// in C++ using an open-source port.  Features of the system are:
-/// 
+///
 /// - Within the code objects - known as loggers - can be created and
 /// used to log messages.  These loggers have names; those with the
 /// same name share characteristics (such as output destination).
@@ -50,7 +50,7 @@ namespace log {
 /// message is logged, it is output only if it is logged at a level equal
 /// to the logger severity level or greater, e.g. if the logger's severity
 /// is WARN, only messages logged at WARN, ERROR or FATAL will be output.
-/// 
+///
 /// \section LoggingApiLoggerNames BIND 10 Logger Names
 /// Within BIND 10, the root logger root logger is given the name of the
 /// program (via the stand-alone function setRootLoggerName()). Other loggers
@@ -58,7 +58,7 @@ namespace log {
 /// This name appears in logging output, allowing users to identify both
 /// the BIND 10 program and the component within the program that generated
 /// the message.
-/// 
+///
 /// When creating a logger, the abbreviated name "<sublogger>" can be used;
 /// the program name will be prepended to it when the logger is created.
 /// In this way, individual libraries can have their own loggers without
@@ -66,7 +66,7 @@ namespace log {
 /// - The origin of the message will be clearly identified.
 /// - The same component can have different options (e.g. logging severity)
 /// in different programs at the same time.
-/// 
+///
 /// \section LoggingApiLoggingMessages Logging Messages
 /// Instead of embedding the text of messages within the code, each message
 /// is referred to using a symbolic name.  The logging code uses this name as
@@ -320,4 +320,4 @@ private:
 } // namespace isc
 
 
-#endif // __LOGGER_H
+#endif // LOGGER_H
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 10d3db4..7280d5c 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_IMPL_H
-#define __LOGGER_IMPL_H
+#ifndef LOGGER_IMPL_H
+#define LOGGER_IMPL_H
 
 #include <stdarg.h>
 #include <time.h>
@@ -200,4 +200,4 @@ private:
 } // namespace isc
 
 
-#endif // __LOGGER_IMPL_H
+#endif // LOGGER_IMPL_H
diff --git a/src/lib/log/logger_level.h b/src/lib/log/logger_level.h
index ea60c3c..ac4a61a 100644
--- a/src/lib/log/logger_level.h
+++ b/src/lib/log/logger_level.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_LEVEL_H
-#define __LOGGER_LEVEL_H
+#ifndef LOGGER_LEVEL_H
+#define LOGGER_LEVEL_H
 
 #include <string>
 
@@ -73,4 +73,4 @@ isc::log::Severity getSeverity(const std::string& sev_str);
 }   // namespace log
 }   // namespace isc
 
-#endif // __LOGGER_LEVEL_H
+#endif // LOGGER_LEVEL_H
diff --git a/src/lib/log/logger_level_impl.h b/src/lib/log/logger_level_impl.h
index 17b866d..4e18e46 100644
--- a/src/lib/log/logger_level_impl.h
+++ b/src/lib/log/logger_level_impl.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_LEVEL_IMPL_H
-#define __LOGGER_LEVEL_IMPL_H
+#ifndef LOGGER_LEVEL_IMPL_H
+#define LOGGER_LEVEL_IMPL_H
 
 #include <log4cplus/logger.h>
 #include <log4cplus/version.h>
@@ -131,4 +131,4 @@ public:
 } // namespace log
 } // namespace isc
 
-#endif // __LOGGER_LEVEL_IMPL_H
+#endif // LOGGER_LEVEL_IMPL_H
diff --git a/src/lib/log/logger_manager.h b/src/lib/log/logger_manager.h
index dece0c9..63699c9 100644
--- a/src/lib/log/logger_manager.h
+++ b/src/lib/log/logger_manager.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_MANAGER_H
-#define __LOGGER_MANAGER_H
+#ifndef LOGGER_MANAGER_H
+#define LOGGER_MANAGER_H
 
 #include "exceptions/exceptions.h"
 #include <log/logger_specification.h>
@@ -138,4 +138,4 @@ private:
 } // namespace isc
 
 
-#endif // __LOGGER_MANAGER_H
+#endif // LOGGER_MANAGER_H
diff --git a/src/lib/log/logger_manager_impl.h b/src/lib/log/logger_manager_impl.h
index 42a98f1..2bce655 100644
--- a/src/lib/log/logger_manager_impl.h
+++ b/src/lib/log/logger_manager_impl.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_MANAGER_IMPL_H
-#define __LOGGER_MANAGER_IMPL_H
+#ifndef LOGGER_MANAGER_IMPL_H
+#define LOGGER_MANAGER_IMPL_H
 
 #include <string>
 
@@ -166,4 +166,4 @@ private:
 } // namespace log
 } // namespace isc
 
-#endif // __LOGGER_MANAGER_IMPL_H
+#endif // LOGGER_MANAGER_IMPL_H
diff --git a/src/lib/log/logger_name.h b/src/lib/log/logger_name.h
index 82ea2ad..b9ebd1b 100644
--- a/src/lib/log/logger_name.h
+++ b/src/lib/log/logger_name.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_NAME_H
-#define __LOGGER_NAME_H
+#ifndef LOGGER_NAME_H
+#define LOGGER_NAME_H
 
 #include <string>
 
@@ -54,4 +54,4 @@ std::string expandLoggerName(const std::string& name);
 }
 }
 
-#endif // __LOGGER_NAME_H
+#endif // LOGGER_NAME_H
diff --git a/src/lib/log/logger_specification.h b/src/lib/log/logger_specification.h
index 78df054..663b0df 100644
--- a/src/lib/log/logger_specification.h
+++ b/src/lib/log/logger_specification.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_SPECIFICATION_H
-#define __LOGGER_SPECIFICATION_H
+#ifndef LOGGER_SPECIFICATION_H
+#define LOGGER_SPECIFICATION_H
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -146,11 +146,11 @@ private:
     std::string                 name_;          ///< Logger name
     isc::log::Severity          severity_;      ///< Severity for this logger
     int                         dbglevel_;      ///< Debug level
-    bool                        additive_;      ///< Chaining output 
+    bool                        additive_;      ///< Chaining output
     std::vector<OutputOption>   options_;       ///< Logger options
 };
 
 } // namespace log
 } // namespace isc
 
-#endif // __LOGGER_SPEC_IFICATIONH
+#endif // LOGGER_SPECIFICATION_H
diff --git a/src/lib/log/logger_support.h b/src/lib/log/logger_support.h
index 4ce3ced..f59be60 100644
--- a/src/lib/log/logger_support.h
+++ b/src/lib/log/logger_support.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_SUPPORT_H
-#define __LOGGER_SUPPORT_H
+#ifndef LOGGER_SUPPORT_H
+#define LOGGER_SUPPORT_H
 
 #include <unistd.h>
 
@@ -68,4 +68,4 @@ void initLogger(const std::string& root,
 } // namespace log
 } // namespace isc
 
-#endif // __LOGGER_SUPPORT_H
+#endif // LOGGER_SUPPORT_H
diff --git a/src/lib/log/logger_unittest_support.h b/src/lib/log/logger_unittest_support.h
index ce9121b..70f34e8 100644
--- a/src/lib/log/logger_unittest_support.h
+++ b/src/lib/log/logger_unittest_support.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOGGER_UNITTEST_SUPPORT_H
-#define __LOGGER_UNITTEST_SUPPORT_H
+#ifndef LOGGER_UNITTEST_SUPPORT_H
+#define LOGGER_UNITTEST_SUPPORT_H
 
 #include <string>
 #include <log/logger.h>
@@ -123,4 +123,4 @@ resetUnitTestRootLogger();
 
 
 
-#endif // __LOGGER_UNITTEST_SUPPORT_H
+#endif // LOGGER_UNITTEST_SUPPORT_H
diff --git a/src/lib/log/logimpl_messages.h b/src/lib/log/logimpl_messages.h
index 1b94838..71a50d6 100644
--- a/src/lib/log/logimpl_messages.h
+++ b/src/lib/log/logimpl_messages.h
@@ -1,7 +1,7 @@
 // File created from logimpl_messages.mes on Wed Jun 22 10:57:02 2011
 
-#ifndef __LOGIMPL_MESSAGES_H
-#define __LOGIMPL_MESSAGES_H
+#ifndef LOGIMPL_MESSAGES_H
+#define LOGIMPL_MESSAGES_H
 
 #include <log/message_types.h>
 
@@ -15,4 +15,4 @@ extern const isc::log::MessageID LOGIMPL_BELOW_MIN_DEBUG;
 } // namespace log
 } // namespace isc
 
-#endif // __LOGIMPL_MESSAGES_H
+#endif // LOGIMPL_MESSAGES_H
diff --git a/src/lib/log/macros.h b/src/lib/log/macros.h
index 42fb42e..f602555 100644
--- a/src/lib/log/macros.h
+++ b/src/lib/log/macros.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOG_MACROS_H
-#define __LOG_MACROS_H
+#ifndef LOG_MACROS_H
+#define LOG_MACROS_H
 
 #include <log/logger.h>
 #include <log/log_dbglevels.h>
diff --git a/src/lib/log/message_dictionary.h b/src/lib/log/message_dictionary.h
index 519986d..3d622cd 100644
--- a/src/lib/log/message_dictionary.h
+++ b/src/lib/log/message_dictionary.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_DICTIONARY_H
-#define __MESSAGE_DICTIONARY_H
+#ifndef MESSAGE_DICTIONARY_H
+#define MESSAGE_DICTIONARY_H
 
 #include <cstddef>
 #include <string>
@@ -187,4 +187,4 @@ private:
 } // namespace log
 } // namespace isc
 
-#endif // __MESSAGE_DICTIONARY_H
+#endif // MESSAGE_DICTIONARY_H
diff --git a/src/lib/log/message_exception.h b/src/lib/log/message_exception.h
index 8b9d58a..5f1ad12 100644
--- a/src/lib/log/message_exception.h
+++ b/src/lib/log/message_exception.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_EXCEPTION_H
-#define __MESSAGE_EXCEPTION_H
+#ifndef MESSAGE_EXCEPTION_H
+#define MESSAGE_EXCEPTION_H
 
 #include <exceptions/exceptions.h>
 #include <log/message_types.h>
@@ -117,4 +117,4 @@ private:
 } // namespace log
 } // namespace isc
 
-#endif // __MESSAGE_EXCEPTION_H
+#endif // MESSAGE_EXCEPTION_H
diff --git a/src/lib/log/message_initializer.h b/src/lib/log/message_initializer.h
index 28b0e61..3be973d 100644
--- a/src/lib/log/message_initializer.h
+++ b/src/lib/log/message_initializer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGEINITIALIZER_H
-#define __MESSAGEINITIALIZER_H
+#ifndef MESSAGEINITIALIZER_H
+#define MESSAGEINITIALIZER_H
 
 #include <cstdlib>
 #include <string>
@@ -108,4 +108,4 @@ public:
 } // namespace log
 } // namespace isc
 
-#endif // __MESSAGEINITIALIZER_H
+#endif // MESSAGEINITIALIZER_H
diff --git a/src/lib/log/message_reader.h b/src/lib/log/message_reader.h
index a468d43..62d50b9 100644
--- a/src/lib/log/message_reader.h
+++ b/src/lib/log/message_reader.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_READER_H
-#define __MESSAGE_READER_H
+#ifndef MESSAGE_READER_H
+#define MESSAGE_READER_H
 
 #include <map>
 #include <string>
@@ -212,4 +212,4 @@ private:
 } // namespace log
 } // namespace isc
 
-#endif // __MESSAGE_READER_H
+#endif // MESSAGE_READER_H
diff --git a/src/lib/log/message_types.h b/src/lib/log/message_types.h
index 9f625a9..7966f98 100644
--- a/src/lib/log/message_types.h
+++ b/src/lib/log/message_types.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MESSAGE_TYPES_H
-#define __MESSAGE_TYPES_H
+#ifndef MESSAGE_TYPES_H
+#define MESSAGE_TYPES_H
 
 #include <string.h>
 
@@ -34,4 +34,4 @@ bool equalMessageID(const MessageID& m1, const MessageID& m2);
 
 
 
-#endif // __MESSAGE_TYPES_H
+#endif // MESSAGE_TYPES_H
diff --git a/src/lib/log/output_option.h b/src/lib/log/output_option.h
index 8dfdd70..8dcb28d 100644
--- a/src/lib/log/output_option.h
+++ b/src/lib/log/output_option.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __OUTPUT_OPTION_H
-#define __OUTPUT_OPTION_H
+#ifndef OUTPUT_OPTION_H
+#define OUTPUT_OPTION_H
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -82,4 +82,4 @@ OutputOption::Stream getStream(const std::string& stream_str);
 } // namespace log
 } // namespace isc
 
-#endif // __OUTPUT_OPTION_H
+#endif // OUTPUT_OPTION_H
diff --git a/src/lib/log/tests/log_formatter_unittest.cc b/src/lib/log/tests/log_formatter_unittest.cc
index 435b200..f0a9a59 100644
--- a/src/lib/log/tests/log_formatter_unittest.cc
+++ b/src/lib/log/tests/log_formatter_unittest.cc
@@ -16,6 +16,7 @@
 #include <gtest/gtest.h>
 
 #include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
 
 #include <log/log_formatter.h>
 #include <log/logger_level.h>
@@ -119,12 +120,13 @@ TEST_F(FormatterTest, mismatchedPlaceholders) {
     // Likewise, if there's a redundant placeholder (or missing argument), the
     // check detects it and aborts the program.  Due to the restriction of the
     // current implementation, it doesn't throw.
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
-        Formatter(isc::log::INFO, s("Too many arguments in %1 %2"), this).
-            arg("only one");
-    }, ".*");
-
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
+            Formatter(isc::log::INFO, s("Too many arguments in %1 %2"), this).
+                arg("only one");
+        }, ".*");
+    }
 #endif /* EXPECT_DEATH */
     // Mixed case of above two: the exception will be thrown due to the missing
     // placeholder. The other check is disabled due to that.
diff --git a/src/lib/log/tests/logger_unittest.cc b/src/lib/log/tests/logger_unittest.cc
index a9330a9..7b62d79 100644
--- a/src/lib/log/tests/logger_unittest.cc
+++ b/src/lib/log/tests/logger_unittest.cc
@@ -11,13 +11,10 @@
 // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
-
-#include <iostream>
-#include <string>
-
 #include <gtest/gtest.h>
 
 #include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
 
 #include <log/logger.h>
 #include <log/logger_manager.h>
@@ -27,6 +24,9 @@
 
 #include <util/interprocess_sync_file.h>
 
+#include <iostream>
+#include <string>
+
 using namespace isc;
 using namespace isc::log;
 using namespace std;
@@ -356,7 +356,6 @@ TEST_F(LoggerTest, IsDebugEnabledLevel) {
 
 // Check that if a logger name is too long, it triggers the appropriate
 // assertion.
-
 TEST_F(LoggerTest, LoggerNameLength) {
     // The following statements should just declare a logger and nothing
     // should happen.
@@ -374,12 +373,14 @@ TEST_F(LoggerTest, LoggerNameLength) {
     // Too long a logger name should trigger an assertion failure.
     // Note that we just check that it dies - we don't check what message is
     // output.
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
 
-        string ok3(Logger::MAX_LOGGER_NAME_SIZE + 1, 'x');
-        Logger l3(ok3.c_str());
-    }, ".*");
+            string ok3(Logger::MAX_LOGGER_NAME_SIZE + 1, 'x');
+            Logger l3(ok3.c_str());
+        }, ".*");
+    }
 #endif
 }
 
diff --git a/src/lib/log/tests/message_initializer_2_unittest.cc b/src/lib/log/tests/message_initializer_2_unittest.cc
index b479eee..8cc78fa 100644
--- a/src/lib/log/tests/message_initializer_2_unittest.cc
+++ b/src/lib/log/tests/message_initializer_2_unittest.cc
@@ -16,6 +16,7 @@
 #include <gtest/gtest.h>
 
 #include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
 
 using namespace isc::log;
 
@@ -43,10 +44,12 @@ TEST(MessageInitializerTest2, MessageLoadTest) {
     // test for its presence and bypass the test if not available.
 #ifdef EXPECT_DEATH
     // Adding one more should take us over the limit.
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
 
-        MessageInitializer initializer2(values);
-      }, ".*");
+            MessageInitializer initializer2(values);
+          }, ".*");
+    }
 #endif
 }
diff --git a/src/lib/log/tests/tempdir.h.in b/src/lib/log/tests/tempdir.h.in
index 366fea3..96ce8d4 100644
--- a/src/lib/log/tests/tempdir.h.in
+++ b/src/lib/log/tests/tempdir.h.in
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TEMPDIR_H
-#define __TEMPDIR_H
+#ifndef TEMPDIR_H
+#define TEMPDIR_H
 
 /// \brief Define temporary directory
 ///
@@ -26,4 +26,4 @@ namespace {
 std::string TEMP_DIR("@builddir@");
 }
 
-#endif // __TEMPDIR_H
+#endif // TEMPDIR_H
diff --git a/src/lib/nsas/address_entry.h b/src/lib/nsas/address_entry.h
index 8698017..0c165ea 100644
--- a/src/lib/nsas/address_entry.h
+++ b/src/lib/nsas/address_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ADDRESS_ENTRY_H
-#define __ADDRESS_ENTRY_H
+#ifndef ADDRESS_ENTRY_H
+#define ADDRESS_ENTRY_H
 
 /// \brief Address Entry
 ///
@@ -99,4 +99,4 @@ private:
 }   // namespace isc
 
 
-#endif // __ADDRESS_ENTRY_H
+#endif // ADDRESS_ENTRY_H
diff --git a/src/lib/nsas/address_request_callback.h b/src/lib/nsas/address_request_callback.h
index ad0630e..457c587 100644
--- a/src/lib/nsas/address_request_callback.h
+++ b/src/lib/nsas/address_request_callback.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ADDRESS_REQUEST_CALLBACK_H
-#define __ADDRESS_REQUEST_CALLBACK_H
+#ifndef ADDRESS_REQUEST_CALLBACK_H
+#define ADDRESS_REQUEST_CALLBACK_H
 
 #include "asiolink.h"
 #include "nameserver_address.h"
@@ -69,4 +69,4 @@ public:
 } // namespace nsas
 } // namespace isc
 
-#endif // __ADDRESS_REQUEST_CALLBACK_H
+#endif // ADDRESS_REQUEST_CALLBACK_H
diff --git a/src/lib/nsas/asiolink.h b/src/lib/nsas/asiolink.h
index d95868f..b236a0e 100644
--- a/src/lib/nsas/asiolink.h
+++ b/src/lib/nsas/asiolink.h
@@ -12,10 +12,10 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ASIOLINK_H
-#define __ASIOLINK_H
+#ifndef ASIOLINK_H
+#define ASIOLINK_H
 
 #include <string>
 #include <sys/socket.h>
 
-#endif // __ASIOLINK_H
+#endif // ASIOLINK_H
diff --git a/src/lib/nsas/fetchable.h b/src/lib/nsas/fetchable.h
index 461cfca..7e8ce5c 100644
--- a/src/lib/nsas/fetchable.h
+++ b/src/lib/nsas/fetchable.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __FETCHABLE_H
-#define __FETCHABLE_H
+#ifndef FETCHABLE_H
+#define FETCHABLE_H
 
 /**
  * \file fetchable.h
@@ -63,4 +63,4 @@ class Fetchable {
 } // namespace nsas
 } // namespace isc
 
-#endif // __FETCHABLE_H
+#endif // FETCHABLE_H
diff --git a/src/lib/nsas/glue_hints.h b/src/lib/nsas/glue_hints.h
index 8e6ecf1..ccac382 100644
--- a/src/lib/nsas/glue_hints.h
+++ b/src/lib/nsas/glue_hints.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __GLUE_HINTS_H
-#define __GLUE_HINTS_H
+#ifndef GLUE_HINTS_H
+#define GLUE_HINTS_H
 
 #include <vector>
 
@@ -68,4 +68,4 @@ private:
 }
 
 
-#endif // __GLUE_HINTS_H
+#endif // GLUE_HINTS_H
diff --git a/src/lib/nsas/hash.h b/src/lib/nsas/hash.h
index 85b82c3..cc03b3f 100644
--- a/src/lib/nsas/hash.h
+++ b/src/lib/nsas/hash.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HASH_H
-#define __HASH_H
+#ifndef HASH_H
+#define HASH_H
 
 #include <stdint.h>
 #include <vector>
@@ -122,4 +122,4 @@ private:
 } // namspace nsas
 } // namespace isc
 
-#endif // __HASH_H
+#endif // HASH_H
diff --git a/src/lib/nsas/hash_deleter.h b/src/lib/nsas/hash_deleter.h
index 27f066e..6fcd3da 100644
--- a/src/lib/nsas/hash_deleter.h
+++ b/src/lib/nsas/hash_deleter.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HASH_DELETER_H
-#define __HASH_DELETER_H
+#ifndef HASH_DELETER_H
+#define HASH_DELETER_H
 
 #include <boost/shared_ptr.hpp>
 #include <util/lru_list.h>
@@ -72,4 +72,4 @@ void HashDeleter<T>::operator()(T* element) const {
 } // namespace nsas
 } // namespace isc
 
-#endif // __HASH_DELETER_H
+#endif // HASH_DELETER_H
diff --git a/src/lib/nsas/hash_key.h b/src/lib/nsas/hash_key.h
index c89b327..5f60735 100644
--- a/src/lib/nsas/hash_key.h
+++ b/src/lib/nsas/hash_key.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HASH_KEY_H
-#define __HASH_KEY_H
+#ifndef HASH_KEY_H
+#define HASH_KEY_H
 
 #include <dns/rrclass.h>
 
@@ -93,4 +93,4 @@ struct HashKey {
 } // namespace nsas
 } // namespace isc
 
-#endif // __HASH_KEY_H
+#endif // HASH_KEY_H
diff --git a/src/lib/nsas/hash_table.h b/src/lib/nsas/hash_table.h
index 6028473..13cafc7 100644
--- a/src/lib/nsas/hash_table.h
+++ b/src/lib/nsas/hash_table.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HASH_TABLE_H
-#define __HASH_TABLE_H
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
 
 #include <list>
 
@@ -334,4 +334,4 @@ bool HashTable<T>::addInternal(boost::shared_ptr<T>& object,
 }   // namespace nsas
 }   // namespace isc
 
-#endif // __HASH_TABLE_H
+#endif // HASH_TABLE_H
diff --git a/src/lib/nsas/nameserver_address.h b/src/lib/nsas/nameserver_address.h
index 07b6d4a..5f5c7c9 100644
--- a/src/lib/nsas/nameserver_address.h
+++ b/src/lib/nsas/nameserver_address.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NAMESERVER_ADDRESS_H
-#define __NAMESERVER_ADDRESS_H
+#ifndef NAMESERVER_ADDRESS_H
+#define NAMESERVER_ADDRESS_H
 
 #include <boost/shared_ptr.hpp>
 
@@ -114,4 +114,4 @@ private:
 } // namespace nsas
 } // namespace isc
 
-#endif//__NAMESERVER_ADDRESS_H
+#endif//NAMESERVER_ADDRESS_H
diff --git a/src/lib/nsas/nameserver_address_store.h b/src/lib/nsas/nameserver_address_store.h
index 1af535a..b107b3b 100644
--- a/src/lib/nsas/nameserver_address_store.h
+++ b/src/lib/nsas/nameserver_address_store.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NAMESERVER_ADDRESS_STORE_H
-#define __NAMESERVER_ADDRESS_STORE_H
+#ifndef NAMESERVER_ADDRESS_STORE_H
+#define NAMESERVER_ADDRESS_STORE_H
 
 #include <string>
 #include <vector>
@@ -129,4 +129,4 @@ private:
 } // namespace isc
 
 
-#endif // __NAMESERVER_ADDRESS_STORE_H
+#endif // NAMESERVER_ADDRESS_STORE_H
diff --git a/src/lib/nsas/nameserver_entry.h b/src/lib/nsas/nameserver_entry.h
index 0f214c6..77a640d 100644
--- a/src/lib/nsas/nameserver_entry.h
+++ b/src/lib/nsas/nameserver_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NAMESERVER_ENTRY_H
-#define __NAMESERVER_ENTRY_H
+#ifndef NAMESERVER_ENTRY_H
+#define NAMESERVER_ENTRY_H
 
 #include <string>
 #include <vector>
@@ -281,4 +281,4 @@ private:
 }   // namespace dns
 }   // namespace isc
 
-#endif // __NAMESERVER_ENTRY_H
+#endif // NAMESERVER_ENTRY_H
diff --git a/src/lib/nsas/nsas_entry.h b/src/lib/nsas/nsas_entry.h
index 9cbed11..e797fd8 100644
--- a/src/lib/nsas/nsas_entry.h
+++ b/src/lib/nsas/nsas_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_ENTRY_H
-#define __NSAS_ENTRY_H
+#ifndef NSAS_ENTRY_H
+#define NSAS_ENTRY_H
 
 #include <boost/enable_shared_from_this.hpp>
 #include <iostream>
@@ -135,4 +135,4 @@ private:
 } // namespace isc
 
 
-#endif // __NSAS_ENTRY_H
+#endif // NSAS_ENTRY_H
diff --git a/src/lib/nsas/nsas_entry_compare.h b/src/lib/nsas/nsas_entry_compare.h
index 9e9ba7d..6291456 100644
--- a/src/lib/nsas/nsas_entry_compare.h
+++ b/src/lib/nsas/nsas_entry_compare.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_ENTRY_COMPARE_H
-#define __NSAS_ENTRY_COMPARE_H
+#ifndef NSAS_ENTRY_COMPARE_H
+#define NSAS_ENTRY_COMPARE_H
 
 #include "hash_key.h"
 #include "hash_table.h"
@@ -50,4 +50,4 @@ public:
 } // namespace nsas
 } // namespace isc
 
-#endif // __NSAS_ENTRY_COMPARE_H
+#endif // NSAS_ENTRY_COMPARE_H
diff --git a/src/lib/nsas/nsas_log.h b/src/lib/nsas/nsas_log.h
index 031f46d..d4fed3c 100644
--- a/src/lib/nsas/nsas_log.h
+++ b/src/lib/nsas/nsas_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_LOG__H
-#define __NSAS_LOG__H
+#ifndef NSAS_LOG_H
+#define NSAS_LOG_H
 
 #include <log/macros.h>
 #include "nsas_messages.h"
@@ -50,4 +50,4 @@ extern isc::log::Logger nsas_logger;    // isc::nsas::logger is the NSAS logger
 } // namespace nsas
 } // namespace isc
 
-#endif // __NSAS_LOG__H
+#endif // NSAS_LOG_H
diff --git a/src/lib/nsas/nsas_types.h b/src/lib/nsas/nsas_types.h
index 940cc3e..07190a4 100644
--- a/src/lib/nsas/nsas_types.h
+++ b/src/lib/nsas/nsas_types.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_TYPES_H
-#define __NSAS_TYPES_H
+#ifndef NSAS_TYPES_H
+#define NSAS_TYPES_H
 
 /// \file nsas_types.h
 /// \brief Nameserver Address Store Types
@@ -44,4 +44,4 @@ enum AddressFamily {
 }
 }
 
-#endif // __NSAS_TYPES_H
+#endif // NSAS_TYPES_H
diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h
index 2dd95ef..d6b4d92 100644
--- a/src/lib/nsas/tests/nsas_test.h
+++ b/src/lib/nsas/tests/nsas_test.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_TEST_H
-#define __NSAS_TEST_H
+#ifndef NSAS_TEST_H
+#define NSAS_TEST_H
 
 /// \file nsas_test.h
 ///
@@ -293,4 +293,4 @@ protected:
 } // namespace nsas
 } // namespace isc
 
-#endif // __NSAS_TEST_H
+#endif // NSAS_TEST_H
diff --git a/src/lib/nsas/zone_entry.h b/src/lib/nsas/zone_entry.h
index 482b89f..7e5ab5b 100644
--- a/src/lib/nsas/zone_entry.h
+++ b/src/lib/nsas/zone_entry.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ZONE_ENTRY_H
-#define __ZONE_ENTRY_H
+#ifndef ZONE_ENTRY_H
+#define ZONE_ENTRY_H
 
 #include <string>
 #include <vector>
@@ -189,4 +189,4 @@ private:
 } // namespace nsas
 } // namespace isc
 
-#endif // __ZONE_ENTRY_H
+#endif // ZONE_ENTRY_H
diff --git a/src/lib/python/bind10_config.py.in b/src/lib/python/bind10_config.py.in
index b8975cf..6db64e2 100644
--- a/src/lib/python/bind10_config.py.in
+++ b/src/lib/python/bind10_config.py.in
@@ -51,7 +51,7 @@ def reload():
     #  tree the programs in the tree (not installed ones) will be used.
     #
     # B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
-    # tests where we want to use variuos types of configuration within the test
+    # 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)
     if "B10_FROM_SOURCE" in os.environ:
@@ -60,6 +60,8 @@ def reload():
         else:
             DATA_PATH = os.environ["B10_FROM_SOURCE"]
         PLUGIN_PATHS = [os.environ["B10_FROM_SOURCE"] +
+                            '/src/bin/cfgmgr/local_plugins',
+                             os.environ["B10_FROM_SOURCE"] +
                             '/src/bin/cfgmgr/plugins']
         programdirs = ['auth', 'cfgmgr', 'cmdctl', 'ddns', 'dhcp6', 'msgq',
                        'resolver', 'sockcreator', 'stats', 'xfrin', 'xfrout',
diff --git a/src/lib/python/isc/acl/dns.h b/src/lib/python/isc/acl/dns.h
index 76849c5..424a7f8 100644
--- a/src/lib/python/isc/acl/dns.h
+++ b/src/lib/python/isc/acl/dns.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_ACL_DNS_H
-#define __PYTHON_ACL_DNS_H 1
+#ifndef PYTHON_ACL_DNS_H
+#define PYTHON_ACL_DNS_H 1
 
 #include <Python.h>
 
@@ -45,7 +45,7 @@ extern PyObject* getACLException(const char* ex_name);
 } // namespace acl
 } // namespace isc
 
-#endif // __PYTHON_ACL_DNS_H
+#endif // PYTHON_ACL_DNS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/acl/dns_requestacl_python.h b/src/lib/python/isc/acl/dns_requestacl_python.h
index 8f7ad8a..ea1cb5e 100644
--- a/src/lib/python/isc/acl/dns_requestacl_python.h
+++ b/src/lib/python/isc/acl/dns_requestacl_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_REQUESTACL_H
-#define __PYTHON_REQUESTACL_H 1
+#ifndef PYTHON_REQUESTACL_H
+#define PYTHON_REQUESTACL_H 1
 
 #include <Python.h>
 
@@ -46,7 +46,7 @@ bool initModulePart_RequestACL(PyObject* mod);
 } // namespace dns
 } // namespace acl
 } // namespace isc
-#endif // __PYTHON_REQUESTACL_H
+#endif // PYTHON_REQUESTACL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/acl/dns_requestcontext_python.h b/src/lib/python/isc/acl/dns_requestcontext_python.h
index 766133b..567e86f 100644
--- a/src/lib/python/isc/acl/dns_requestcontext_python.h
+++ b/src/lib/python/isc/acl/dns_requestcontext_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_REQUESTCONTEXT_H
-#define __PYTHON_REQUESTCONTEXT_H 1
+#ifndef PYTHON_REQUESTCONTEXT_H
+#define PYTHON_REQUESTCONTEXT_H 1
 
 #include <Python.h>
 
@@ -47,7 +47,7 @@ bool initModulePart_RequestContext(PyObject* mod);
 } // namespace dns
 } // namespace acl
 } // namespace isc
-#endif // __PYTHON_REQUESTCONTEXT_H
+#endif // PYTHON_REQUESTCONTEXT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/acl/dns_requestloader_python.h b/src/lib/python/isc/acl/dns_requestloader_python.h
index 9d0b63e..80cb6be 100644
--- a/src/lib/python/isc/acl/dns_requestloader_python.h
+++ b/src/lib/python/isc/acl/dns_requestloader_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_REQUESTLOADER_H
-#define __PYTHON_REQUESTLOADER_H 1
+#ifndef PYTHON_REQUESTLOADER_H
+#define PYTHON_REQUESTLOADER_H 1
 
 #include <Python.h>
 
@@ -39,7 +39,7 @@ bool initModulePart_RequestLoader(PyObject* mod);
 } // namespace dns
 } // namespace acl
 } // namespace isc
-#endif // __PYTHON_REQUESTLOADER_H
+#endif // PYTHON_REQUESTLOADER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/bind10/sockcreator.py b/src/lib/python/isc/bind10/sockcreator.py
index c681d07..593d1a6 100644
--- a/src/lib/python/isc/bind10/sockcreator.py
+++ b/src/lib/python/isc/bind10/sockcreator.py
@@ -16,6 +16,7 @@
 import socket
 import struct
 import os
+import errno
 import copy
 import subprocess
 import copy
@@ -36,16 +37,16 @@ class CreatorError(Exception):
     passed to the __init__ function.
     """
 
-    def __init__(self, message, fatal, errno=None):
+    def __init__(self, message, fatal, error_num=None):
         """
         Creates the exception. The message argument is the usual string.
         The fatal one tells if the error is fatal (eg. the creator crashed)
-        and errno is the errno value returned from socket creator, if
+        and error_num is the errno value returned from socket creator, if
         applicable.
         """
         Exception.__init__(self, message)
         self.fatal = fatal
-        self.errno = errno
+        self.errno = error_num
 
 class Parser:
     """
@@ -94,6 +95,13 @@ class Parser:
             self.__socket = None
             raise CreatorError(str(se), True)
 
+    def __addrport_str(self, address, port):
+        '''Convert a pair of IP address and port to common form for logging.'''
+        if address.family == socket.AF_INET:
+            return str(address) + ':' + str(port)
+        else:
+            return '[' + str(address) + ']:' + str(port)
+
     def get_socket(self, address, port, socktype):
         """
         Asks the socket creator process to create a socket. Pass an address
@@ -136,9 +144,9 @@ class Parser:
             elif answer == b'E':
                 # There was an error, read the error as well
                 error = self.__socket.recv(1)
-                errno = struct.unpack('i',
-                                      self.__read_all(len(struct.pack('i',
-                                                                      0))))
+                rcv_errno = struct.unpack('i',
+                                          self.__read_all(len(struct.pack('i',
+                                                                          0))))
                 if error == b'S':
                     cause = 'socket'
                 elif error == b'B':
@@ -147,10 +155,22 @@ class Parser:
                     self.__socket = None
                     logger.fatal(BIND10_SOCKCREATOR_BAD_CAUSE, error)
                     raise CreatorError('Unknown error cause' + str(answer), True)
-                logger.error(BIND10_SOCKET_ERROR, cause, errno[0],
-                             os.strerror(errno[0]))
-                raise CreatorError('Error creating socket on ' + cause, False,
-                                   errno[0])
+                logger.error(BIND10_SOCKET_ERROR, cause, rcv_errno[0],
+                             os.strerror(rcv_errno[0]))
+
+                # Provide as detailed information as possible on the error,
+                # as error related to socket creation is a common operation
+                # trouble.  In particular, we are intentionally very verbose
+                # if it fails due to "permission denied" so the administrator
+                # can easily identify what is wrong and how to fix it.
+                addrport = self.__addrport_str(address, port)
+                error_text = 'Error creating socket on ' + cause + \
+                    ' to be bound to ' + addrport + ': ' + \
+                    os.strerror(rcv_errno[0])
+                if rcv_errno[0] == errno.EACCES:
+                    error_text += ' - probably need to restart BIND 10 ' + \
+                        'as a super user'
+                raise CreatorError(error_text, False, rcv_errno[0])
             else:
                 self.__socket = None
                 logger.fatal(BIND10_SOCKCREATOR_BAD_RESPONSE, answer)
@@ -214,9 +234,14 @@ class Creator(Parser):
                                 socket.SOCK_STREAM)
         env = copy.deepcopy(os.environ)
         env['PATH'] = path
+        # We explicitly set close_fs to True; it's False by default before
+        # Python 3.2.  If we don't close the remaining FDs, the copy of
+        # 'local' will prevent the child process from terminating when
+        # the parent process died abruptly.
         self.__process = subprocess.Popen(['b10-sockcreator'], env=env,
                                           stdin=remote.fileno(),
                                           stdout=remote2.fileno(),
+                                          close_fds=True,
                                           preexec_fn=self.__preexec_work)
         remote.close()
         remote2.close()
diff --git a/src/lib/python/isc/datasrc/client_python.h b/src/lib/python/isc/datasrc/client_python.h
index 98a256e..71aee8b 100644
--- a/src/lib/python/isc/datasrc/client_python.h
+++ b/src/lib/python/isc/datasrc/client_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_CLIENT_H
-#define __PYTHON_DATASRC_CLIENT_H 1
+#ifndef PYTHON_DATASRC_CLIENT_H
+#define PYTHON_DATASRC_CLIENT_H 1
 
 #include <datasrc/client_list.h>
 
@@ -47,7 +47,7 @@ wrapDataSourceClient(DataSourceClient* client,
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_DATASRC_CLIENT_H
+#endif // PYTHON_DATASRC_CLIENT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/configurableclientlist_python.h b/src/lib/python/isc/datasrc/configurableclientlist_python.h
index 155d262..bcd76fe 100644
--- a/src/lib/python/isc/datasrc/configurableclientlist_python.h
+++ b/src/lib/python/isc/datasrc/configurableclientlist_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_CONFIGURABLECLIENTLIST_H
-#define __PYTHON_CONFIGURABLECLIENTLIST_H 1
+#ifndef PYTHON_CONFIGURABLECLIENTLIST_H
+#define PYTHON_CONFIGURABLECLIENTLIST_H 1
 
 #include <Python.h>
 
@@ -37,7 +37,7 @@ bool initModulePart_ConfigurableClientList(PyObject* mod);
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_CONFIGURABLECLIENTLIST_H
+#endif // PYTHON_CONFIGURABLECLIENTLIST_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/datasrc.h b/src/lib/python/isc/datasrc/datasrc.h
index d82881b..5a7a8f0 100644
--- a/src/lib/python/isc/datasrc/datasrc.h
+++ b/src/lib/python/isc/datasrc/datasrc.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_H
-#define __PYTHON_DATASRC_H 1
+#ifndef PYTHON_DATASRC_H
+#define PYTHON_DATASRC_H 1
 
 #include <Python.h>
 
@@ -43,7 +43,7 @@ extern PyObject* getDataSourceException(const char* ex_name);
 } // namespace datasrc
 } // namespace isc
 
-#endif // __PYTHON_ACL_DNS_H
+#endif // PYTHON_DATASRC_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/finder_python.h b/src/lib/python/isc/datasrc/finder_python.h
index 23bc457..8d4c9b6 100644
--- a/src/lib/python/isc/datasrc/finder_python.h
+++ b/src/lib/python/isc/datasrc/finder_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_FINDER_H
-#define __PYTHON_DATASRC_FINDER_H 1
+#ifndef PYTHON_DATASRC_FINDER_H
+#define PYTHON_DATASRC_FINDER_H 1
 
 #include <Python.h>
 
@@ -37,7 +37,7 @@ PyObject* createZoneFinderObject(isc::datasrc::ZoneFinderPtr source,
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_DATASRC_FINDER_H
+#endif // PYTHON_DATASRC_FINDER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/iterator_python.h b/src/lib/python/isc/datasrc/iterator_python.h
index 7c1b0eb..c64dea3 100644
--- a/src/lib/python/isc/datasrc/iterator_python.h
+++ b/src/lib/python/isc/datasrc/iterator_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_ITERATOR_H
-#define __PYTHON_DATASRC_ITERATOR_H 1
+#ifndef PYTHON_DATASRC_ITERATOR_H
+#define PYTHON_DATASRC_ITERATOR_H 1
 
 #include <Python.h>
 
@@ -39,7 +39,7 @@ PyObject* createZoneIteratorObject(isc::datasrc::ZoneIteratorPtr source,
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_DATASRC_ITERATOR_H
+#endif // PYTHON_DATASRC_ITERATOR_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/journal_reader_python.h b/src/lib/python/isc/datasrc/journal_reader_python.h
index 56344df..6708c36 100644
--- a/src/lib/python/isc/datasrc/journal_reader_python.h
+++ b/src/lib/python/isc/datasrc/journal_reader_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_JOURNAL_READER_H
-#define __PYTHON_DATASRC_JOURNAL_READER_H 1
+#ifndef PYTHON_DATASRC_JOURNAL_READER_H
+#define PYTHON_DATASRC_JOURNAL_READER_H 1
 
 #include <Python.h>
 
@@ -40,7 +40,7 @@ PyObject* createZoneJournalReaderObject(
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_DATASRC_JOURNAL_READER_H
+#endif // PYTHON_DATASRC_JOURNAL_READER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/datasrc/updater_python.h b/src/lib/python/isc/datasrc/updater_python.h
index 8228578..b09c524 100644
--- a/src/lib/python/isc/datasrc/updater_python.h
+++ b/src/lib/python/isc/datasrc/updater_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_DATASRC_UPDATER_H
-#define __PYTHON_DATASRC_UPDATER_H 1
+#ifndef PYTHON_DATASRC_UPDATER_H
+#define PYTHON_DATASRC_UPDATER_H 1
 
 #include <Python.h>
 
@@ -40,7 +40,7 @@ PyObject* createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source,
 } // namespace python
 } // namespace datasrc
 } // namespace isc
-#endif // __PYTHON_DATASRC_UPDATER_H
+#endif // PYTHON_DATASRC_UPDATER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/sysinfo/sysinfo.py b/src/lib/python/isc/sysinfo/sysinfo.py
index 97b9e59..8e4610c 100644
--- a/src/lib/python/isc/sysinfo/sysinfo.py
+++ b/src/lib/python/isc/sysinfo/sysinfo.py
@@ -22,6 +22,7 @@ import subprocess
 import os.path
 import platform
 import time
+from datetime import timedelta
 
 class SysInfo:
     def __init__(self):
@@ -93,6 +94,18 @@ class SysInfo:
         """Returns the uptime in seconds."""
         return self._uptime
 
+    def get_uptime_desc(self):
+        """Returns the uptime in human readable form.
+
+        The format is the result of str() method of the standard library
+        datetime.timedelta class.  It returns None if _uptime is None.
+
+        """
+        if self._uptime is None:
+            return None
+
+        return str(timedelta(seconds=self._uptime))
+
     def get_loadavg(self):
         """Returns the load average as 3 floating point values in an array."""
         return self._loadavg
@@ -333,11 +346,11 @@ class SysInfoOpenBSD(SysInfoBSD):
             pass
 
         try:
+            # We use the size of free-list from the vmstat result.
             s = subprocess.check_output(['vmstat'])
             lines = s.decode('utf-8').split('\n')
             v = re.split('\s+', lines[2])
-            used = int(v[4]) * 1024
-            self._mem_free = self._mem_total - used
+            self._mem_free = int(v[5]) * 1024
         except (subprocess.CalledProcessError, OSError):
             pass
 
@@ -389,17 +402,27 @@ class SysInfoFreeBSD(SysInfoFreeBSDOSX):
         super().__init__()
 
         try:
-            s = subprocess.check_output(['sysctl', '-n', 'kern.smp.active'])
-            self._platform_is_smp = int(s.decode('utf-8').strip()) > 0
-        except (subprocess.CalledProcessError, OSError):
+            # There doesn't seem to be an easy way to reliably detect whether
+            # the kernel was built with SMP support on FreeBSD.  We use
+            # a sysctl variable that is only defined in SMP kernels.
+            # This assumption seems to hold for several recent versions of
+            # FreeBSD, but it may not always be so for future versions.
+            s = subprocess.check_output(['sysctl', '-n',
+                                         'kern.smp.forward_signal_enabled'])
+            self._platform_is_smp = True # the value doesn't matter
+        except subprocess.CalledProcessError:
+            # if this variable isn't defined we should see this exception.
+            # intepret it as an indication of non-SMP kernel.
+            self._platform_is_smp = False
+        except OSError:
             pass
 
         try:
+            # We use the size of free-list from the vmstat result.
             s = subprocess.check_output(['vmstat', '-H'])
             lines = s.decode('utf-8').split('\n')
             v = re.split('\s+', lines[2])
-            used = int(v[4]) * 1024
-            self._mem_free = self._mem_total - used
+            self._mem_free = int(v[5]) * 1024
         except (subprocess.CalledProcessError, OSError):
             pass
 
diff --git a/src/lib/python/isc/sysinfo/tests/sysinfo_test.py b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
index 0add036..8f11df0 100644
--- a/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
+++ b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
@@ -49,7 +49,7 @@ class MyLinuxFile:
         elif self._filename == '/proc/version':
             return 'An SMP version string'
         elif self._filename == '/proc/uptime':
-            return '86400.75 139993.71'
+            return '172800.75 139993.71'
         elif self._filename == '/proc/loadavg':
             return '0.1 0.2 0.3 0.4'
         else:
@@ -171,26 +171,33 @@ def _my_freebsd_os_sysconf(key):
 def _my_freebsd_platform_uname():
     return ('FreeBSD', 'freebsd', '8.2-RELEASE', '', 'i386')
 
-def _my_freebsd_osx_subprocess_check_output(command):
+def _my_freebsd_osx_subprocess_check_output(command, faked_output={}):
     '''subprocess output shared for freebsd and osx'''
     assert type(command) == list, 'command argument is not a list'
     if command == ['sysctl', '-n', 'kern.boottime']:
-        return bytes('{ sec = ' + str(int(time.time() - 76632)) + ', usec = 0 }\n', 'utf-8')
+        if 'boottime-sysctl' in faked_output:
+            return faked_output['boottime-sysctl']
+        return bytes('{ sec = ' + str(int(time.time() - 76632)) +
+                     ', usec = 0 }\n', 'utf-8')
     elif command == ['sysctl', '-n', 'vm.loadavg']:
         return b'{ 0.2 0.4 0.6 }\n'
     else:
         return _my_bsd_subprocess_check_output(command)
 
-def _my_freebsd_subprocess_check_output(command):
+def _my_freebsd_subprocess_check_output(command, faked_output):
     assert type(command) == list, 'command argument is not a list'
-    if command == ['sysctl', '-n', 'kern.smp.active']:
-        return b'1\n'
+    if command == ['sysctl', '-n', 'kern.smp.forward_signal_enabled']:
+        output = faked_output['smp-sysctl']
+        if isinstance(output, Exception):
+            raise output
+        return output
     elif command == ['vmstat', '-H']:
         return b' procs    memory       page                    disks    traps          cpu\n r b w    avm     fre  flt  re  pi  po  fr  sr wd0 cd0  int   sys   cs us sy id\n 0 0 0   343434  123456   47   0   0   0   0   0   2   0    2    80   14  0  1 99\n'
     elif command == ['swapctl', '-s', '-k']:
         return b'Total:         1013216    0\n'
     else:
-        freebsd_osx_output = _my_freebsd_osx_subprocess_check_output(command)
+        freebsd_osx_output = \
+            _my_freebsd_osx_subprocess_check_output(command, faked_output)
         if freebsd_osx_output is not None:
             return freebsd_osx_output
         else:
@@ -252,6 +259,7 @@ class SysInfoTest(unittest.TestCase):
         self.assertEqual('Unknown', s.get_platform_machine())
         self.assertFalse(s.get_platform_is_smp())
         self.assertEqual(None, s.get_uptime())
+        self.assertEqual(None, s.get_uptime_desc())
         self.assertEqual(None, s.get_loadavg())
         self.assertEqual(None, s.get_mem_total())
         self.assertEqual(None, s.get_mem_free())
@@ -267,7 +275,11 @@ class SysInfoTest(unittest.TestCase):
 
     def test_sysinfo_factory(self):
         """Test that SysInfoFromFactory returns a valid system-specific
-        SysInfo implementation."""
+        SysInfo implementation.
+
+        See sysinfo.SysInfoTestcase() for some of the parameters.
+
+        """
 
         old_platform_system = platform.system
         platform.system = _my_testcase_platform_system
@@ -281,6 +293,8 @@ class SysInfoTest(unittest.TestCase):
         self.assertEqual('Unknown', s.get_platform_machine())
         self.assertFalse(s.get_platform_is_smp())
         self.assertEqual(131072, s.get_uptime())
+        # We check that we do NOT add 's' to 'day' (because it's singular):
+        self.assertEqual('1 day, 12:24:32', s.get_uptime_desc())
         self.assertEqual(None, s.get_loadavg())
         self.assertEqual(None, s.get_mem_total())
         self.assertEqual(None, s.get_mem_free())
@@ -312,7 +326,10 @@ class SysInfoTest(unittest.TestCase):
         self.assertEqual(NPROCESSORS_LINUX, s.get_num_processors())
         self.assertEqual('myhostname', s.get_platform_hostname())
         self.assertTrue(s.get_platform_is_smp())
-        self.assertEqual(86401, s.get_uptime())
+        self.assertEqual(172801, s.get_uptime())
+        # We check that we add 's' to 'day', and that the mm part has an
+        # additional 0, i.e., not '0:0' but '0:00':
+        self.assertEqual('2 days, 0:00:01', s.get_uptime_desc())
         self.assertEqual((0.1, 0.2, 0.3), s.get_loadavg())
         self.assertEqual(3157884928, s.get_mem_total())
         self.assertEqual(891383808, s.get_mem_free())
@@ -366,7 +383,7 @@ class SysInfoTest(unittest.TestCase):
         self.assertEqual((0.7, 0.9, 0.8), s.get_loadavg())
         self.assertFalse(s.get_platform_is_smp())
         self.assertEqual(543214321, s.get_mem_total())
-        self.assertEqual(543214321 - (121212 * 1024), s.get_mem_free())
+        self.assertEqual(123456 * 1024, s.get_mem_free())
         self.assertEqual(566791168, s.get_mem_swap_total())
         self.assertEqual(566789120, s.get_mem_swap_free())
 
@@ -379,18 +396,42 @@ class SysInfoTest(unittest.TestCase):
         # with mock ones for testing.
         platform.system = _my_freebsd_platform_system
         os.sysconf = _my_freebsd_os_sysconf
-        subprocess.check_output = _my_freebsd_subprocess_check_output
+
+        # We use a lambda object so we can tweak the subprocess output during
+        # the tests later.
+        faked_process_output = { 'smp-sysctl': b'1\n' }
+        subprocess.check_output = lambda command : \
+            _my_freebsd_subprocess_check_output(command, faked_process_output)
+
         os.uname = _my_freebsd_platform_uname
 
         s = SysInfoFromFactory()
         self.assertEqual(NPROCESSORS_FREEBSD, s.get_num_processors())
         self.assertTrue(s.get_platform_is_smp())
 
+        # We check the kernel SMP support by the availability of a sysctl
+        # variable.  The value (especially a 0 value) shouldn't matter.
+        faked_process_output['smp-sysctl'] = b'0\n'
+        s = SysInfoFromFactory()
+        self.assertTrue(s.get_platform_is_smp())
+
+        # if the sysctl raises CalledProcessError, we treat it as non-SMP
+        # kernel.
+        faked_process_output['smp-sysctl'] = \
+            subprocess.CalledProcessError(1, 'sysctl')
+        s = SysInfoFromFactory()
+        self.assertFalse(s.get_platform_is_smp())
+
+        # if it results in OSError, no SMP information will be provided.
+        faked_process_output['smp-sysctl'] = OSError()
+        s = SysInfoFromFactory()
+        self.assertIsNone(s.get_platform_is_smp())
+
         self.check_bsd_values(s)
 
         self.assertEqual((0.2, 0.4, 0.6), s.get_loadavg())
         self.assertEqual(543214321, s.get_mem_total())
-        self.assertEqual(543214321 - (343434 * 1024), s.get_mem_free())
+        self.assertEqual(123456 * 1024, s.get_mem_free())
         self.assertEqual(1037533184, s.get_mem_swap_total())
         self.assertEqual(1037533184, s.get_mem_swap_free())
 
diff --git a/src/lib/python/isc/util/cio/socketsession_python.h b/src/lib/python/isc/util/cio/socketsession_python.h
index b0703ac..da83047 100644
--- a/src/lib/python/isc/util/cio/socketsession_python.h
+++ b/src/lib/python/isc/util/cio/socketsession_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_SOCKETSESSION_H
-#define __PYTHON_SOCKETSESSION_H 1
+#ifndef PYTHON_SOCKETSESSION_H
+#define PYTHON_SOCKETSESSION_H 1
 
 #include <Python.h>
 
@@ -28,7 +28,7 @@ extern PyObject* po_SocketSessionError;
 } // namespace io
 } // namespace util
 } // namespace isc
-#endif // __PYTHON_SOCKETSESSION_H
+#endif // PYTHON_SOCKETSESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/util/cio/socketsessionforwarder_python.h b/src/lib/python/isc/util/cio/socketsessionforwarder_python.h
index 2ce220a..968ce7f 100644
--- a/src/lib/python/isc/util/cio/socketsessionforwarder_python.h
+++ b/src/lib/python/isc/util/cio/socketsessionforwarder_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_SOCKETSESSIONFORWARDER_H
-#define __PYTHON_SOCKETSESSIONFORWARDER_H 1
+#ifndef PYTHON_SOCKETSESSIONFORWARDER_H
+#define PYTHON_SOCKETSESSIONFORWARDER_H 1
 
 #include <Python.h>
 
@@ -38,7 +38,7 @@ bool initModulePart_SocketSessionForwarder(PyObject* mod);
 } // namespace io
 } // namespace util
 } // namespace isc
-#endif // __PYTHON_SOCKETSESSIONFORWARDER_H
+#endif // PYTHON_SOCKETSESSIONFORWARDER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/python/isc/util/cio/socketsessionreceiver_python.h b/src/lib/python/isc/util/cio/socketsessionreceiver_python.h
index 14e8a1b..eb9a884 100644
--- a/src/lib/python/isc/util/cio/socketsessionreceiver_python.h
+++ b/src/lib/python/isc/util/cio/socketsessionreceiver_python.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_SOCKETSESSIONRECEIVER_H
-#define __PYTHON_SOCKETSESSIONRECEIVER_H 1
+#ifndef PYTHON_SOCKETSESSIONRECEIVER_H
+#define PYTHON_SOCKETSESSIONRECEIVER_H 1
 
 #include <Python.h>
 
@@ -39,7 +39,7 @@ bool initModulePart_SocketSessionReceiver(PyObject* mod);
 } // namespace python
 } // namespace util
 } // namespace isc
-#endif // __PYTHON_SOCKETSESSIONRECEIVER_H
+#endif // PYTHON_SOCKETSESSIONRECEIVER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index c5b280f..7eae6fe 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -122,8 +122,6 @@ deepestDelegation(Name name, RRClass rrclass,
     return (".");
 }
 
-typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
-
 // Here we do not use the typedef above, as the SunStudio compiler
 // mishandles this in its name mangling, and wouldn't compile.
 // We can probably use a typedef, but need to move it to a central
@@ -161,7 +159,6 @@ RecursiveQuery::setRttRecorder(boost::shared_ptr<RttRecorder>& recorder) {
 }
 
 namespace {
-
 typedef std::pair<std::string, uint16_t> addr_t;
 
 /*
@@ -171,7 +168,7 @@ typedef std::pair<std::string, uint16_t> addr_t;
  *
  * Used by RecursiveQuery::sendQuery.
  */
-class RunningQuery : public IOFetch::Callback {
+class RunningQuery : public IOFetch::Callback, public AbstractRunningQuery {
 
 class ResolverNSASCallback : public isc::nsas::AddressRequestCallback {
 public:
@@ -730,6 +727,8 @@ public:
         doLookup();
     }
 
+    virtual ~RunningQuery() {};
+
     // called if we have a lookup timeout; if our callback has
     // not been called, call it now. Then stop.
     void lookupTimeout() {
@@ -894,11 +893,13 @@ public:
     // Clear the answer parts of answer_message, and set the rcode
     // to servfail
     void makeSERVFAIL() {
-        isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
+        if (answer_message_) {
+            isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
+        }
     }
 };
 
-class ForwardQuery : public IOFetch::Callback {
+class ForwardQuery : public IOFetch::Callback, public AbstractRunningQuery {
 private:
     // The io service to handle async calls
     IOService& io_;
@@ -999,6 +1000,8 @@ public:
         send();
     }
 
+    virtual ~ForwardQuery() {};
+
     virtual void lookupTimeout() {
         if (!callback_called_) {
             makeSERVFAIL();
@@ -1076,7 +1079,7 @@ public:
 
 }
 
-void
+AbstractRunningQuery*
 RecursiveQuery::resolve(const QuestionPtr& question,
     const isc::resolve::ResolverInterface::CallbackPtr callback)
 {
@@ -1119,16 +1122,17 @@ RecursiveQuery::resolve(const QuestionPtr& question,
             // delete itself when it is done
             LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
                       .arg(questionText(*question)).arg(1);
-            new RunningQuery(io, *question, answer_message,
-                             test_server_, buffer, callback,
-                             query_timeout_, client_timeout_,
-                             lookup_timeout_, retries_, nsas_,
-                             cache_, rtt_recorder_);
+            return (new RunningQuery(io, *question, answer_message,
+                                     test_server_, buffer, callback,
+                                     query_timeout_, client_timeout_,
+                                     lookup_timeout_, retries_, nsas_,
+                                     cache_, rtt_recorder_));
         }
     }
+    return (NULL);
 }
 
-void
+AbstractRunningQuery*
 RecursiveQuery::resolve(const Question& question,
                         MessagePtr answer_message,
                         OutputBufferPtr buffer,
@@ -1181,15 +1185,16 @@ RecursiveQuery::resolve(const Question& question,
             // delete itself when it is done
             LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
                       .arg(questionText(question)).arg(2);
-            new RunningQuery(io, question, answer_message,
-                             test_server_, buffer, crs, query_timeout_,
-                             client_timeout_, lookup_timeout_, retries_,
-                             nsas_, cache_, rtt_recorder_);
+            return (new RunningQuery(io, question, answer_message,
+                                     test_server_, buffer, crs, query_timeout_,
+                                     client_timeout_, lookup_timeout_, retries_,
+                                     nsas_, cache_, rtt_recorder_));
         }
     }
+    return (NULL);
 }
 
-void
+AbstractRunningQuery*
 RecursiveQuery::forward(ConstMessagePtr query_message,
     MessagePtr answer_message,
     OutputBufferPtr buffer,
@@ -1215,9 +1220,9 @@ RecursiveQuery::forward(ConstMessagePtr query_message,
     // everything throught without interpretation, except
     // QID, port number. The response will not be cached.
     // It will delete itself when it is done
-    new ForwardQuery(io, query_message, answer_message,
-                      upstream_, buffer, callback, query_timeout_,
-                      client_timeout_, lookup_timeout_);
+    return (new ForwardQuery(io, query_message, answer_message,
+                             upstream_, buffer, callback, query_timeout_,
+                             client_timeout_, lookup_timeout_));
 }
 
 } // namespace asiodns
diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h
index a819a94..2875441 100644
--- a/src/lib/resolve/recursive_query.h
+++ b/src/lib/resolve/recursive_query.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RECURSIVE_QUERY_H
-#define __RECURSIVE_QUERY_H 1
+#ifndef RECURSIVE_QUERY_H
+#define RECURSIVE_QUERY_H 1
 
 #include <util/buffer.h>
 #include <asiodns/dns_service.h>
@@ -52,6 +52,26 @@ private:
     std::vector<uint32_t>   rtt_;   ///< Stored round-trip times
 };
 
+typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
+
+/// \brief A Running query
+///
+/// This base class represents an active running query object;
+/// i.e. an outstanding query to an authoritative name server or
+/// upstream server (when running in forwarder mode).
+///
+/// It can not be instantiated directly, but is created by
+/// RecursiveQuery::resolve() and RecursiveQuery::forward().
+///
+/// Its only public method is its destructor, and that should in theory
+/// not be called either except in some unit tests. Instances should
+/// delete themselves when the query is finished.
+class AbstractRunningQuery {
+protected:
+    AbstractRunningQuery() {};
+public:
+    virtual ~AbstractRunningQuery() {};
+};
 
 /// \brief Recursive Query
 ///
@@ -126,8 +146,8 @@ public:
     /// \param question The question being answered <qname/qclass/qtype>
     /// \param callback Callback object. See
     ///        \c ResolverInterface::Callback for more information
-    void resolve(const isc::dns::QuestionPtr& question,
-                 const isc::resolve::ResolverInterface::CallbackPtr callback);
+    AbstractRunningQuery* resolve(const isc::dns::QuestionPtr& question,
+        const isc::resolve::ResolverInterface::CallbackPtr callback);
 
 
     /// \brief Initiates resolving for the given question.
@@ -142,10 +162,17 @@ public:
     /// \param buffer An output buffer into which the intermediate responses will
     ///        be copied.
     /// \param server A pointer to the \c DNSServer object handling the client
-    void resolve(const isc::dns::Question& question,
-                 isc::dns::MessagePtr answer_message,
-                 isc::util::OutputBufferPtr buffer,
-                 DNSServer* server);
+    /// \return A pointer to the active AbstractRunningQuery object
+    ///         created by this call (if any); this object should delete
+    ///         itself in normal circumstances, and can normally be ignored
+    ///         by the caller, but a pointer is returned for use-cases
+    ///         such as unit tests.
+    ///         Returns NULL if the data was found internally and no actual
+    ///         query was sent.
+    AbstractRunningQuery* resolve(const isc::dns::Question& question,
+                          isc::dns::MessagePtr answer_message,
+                          isc::util::OutputBufferPtr buffer,
+                          DNSServer* server);
 
     /// \brief Initiates forwarding for the given query.
     ///
@@ -158,7 +185,11 @@ public:
     /// \param server Server object that handles receipt and processing of the
     ///               received messages.
     /// \param callback callback object
-    void forward(isc::dns::ConstMessagePtr query_message,
+    /// \return A pointer to the active ForwardQuery created by this call;
+    ///         this object should delete itself in normal circumstances,
+    ///         and can normally be ignored by the caller, but a pointer
+    ///         is returned for use-cases such as unit tests.
+    AbstractRunningQuery* forward(isc::dns::ConstMessagePtr query_message,
                  isc::dns::MessagePtr answer_message,
                  isc::util::OutputBufferPtr buffer,
                  DNSServer* server,
@@ -195,4 +226,4 @@ private:
 
 }      // namespace asiodns
 }      // namespace isc
-#endif // __RECURSIVE_QUERY_H
+#endif // RECURSIVE_QUERY_H
diff --git a/src/lib/resolve/resolve.h b/src/lib/resolve/resolve.h
index 0a588e2..c7ff195 100644
--- a/src/lib/resolve/resolve.h
+++ b/src/lib/resolve/resolve.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_RESOLVE_H
-#define _ISC_RESOLVE_H 1
+#ifndef ISC_RESOLVE_H
+#define ISC_RESOLVE_H 1
 
 /// This file includes all other libresolve headers, and provides
 /// several helper functions used in resolving.
diff --git a/src/lib/resolve/resolve_log.h b/src/lib/resolve/resolve_log.h
index 828b9d3..15a7a72 100644
--- a/src/lib/resolve/resolve_log.h
+++ b/src/lib/resolve/resolve_log.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RESOLVE_LOG__H
-#define __RESOLVE_LOG__H
+#ifndef RESOLVE_LOG_H
+#define RESOLVE_LOG_H
 
 #include <log/macros.h>
 #include "resolve_messages.h"
@@ -50,4 +50,4 @@ extern isc::log::Logger logger;
 } // namespace resolve
 } // namespace isc
 
-#endif // __RESOLVE_LOG__H
+#endif // RESOLVE_LOG_H
diff --git a/src/lib/resolve/resolver_callback.h b/src/lib/resolve/resolver_callback.h
index 79138e8..9a24501 100644
--- a/src/lib/resolve/resolver_callback.h
+++ b/src/lib/resolve/resolver_callback.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _ISC_RESOLVER_CALLBACK_H
-#define _ISC_RESOLVER_CALLBACK_H 1
+#ifndef ISC_RESOLVER_CALLBACK_H
+#define ISC_RESOLVER_CALLBACK_H 1
 
 #include <asiodns/dns_server.h>
 #include <dns/message.h>
diff --git a/src/lib/resolve/resolver_interface.h b/src/lib/resolve/resolver_interface.h
index 1d01e90..5002c80 100644
--- a/src/lib/resolve/resolver_interface.h
+++ b/src/lib/resolve/resolver_interface.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RESOLVER_INTERFACE_H
-#define __RESOLVER_INTERFACE_H
+#ifndef RESOLVER_INTERFACE_H
+#define RESOLVER_INTERFACE_H
 
 #include <dns/message.h>
 
@@ -95,4 +95,4 @@ class ResolverInterface {
 } // namespace nsas
 } // namespace isc
 
-#endif //__RESOLVER_INTERFACE_H
+#endif //RESOLVER_INTERFACE_H
diff --git a/src/lib/resolve/response_classifier.h b/src/lib/resolve/response_classifier.h
index a027bd0..ce99bf0 100644
--- a/src/lib/resolve/response_classifier.h
+++ b/src/lib/resolve/response_classifier.h
@@ -14,8 +14,8 @@
 
 // $Id$
 
-#ifndef __RESPONSE_CLASSIFIER_H
-#define __RESPONSE_CLASSIFIER_H
+#ifndef RESPONSE_CLASSIFIER_H
+#define RESPONSE_CLASSIFIER_H
 
 #include <cstddef>
 
@@ -154,4 +154,4 @@ private:
 } // namespace resolve
 } // namespace isc
 
-#endif // __RESPONSE_CLASSIFIER_H
+#endif // RESPONSE_CLASSIFIER_H
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index 4513458..e5e46e1 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -173,6 +173,9 @@ protected:
         // It would delete itself, but after the io_service_, which could
         // segfailt in case there were unhandled requests
         resolver_.reset();
+        // In a similar note, we wait until the resolver has been cleaned up
+        // until deleting and active test running_query_
+        delete running_query_;
     }
 
     void SetUp() {
@@ -507,11 +510,13 @@ protected:
     vector<uint8_t> callback_data_;
     ScopedSocket sock_;
     boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
+    AbstractRunningQuery* running_query_;
 };
 
 RecursiveQueryTest::RecursiveQueryTest() :
     dns_service_(NULL), callback_(NULL), callback_protocol_(0),
-    callback_native_(-1), resolver_(new isc::util::unittests::TestResolver())
+    callback_native_(-1), resolver_(new isc::util::unittests::TestResolver()),
+    running_query_(NULL)
 {
     nsas_.reset(new isc::nsas::NameserverAddressStore(resolver_));
 }
@@ -652,12 +657,12 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
                       singleAddress(TEST_IPV4_ADDR, port));
 
     Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
-    Message query_message(Message::RENDER);
-    isc::resolve::initResponseMessage(q, query_message);
+    MessagePtr query_message(new Message(Message::RENDER));
+    isc::resolve::initResponseMessage(q, *query_message);
 
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.forward(ConstMessagePtr(&query_message), answer, buffer, &server);
+    running_query_ = rq.forward(query_message, answer, buffer, &server);
 
     char data[4096];
     size_t size = sizeof(data);
@@ -749,11 +754,11 @@ TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    Message query_message(Message::RENDER);
-    isc::resolve::initResponseMessage(question, query_message);
+    MessagePtr query_message(new Message(Message::RENDER));
+    isc::resolve::initResponseMessage(question, *query_message);
 
     boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
-    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
+    running_query_ = query.forward(query_message, answer, buffer, &server, callback);
     // Run the test
     io_service_.run();
     EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
@@ -784,11 +789,11 @@ TEST_F(RecursiveQueryTest, forwardClientTimeout) {
                          1000, 10, 4000, 4);
     Question q(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    Message query_message(Message::RENDER);
-    isc::resolve::initResponseMessage(q, query_message);
+    MessagePtr query_message(new Message(Message::RENDER));
+    isc::resolve::initResponseMessage(q, *query_message);
 
     boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
-    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
+    running_query_ = query.forward(query_message, answer, buffer, &server, callback);
     // Run the test
     io_service_.run();
     EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
@@ -819,11 +824,12 @@ TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
 
-    Message query_message(Message::RENDER);
-    isc::resolve::initResponseMessage(question, query_message);
+    //Message query_message(Message::RENDER);
+    MessagePtr query_message(new Message(Message::RENDER));
+    isc::resolve::initResponseMessage(question, *query_message);
 
     boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
-    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
+    running_query_ = query.forward(query_message, answer, buffer, &server, callback);
     // Run the test
     io_service_.run();
     EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
@@ -854,11 +860,11 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
 
-    Message query_message(Message::RENDER);
-    isc::resolve::initResponseMessage(question, query_message);
+    MessagePtr query_message(new Message(Message::RENDER));
+    isc::resolve::initResponseMessage(question, *query_message);
 
     boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
-    query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
+    running_query_ = query.forward(query_message, answer, buffer, &server, callback);
     // Run the test
     io_service_.run();
     EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
@@ -882,7 +888,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
     Question q(Name("www.isc.org"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.resolve(q, answer, buffer, &server);
+    running_query_ = rq.resolve(q, answer, buffer, &server);
     io_service_.run();
 
     // Check that the answer we got matches the one we wanted
@@ -908,7 +914,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
     Question q(Name("wwwdoesnotexist.isc.org"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.resolve(q, answer, buffer, &server);
+    running_query_ = rq.resolve(q, answer, buffer, &server);
     io_service_.run();
 
     // Check that the answer we got matches the one we wanted
@@ -972,9 +978,9 @@ TEST_F(RecursiveQueryTest, CachedNS) {
     // Prepare the recursive query
     vector<pair<string, uint16_t> > roots;
     roots.push_back(pair<string, uint16_t>("192.0.2.2", 53));
-
+    vector<pair<string, uint16_t> > upstream;
     RecursiveQuery rq(*dns_service_, *nsas_, cache_,
-                      vector<pair<string, uint16_t> >(), roots);
+                      upstream, roots);
     // Ask a question at the bottom. It should not use the lower NS, because
     // it would lead to a loop in NS. But it can use the nsUpper one, it has
     // an IP address and we can avoid asking root.
@@ -984,7 +990,7 @@ TEST_F(RecursiveQueryTest, CachedNS) {
     MessagePtr answer(new Message(Message::RENDER));
     // The server is here so we have something to pass there
     MockServer server(io_service_);
-    rq.resolve(q, answer, buffer, &server);
+    running_query_ = rq.resolve(q, answer, buffer, &server);
     // We don't need to run the service in this test. We are interested only
     // in the place it starts resolving at
 
diff --git a/src/lib/resolve/tests/recursive_query_unittest_2.cc b/src/lib/resolve/tests/recursive_query_unittest_2.cc
index 6cb404d..0b38c59 100644
--- a/src/lib/resolve/tests/recursive_query_unittest_2.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest_2.cc
@@ -149,6 +149,12 @@ public:
     OutputBufferPtr udp_send_buffer_;           ///< Send buffer for UDP I/O
     udp::socket     udp_socket_;                ///< Socket used by UDP server
 
+    /// Some of the tests cause an 'active' running query to be created, but
+    /// don't complete the framework that makes that query delete itself.
+    /// This member can be used to store it so that it is deleted automatically
+    /// when the test is finished.
+    AbstractRunningQuery* running_query_;
+
     /// \brief Constructor
     RecursiveQueryTest2() :
         debug_(DEBUG_PRINT),
@@ -170,8 +176,18 @@ public:
         udp_length_(0),
         udp_receive_buffer_(),
         udp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
-        udp_socket_(service_.get_io_service(), udp::v4())
-    {
+        udp_socket_(service_.get_io_service(), udp::v4()),
+        running_query_(NULL)
+    {}
+
+    ~RecursiveQueryTest2() {
+        // It would delete itself, but after the io_service_, which could
+        // segfailt in case there were unhandled requests
+        resolver_.reset();
+        // In a similar note, we wait until the resolver has been cleaned up
+        // until deleting and active test running_query_
+        delete running_query_;
+        delete nsas_;
     }
 
     /// \brief Set Common Message Bits
@@ -686,7 +702,7 @@ TEST_F(RecursiveQueryTest2, Resolve) {
     // Kick off the resolution process.  We expect the first question to go to
     // "root".
     expected_ = UDP_ROOT;
-    query.resolve(question_, resolver_callback);
+    running_query_ = query.resolve(question_, resolver_callback);
     service_.run();
 
     // Check what ran. (We have to cast the callback to ResolverCallback as we
diff --git a/src/lib/resolve/tests/recursive_query_unittest_3.cc b/src/lib/resolve/tests/recursive_query_unittest_3.cc
index abfea9a..92ec589 100644
--- a/src/lib/resolve/tests/recursive_query_unittest_3.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest_3.cc
@@ -132,6 +132,12 @@ public:
     OutputBufferPtr udp_send_buffer_;           ///< Send buffer for UDP I/O
     udp::socket     udp_socket_;                ///< Socket used by UDP server
 
+    /// Some of the tests cause an 'active' running query to be created, but
+    /// don't complete the framework that makes that query delete itself.
+    /// This member can be used to store it so that it is deleted automatically
+    /// when the test is finished.
+    AbstractRunningQuery* running_query_;
+
     /// \brief Constructor
     RecursiveQueryTest3() :
         service_(),
@@ -154,10 +160,21 @@ public:
         udp_length_(0),
         udp_receive_buffer_(),
         udp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
-        udp_socket_(service_.get_io_service(), udp::v4())
+        udp_socket_(service_.get_io_service(), udp::v4()),
+        running_query_(NULL)
     {
     }
 
+    ~RecursiveQueryTest3() {
+        delete nsas_;
+        // It would delete itself, but after the io_service_, which could
+        // segfailt in case there were unhandled requests
+        resolver_.reset();
+        // In a similar note, we wait until the resolver has been cleaned up
+        // until deleting and active test running_query_
+        delete running_query_;
+    }
+
     /// \brief Set Common Message Bits
     ///
     /// Sets up the common bits of a response message returned by the handlers.
@@ -542,7 +559,7 @@ TEST_F(RecursiveQueryTest3, Resolve) {
 
     // Kick off the resolution process.
     expected_ = EDNS_UDP;
-    query.resolve(question_, resolver_callback);
+    running_query_ = query.resolve(question_, resolver_callback);
     service_.run();
 
     // Check what ran. (We have to cast the callback to ResolverCallback3 as we
diff --git a/src/lib/server_common/client.h b/src/lib/server_common/client.h
index 8cafb1e..912e7a6 100644
--- a/src/lib/server_common/client.h
+++ b/src/lib/server_common/client.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __CLIENT_H
-#define __CLIENT_H 1
+#ifndef CLIENT_H
+#define CLIENT_H 1
 
 #include <string>
 #include <ostream>
@@ -147,7 +147,7 @@ std::ostream& operator<<(std::ostream& os, const Client& client);
 }
 }
 
-#endif  // __CLIENT_H
+#endif  // CLIENT_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/server_common/logger.h b/src/lib/server_common/logger.h
index 80bc81d..5d565bf 100644
--- a/src/lib/server_common/logger.h
+++ b/src/lib/server_common/logger.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SERVER_COMMON_LOGGER_H
-#define __SERVER_COMMON_LOGGER_H
+#ifndef SERVER_COMMON_LOGGER_H
+#define SERVER_COMMON_LOGGER_H
 
 #include <log/macros.h>
 #include <server_common/server_common_messages.h>
diff --git a/src/lib/server_common/socket_request.h b/src/lib/server_common/socket_request.h
index aac95d1..b532153 100644
--- a/src/lib/server_common/socket_request.h
+++ b/src/lib/server_common/socket_request.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SOCKET_REQUEST_H
-#define __SOCKET_REQUEST_H 1
+#ifndef SOCKET_REQUEST_H
+#define SOCKET_REQUEST_H 1
 
 #include <exceptions/exceptions.h>
 
@@ -275,4 +275,4 @@ void cleanupSocketRequestor();
 }
 }
 
-#endif  // __SOCKET_REQUEST_H
+#endif  // SOCKET_REQUEST_H
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
index ac880c0..0c971ee 100644
--- a/src/lib/server_common/tests/portconfig_unittest.cc
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -18,6 +18,7 @@
 #include <testutils/socket_request.h>
 #include <testutils/mockups.h>
 
+#include <util/unittests/check_valgrind.h>
 #include <util/unittests/resource.h>
 
 #include <cc/data.h>
@@ -311,44 +312,48 @@ typedef InstallListenAddresses InstallListenAddressesDeathTest;
 // We make the socket requestor throw a "fatal" exception, one where we can't be
 // sure the state between processes is consistent. So we abort in that case.
 TEST_F(InstallListenAddressesDeathTest, inconsistent) {
-    AddressList deathAddresses;
-    deathAddresses.push_back(AddressPair("192.0.2.3", 5288));
-    // Make sure it actually kills the application (there should be an abort
-    // in this case)
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
+    if (!isc::util::unittests::runningOnValgrind()) {
+        AddressList deathAddresses;
+        deathAddresses.push_back(AddressPair("192.0.2.3", 5288));
+        // Make sure it actually kills the application (there should be an abort
+        // in this case)
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
 
-        try {
-          installListenAddresses(deathAddresses, store_, dnss_);
-        } catch (...) {
-          // Prevent exceptions killing the application, we need
-          // to make sure it dies the real hard way
-        };
-      }, "");
+            try {
+              installListenAddresses(deathAddresses, store_, dnss_);
+            } catch (...) {
+              // Prevent exceptions killing the application, we need
+              // to make sure it dies the real hard way
+            };
+          }, "");
+    }
 }
 
 // If we are unable to tell the boss we closed a socket, we abort, as we are
 // not consistent with the boss most probably.
 TEST_F(InstallListenAddressesDeathTest, cantClose) {
-    installListenAddresses(valid_, store_, dnss_);
-    AddressList empty;
-    // Instruct it to fail on close
-    sock_requestor_.break_release_ = true;
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
+    if (!isc::util::unittests::runningOnValgrind()) {
+        installListenAddresses(valid_, store_, dnss_);
+        AddressList empty;
+        // Instruct it to fail on close
+        sock_requestor_.break_release_ = true;
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
 
-        try {
-          // Setting to empty will close all current sockets.
-          // And thanks to the break_release_, the close will
-          // throw, which will make it crash.
-          installListenAddresses(empty, store_, dnss_);
-        } catch (...) {
-          // To make sure it is killed by abort, not by some
-          // (unhandled) exception
-        };
-      }, "");
-    // And reset it back, so it can safely clean up itself.
-    sock_requestor_.break_release_ = false;
+            try {
+              // Setting to empty will close all current sockets.
+              // And thanks to the break_release_, the close will
+              // throw, which will make it crash.
+              installListenAddresses(empty, store_, dnss_);
+            } catch (...) {
+              // To make sure it is killed by abort, not by some
+              // (unhandled) exception
+            };
+          }, "");
+        // And reset it back, so it can safely clean up itself.
+        sock_requestor_.break_release_ = false;
+    }
 }
 #endif // EXPECT_DEATH
 
diff --git a/src/lib/statistics/Makefile.am b/src/lib/statistics/Makefile.am
index 206b527..a395bf5 100644
--- a/src/lib/statistics/Makefile.am
+++ b/src/lib/statistics/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
@@ -17,8 +17,9 @@ if USE_CLANGPP
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 
-lib_LTLIBRARIES = libb10-statistics.la
-libb10_statistics_la_SOURCES  = counter.h counter.cc
-libb10_statistics_la_SOURCES  += counter_dict.h counter_dict.cc
-
 CLEANFILES = *.gcno *.gcda
+
+# These are header-only shared classes and required to build BIND 10.
+# Include them in the distributed tarball with EXTRA_DIST (like as
+# external sources in ext/).
+EXTRA_DIST = counter.h counter_dict.h
diff --git a/src/lib/statistics/counter.cc b/src/lib/statistics/counter.cc
deleted file mode 100644
index 53dc58e..0000000
--- a/src/lib/statistics/counter.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <vector>
-
-#include <boost/noncopyable.hpp>
-
-#include <statistics/counter.h>
-
-namespace {
-const unsigned int InitialValue = 0;
-} // namespace
-
-namespace isc {
-namespace statistics {
-
-class CounterImpl : boost::noncopyable {
-    private:
-        std::vector<Counter::Value> counters_;
-    public:
-        CounterImpl(const size_t nelements);
-        ~CounterImpl();
-        void inc(const Counter::Type&);
-        const Counter::Value& get(const Counter::Type&) const;
-};
-
-CounterImpl::CounterImpl(const size_t items) :
-    counters_(items, InitialValue)
-{
-    if (items == 0) {
-        isc_throw(isc::InvalidParameter, "Items must not be 0");
-    }
-}
-
-CounterImpl::~CounterImpl() {}
-
-void
-CounterImpl::inc(const Counter::Type& type) {
-    if(type >= counters_.size()) {
-        isc_throw(isc::OutOfRange, "Counter type is out of range");
-    }
-    ++counters_.at(type);
-    return;
-}
-
-const Counter::Value&
-CounterImpl::get(const Counter::Type& type) const {
-    if(type >= counters_.size()) {
-        isc_throw(isc::OutOfRange, "Counter type is out of range");
-    }
-    return (counters_.at(type));
-}
-
-Counter::Counter(const size_t items) : impl_(new CounterImpl(items))
-{}
-
-Counter::~Counter() {}
-
-void
-Counter::inc(const Type& type) {
-    impl_->inc(type);
-    return;
-}
-
-const Counter::Value&
-Counter::get(const Type& type) const {
-    return (impl_->get(type));
-}
-
-}   // namespace statistics
-}   // namespace isc
diff --git a/src/lib/statistics/counter.h b/src/lib/statistics/counter.h
index 9e467ce..af52da4 100644
--- a/src/lib/statistics/counter.h
+++ b/src/lib/statistics/counter.h
@@ -12,27 +12,32 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COUNTER_H
-#define __COUNTER_H 1
+#ifndef COUNTER_H
+#define COUNTER_H 1
+
+#include <exceptions/exceptions.h>
 
 #include <boost/noncopyable.hpp>
 #include <boost/scoped_ptr.hpp>
 
-#include <exceptions/exceptions.h>
+#include <vector>
+
+namespace {
+const unsigned int InitialValue = 0;
+} // anonymous namespace
 
 namespace isc {
 namespace statistics {
 
-// forward declaration for pImpl idiom
-class CounterImpl;
-
 class Counter : boost::noncopyable {
-private:
-    boost::scoped_ptr<CounterImpl> impl_;
 public:
     typedef unsigned int Type;
     typedef unsigned int Value;
 
+private:
+    std::vector<Counter::Value> counters_;
+
+public:
     /// The constructor.
     ///
     /// This constructor is mostly exception free. But it may still throw
@@ -41,29 +46,46 @@ public:
     /// \param items A number of counter items to hold (greater than 0)
     ///
     /// \throw isc::InvalidParameter \a items is 0
-    Counter(const size_t items);
+    explicit Counter(const size_t items) :
+        counters_(items, InitialValue)
+    {
+        if (items == 0) {
+            isc_throw(isc::InvalidParameter, "Items must not be 0");
+        }
+    };
 
     /// The destructor.
     ///
     /// This method never throws an exception.
-    ~Counter();
+    ~Counter() {};
 
     /// \brief Increment a counter item specified with \a type.
     ///
     /// \param type %Counter item to increment
     ///
     /// \throw isc::OutOfRange \a type is invalid
-    void inc(const Type& type);
+    void inc(const Counter::Type type) {
+        if (type >= counters_.size()) {
+            isc_throw(isc::OutOfRange, "Counter type is out of range");
+        }
+        ++counters_.at(type);
+        return;
+    };
 
     /// \brief Get the value of a counter item specified with \a type.
     ///
     /// \param type %Counter item to get the value of
     ///
     /// \throw isc::OutOfRange \a type is invalid
-    const Value& get(const Type& type) const;
+    const Counter::Value& get(const Counter::Type type) const {
+        if (type >= counters_.size()) {
+            isc_throw(isc::OutOfRange, "Counter type is out of range");
+        }
+        return (counters_.at(type));
+    };
 };
 
 }   // namespace statistics
 }   // namespace isc
 
-#endif
+#endif // __COUNTER_H
diff --git a/src/lib/statistics/counter_dict.cc b/src/lib/statistics/counter_dict.cc
deleted file mode 100644
index 55353b2..0000000
--- a/src/lib/statistics/counter_dict.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <cassert>
-#include <stdexcept>
-#include <iterator>
-#include <map>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <statistics/counter_dict.h>
-
-namespace {
-typedef boost::shared_ptr<isc::statistics::Counter> CounterPtr;
-typedef std::map<std::string, CounterPtr> DictionaryMap;
-}
-
-namespace isc {
-namespace statistics {
-
-// Implementation detail class for CounterDictionary::ConstIterator
-class CounterDictionaryConstIteratorImpl;
-
-class CounterDictionaryImpl : boost::noncopyable {
-private:
-    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.
-    CounterDictionaryImpl();
-public:
-    CounterDictionaryImpl(const size_t items);
-    ~CounterDictionaryImpl();
-    void addElement(const std::string& name);
-    void deleteElement(const std::string& name);
-    Counter& getElement(const std::string& name);
-public:
-    CounterDictionaryConstIteratorImpl begin() const;
-    CounterDictionaryConstIteratorImpl end() const;
-};
-
-// Constructor with number of items
-CounterDictionaryImpl::CounterDictionaryImpl(const size_t items) :
-    items_(items)
-{
-    // The number of items must not be 0
-    if (items == 0) {
-        isc_throw(isc::InvalidParameter, "Items must not be 0");
-    }
-}
-
-// Destructor
-CounterDictionaryImpl::~CounterDictionaryImpl() {}
-
-void
-CounterDictionaryImpl::addElement(const std::string& name) {
-    // throw if the element already exists
-    if (dictionary_.count(name) != 0) {
-        isc_throw(isc::InvalidParameter,
-                  "Element " << name << " already exists");
-    }
-    assert(items_ != 0);
-    // Create a new Counter and add to the map
-    dictionary_.insert(
-        DictionaryMap::value_type(name, CounterPtr(new Counter(items_))));
-}
-
-void
-CounterDictionaryImpl::deleteElement(const std::string& name) {
-    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");
-    }
-}
-
-Counter&
-CounterDictionaryImpl::getElement(const std::string& name) {
-    DictionaryMap::const_iterator i = dictionary_.find(name);
-    if (i != dictionary_.end()) {
-        // the key was found. return the element.
-        return (*(i->second));
-    } else {
-        // If an element with specified name does not exist, throw
-        // isc::OutOfRange.
-        isc_throw(isc::OutOfRange, "Element " << name << " does not exist");
-    }
-}
-
-// Constructor
-// Initialize impl_
-CounterDictionary::CounterDictionary(const size_t items) :
-    impl_(new CounterDictionaryImpl(items))
-{}
-
-// Destructor
-// impl_ will be freed automatically with scoped_ptr
-CounterDictionary::~CounterDictionary() {}
-
-void
-CounterDictionary::addElement(const std::string& name) {
-    impl_->addElement(name);
-}
-
-void
-CounterDictionary::deleteElement(const std::string& name) {
-    impl_->deleteElement(name);
-}
-
-Counter&
-CounterDictionary::getElement(const std::string& name) const {
-    return (impl_->getElement(name));
-}
-
-Counter&
-CounterDictionary::operator[](const std::string& name) const {
-    return (impl_->getElement(name));
-}
-
-// Implementation detail class for CounterDictionary::ConstIterator
-class CounterDictionaryConstIteratorImpl {
-    public:
-        CounterDictionaryConstIteratorImpl();
-        ~CounterDictionaryConstIteratorImpl();
-        CounterDictionaryConstIteratorImpl(
-            const CounterDictionaryConstIteratorImpl &other);
-        CounterDictionaryConstIteratorImpl &operator=(
-            const CounterDictionaryConstIteratorImpl &source);
-        CounterDictionaryConstIteratorImpl(
-            DictionaryMap::const_iterator iterator);
-    public:
-        void increment();
-        const CounterDictionary::ConstIterator::value_type&
-            dereference() const;
-        bool equal(const CounterDictionaryConstIteratorImpl& other) const;
-    private:
-        DictionaryMap::const_iterator iterator_;
-};
-
-CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl() {}
-
-CounterDictionaryConstIteratorImpl::~CounterDictionaryConstIteratorImpl() {}
-
-// Copy constructor: deep copy of iterator_
-CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
-    const CounterDictionaryConstIteratorImpl &other) :
-    iterator_(other.iterator_)
-{}
-
-// Assignment operator: deep copy of iterator_
-CounterDictionaryConstIteratorImpl &
-CounterDictionaryConstIteratorImpl::operator=(
-    const CounterDictionaryConstIteratorImpl &source)
-{
-    iterator_ = source.iterator_;
-    return (*this);
-}
-
-// Constructor from implementation detail DictionaryMap::const_iterator
-CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
-    DictionaryMap::const_iterator iterator) :
-    iterator_(iterator)
-{}
-
-CounterDictionaryConstIteratorImpl
-CounterDictionaryImpl::begin() const {
-    return (CounterDictionaryConstIteratorImpl(dictionary_.begin()));
-}
-
-CounterDictionaryConstIteratorImpl
-CounterDictionaryImpl::end() const {
-    return (CounterDictionaryConstIteratorImpl(dictionary_.end()));
-}
-
-void
-CounterDictionaryConstIteratorImpl::increment() {
-    ++iterator_;
-    return;
-}
-
-const CounterDictionary::ConstIterator::value_type&
-CounterDictionaryConstIteratorImpl::dereference() const {
-    return (iterator_->first);
-}
-
-bool
-CounterDictionaryConstIteratorImpl::equal(
-    const CounterDictionaryConstIteratorImpl& other) const
-{
-    return (iterator_ == other.iterator_);
-}
-
-CounterDictionary::ConstIterator
-CounterDictionary::begin() const {
-    return (CounterDictionary::ConstIterator(
-               CounterDictionaryConstIteratorImpl(impl_->begin())));
-}
-
-CounterDictionary::ConstIterator
-CounterDictionary::end() const {
-    return (CounterDictionary::ConstIterator(
-               CounterDictionaryConstIteratorImpl(impl_->end())));
-}
-
-CounterDictionary::ConstIterator::ConstIterator() :
-    impl_(new CounterDictionaryConstIteratorImpl())
-{}
-
-CounterDictionary::ConstIterator::~ConstIterator() {}
-
-// Copy constructor: deep copy of impl_
-CounterDictionary::ConstIterator::ConstIterator(
-    const CounterDictionary::ConstIterator& source) :
-    impl_(new CounterDictionaryConstIteratorImpl(*(source.impl_)))
-{}
-
-// Assignment operator: deep copy of impl_
-CounterDictionary::ConstIterator &
-CounterDictionary::ConstIterator::operator=(
-    const CounterDictionary::ConstIterator &source)
-{
-    *impl_ = *source.impl_;
-    return (*this);
-}
-
-// The constructor from implementation detail
-CounterDictionary::ConstIterator::ConstIterator(
-    const CounterDictionaryConstIteratorImpl& source) :
-    impl_(new CounterDictionaryConstIteratorImpl(source))
-{}
-
-const CounterDictionary::ConstIterator::value_type&
-CounterDictionary::ConstIterator::dereference() const
-{
-    return (impl_->dereference());
-}
-
-bool
-CounterDictionary::ConstIterator::equal(
-    CounterDictionary::ConstIterator const& other) const
-{
-    return (impl_->equal(*(other.impl_)));
-}
-
-void
-CounterDictionary::ConstIterator::increment() {
-    impl_->increment();
-    return;
-}
-
-}   // namespace statistics
-}   // namespace isc
diff --git a/src/lib/statistics/counter_dict.h b/src/lib/statistics/counter_dict.h
index e322119..e288dfe 100644
--- a/src/lib/statistics/counter_dict.h
+++ b/src/lib/statistics/counter_dict.h
@@ -12,70 +12,86 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COUNTER_DICT_H
-#define __COUNTER_DICT_H 1
+#ifndef COUNTER_DICT_H
+#define COUNTER_DICT_H 1
+
+#include <statistics/counter.h>
+#include <exceptions/exceptions.h>
 
-#include <string>
-#include <vector>
-#include <utility>
 #include <boost/noncopyable.hpp>
 #include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
 #include <boost/iterator/iterator_facade.hpp>
 
-#include <exceptions/exceptions.h>
-#include <statistics/counter.h>
+#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 CounterDictionaryImpl;
-class CounterDictionaryConstIteratorImpl;
-
 class CounterDictionary : boost::noncopyable {
 private:
-    boost::scoped_ptr<CounterDictionaryImpl> impl_;
+    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 is mostly exception free. But it may still throw
-    /// a standard exception if memory allocation fails inside the method.
-    ///
-    /// \param items A number of counter items to hold (greater than 0)
-    ///
-    /// \throw isc::InvalidParameter \a items is 0
-    CounterDictionary(const size_t items);
-
-    /// The destructor.
-    ///
-    /// This method never throws an exception.
-    ~CounterDictionary();
-
-    /// \brief Add an element
-    ///
-    /// \throw isc::InvalidParameter \a element already exists.
-    ///
-    /// \param name A name of the element to append
-    void addElement(const std::string& name);
-
-    /// \brief Delete
-    ///
-    /// \throw isc::OutOfRange \a element does not exist.
-    ///
-    /// \param name A name of the element to delete
-    void deleteElement(const std::string& name);
-
-    /// \brief Lookup
-    ///
-    /// \throw isc::OutOfRange \a element does not exist.
-    ///
-    /// \param name A name of the element to get the counters
-    Counter& getElement(const std::string &name) const;
-
-    /// Same as getElement()
-    Counter& operator[](const std::string &name) const;
-
+    explicit CounterDictionary(const size_t items) :
+        items_(items)
+    {
+        // The number of items must not be 0
+        if (items == 0) {
+            isc_throw(isc::InvalidParameter, "Items must not be 0");
+        }
+    };
+    ~CounterDictionary() {};
+    void addElement(const std::string& name) {
+        // throw if the element already exists
+        if (dictionary_.count(name) != 0) {
+            isc_throw(isc::InvalidParameter,
+                      "Element " << name << " already exists");
+        }
+        assert(items_ != 0);
+        // Create a new Counter and add to the map
+        dictionary_.insert(
+            DictionaryMap::value_type(name, CounterPtr(new Counter(items_))));
+    };
+    void deleteElement(const std::string& name) {
+        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");
+        }
+    };
+    Counter& getElement(const std::string& name) {
+        DictionaryMap::const_iterator i = dictionary_.find(name);
+        if (i != dictionary_.end()) {
+            // the key was found. return the element.
+            return (*(i->second));
+        } else {
+            // If an element with specified name does not exist, throw
+            // isc::OutOfRange.
+            isc_throw(isc::OutOfRange,
+                      "Element " << name << " does not exist");
+        }
+    };
+    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.
     ///
@@ -90,67 +106,53 @@ public:
                                 const std::string,
                                 boost::forward_traversal_tag>
     {
-        private:
-            boost::scoped_ptr<CounterDictionaryConstIteratorImpl> impl_;
         public:
             /// The constructor.
             ///
             /// This constructor is mostly exception free. But it may still
             /// throw a standard exception if memory allocation fails
             /// inside the method.
-            ConstIterator();
+            ConstIterator() {}
             /// The destructor.
             ///
             /// This method never throws an exception.
-            ~ConstIterator();
-            /// The assignment operator.
-            ///
-            /// This method is mostly exception free. But it may still
-            /// throw a standard exception if memory allocation fails
-            /// inside the method.
-            ConstIterator& operator=(const ConstIterator &source);
-            /// The copy constructor.
-            ///
-            /// This constructor is mostly exception free. But it may still
-            /// throw a standard exception if memory allocation fails
-            /// inside the method.
-            ConstIterator(const ConstIterator& source);
-            /// The constructor from implementation detail.
-            ///
-            /// This method is used to create an instance of ConstIterator
-            /// by CounterDict::begin() and CounterDict::end().
-            ///
-            /// This constructor is mostly exception free. But it may still
-            /// throw a standard exception if memory allocation fails
-            /// inside the method.
+            ~ConstIterator() {}
+            /// Constructor from implementation detail DictionaryMap::const_iterator
             ConstIterator(
-                const CounterDictionaryConstIteratorImpl& source);
+                DictionaryMap::const_iterator iterator) :
+                iterator_(iterator)
+            {}
+
         private:
             /// \brief An internal method to increment this iterator.
-            void increment();
+            void increment() {
+                ++iterator_;
+                return;
+            }
+
             /// \brief An internal method to check equality.
-            bool equal(const ConstIterator& other) const;
+            bool equal(const ConstIterator& other) const {
+                return (iterator_ == other.iterator_);
+            }
+
             /// \brief An internal method to dereference this iterator.
-            const value_type& dereference() const;
+            const value_type& dereference() const {
+                return (iterator_->first);
+            }
+
         private:
             friend class boost::iterator_core_access;
+            DictionaryMap::const_iterator iterator_;
     };
 
-    typedef ConstIterator const_iterator;
-
-    /// \brief Return an iterator corresponding to the beginning of the
-    /// elements stored in CounterDictionary.
-    ///
-    /// This method is mostly exception free. But it may still throw a
-    /// standard exception if memory allocation fails inside the method.
-    const_iterator begin() const;
+    ConstIterator begin() const {
+        return (CounterDictionary::ConstIterator(dictionary_.begin()));
+    };
+    ConstIterator end() const {
+        return (CounterDictionary::ConstIterator(dictionary_.end()));
+    };
 
-    /// \brief Return an iterator corresponding to the end of the elements
-    /// stored in CounterDictionary.
-    ///
-    /// This method is mostly exception free. But it may still throw a
-    /// standard exception if memory allocation fails inside the method.
-    const_iterator end() const;
+    typedef ConstIterator const_iterator;
 };
 
 }   // namespace statistics
diff --git a/src/lib/statistics/tests/Makefile.am b/src/lib/statistics/tests/Makefile.am
index 007c8b0..25a3db2 100644
--- a/src/lib/statistics/tests/Makefile.am
+++ b/src/lib/statistics/tests/Makefile.am
@@ -28,7 +28,6 @@ run_unittests_SOURCES += counter_dict_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
 run_unittests_LDADD  = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
diff --git a/src/lib/testutils/dnsmessage_test.h b/src/lib/testutils/dnsmessage_test.h
index fd1d51a..262d177 100644
--- a/src/lib/testutils/dnsmessage_test.h
+++ b/src/lib/testutils/dnsmessage_test.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ISC_TESTUTILS_DNSMESSAGETEST_H
-#define __ISC_TESTUTILS_DNSMESSAGETEST_H 1
+#ifndef ISC_TESTUTILS_DNSMESSAGETEST_H
+#define ISC_TESTUTILS_DNSMESSAGETEST_H 1
 
 #include <algorithm>
 #include <functional>
@@ -160,22 +160,6 @@ public:
 private:
     std::vector<isc::dns::ConstRRsetPtr>& rrsets_;
 };
-
-class RRsetDumper {
-public:
-    RRsetDumper(std::string& output) :
-        output_(output)
-    {}
-    void operator()(isc::dns::ConstRRsetPtr rrset) {
-        output_ += "  " + rrset->toText();
-
-        if (rrset->getRRsig()) {
-            output_ += "  " + rrset->getRRsig()->toText();
-        }
-    }
-private:
-    std::string& output_;
-};
 }
 
 /// \brief A converter from a string to RRset.
@@ -201,6 +185,37 @@ isc::dns::RRsetPtr textToRRset(const std::string& text_rrset,
                                const isc::dns::Name& origin =
                                isc::dns::Name::ROOT_NAME());
 
+/// \brief Pull out signatures and convert to text
+///
+/// This is a helper function for rrsetsCheck.
+///
+/// It adds all the rrsets to the given vector. It also adds the
+/// signatures of those rrsets as separate rrsets into the vector
+/// (but does not modify the original rrset; i.e. technically the
+/// signatures are in the resulting vector twice).
+///
+/// Additionally, it adds the string representation of all rrsets
+/// and their signatures to the given string (for use in scoped_trace).
+///
+/// \param rrsets A vector to add the rrsets and signatures to
+/// \param text A string to add the rrsets string representations to
+/// \param begin The beginning of the rrsets iterator
+/// \param end The end of the rrsets iterator
+template <typename ITERATOR>
+void
+pullSigs(std::vector<isc::dns::ConstRRsetPtr>& rrsets,
+         std::string& text, ITERATOR begin, ITERATOR end)
+{
+    for (ITERATOR it = begin; it != end; ++it) {
+        rrsets.push_back(*it);
+        text += (*it)->toText();
+        if ((*it)->getRRsig()) {
+            rrsets.push_back((*it)->getRRsig());
+            text += (*it)->getRRsig()->toText();
+        }
+    }
+}
+
 /// Set of unit tests to check if two sets of RRsets are identical.
 ///
 /// This templated function takes two sets of sequences, each defined by
@@ -236,55 +251,50 @@ void
 rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
             ACTUAL_ITERATOR actual_begin, ACTUAL_ITERATOR actual_end)
 {
-    std::vector<isc::dns::ConstRRsetPtr> checked_rrsets; // for duplicate check
+    // Iterators can have their RRsig sets as separate RRsets,
+    // or they can have them attached to the RRset they cover.
+    // For ease of use of this method, we first flatten out both
+    // iterators, and pull out the signature sets, and add them as
+    // separate RRsets (rrsetCheck() later does not check signatures
+    // attached to rrsets)
+    std::vector<isc::dns::ConstRRsetPtr> expected_rrsets, actual_rrsets;
     std::string expected_text, actual_text;
-    std::for_each(expected_begin, expected_end,
-                  detail::RRsetDumper(expected_text));
-    std::for_each(actual_begin, actual_end, detail::RRsetDumper(actual_text));
-    unsigned int rrset_matched = 0;
-    ACTUAL_ITERATOR it;
-    for (it = actual_begin; it != actual_end; ++it) {
+
+    pullSigs(expected_rrsets, expected_text, expected_begin, expected_end);
+    pullSigs(actual_rrsets, actual_text, actual_begin, actual_end);
+
+    SCOPED_TRACE(std::string("Comparing two RRset lists:\n") +
+                 "Actual:\n" + actual_text +
+                 "Expected:\n" + expected_text);
+
+    // The vectors should have the same number of sets
+    ASSERT_EQ(expected_rrsets.size(), actual_rrsets.size());
+
+    // Now we check if all RRsets from the actual_rrsets are in
+    // expected_rrsets, and that actual_rrsets has no duplicates.
+    std::vector<isc::dns::ConstRRsetPtr> checked_rrsets; // for duplicate check
+
+    std::vector<isc::dns::ConstRRsetPtr>::const_iterator it;
+    for (it = actual_rrsets.begin(); it != actual_rrsets.end(); ++it) {
         // Make sure there's no duplicate RRset in actual (using a naive
-        // search).  Since the actual set is guaranteed to be unique, we can
-        // detect it if the expected data has a duplicate by the match/size
-        // checks at the end of the function.
+        // search).  By guaranteeing the actual set is unique, and the
+        // size of both vectors is the same, we can conclude that
+        // the two sets are identical after this loop.
         // Note: we cannot use EXPECT_EQ for iterators
         EXPECT_TRUE(checked_rrsets.end() ==
                     std::find_if(checked_rrsets.begin(), checked_rrsets.end(),
                                  detail::RRsetMatch(*it)));
         checked_rrsets.push_back(*it);
 
-        EXPECTED_ITERATOR found_rrset_it =
-            std::find_if(expected_begin, expected_end,
+        std::vector<isc::dns::ConstRRsetPtr>::const_iterator found_rrset_it =
+            std::find_if(expected_rrsets.begin(), expected_rrsets.end(),
                          detail::RRsetMatch(*it));
-        if (found_rrset_it != expected_end) {
+        if (found_rrset_it != expected_rrsets.end()) {
             rrsetCheck(*found_rrset_it, *it);
-            ++rrset_matched;
-            rrset_matched += (*it)->getRRsigDataCount();
+        } else {
+            FAIL() << (*it)->toText() << " not found in expected rrsets";
         }
     }
-
-    {
-        SCOPED_TRACE(std::string("Comparing two RRsets:\n") +
-                     "Actual:\n" + actual_text +
-                     "Expected:\n" + expected_text);
-        // make sure all expected RRsets are in actual sets
-        EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
-
-#if (0)
-        // TODO: see bug #2223. The following code was
-        // disabled by #2165. The RRSIG RRsets are no longer directly
-        // stored in the Message's rrsets, so the iterator will not find
-        // them. The expected text used in many tests are flattened,
-        // where the RRSIGs are inline. In other words, RRSIGs may occur
-        // between (expected_begin, expected_end) but not between
-        // (actual_begin, actual_end).
-
-        // make sure rrsets only contains expected RRsets
-        EXPECT_EQ(std::distance(expected_begin, expected_end),
-                  std::distance(actual_begin, actual_end));
-#endif
-    }
 }
 
 /// Set of unit tests to check if two sets of RRsets are identical using
@@ -381,7 +391,7 @@ rrsetsCheck(const std::string& expected,
 
 } // end of namespace testutils
 } // end of namespace isc
-#endif  // __ISC_TESTUTILS_DNSMESSAGETEST_H
+#endif  // ISC_TESTUTILS_DNSMESSAGETEST_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h
index 3028d7f..fc8a2e0 100644
--- a/src/lib/testutils/mockups.h
+++ b/src/lib/testutils/mockups.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ISC_TESTUTILS_MOCKUPS_H
-#define __ISC_TESTUTILS_MOCKUPS_H 1
+#ifndef ISC_TESTUTILS_MOCKUPS_H
+#define ISC_TESTUTILS_MOCKUPS_H 1
 
 #include <config.h>
 
@@ -210,7 +210,7 @@ private:
 
 } // end of testutils
 } // end of isc
-#endif  // __ISC_TESTUTILS_MOCKUPS_H
+#endif  // ISC_TESTUTILS_MOCKUPS_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/testutils/portconfig.h b/src/lib/testutils/portconfig.h
index ce1bb39..8e8cab1 100644
--- a/src/lib/testutils/portconfig.h
+++ b/src/lib/testutils/portconfig.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ISC_TESTUTILS_PORTCONFIG_H
-#define __ISC_TESTUTILS_PORTCONFIG_H
+#ifndef ISC_TESTUTILS_PORTCONFIG_H
+#define ISC_TESTUTILS_PORTCONFIG_H
 
 #include <gtest/gtest.h>
 #include <cc/data.h>
@@ -186,4 +186,4 @@ invalidListenAddressConfig(Server& server) {
 }
 }
 
-#endif  // __ISC_TESTUTILS_PORTCONFIG_H
+#endif  // ISC_TESTUTILS_PORTCONFIG_H
diff --git a/src/lib/testutils/socket_request.h b/src/lib/testutils/socket_request.h
index 0ae15f3..d511401 100644
--- a/src/lib/testutils/socket_request.h
+++ b/src/lib/testutils/socket_request.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ISC_TESTUTILS_SOCKETREQUEST_H
-#define __ISC_TESTUTILS_SOCKETREQUEST_H 1
+#ifndef ISC_TESTUTILS_SOCKETREQUEST_H
+#define ISC_TESTUTILS_SOCKETREQUEST_H 1
 
 #include <server_common/socket_request.h>
 #include <server_common/portconfig.h>
@@ -216,4 +216,4 @@ private:
 
 }
 }
-#endif  // __ISC_TESTUTILS_SOCKETREQUEST_H
+#endif  // ISC_TESTUTILS_SOCKETREQUEST_H
diff --git a/src/lib/testutils/srv_test.h b/src/lib/testutils/srv_test.h
index a5c516e..e867595 100644
--- a/src/lib/testutils/srv_test.h
+++ b/src/lib/testutils/srv_test.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __ISC_TESTUTILS_SRVTEST_H
-#define __ISC_TESTUTILS_SRVTEST_H 1
+#ifndef ISC_TESTUTILS_SRVTEST_H
+#define ISC_TESTUTILS_SRVTEST_H 1
 
 #include <util/buffer.h>
 #include <dns/name.h>
@@ -112,7 +112,7 @@ protected:
 };
 } // end of namespace testutils
 } // end of namespace isc
-#endif  // __ISC_TESTUTILS_SRVTEST_H
+#endif  // ISC_TESTUTILS_SRVTEST_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/util/buffer.h b/src/lib/util/buffer.h
index 7e88108..4800e99 100644
--- a/src/lib/util/buffer.h
+++ b/src/lib/util/buffer.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __BUFFER_H
-#define __BUFFER_H 1
+#ifndef BUFFER_H
+#define BUFFER_H 1
 
 #include <stdlib.h>
 #include <cstring>
@@ -535,7 +535,7 @@ typedef boost::shared_ptr<OutputBuffer> OutputBufferPtr;
 
 } // namespace util
 } // namespace isc
-#endif  // __BUFFER_H
+#endif  // BUFFER_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/encode/base32hex.h b/src/lib/util/encode/base32hex.h
index d7129d7..83fd0d3 100644
--- a/src/lib/util/encode/base32hex.h
+++ b/src/lib/util/encode/base32hex.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __BASE32HEX_H
-#define __BASE32HEX_H 1
+#ifndef BASE32HEX_H
+#define BASE32HEX_H 1
 
 #include <stdint.h>
 #include <string>
@@ -57,7 +57,7 @@ void decodeBase32Hex(const std::string& input, std::vector<uint8_t>& result);
 } // namespace util
 } // namespace isc
 
-#endif  // __BASE32HEX_H
+#endif  // BASE32HEX_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/encode/base64.h b/src/lib/util/encode/base64.h
index 6b1b346..1c7c74d 100644
--- a/src/lib/util/encode/base64.h
+++ b/src/lib/util/encode/base64.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __BASE64_H
-#define __BASE64_H 1
+#ifndef BASE64_H
+#define BASE64_H 1
 
 #include <stdint.h>
 #include <string>
@@ -72,7 +72,7 @@ void decodeBase64(const std::string& input, std::vector<uint8_t>& result);
 } // namespace util
 } // namespace isc
 
-#endif  // __BASE64_H
+#endif  // BASE64_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/util/encode/hex.h b/src/lib/util/encode/hex.h
index 5c806fc..32b5071 100644
--- a/src/lib/util/encode/hex.h
+++ b/src/lib/util/encode/hex.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HEX_H
-#define __HEX_H 1
+#ifndef HEX_H
+#define HEX_H 1
 
 #include <stdint.h>
 #include <string>
@@ -58,7 +58,7 @@ void decodeHex(const std::string& input, std::vector<uint8_t>& result);
 } // namespace util
 } // namespace isc
 
-#endif  // __HEX_H
+#endif  // HEX_H
 
 // Local Variables: 
 // mode: c++
diff --git a/src/lib/util/filename.h b/src/lib/util/filename.h
index f625938..a4ba47c 100644
--- a/src/lib/util/filename.h
+++ b/src/lib/util/filename.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __FILENAME_H
-#define __FILENAME_H
+#ifndef FILENAME_H
+#define FILENAME_H
 
 #include <string>
 
@@ -170,4 +170,4 @@ private:
 } // namespace util
 } // namespace isc
 
-#endif // __FILENAME_H
+#endif // FILENAME_H
diff --git a/src/lib/util/hash/sha1.h b/src/lib/util/hash/sha1.h
index 6089ca8..165d93f 100644
--- a/src/lib/util/hash/sha1.h
+++ b/src/lib/util/hash/sha1.h
@@ -30,8 +30,8 @@
  *      without express or implied warranty of any kind.
  */
 
-#ifndef _SHA1_H_
-#define _SHA1_H_
+#ifndef SHA1_H
+#define SHA1_H
 
 #include <stdint.h>
 
diff --git a/src/lib/util/interprocess_sync.h b/src/lib/util/interprocess_sync.h
index e4fa7af..f55f0ac 100644
--- a/src/lib/util/interprocess_sync.h
+++ b/src/lib/util/interprocess_sync.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __INTERPROCESS_SYNC_H__
-#define __INTERPROCESS_SYNC_H__
+#ifndef INTERPROCESS_SYNC_H
+#define INTERPROCESS_SYNC_H
 
 #include <string>
 
@@ -146,4 +146,4 @@ protected:
 } // namespace util
 } // namespace isc
 
-#endif // __INTERPROCESS_SYNC_H__
+#endif // INTERPROCESS_SYNC_H
diff --git a/src/lib/util/interprocess_sync_file.cc b/src/lib/util/interprocess_sync_file.cc
index d045449..25af55c 100644
--- a/src/lib/util/interprocess_sync_file.cc
+++ b/src/lib/util/interprocess_sync_file.cc
@@ -15,6 +15,8 @@
 #include "interprocess_sync_file.h"
 
 #include <string>
+#include <cerrno>
+#include <cstring>
 
 #include <stdlib.h>
 #include <string.h>
@@ -68,8 +70,8 @@ InterprocessSyncFile::do_lock(int cmd, short l_type) {
 
         if (fd_ == -1) {
             isc_throw(InterprocessSyncFileError,
-                      "Unable to use interprocess sync lockfile: " +
-                      lockfile_path);
+                      "Unable to use interprocess sync lockfile ("
+                      << std::strerror(errno) << "): " << lockfile_path);
         }
     }
 
diff --git a/src/lib/util/interprocess_sync_file.h b/src/lib/util/interprocess_sync_file.h
index fd8da1b..153b391 100644
--- a/src/lib/util/interprocess_sync_file.h
+++ b/src/lib/util/interprocess_sync_file.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __INTERPROCESS_SYNC_FILE_H__
-#define __INTERPROCESS_SYNC_FILE_H__
+#ifndef INTERPROCESS_SYNC_FILE_H
+#define INTERPROCESS_SYNC_FILE_H
 
 #include <util/interprocess_sync.h>
 #include <exceptions/exceptions.h>
@@ -88,4 +88,4 @@ private:
 } // namespace util
 } // namespace isc
 
-#endif // __INTERPROCESS_SYNC_FILE_H__
+#endif // INTERPROCESS_SYNC_FILE_H
diff --git a/src/lib/util/interprocess_sync_null.h b/src/lib/util/interprocess_sync_null.h
index 6ac0322..be77514 100644
--- a/src/lib/util/interprocess_sync_null.h
+++ b/src/lib/util/interprocess_sync_null.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __INTERPROCESS_SYNC_NULL_H__
-#define __INTERPROCESS_SYNC_NULL_H__
+#ifndef INTERPROCESS_SYNC_NULL_H
+#define INTERPROCESS_SYNC_NULL_H
 
 #include <util/interprocess_sync.h>
 
@@ -61,4 +61,4 @@ protected:
 } // namespace util
 } // namespace isc
 
-#endif // __INTERPROCESS_SYNC_NULL_H__
+#endif // INTERPROCESS_SYNC_NULL_H
diff --git a/src/lib/util/io/fd.h b/src/lib/util/io/fd.h
index bdd2d41..e90e16e 100644
--- a/src/lib/util/io/fd.h
+++ b/src/lib/util/io/fd.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_IO_FD_H
-#define __UTIL_IO_FD_H 1
+#ifndef UTIL_IO_FD_H
+#define UTIL_IO_FD_H 1
 
 #include <unistd.h>
 
@@ -58,4 +58,4 @@ read_data(const int fd, void *buffer, const size_t length);
 }
 }
 
-#endif // __UTIL_IO_FD_H
+#endif // UTIL_IO_FD_H
diff --git a/src/lib/util/io/pktinfo_utilities.h b/src/lib/util/io/pktinfo_utilities.h
index 9883c30..74dc37d 100644
--- a/src/lib/util/io/pktinfo_utilities.h
+++ b/src/lib/util/io/pktinfo_utilities.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PKTINFO_UTIL_H_
-#define __PKTINFO_UTIL_H_ 1
+#ifndef PKTINFO_UTIL_H
+#define PKTINFO_UTIL_H 1
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -48,4 +48,4 @@ convertPktInfo6(unsigned char* pktinfo) {
 }
 }
 
-#endif  // __PKTINFO_UTIL_H_
+#endif  // PKTINFO_UTIL_H
diff --git a/src/lib/util/io/sockaddr_util.h b/src/lib/util/io/sockaddr_util.h
index 0cd7c7b..847a0cb 100644
--- a/src/lib/util/io/sockaddr_util.h
+++ b/src/lib/util/io/sockaddr_util.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SOCKADDR_UTIL_H_
-#define __SOCKADDR_UTIL_H_ 1
+#ifndef SOCKADDR_UTIL_H
+#define SOCKADDR_UTIL_H 1
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -77,7 +77,7 @@ convertSockAddr(struct sockaddr* sa) {
 }
 }
 
-#endif  // __SOCKADDR_UTIL_H_
+#endif  // SOCKADDR_UTIL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/io/socketsession.h b/src/lib/util/io/socketsession.h
index 48b7f19..023ef8e 100644
--- a/src/lib/util/io/socketsession.h
+++ b/src/lib/util/io/socketsession.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SOCKETSESSION_H_
-#define __SOCKETSESSION_H_ 1
+#ifndef SOCKETSESSION_H
+#define SOCKETSESSION_H 1
 
 #include <boost/noncopyable.hpp>
 
@@ -492,7 +492,7 @@ private:
 }
 }
 
-#endif  // __SOCKETSESSION_H_
+#endif  // SOCKETSESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/io_utilities.h b/src/lib/util/io_utilities.h
index 61d4c9c..cd35364 100644
--- a/src/lib/util/io_utilities.h
+++ b/src/lib/util/io_utilities.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __IO_UTILITIES_H
-#define __IO_UTILITIES_H
+#ifndef IO_UTILITIES_H
+#define IO_UTILITIES_H
 
 #include <cstddef>
 
@@ -101,4 +101,4 @@ writeUint32(uint32_t value, uint8_t* buffer) {
 } // namespace util
 } // namespace isc
 
-#endif // __ASIOLINK_UTILITIES_H
+#endif // IO_UTILITIES_H
diff --git a/src/lib/util/locks.h b/src/lib/util/locks.h
index f33ff96..34296f2 100644
--- a/src/lib/util/locks.h
+++ b/src/lib/util/locks.h
@@ -23,8 +23,8 @@
 /// to be set. we might want to enfore this at compile time with a check
 /// (TODO)
 
-#ifndef __LOCKS_
-#define __LOCKS_
+#ifndef LOCKS
+#define LOCKS
 
 namespace isc {
 namespace util {
@@ -62,4 +62,4 @@ public:
 } // namespace util
 } // namespace isc
 
-#endif // __LOCKS_
+#endif // LOCKS
diff --git a/src/lib/util/lru_list.h b/src/lib/util/lru_list.h
index 797c3c9..e5db869 100644
--- a/src/lib/util/lru_list.h
+++ b/src/lib/util/lru_list.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LRU_LIST_H
-#define __LRU_LIST_H
+#ifndef LRU_LIST_H
+#define LRU_LIST_H
 
 #include <list>
 #include <string>
@@ -257,4 +257,4 @@ void LruList<T>::clear() {
 }   // namespace util
 }   // namespace isc
 
-#endif // __LRU_LIST_H
+#endif // LRU_LIST_H
diff --git a/src/lib/util/memory_segment.h b/src/lib/util/memory_segment.h
index 97d2e02..664bd3c 100644
--- a/src/lib/util/memory_segment.h
+++ b/src/lib/util/memory_segment.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MEMORY_SEGMENT_H__
-#define __MEMORY_SEGMENT_H__
+#ifndef MEMORY_SEGMENT_H
+#define MEMORY_SEGMENT_H
 
 #include <stdlib.h>
 
@@ -66,4 +66,4 @@ public:
 } // namespace util
 } // namespace isc
 
-#endif // __MEMORY_SEGMENT_H__
+#endif // MEMORY_SEGMENT_H
diff --git a/src/lib/util/memory_segment_local.h b/src/lib/util/memory_segment_local.h
index 5e43e53..de35b87 100644
--- a/src/lib/util/memory_segment_local.h
+++ b/src/lib/util/memory_segment_local.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __MEMORY_SEGMENT_LOCAL_H__
-#define __MEMORY_SEGMENT_LOCAL_H__
+#ifndef MEMORY_SEGMENT_LOCAL_H
+#define MEMORY_SEGMENT_LOCAL_H
 
 #include <util/memory_segment.h>
 
@@ -73,4 +73,4 @@ private:
 } // namespace util
 } // namespace isc
 
-#endif // __MEMORY_SEGMENT_LOCAL_H__
+#endif // MEMORY_SEGMENT_LOCAL_H
diff --git a/src/lib/util/python/pycppwrapper_util.h b/src/lib/util/python/pycppwrapper_util.h
index 462e715..31041ba 100644
--- a/src/lib/util/python/pycppwrapper_util.h
+++ b/src/lib/util/python/pycppwrapper_util.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYCPPWRAPPER_UTIL_H
-#define __PYCPPWRAPPER_UTIL_H 1
+#ifndef PYCPPWRAPPER_UTIL_H
+#define PYCPPWRAPPER_UTIL_H 1
 
 #include <Python.h>
 
@@ -328,7 +328,7 @@ installClassVariable(PyTypeObject& pyclass, const char* name, PyObject* obj) {
 } // namespace python
 } // namespace util
 } // namespace isc
-#endif // __PYCPPWRAPPER_UTIL_H
+#endif // PYCPPWRAPPER_UTIL_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/python/wrapper_template.h b/src/lib/util/python/wrapper_template.h
index be701e1..787a296 100644
--- a/src/lib/util/python/wrapper_template.h
+++ b/src/lib/util/python/wrapper_template.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PYTHON_ at CPPCLASS@_H
-#define __PYTHON_ at CPPCLASS@_H 1
+#ifndef PYTHON_ at CPPCLASS@_H
+#define PYTHON_ at CPPCLASS@_H 1
 
 #include <Python.h>
 
@@ -52,7 +52,7 @@ PyObject* create at CPPCLASS@Object(const @CPPCLASS@& source);
 } // namespace python
 } // namespace @MODULE@
 } // namespace isc
-#endif // __PYTHON_ at CPPCLASS@_H
+#endif // PYTHON_ at CPPCLASS@_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/random/qid_gen.h b/src/lib/util/random/qid_gen.h
index 1af43c1..80f532f 100644
--- a/src/lib/util/random/qid_gen.h
+++ b/src/lib/util/random/qid_gen.h
@@ -18,8 +18,8 @@
 // (and other parts where we need randomness, perhaps another thing
 // for a general libutil?)
 
-#ifndef __QID_GEN_H
-#define __QID_GEN_H
+#ifndef QID_GEN_H
+#define QID_GEN_H
 
 #include <boost/random/mersenne_twister.hpp>
 #include <boost/random/uniform_int.hpp>
@@ -84,4 +84,4 @@ private:
 } // namespace util
 } // namespace isc
 
-#endif // __QID_GEN_H
+#endif // QID_GEN_H
diff --git a/src/lib/util/random/random_number_generator.h b/src/lib/util/random/random_number_generator.h
index 485ea7a..f0c0fb3 100644
--- a/src/lib/util/random/random_number_generator.h
+++ b/src/lib/util/random/random_number_generator.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __NSAS_RANDOM_NUMBER_GENERATOR_H
-#define __NSAS_RANDOM_NUMBER_GENERATOR_H
+#ifndef NSAS_RANDOM_NUMBER_GENERATOR_H
+#define NSAS_RANDOM_NUMBER_GENERATOR_H
 
 #include <algorithm>
 #include <cmath>
@@ -205,4 +205,4 @@ private:
 }   // namespace util
 }   // namespace isc
 
-#endif//__NSAS_RANDOM_NUMBER_GENERATOR_H
+#endif//NSAS_RANDOM_NUMBER_GENERATOR_H
diff --git a/src/lib/util/range_utilities.h b/src/lib/util/range_utilities.h
index 3f8b971..4d5b0bb 100644
--- a/src/lib/util/range_utilities.h
+++ b/src/lib/util/range_utilities.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __RANGE_UTIL_H_
-#define __RANGE_UTIL_H_ 1
+#ifndef RANGE_UTIL_H
+#define RANGE_UTIL_H 1
 
 #include <stdlib.h>
 #include <algorithm>
@@ -41,16 +41,17 @@ isRangeZero(Iterator begin, Iterator end) {
 
 /// @brief Fill in specified range with a random data.
 ///
-/// Make sure that random number generator is initialized properly. Otherwise you
-/// will get a the same pseudo-random sequence after every start of your process.
-/// Calling srand() is enough. This method uses default rand(), which is usually
-/// a LCG pseudo-random number generator, so it is not suitable for security
-/// purposes. Please get a decent PRNG implementation, like mersene twister, if
-/// you are doing anything related with security.
+/// Make sure that random number generator is initialized
+/// properly. Otherwise you will get a the same pseudo-random sequence
+/// after every start of your process.  Calling srand() is enough. This
+/// method uses default rand(), which is usually a LCG pseudo-random
+/// number generator, so it is not suitable for security
+/// purposes. Please get a decent PRNG implementation, like mersene
+/// twister, if you are doing anything related with security.
 ///
-/// PRNG initialization is left out of this function on purpose. It may be
-/// initialized to specific value on purpose, e.g. to repeat exactly the same
-/// sequence in a test.
+/// PRNG initialization is left out of this function on purpose. It may
+/// be initialized to specific value on purpose, e.g. to repeat exactly
+/// the same sequence in a test.
 ///
 /// @param begin
 /// @param end
@@ -65,4 +66,4 @@ fillRandom(Iterator begin, Iterator end) {
 } // end of isc::util namespace
 } // end of isc namespace
 
-#endif  // __PKTINFO_UTIL_H_
+#endif  // RANGE_UTIL_H
diff --git a/src/lib/util/strutil.h b/src/lib/util/strutil.h
index 0dbbe96..6b60009 100644
--- a/src/lib/util/strutil.h
+++ b/src/lib/util/strutil.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __STRUTIL_H
-#define __STRUTIL_H
+#ifndef STRUTIL_H
+#define STRUTIL_H
 
 #include <algorithm>
 #include <cctype>
@@ -206,4 +206,4 @@ tokenToNum(const std::string& num_token) {
 } // namespace util
 } // namespace isc
 
-#endif // __STRUTIL_H
+#endif // STRUTIL_H
diff --git a/src/lib/util/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc
index 9af3d57..02ca83d 100644
--- a/src/lib/util/tests/buffer_unittest.cc
+++ b/src/lib/util/tests/buffer_unittest.cc
@@ -18,6 +18,7 @@
 
 #ifdef EXPECT_DEATH
 #include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
 #endif /* EXPECT_DEATH */
 
 #include <util/buffer.h>
@@ -188,16 +189,18 @@ TEST_F(BufferTest, outputBufferReadat) {
     }
 #ifdef EXPECT_DEATH
     // We use assert now, so we check it dies
-    EXPECT_DEATH({
-        isc::util::unittests::dontCreateCoreDumps();
-
-        try {
-            obuffer[sizeof(testdata)];
-        } catch (...) {
-            // Prevent exceptions killing the application, we need
-            // to make sure it dies the real hard way
-        }
-        }, "");
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH({
+            isc::util::unittests::dontCreateCoreDumps();
+
+            try {
+                obuffer[sizeof(testdata)];
+            } catch (...) {
+                // Prevent exceptions killing the application, we need
+                // to make sure it dies the real hard way
+            }
+            }, "");
+    }
 #endif
 }
 
diff --git a/src/lib/util/threads/Makefile.am b/src/lib/util/threads/Makefile.am
index 7b9fb8f..121e4ab 100644
--- a/src/lib/util/threads/Makefile.am
+++ b/src/lib/util/threads/Makefile.am
@@ -5,7 +5,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
 
 lib_LTLIBRARIES = libb10-threads.la
-libb10_threads_la_SOURCES  = lock.h lock.cc
+libb10_threads_la_SOURCES  = sync.h sync.cc
 libb10_threads_la_SOURCES += thread.h thread.cc
 libb10_threads_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 
diff --git a/src/lib/util/threads/lock.cc b/src/lib/util/threads/lock.cc
deleted file mode 100644
index 6a165aa..0000000
--- a/src/lib/util/threads/lock.cc
+++ /dev/null
@@ -1,138 +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 "lock.h"
-
-#include <exceptions/exceptions.h>
-
-#include <cstring>
-#include <memory>
-#include <cerrno>
-#include <cassert>
-
-#include <pthread.h>
-
-using std::auto_ptr;
-
-namespace isc {
-namespace util {
-namespace thread {
-
-class Mutex::Impl {
-public:
-    Impl() :
-        locked_count(0)
-    {}
-    pthread_mutex_t mutex;
-    // Only in debug mode
-    size_t locked_count;
-};
-
-namespace {
-
-struct Deinitializer {
-    Deinitializer(pthread_mutexattr_t& attributes):
-        attributes_(attributes)
-    {}
-    ~Deinitializer() {
-        const int result = pthread_mutexattr_destroy(&attributes_);
-        // This should never happen. According to the man page,
-        // if there's error, it's our fault.
-        assert(result == 0);
-    }
-    pthread_mutexattr_t& attributes_;
-};
-
-}
-
-Mutex::Mutex() :
-    impl_(NULL)
-{
-    pthread_mutexattr_t attributes;
-    int result = pthread_mutexattr_init(&attributes);
-    switch (result) {
-        case 0: // All 0K
-            break;
-        case ENOMEM:
-            throw std::bad_alloc();
-        default:
-            isc_throw(isc::InvalidOperation, std::strerror(result));
-    }
-    Deinitializer deinitializer(attributes);
-    // TODO: Distinguish if debug mode is enabled in compilation.
-    // If so, it should be PTHREAD_MUTEX_NORMAL or NULL
-    result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_ERRORCHECK);
-    if (result != 0) {
-        isc_throw(isc::InvalidOperation, std::strerror(result));
-    }
-    auto_ptr<Impl> impl(new Impl);
-    result = pthread_mutex_init(&impl->mutex, &attributes);
-    switch (result) {
-        case 0: // All 0K
-            impl_ = impl.release();
-            break;
-        case ENOMEM:
-        case EAGAIN:
-            throw std::bad_alloc();
-        default:
-            isc_throw(isc::InvalidOperation, std::strerror(result));
-    }
-}
-
-Mutex::~Mutex() {
-    if (impl_ != NULL) {
-        const int result = pthread_mutex_destroy(&impl_->mutex);
-        const bool locked = impl_->locked_count != 0;
-        delete impl_;
-        // We don't want to throw from the destructor. Also, if this ever
-        // fails, something is really screwed up a lot.
-        assert(result == 0);
-
-        // We should not try to destroy a locked mutex, bad threaded monsters
-        // could get loose if we ever do and it is also forbidden by pthreads.
-
-        // This should not be possible to happen, since the
-        // pthread_mutex_destroy should check for it already. But it seems
-        // there are systems that don't check it.
-        assert(!locked);
-    }
-}
-
-void
-Mutex::lock() {
-    assert(impl_ != NULL);
-    const int result = pthread_mutex_lock(&impl_->mutex);
-    if (result != 0) {
-        isc_throw(isc::InvalidOperation, std::strerror(result));
-    }
-    ++impl_->locked_count; // Only in debug mode
-}
-
-void
-Mutex::unlock() {
-    assert(impl_ != NULL);
-    --impl_->locked_count; // Only in debug mode
-    const int result = pthread_mutex_unlock(&impl_->mutex);
-    assert(result == 0); // This should never be possible
-}
-
-// TODO: Disable in non-debug build
-bool
-Mutex::locked() const {
-    return (impl_->locked_count != 0);
-}
-
-}
-}
-}
diff --git a/src/lib/util/threads/lock.h b/src/lib/util/threads/lock.h
deleted file mode 100644
index fef537b..0000000
--- a/src/lib/util/threads/lock.h
+++ /dev/null
@@ -1,128 +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 B10_THREAD_LOCK_H
-#define B10_THREAD_LOCK_H
-
-#include <boost/noncopyable.hpp>
-
-#include <cstdlib> // for NULL.
-
-namespace isc {
-namespace util {
-namespace thread {
-
-/// \brief Mutex with very simple interface
-///
-/// Since mutexes are very system dependant, we create our own wrapper around
-/// whatever is available on the system and hide it.
-///
-/// To use this mutex, create it and then lock and unlock it by creating the
-/// Mutex::Locker object.
-///
-/// Also, as mutex is a low-level system object, an error might happen at any
-/// operation with it. We convert many errors to the isc::InvalidOperation,
-/// since the errors usually happen only when used in a wrong way. Any methods
-/// or constructors in this class can throw. Allocation errors are converted
-/// to std::bad_alloc (for example when OS-dependant limit of mutexes is
-/// exceeded). Some errors which usually mean a programmer error abort the
-/// program, since there could be no safe way to recover from them.
-///
-/// The current interface is somewhat minimalistic. If we ever need more, we
-/// can add it later.
-class Mutex : public boost::noncopyable {
-public:
-    /// \brief Constructor.
-    ///
-    /// Creates a mutex. It is a non-recursive mutex (can be locked just once,
-    /// if the same threads tries to lock it again, Bad Things Happen).
-    ///
-    /// Depending on compilation parameters and OS, the mutex may or may not
-    /// do some error and sanity checking. However, such checking is meant
-    /// only to aid development, not rely on it as a feature.
-    ///
-    /// \throw std::bad_alloc In case allocation of something (memory, the
-    ///     OS mutex) fails.
-    /// \throw isc::InvalidOperation Other unspecified errors around the mutex.
-    ///     This should be rare.
-    Mutex();
-
-    /// \brief Destructor.
-    ///
-    /// Destroys the mutex. It is not allowed to destroy a mutex which is
-    /// currently locked. This means a Locker created with this Mutex must
-    /// never live longer than the Mutex itself.
-    ~Mutex();
-
-    /// \brief This holds a lock on a Mutex.
-    ///
-    /// To lock a mutex, create a locker. It'll get unlocked when the locker
-    /// is destroyed.
-    ///
-    /// If you create the locker on the stack or using some other "garbage
-    /// collecting" mechanism (auto_ptr, for example), it ensures exception
-    /// safety with regards to the mutex - it'll get released on the exit
-    /// of function no matter by what means.
-    class Locker : public boost::noncopyable {
-    public:
-        /// \brief Constructor.
-        ///
-        /// Locks the mutex. May block for extended period of time.
-        ///
-        /// \throw isc::InvalidOperation when OS reports error. This usually
-        ///     means an attempt to use the mutex in a wrong way (locking
-        ///     a mutex second time from the same thread, for example).
-        Locker(Mutex& mutex) :
-            mutex_(NULL)
-        {
-            // Set the mutex_ after we acquire the lock. This is because of
-            // exception safety. If lock() throws, it didn't work, so we must
-            // not unlock when we are destroyed. In such case, mutex_ is
-            // NULL and checked in the destructor.
-            mutex.lock();
-            mutex_ = &mutex;
-        }
-
-        /// \brief Destructor.
-        ///
-        /// Unlocks the mutex.
-        ~Locker() {
-            if (mutex_ != NULL) {
-                mutex_->unlock();
-            }
-        }
-    private:
-        Mutex* mutex_;
-    };
-    /// \brief If the mutex is currently locked
-    ///
-    /// This is debug aiding method only. And it might be unavailable in
-    /// non-debug build (because keeping the state might be needlesly
-    /// slow).
-    ///
-    /// \todo Disable in non-debug build
-    bool locked() const;
-private:
-    class Impl;
-    Impl* impl_;
-    void lock();
-    void unlock();
-};
-
-
-}
-}
-}
-
-#endif
diff --git a/src/lib/util/threads/sync.cc b/src/lib/util/threads/sync.cc
new file mode 100644
index 0000000..46a5646
--- /dev/null
+++ b/src/lib/util/threads/sync.cc
@@ -0,0 +1,240 @@
+// 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 "config.h"
+
+#include "sync.h"
+
+#include <exceptions/exceptions.h>
+
+#include <cstring>
+#include <memory>
+#include <cerrno>
+#include <cassert>
+
+#include <pthread.h>
+
+using std::auto_ptr;
+
+namespace isc {
+namespace util {
+namespace thread {
+
+class Mutex::Impl {
+public:
+    Impl()
+#ifdef ENABLE_DEBUG
+        : locked_count(0)
+#endif // ENABLE_DEBUG
+    {}
+
+    pthread_mutex_t mutex;
+#ifdef ENABLE_DEBUG
+    size_t locked_count;
+#endif // ENABLE_DEBUG
+};
+
+namespace {
+
+struct Deinitializer {
+    Deinitializer(pthread_mutexattr_t& attributes):
+        attributes_(attributes)
+    {}
+    ~Deinitializer() {
+        const int result = pthread_mutexattr_destroy(&attributes_);
+        // This should never happen. According to the man page,
+        // if there's error, it's our fault.
+        assert(result == 0);
+    }
+    pthread_mutexattr_t& attributes_;
+};
+
+}
+
+Mutex::Mutex() :
+    impl_(NULL)
+{
+    pthread_mutexattr_t attributes;
+    int result = pthread_mutexattr_init(&attributes);
+    switch (result) {
+        case 0: // All 0K
+            break;
+        case ENOMEM:
+            throw std::bad_alloc();
+        default:
+            isc_throw(isc::InvalidOperation, std::strerror(result));
+    }
+    Deinitializer deinitializer(attributes);
+
+    // If debug mode is enabled in compilation, use the slower
+    // error-checking mutexes that detect deadlocks. Otherwise, use fast
+    // mutexes which don't. See the pthread_mutexattr_settype() POSIX
+    // documentation which describes these type attributes.
+#ifdef ENABLE_DEBUG
+    result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_ERRORCHECK);
+#else
+    result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_NORMAL);
+#endif // ENABLE_DEBUG
+    if (result != 0) {
+        isc_throw(isc::InvalidOperation, std::strerror(result));
+    }
+
+    auto_ptr<Impl> impl(new Impl);
+    result = pthread_mutex_init(&impl->mutex, &attributes);
+    switch (result) {
+        case 0: // All 0K
+            impl_ = impl.release();
+            break;
+        case ENOMEM:
+        case EAGAIN:
+            throw std::bad_alloc();
+        default:
+            isc_throw(isc::InvalidOperation, std::strerror(result));
+    }
+}
+
+Mutex::~Mutex() {
+    if (impl_ != NULL) {
+        const int result = pthread_mutex_destroy(&impl_->mutex);
+
+#ifdef ENABLE_DEBUG
+        const bool locked = impl_->locked_count != 0;
+#endif // ENABLE_DEBUG
+
+        delete impl_;
+        // We don't want to throw from the destructor. Also, if this ever
+        // fails, something is really screwed up a lot.
+        assert(result == 0);
+
+#ifdef ENABLE_DEBUG
+        // We should not try to destroy a locked mutex, bad threaded monsters
+        // could get loose if we ever do and it is also forbidden by pthreads.
+
+        // This should not be possible to happen, since the
+        // pthread_mutex_destroy should check for it already. But it seems
+        // there are systems that don't check it.
+        assert(!locked);
+#endif // ENABLE_DEBUG
+    }
+}
+
+#ifdef ENABLE_DEBUG
+
+void
+Mutex::postLockAction() {
+    assert(impl_->locked_count == 0);
+    ++impl_->locked_count;
+}
+
+void
+Mutex::preUnlockAction(bool throw_ok) {
+    if (impl_->locked_count == 0) {
+        if (throw_ok) {
+            isc_throw(isc::InvalidOperation,
+                      "Unlock attempt for unlocked mutex");
+        } else {
+            assert(false);
+        }
+    }
+    --impl_->locked_count;
+}
+
+bool
+Mutex::locked() const {
+    return (impl_->locked_count != 0);
+}
+
+#endif // ENABLE_DEBUG
+
+void
+Mutex::lock() {
+    assert(impl_ != NULL);
+    const int result = pthread_mutex_lock(&impl_->mutex);
+    if (result != 0) {
+        isc_throw(isc::InvalidOperation, std::strerror(result));
+    }
+#ifdef ENABLE_DEBUG
+    postLockAction();           // Only in debug mode
+#endif // ENABLE_DEBUG
+}
+
+void
+Mutex::unlock() {
+    assert(impl_ != NULL);
+#ifdef ENABLE_DEBUG
+    preUnlockAction(false);     // Only in debug mode.  Ensure no throw.
+#endif // ENABLE_DEBUG
+    const int result = pthread_mutex_unlock(&impl_->mutex);
+    assert(result == 0); // This should never be possible
+}
+
+class CondVar::Impl {
+public:
+    Impl() {
+        const int result = pthread_cond_init(&cond_, NULL);
+        if (result != 0) {
+            isc_throw(isc::Unexpected, "pthread_cond_init failed: "
+                      << std::strerror(result));
+        }
+    }
+    ~Impl() {
+        const int result = pthread_cond_destroy(&cond_);
+
+        // This can happen if we try to destroy cond_ while some other thread
+        // is waiting on it.  assert() may be too strong for such a case,
+        // but we cannot safely destroy cond_ anyway.  In order to avoid
+        // throwing from a destructor we simply let the process die.
+        assert(result == 0);
+    }
+
+    // For convenience allow the main class to access this directly.
+    pthread_cond_t cond_;
+};
+
+CondVar::CondVar() : impl_(new Impl)
+{}
+
+CondVar::~CondVar() {
+    delete impl_;
+}
+
+void
+CondVar::wait(Mutex& mutex) {
+#ifdef ENABLE_DEBUG
+    mutex.preUnlockAction(true);    // Only in debug mode
+    const int result = pthread_cond_wait(&impl_->cond_, &mutex.impl_->mutex);
+    mutex.postLockAction();     // Only in debug mode
+#else
+    const int result = pthread_cond_wait(&impl_->cond_, &mutex.impl_->mutex);
+#endif
+    // pthread_cond_wait should normally succeed unless mutex is completely
+    // broken.
+    if (result != 0) {
+        isc_throw(isc::BadValue, "pthread_cond_wait failed unexpectedly: " <<
+                  std::strerror(result));
+    }
+}
+
+void
+CondVar::signal() {
+    const int result = pthread_cond_signal(&impl_->cond_);
+
+    // pthread_cond_signal() can only fail when if cond_ is invalid.  It
+    //should be impossible as long as this is a valid CondVar object.
+    assert(result == 0);
+}
+
+}
+}
+}
diff --git a/src/lib/util/threads/sync.h b/src/lib/util/threads/sync.h
new file mode 100644
index 0000000..87c78be
--- /dev/null
+++ b/src/lib/util/threads/sync.h
@@ -0,0 +1,229 @@
+// 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 B10_THREAD_SYNC_H
+#define B10_THREAD_SYNC_H
+
+#include <boost/noncopyable.hpp>
+
+#include <cstdlib> // for NULL.
+
+namespace isc {
+namespace util {
+namespace thread {
+class CondVar;
+
+/// \brief Mutex with very simple interface
+///
+/// Since mutexes are very system dependant, we create our own wrapper around
+/// whatever is available on the system and hide it.
+///
+/// To use this mutex, create it and then lock and unlock it by creating the
+/// Mutex::Locker object.
+///
+/// Also, as mutex is a low-level system object, an error might happen at any
+/// operation with it. We convert many errors to the isc::InvalidOperation,
+/// since the errors usually happen only when used in a wrong way. Any methods
+/// or constructors in this class can throw. Allocation errors are converted
+/// to std::bad_alloc (for example when OS-dependant limit of mutexes is
+/// exceeded). Some errors which usually mean a programmer error abort the
+/// program, since there could be no safe way to recover from them.
+///
+/// The current interface is somewhat minimalistic. If we ever need more, we
+/// can add it later.
+class Mutex : boost::noncopyable {
+public:
+    /// \brief Constructor.
+    ///
+    /// Creates a mutex. It is a non-recursive mutex (can be locked just once,
+    /// if the same threads tries to lock it again, Bad Things Happen).
+    ///
+    /// Depending on compilation parameters and OS, the mutex may or may not
+    /// do some error and sanity checking. However, such checking is meant
+    /// only to aid development, not rely on it as a feature.
+    ///
+    /// \throw std::bad_alloc In case allocation of something (memory, the
+    ///     OS mutex) fails.
+    /// \throw isc::InvalidOperation Other unspecified errors around the mutex.
+    ///     This should be rare.
+    Mutex();
+
+    /// \brief Destructor.
+    ///
+    /// Destroys the mutex. It is not allowed to destroy a mutex which is
+    /// currently locked. This means a Locker created with this Mutex must
+    /// never live longer than the Mutex itself.
+    ~Mutex();
+
+    /// \brief This holds a lock on a Mutex.
+    ///
+    /// To lock a mutex, create a locker. It'll get unlocked when the locker
+    /// is destroyed.
+    ///
+    /// If you create the locker on the stack or using some other "garbage
+    /// collecting" mechanism (auto_ptr, for example), it ensures exception
+    /// safety with regards to the mutex - it'll get released on the exit
+    /// of function no matter by what means.
+    class Locker : boost::noncopyable {
+    public:
+        /// \brief Constructor.
+        ///
+        /// Locks the mutex. May block for extended period of time.
+        ///
+        /// \throw isc::InvalidOperation when OS reports error. This usually
+        ///     means an attempt to use the mutex in a wrong way (locking
+        ///     a mutex second time from the same thread, for example).
+        Locker(Mutex& mutex) :
+            mutex_(mutex)
+        {
+            mutex.lock();
+        }
+
+        /// \brief Destructor.
+        ///
+        /// Unlocks the mutex.
+        ~Locker() {
+            mutex_.unlock();
+        }
+    private:
+        Mutex& mutex_;
+    };
+    /// \brief If the mutex is currently locked
+    ///
+    /// This is debug aiding method only. And it might be unavailable in
+    /// non-debug build (because keeping the state might be needlesly
+    /// slow).
+    ///
+    /// \todo Disable in non-debug build
+    bool locked() const;
+private:
+    friend class CondVar;
+
+    // Commonly called after acquiring the lock, checking and updating
+    // internal state for debug.
+    //
+    // Note that this method is only available when the build is
+    // configured with debugging support.
+    void postLockAction();
+
+    // Commonly called before releasing the lock, checking and updating
+    // internal state for debug.
+    //
+    // If throw_ok is true, it throws \c isc::InvalidOperation when the check
+    // fails; otherwise it aborts the process.  This parameter must be set
+    // to false if the call to this shouldn't result in an exception (e.g.
+    // when called from a destructor).
+    //
+    // Note that this method is only available when the build is
+    // configured with debugging support.
+    void preUnlockAction(bool throw_ok);
+
+    class Impl;
+    Impl* impl_;
+    void lock();
+    void unlock();
+};
+
+/// \brief Encapsulation for a condition variable.
+///
+/// This class provides a simple encapsulation of condition variable for
+/// inter-thread synchronization.  It has similar but simplified interface as
+/// that for \c pthread_cond_ variants.
+///
+/// It uses the \c Mutex class object for the mutex used with the condition
+/// variable.  Since for normal applications the internal \c Mutex::Locker
+/// class is the only available interface to acquire a lock, sample code
+/// for waiting on a condition variable would look like this:
+/// \code
+/// CondVar cond;
+/// Mutex mutex;
+/// {
+///     Mutex::Locker locker(mutex);
+///     while (some_condition) {
+///         cond.wait(mutex);
+///     }
+///     // do something under the protection of locker
+/// }   // lock is released here
+/// \endcode
+/// Note that \c mutex passed to the \c wait() method must be the same one
+/// used to construct the \c locker.
+///
+/// Right now there is no equivalent to pthread_cond_broadcast() or
+/// pthread_cond_timedwait() in this class, because this class is meant
+/// for internal development of BIND 10 and we don't need these at the
+/// moment.  If and when we need these interfaces they can be added at that
+/// point.
+///
+/// \note This class is defined as a friend class of \c Mutex and directly
+/// refers to and modifies private internals of the \c Mutex class.  It breaks
+/// the assumption that the lock is only acquired or released via the
+/// \c Locker class and breaks other integrity assumption on \c Mutex,
+/// thereby making it more fragile, but we couldn't find other way to
+/// implement a safe and still simple realization of condition variables.
+/// So, this is a kind of compromise.  If this class is needed to be
+/// extended, first consider a way to use public interfaces of \c Mutex;
+/// do not easily rely on the fact that this class is a friend of it.
+class CondVar : boost::noncopyable {
+public:
+    /// \brief Constructor.
+    ///
+    /// \throw std::bad_alloc memory allocation failure
+    /// \throw isc::Unexpected other unexpected shortage of system resource
+    CondVar();
+
+    /// \brief Destructor.
+    ///
+    /// An object of this class must not be destroyed while some thread
+    /// is waiting on it.  If this condition isn't met the destructor will
+    /// terminate the program.
+    ~CondVar();
+
+    /// \brief Wait on the condition variable.
+    ///
+    /// This method works like \c pthread_cond_wait().  For mutex it takes
+    /// an \c Mutex class object.  A lock for the mutex must have been
+    /// acquired.  If this condition isn't met, it can throw an exception
+    /// (in the debug mode build) or result in undefined behavior.
+    ///
+    /// The lock will be automatically released within this method, and
+    /// will be re-acquired on the exit of this method.
+    ///
+    /// \throw isc::InvalidOperation mutex isn't locked
+    /// \throw isc::BadValue mutex is not a valid \c Mutex object
+    ///
+    /// \param mutex A \c Mutex object to be released on wait().
+    void wait(Mutex& mutex);
+
+    /// \brief Unblock a thread waiting for the condition variable.
+    ///
+    /// This method wakes one of other threads (if any) waiting on this object
+    /// via the \c wait() call.
+    ///
+    /// This method never throws; if some unexpected low level error happens
+    /// it terminates the program.
+    void signal();
+private:
+    class Impl;
+    Impl* impl_;
+};
+
+} // namespace thread
+} // namespace util
+} // namespace isc
+
+#endif
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/threads/tests/Makefile.am b/src/lib/util/threads/tests/Makefile.am
index 2d9d4f9..a12d221 100644
--- a/src/lib/util/threads/tests/Makefile.am
+++ b/src/lib/util/threads/tests/Makefile.am
@@ -23,6 +23,7 @@ TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += thread_unittest.cc
 run_unittests_SOURCES += lock_unittest.cc
+run_unittests_SOURCES += condvar_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
diff --git a/src/lib/util/threads/tests/condvar_unittest.cc b/src/lib/util/threads/tests/condvar_unittest.cc
new file mode 100644
index 0000000..1e04efa
--- /dev/null
+++ b/src/lib/util/threads/tests/condvar_unittest.cc
@@ -0,0 +1,169 @@
+// 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 <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/threads/sync.h>
+#include <util/threads/thread.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <cstring>
+
+#include <unistd.h>
+#include <signal.h>
+
+using namespace isc::util::thread;
+
+namespace {
+// Used as a signal handler below.
+volatile bool do_exit;          // use for emergency escape
+void
+alarmHandler(int) {
+    do_exit = true;
+}
+
+class CondVarTest : public ::testing::Test {
+protected:
+    // We use a signal in case some of the thread synchronization tests
+    // unexpectedly cause a deadlock.
+    void SetUp() {
+        do_exit = false;
+
+        std::memset(&handler_, 0, sizeof(handler_));
+        handler_.sa_handler = alarmHandler;
+        if (sigaction(SIGALRM, &handler_, &original_) != 0) {
+            FAIL() << "Couldn't set alarm";
+        }
+        alarm(10);                  // 10sec duration: arbitrary choice
+    }
+    void TearDown() {
+        // Cancel the alarm and return the original handler
+        alarm(0);
+        if (sigaction(SIGALRM, &original_, NULL)) {
+            FAIL() << "Couldn't restore alarm";
+        }
+    }
+
+    CondVar condvar_;
+    Mutex mutex_;
+private:
+    struct sigaction handler_, original_;
+};
+
+TEST(CondVarTest0, create) {
+    // Just construct and destruct it.  Nothing unusual should happen.
+    EXPECT_NO_THROW(CondVar condvar);
+}
+
+// Running on a separate thread, just updating the argument and waking up
+// the other thread via the condition variable passed.
+void
+ringSignal(CondVar* condvar, Mutex* mutex, int* arg) {
+    assert(*arg == 0);
+    Mutex::Locker locker(*mutex);
+    ++*arg;
+    condvar->signal();
+}
+
+// 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);
+}
+
+// Thread's main code for the next test
+void
+signalAndWait(CondVar* condvar1, CondVar* condvar2, Mutex* mutex, int* arg) {
+    Mutex::Locker locker(*mutex);
+    ++*arg;
+    condvar2->signal();  // let the main thread know this one is ready
+    condvar1->wait(*mutex);
+    ++*arg;
+}
+
+// Similar to the previous test, but having two threads wait for a condvar.
+TEST_F(CondVarTest, multiWaits) {
+    boost::scoped_ptr<Mutex::Locker> locker(new Mutex::Locker(mutex_));
+    CondVar condvar2; // separate cond var for initial synchronization
+    int shared_var = 0; // let the other thread increment this
+    Thread t1(boost::bind(&signalAndWait, &condvar_, &condvar2, &mutex_,
+                          &shared_var));
+    Thread t2(boost::bind(&signalAndWait, &condvar_, &condvar2, &mutex_,
+                          &shared_var));
+
+    // Wait until both threads are waiting on condvar_.
+    while (shared_var < 2 && !do_exit) {
+        condvar2.wait(mutex_);
+    }
+    // Check we exited from the loop successfully.
+    ASSERT_FALSE(do_exit);
+    ASSERT_EQ(2, shared_var);
+
+    // release the lock, wake up both threads, wait for them to die, and
+    // confirm they successfully woke up.
+    locker.reset();
+    condvar_.signal();
+    condvar_.signal();
+    t1.wait();
+    t2.wait();
+    EXPECT_EQ(4, shared_var);
+}
+
+// Similar to the previous version of the same function, but just do
+// condvar operations.  It will never wake up.
+void
+signalAndWait(CondVar* condvar, Mutex* mutex) {
+    Mutex::Locker locker(*mutex);
+    condvar->signal();
+    condvar->wait(*mutex);
+}
+
+#ifndef HAS_UNDEFINED_PTHREAD_BEHAVIOR
+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_);
+        }, "");
+}
+#endif // !HAS_UNDEFINED_PTHREAD_BEHAVIOR
+
+#ifdef ENABLE_DEBUG
+
+TEST_F(CondVarTest, badWait) {
+    // In our implementation, wait() requires acquiring the lock beforehand.
+    EXPECT_THROW(condvar_.wait(mutex_), isc::InvalidOperation);
+}
+
+#endif // ENABLE_DEBUG
+
+TEST_F(CondVarTest, emptySignal) {
+    // It's okay to call signal when no one waits.
+    EXPECT_NO_THROW(condvar_.signal());
+}
+
+}
diff --git a/src/lib/util/threads/tests/lock_unittest.cc b/src/lib/util/threads/tests/lock_unittest.cc
index 0b4d3ce..1abc3fa 100644
--- a/src/lib/util/threads/tests/lock_unittest.cc
+++ b/src/lib/util/threads/tests/lock_unittest.cc
@@ -12,11 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <util/threads/lock.h>
-#include <util/threads/thread.h>
+#include <config.h>
 
 #include <gtest/gtest.h>
 
+#include <util/threads/sync.h>
+#include <util/threads/thread.h>
+#include <util/unittests/check_valgrind.h>
+
 #include <boost/bind.hpp>
 #include <unistd.h>
 #include <signal.h>
@@ -25,32 +28,40 @@ using namespace isc::util::thread;
 
 namespace {
 
-// If we try to lock the debug mutex multiple times, it should throw.
+#ifdef ENABLE_DEBUG
+
+// If we try to lock the debug mutex multiple times, it should
+// throw. This test will complete properly only when pthread debugging
+// facilities are enabled by configuring the code for debug build.
 TEST(MutexTest, lockMultiple) {
-    // TODO: Once we support non-debug mutexes, disable the test if we compile
-    // with them.
     Mutex mutex;
     EXPECT_FALSE(mutex.locked()); // Debug-only build
+
     Mutex::Locker l1(mutex);
     EXPECT_TRUE(mutex.locked()); // Debug-only build
+
     EXPECT_THROW({
         Mutex::Locker l2(mutex); // Attempt to lock again.
     }, isc::InvalidOperation);
     EXPECT_TRUE(mutex.locked()); // Debug-only build
 }
 
+#endif // ENABLE_DEBUG
+
+#ifndef HAS_UNDEFINED_PTHREAD_BEHAVIOR
 // Destroying a locked mutex is a bad idea as well
-#ifdef EXPECT_DEATH
 TEST(MutexTest, destroyLocked) {
-    EXPECT_DEATH({
-        Mutex* mutex = new Mutex;
-        new Mutex::Locker(*mutex);
-        delete mutex;
-        // This'll leak the locker, but inside the slave process, it should
-        // not be an issue.
-    }, "");
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH_IF_SUPPORTED({
+            Mutex* mutex = new Mutex;
+            new Mutex::Locker(*mutex);
+            delete mutex;
+            // This'll leak the locker, but inside the slave process, it should
+            // not be an issue.
+        }, "");
+    }
 }
-#endif
+#endif // !HAS_UNDEFINED_PTHREAD_BEHAVIOR
 
 // In this test, we try to check if a mutex really locks. We could try that
 // with a deadlock, but that's not practical (the test would not end).
@@ -80,13 +91,13 @@ performIncrement(volatile double* canary, volatile bool* ready_me,
 }
 
 void
-no_handler(int) {}
+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 = no_handler;
+    memset(&ignored, 0, sizeof(ignored));
+    ignored.sa_handler = noHandler;
     if (sigaction(SIGALRM, &ignored, &original)) {
         FAIL() << "Couldn't set alarm";
     }
diff --git a/src/lib/util/threads/thread.cc b/src/lib/util/threads/thread.cc
index c1c9cdf..5608e49 100644
--- a/src/lib/util/threads/thread.cc
+++ b/src/lib/util/threads/thread.cc
@@ -13,7 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include "thread.h"
-#include "lock.h"
+#include "sync.h"
 
 #include <memory>
 #include <string>
diff --git a/src/lib/util/time_utilities.h b/src/lib/util/time_utilities.h
index a53089d..479f055 100644
--- a/src/lib/util/time_utilities.h
+++ b/src/lib/util/time_utilities.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TIME_UTILITIES_H
-#define __TIME_UTILITIES_H 1
+#ifndef TIME_UTILITIES_H
+#define TIME_UTILITIES_H 1
 
 #include <string>
 
@@ -32,7 +32,7 @@ namespace isc {
 namespace util {
 
 ///
-/// \brief A standard DNS (or ISC) module exception that is thrown if 
+/// \brief A standard DNS (or ISC) module exception that is thrown if
 /// a time conversion function encounters bad input
 ///
 class InvalidTime : public Exception {
@@ -166,7 +166,7 @@ timeToText32(const uint32_t value);
 }
 }
 
-#endif  // __DNSSECTIME_H
+#endif  // TIME_UTILITIES_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am
index 451ab4e..55e0372 100644
--- a/src/lib/util/unittests/Makefile.am
+++ b/src/lib/util/unittests/Makefile.am
@@ -7,6 +7,7 @@ libutil_unittests_la_SOURCES += newhook.h newhook.cc
 libutil_unittests_la_SOURCES += testdata.h testdata.cc
 if HAVE_GTEST
 libutil_unittests_la_SOURCES += resource.h resource.cc
+libutil_unittests_la_SOURCES += check_valgrind.h check_valgrind.cc
 libutil_unittests_la_SOURCES += run_all.h run_all.cc
 libutil_unittests_la_SOURCES += textdata.h
 libutil_unittests_la_SOURCES += wiredata.h wiredata.cc
diff --git a/src/lib/util/unittests/check_valgrind.cc b/src/lib/util/unittests/check_valgrind.cc
new file mode 100644
index 0000000..2951d25
--- /dev/null
+++ b/src/lib/util/unittests/check_valgrind.cc
@@ -0,0 +1,41 @@
+// 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 <config.h>
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+#if HAVE_VALGRIND_HEADERS
+#include <valgrind/valgrind.h>
+/// \brief Check if the program is run in valgrind
+///
+/// \return true if valgrind headers are available, and valgrind is running,
+///         false if the headers are not available, or if valgrind is not
+///         running
+bool
+runningOnValgrind() {
+    return (RUNNING_ON_VALGRIND != 0);
+}
+#else
+bool
+runningOnValgrind() {
+    return (false);
+}
+#endif // HAVE_VALGRIND_HEADERS
+
+} // end of namespace unittests
+} // end of namespace util
+} // end of namespace isc
diff --git a/src/lib/util/unittests/check_valgrind.h b/src/lib/util/unittests/check_valgrind.h
new file mode 100644
index 0000000..80f1f85
--- /dev/null
+++ b/src/lib/util/unittests/check_valgrind.h
@@ -0,0 +1,50 @@
+// 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.
+
+//
+// If we have the valgrind headers available, we can detect whether
+// valgrind is running. This should normally never be done, as you
+// want the to test the actual code in operation with valgrind.
+//
+// However, there is a limited set of operations where we want to
+// skip some tests if run under valgrind, most notably the
+// EXPECT_DEATH tests, as these would report memory leaks by
+// definition.
+//
+// If the valgrind headers are NOT available, the method checkValgrind()
+// always returns false; i.e. it always pretends the program is run
+// natively
+//
+
+#ifndef UTIL_UNITTESTS_CHECK_VALGRIND_H
+#define UTIL_UNITTESTS_CHECK_VALGRIND_H 1
+
+#include <config.h>
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// \brief Check if the program is run in valgrind
+///
+/// \return true if valgrind headers are available, and valgrind is running,
+///         false if the headers are not available, or if valgrind is not
+///         running
+bool runningOnValgrind();
+
+} // end namespace unittests
+} // end namespace util
+} // end namespace isc
+
+#endif // UTIL_UNITTESTS_CHECK_VALGRIND_H
diff --git a/src/lib/util/unittests/fork.h b/src/lib/util/unittests/fork.h
index 2d27a11..d5623a7 100644
--- a/src/lib/util/unittests/fork.h
+++ b/src/lib/util/unittests/fork.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_FORK_H
-#define __UTIL_UNITTESTS_FORK_H 1
+#ifndef UTIL_UNITTESTS_FORK_H
+#define UTIL_UNITTESTS_FORK_H 1
 
 #include <unistd.h>
 
@@ -49,4 +49,4 @@ check_output(int *write_pipe, const void *output, const size_t length);
 }
 }
 
-#endif // __UTIL_UNITTESTS_FORK_H
+#endif // UTIL_UNITTESTS_FORK_H
diff --git a/src/lib/util/unittests/mock_socketsession.h b/src/lib/util/unittests/mock_socketsession.h
index 8078265..01ca34f 100644
--- a/src/lib/util/unittests/mock_socketsession.h
+++ b/src/lib/util/unittests/mock_socketsession.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_MOCKSOCKETSESSION_H
-#define __UTIL_UNITTESTS_MOCKSOCKETSESSION_H 1
+#ifndef UTIL_UNITTESTS_MOCKSOCKETSESSION_H
+#define UTIL_UNITTESTS_MOCKSOCKETSESSION_H 1
 
 #include <exceptions/exceptions.h>
 
@@ -147,7 +147,7 @@ private:
 } // end of unittests
 } // end of util
 } // end of isc
-#endif  // __UTIL_UNITTESTS_MOCKSOCKETSESSION_H
+#endif  // UTIL_UNITTESTS_MOCKSOCKETSESSION_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/newhook.h b/src/lib/util/unittests/newhook.h
index c90751e..d2c1385 100644
--- a/src/lib/util/unittests/newhook.h
+++ b/src/lib/util/unittests/newhook.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_NEWHOOK_H
-#define __UTIL_UNITTESTS_NEWHOOK_H 1
+#ifndef UTIL_UNITTESTS_NEWHOOK_H
+#define UTIL_UNITTESTS_NEWHOOK_H 1
 
 /**
  * \file newhook.h
@@ -75,7 +75,7 @@ extern size_t throw_size_on_new;
 }
 }
 
-#endif // __UTIL_UNITTESTS_NEWHOOK_H
+#endif // UTIL_UNITTESTS_NEWHOOK_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/resource.h b/src/lib/util/unittests/resource.h
index 6430ab2..5a266b2 100644
--- a/src/lib/util/unittests/resource.h
+++ b/src/lib/util/unittests/resource.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_RESOURCE_H
-#define __UTIL_UNITTESTS_RESOURCE_H 1
+#ifndef UTIL_UNITTESTS_RESOURCE_H
+#define UTIL_UNITTESTS_RESOURCE_H 1
 
 namespace isc {
 namespace util {
@@ -32,7 +32,7 @@ void dontCreateCoreDumps();
 } // end of namespace util
 } // end of namespace isc
 
-#endif /* __UTIL_UNITTESTS_RESOURCE_H */
+#endif // UTIL_UNITTESTS_RESOURCE_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/run_all.h b/src/lib/util/unittests/run_all.h
index 94c7cb0..2335df7 100644
--- a/src/lib/util/unittests/run_all.h
+++ b/src/lib/util/unittests/run_all.h
@@ -14,8 +14,8 @@
 
 
 
-#ifndef __RUN_ALL_H
-#define __RUN_ALL_H
+#ifndef RUN_ALL_H
+#define RUN_ALL_H
 
 // Avoid need for user to include this header file.
 
@@ -49,4 +49,4 @@ int run_all();
 
 
 
-#endif // __RUN_ALL_H
+#endif // RUN_ALL_H
diff --git a/src/lib/util/unittests/testdata.h b/src/lib/util/unittests/testdata.h
index a452dc6..c7ee707 100644
--- a/src/lib/util/unittests/testdata.h
+++ b/src/lib/util/unittests/testdata.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_TESTDATA_H
-#define __UTIL_UNITTESTS_TESTDATA_H 1
+#ifndef UTIL_UNITTESTS_TESTDATA_H
+#define UTIL_UNITTESTS_TESTDATA_H 1
 
 /**
  * \file testdata.h
@@ -47,7 +47,7 @@ void openTestData(const char* const datafile, std::ifstream& ifs);
 }
 }
 
-#endif // __UTIL_UNITTESTS_TESTDATA_H
+#endif // UTIL_UNITTESTS_TESTDATA_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/textdata.h b/src/lib/util/unittests/textdata.h
index 3e5fe0f..50d09ea 100644
--- a/src/lib/util/unittests/textdata.h
+++ b/src/lib/util/unittests/textdata.h
@@ -18,8 +18,8 @@
 
 #include <gtest/gtest.h>
 
-#ifndef __UTIL_UNITTESTS_TEXTDATA_H
-#define __UTIL_UNITTESTS_TEXTDATA_H 1
+#ifndef UTIL_UNITTESTS_TEXTDATA_H
+#define UTIL_UNITTESTS_TEXTDATA_H 1
 
 /**
  * \file textdata.h
@@ -96,7 +96,7 @@ matchTextData(const std::string& expected_text,
 }
 }
 
-#endif // __UTIL_UNITTESTS_TEXTDATA_H
+#endif // UTIL_UNITTESTS_TEXTDATA_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/util/unittests/wiredata.h b/src/lib/util/unittests/wiredata.h
index a33a03a..a8c519e 100644
--- a/src/lib/util/unittests/wiredata.h
+++ b/src/lib/util/unittests/wiredata.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __UTIL_UNITTESTS_WIREDATA_H
-#define __UTIL_UNITTESTS_WIREDATA_H 1
+#ifndef UTIL_UNITTESTS_WIREDATA_H
+#define UTIL_UNITTESTS_WIREDATA_H 1
 
 #include <cstddef>
 
@@ -38,7 +38,7 @@ void matchWireData(const void* expected_data, std::size_t expected_len,
 }
 }
 
-#endif // __UTIL_UNITTESTS_WIREDATA_H
+#endif // UTIL_UNITTESTS_WIREDATA_H
 
 // Local Variables:
 // mode: c++
diff --git a/src/lib/xfr/xfrout_client.h b/src/lib/xfr/xfrout_client.h
index bad963c..e691fb1 100644
--- a/src/lib/xfr/xfrout_client.h
+++ b/src/lib/xfr/xfrout_client.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef _XFROUT_CLIENT_H
-#define _XFROUT_CLIENT_H
+#ifndef XFROUT_CLIENT_H
+#define XFROUT_CLIENT_H
 
 #include <stdint.h>
 
diff --git a/tests/lettuce/configurations/auth/.gitignore b/tests/lettuce/configurations/auth/.gitignore
new file mode 100644
index 0000000..07f1b7d
--- /dev/null
+++ b/tests/lettuce/configurations/auth/.gitignore
@@ -0,0 +1 @@
+/auth_basic.config
diff --git a/tests/lettuce/configurations/auth/auth_basic.config.orig b/tests/lettuce/configurations/auth/auth_basic.config.orig
new file mode 100644
index 0000000..4067fb1
--- /dev/null
+++ b/tests/lettuce/configurations/auth/auth_basic.config.orig
@@ -0,0 +1,22 @@
+{
+    "version": 2,
+    "Logging": {
+        "loggers": [ {
+            "debuglevel": 99,
+            "severity": "DEBUG",
+            "name": "*"
+        } ]
+    },
+    "Auth": {
+        "listen_on": [ {
+            "port": 47806,
+            "address": "127.0.0.1"
+        } ]
+    },
+    "Boss": {
+        "components": {
+            "b10-auth": { "kind": "needed", "special": "auth" },
+            "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+        }
+    }
+}
diff --git a/tests/lettuce/features/auth_basic.feature b/tests/lettuce/features/auth_basic.feature
new file mode 100644
index 0000000..4667b64
--- /dev/null
+++ b/tests/lettuce/features/auth_basic.feature
@@ -0,0 +1,20 @@
+Feature: Basic Authoritative DNS server
+    This feature set is for testing the execution of the b10-auth
+    component using its default datasource configurations. This
+    will start it and perform queries against it.
+
+    Scenario: Query builtin bind zone
+        Given I have bind10 running with configuration auth/auth_basic.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
+
+        bind10 module Auth should be running
+        And bind10 module Resolver should not be running
+
+        A query for example.com should have rcode REFUSED
+        A query for version.bind type TXT class CH should have rcode NOERROR
+        A query for authors.bind type TXT class CH should have rcode NOERROR
+
+        # TODO: to be compatible with BIND 9
+        # A query for nonexistent.bind type TXT class CH should have rcode REFUSED
diff --git a/tests/lettuce/features/ddns_system.feature b/tests/lettuce/features/ddns_system.feature
index ee3187c..8e279a7 100644
--- a/tests/lettuce/features/ddns_system.feature
+++ b/tests/lettuce/features/ddns_system.feature
@@ -39,7 +39,7 @@ Feature: DDNS System
         # Test 5
         When I use DDNS to set the SOA serial to 1237
         # also check if Auth server reloaded
-        And wait for new bind10 stderr message AUTH_LOAD_ZONE
+        And wait for new bind10 stderr message AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE
         The DDNS response should be SUCCESS
         And the SOA serial for example.org should be 1237
 
@@ -53,11 +53,12 @@ Feature: DDNS System
 
         # Test 8
         When I use DDNS to set the SOA serial to 1238
+        And wait for new bind10 stderr message AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE
         The DDNS response should be SUCCESS
         And the SOA serial for example.org should be 1238
 
         When I use DDNS to set the SOA serial to 1239
-        And wait for new bind10 stderr message AUTH_LOAD_ZONE
+        And wait for new bind10 stderr message AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE
         The DDNS response should be SUCCESS
         And the SOA serial for example.org should be 1239
 
@@ -69,7 +70,7 @@ Feature: DDNS System
 
         # Test 10
         When I use DDNS to set the SOA serial to 1240
-        And wait for new bind10 stderr message AUTH_LOAD_ZONE
+        And wait for new bind10 stderr message AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE
         The DDNS response should be SUCCESS
         And the SOA serial for example.org should be 1240
 
diff --git a/tests/lettuce/features/inmemory_over_sqlite3.feature b/tests/lettuce/features/inmemory_over_sqlite3.feature
index 851caca..7d8ad6d 100644
--- a/tests/lettuce/features/inmemory_over_sqlite3.feature
+++ b/tests/lettuce/features/inmemory_over_sqlite3.feature
@@ -33,7 +33,7 @@ Feature: In-memory zone using SQLite3 backend
         A query for mail.example.org to [::1]:47806 should have rcode NXDOMAIN
         When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
         Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
-        Then wait for new bind10 stderr message AUTH_LOAD_ZONE
+        Then wait for new bind10 stderr message AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE
 
         A query for www.example.org to [::1]:47807 should have rcode NOERROR
         The answer section of the last query response should be
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index 8720e2d..2bfe7d4 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -49,6 +49,8 @@ copylist = [
      "configurations/example.org.config"],
     ["configurations/bindctl/bindctl.config.orig",
      "configurations/bindctl/bindctl.config"],
+    ["configurations/auth/auth_basic.config.orig",
+     "configurations/auth/auth_basic.config"],
     ["configurations/resolver/resolver_basic.config.orig",
      "configurations/resolver/resolver_basic.config"],
     ["configurations/multi_instance/multi_auth.config.orig",
diff --git a/tests/tools/badpacket/command_options.h b/tests/tools/badpacket/command_options.h
index fc819e9..c6f2825 100644
--- a/tests/tools/badpacket/command_options.h
+++ b/tests/tools/badpacket/command_options.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COMMAND_OPTIONS_H
-#define __COMMAND_OPTIONS_H
+#ifndef COMMAND_OPTIONS_H
+#define COMMAND_OPTIONS_H
 
 #include <cstdlib>
 #include <stdint.h>
@@ -159,4 +159,4 @@ private:
 } // namespace badpacket
 } // namespace isc
 
-#endif // __COMMAND_OPTIONS_H
+#endif // COMMAND_OPTIONS_H
diff --git a/tests/tools/badpacket/header_flags.h b/tests/tools/badpacket/header_flags.h
index 5d74e75..71aa64c 100644
--- a/tests/tools/badpacket/header_flags.h
+++ b/tests/tools/badpacket/header_flags.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __HEADER_FLAGS_H
-#define __HEADER_FLAGS_H
+#ifndef HEADER_FLAGS_H
+#define HEADER_FLAGS_H
 
 #include <exceptions/exceptions.h>
 #include "option_info.h"
@@ -99,4 +99,4 @@ private:
 } // namespace badpacket
 } // namespace isc
 
-#endif // __HEADER_FLAGS_H
+#endif // HEADER_FLAGS_H
diff --git a/tests/tools/badpacket/option_info.h b/tests/tools/badpacket/option_info.h
index a340c1d..aebeb66 100644
--- a/tests/tools/badpacket/option_info.h
+++ b/tests/tools/badpacket/option_info.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __OPTION_INFO_H
-#define __OPTION_INFO_H
+#ifndef OPTION_INFO_H
+#define OPTION_INFO_H
 
 #include <stdint.h>
 #include "exceptions/exceptions.h"
@@ -171,4 +171,4 @@ public:
 } // namespace badpacket
 } // namespace isc
 
-#endif // __OPTION_INFO_H
+#endif // OPTION_INFO_H
diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h
index ca56646..40b5bf6 100644
--- a/tests/tools/badpacket/scan.h
+++ b/tests/tools/badpacket/scan.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __SCAN_H
-#define __SCAN_H
+#ifndef SCAN_H
+#define SCAN_H
 
 #include <stdint.h>
 
@@ -195,4 +195,4 @@ private:
 } // namespace test
 } // namespace isc
 
-#endif // __SCAN_H
+#endif // SCAN_H
diff --git a/tests/tools/badpacket/version.h b/tests/tools/badpacket/version.h
index dc59b11..9f7f280 100644
--- a/tests/tools/badpacket/version.h
+++ b/tests/tools/badpacket/version.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __VERSION_H
-#define __VERSION_H
+#ifndef VERSION_H
+#define VERSION_H
 
 namespace isc {
 namespace badpacket {
@@ -23,4 +23,4 @@ static const char* BADPACKET_VERSION = "1.0-1";
 } // namespace badpacket
 } // namespace isc
 
-#endif // __VERSION_H
+#endif // VERSION_H
diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc
index 9aa6abf..9de07ca 100644
--- a/tests/tools/perfdhcp/command_options.cc
+++ b/tests/tools/perfdhcp/command_options.cc
@@ -23,6 +23,7 @@
 
 #include <exceptions/exceptions.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/duid.h>
 #include "command_options.h"
 
 using namespace std;
@@ -567,8 +568,8 @@ CommandOptions::generateDuidTemplate() {
     const uint8_t duid_template_len = 14;
     duid_template_.resize(duid_template_len);
     // The first four octets consist of DUID LLT and hardware type.
-    duid_template_[0] = DUID_LLT >> 8;
-    duid_template_[1] = DUID_LLT & 0xff;
+    duid_template_[0] = static_cast<uint8_t>(static_cast<uint16_t>(isc::dhcp::DUID::DUID_LLT) >> 8);
+    duid_template_[1] = static_cast<uint8_t>(static_cast<uint16_t>(isc::dhcp::DUID::DUID_LLT) & 0xff);
     duid_template_[2] = HWTYPE_ETHERNET >> 8;
     duid_template_[3] = HWTYPE_ETHERNET & 0xff;
 
diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h
index 4668f73..cbb6236 100644
--- a/tests/tools/perfdhcp/command_options.h
+++ b/tests/tools/perfdhcp/command_options.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COMMAND_OPTIONS_H
-#define __COMMAND_OPTIONS_H
+#ifndef COMMAND_OPTIONS_H
+#define COMMAND_OPTIONS_H
 
 #include <string>
 #include <vector>
@@ -462,4 +462,4 @@ private:
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __COMMAND_OPTIONS_H
+#endif // COMMAND_OPTIONS_H
diff --git a/tests/tools/perfdhcp/localized_option.h b/tests/tools/perfdhcp/localized_option.h
index 336e083..2aa270a 100644
--- a/tests/tools/perfdhcp/localized_option.h
+++ b/tests/tools/perfdhcp/localized_option.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __LOCALIZED_OPTION_H
-#define __LOCALIZED_OPTION_H
+#ifndef LOCALIZED_OPTION_H
+#define LOCALIZED_OPTION_H
 
 #include <dhcp/pkt6.h>
 #include <dhcp/option6_ia.h>
@@ -147,4 +147,4 @@ private:
 } // namespace isc::perfdhcp
 } // namespace isc
 
-#endif // __LOCALIZED_OPTION_H
+#endif // LOCALIZED_OPTION_H
diff --git a/tests/tools/perfdhcp/perf_pkt4.h b/tests/tools/perfdhcp/perf_pkt4.h
index 87c7bb0..6f03193 100644
--- a/tests/tools/perfdhcp/perf_pkt4.h
+++ b/tests/tools/perfdhcp/perf_pkt4.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PERF_PKT4_H
-#define __PERF_PKT4_H
+#ifndef PERF_PKT4_H
+#define PERF_PKT4_H
 
 #include <time.h>
 #include <boost/shared_ptr.hpp>
@@ -136,4 +136,4 @@ typedef boost::shared_ptr<PerfPkt4> PerfPkt4Ptr;
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __PERF_PKT4_H
+#endif // PERF_PKT4_H
diff --git a/tests/tools/perfdhcp/perf_pkt6.h b/tests/tools/perfdhcp/perf_pkt6.h
index 25fb4e5..9a8d69b 100644
--- a/tests/tools/perfdhcp/perf_pkt6.h
+++ b/tests/tools/perfdhcp/perf_pkt6.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PERF_PKT6_H
-#define __PERF_PKT6_H
+#ifndef PERF_PKT6_H
+#define PERF_PKT6_H
 
 #include <time.h>
 #include <boost/shared_ptr.hpp>
@@ -136,4 +136,4 @@ typedef boost::shared_ptr<PerfPkt6> PerfPkt6Ptr;
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __PERF_PKT6_H
+#endif // PERF_PKT6_H
diff --git a/tests/tools/perfdhcp/pkt_transform.h b/tests/tools/perfdhcp/pkt_transform.h
index 1f57105..c94e9ba 100644
--- a/tests/tools/perfdhcp/pkt_transform.h
+++ b/tests/tools/perfdhcp/pkt_transform.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __PKT_TRANSFORM_H
-#define __PKT_TRANSFORM_H
+#ifndef PKT_TRANSFORM_H
+#define PKT_TRANSFORM_H
 
 #include <dhcp/option.h>
 
@@ -166,4 +166,4 @@ private:
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __PKT_TRANSFORM_H
+#endif // PKT_TRANSFORM_H
diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h
index 0c2b68c..537e81d 100644
--- a/tests/tools/perfdhcp/stats_mgr.h
+++ b/tests/tools/perfdhcp/stats_mgr.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __STATS_MGR_H
-#define __STATS_MGR_H
+#ifndef STATS_MGR_H
+#define STATS_MGR_H
 
 #include <iostream>
 #include <map>
@@ -1300,4 +1300,4 @@ private:
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __STATS_MGR_H
+#endif // STATS_MGR_H
diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h
index 2bd7871..245cf6d 100644
--- a/tests/tools/perfdhcp/test_control.h
+++ b/tests/tools/perfdhcp/test_control.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __TEST_CONTROL_H
-#define __TEST_CONTROL_H
+#ifndef TEST_CONTROL_H
+#define TEST_CONTROL_H
 
 #include <string>
 #include <vector>
@@ -97,7 +97,7 @@ static const size_t DHCPV6_IA_NA_OFFSET = 40;
 /// accept 'start' and 'stop' arguments. The first time it is called, it is
 /// called with the argument 'start' and the second time with the argument
 /// 'stop'.
-///   
+///
 /// The application is executed by calling fork() to fork the current perfdhcp
 /// process and then call execlp() to replace the current process image with
 /// the new one.
@@ -987,4 +987,4 @@ private:
 } // namespace perfdhcp
 } // namespace isc
 
-#endif // __COMMAND_OPTIONS_H
+#endif // TEST_CONTROL_H
diff --git a/tests/tools/perfdhcp/tests/command_options_helper.h b/tests/tools/perfdhcp/tests/command_options_helper.h
index f9f6d36..7436bd7 100644
--- a/tests/tools/perfdhcp/tests/command_options_helper.h
+++ b/tests/tools/perfdhcp/tests/command_options_helper.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef __COMMAND_OPTIONS_HELPER_H
-#define __COMMAND_OPTIONS_HELPER_H
+#ifndef COMMAND_OPTIONS_HELPER_H
+#define COMMAND_OPTIONS_HELPER_H
 
 #include <string>
 #include <vector>
@@ -136,4 +136,4 @@ private:
 } // namespace isc::perfdhcp
 } // namespace isc
 
-#endif // __COMMAND_OPTIONS_HELPER_H
+#endif // COMMAND_OPTIONS_HELPER_H



More information about the bind10-changes mailing list