BIND 10 master, updated. ce492ecf70bdd3fe483a7f4282e98443f72b6989 [2378] Fix ZoneLoader after merge
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Dec 13 11:17:36 UTC 2012
The branch, master has been updated
via ce492ecf70bdd3fe483a7f4282e98443f72b6989 (commit)
via fd3ff10fe28782177dff77b15293bbb3306522b3 (commit)
via 91d77e0da5203fe0d925d297d448258f40f21099 (commit)
via 27033b59dcaf34216802401f19ec0b51e572b098 (commit)
via af1da46eef54e96be6765922f42a786b84db2014 (commit)
via b8fde1ab760f06e76c06e795b127f66784eb6aa7 (commit)
via 01461d51fa2a533092b135604b33747908891792 (commit)
via a6709a421381c61dae6208d3cc503ef14fbebd43 (commit)
via 807b5a13c25760f09f10bb8ea9242277b8928fdb (commit)
via c1ba429f5eb098d7b1a9498fe11b354bca8283bd (commit)
via 235a1870910da0a8b567bf47c5fc8467d4bcb102 (commit)
via a8326a6fcae7f3b0fb708323750e781221511ffc (commit)
via c9825a5714cebba054619150cc6dc74dee8f94f5 (commit)
via c842187ad91270660a91ac054953649d3f011d54 (commit)
via 86233a2049f66fc932915367dc7f26e499b0303c (commit)
via 62df1d46455dc5cef85adc07031a07fb3d0e4b6b (commit)
via 8743e25c800ac5994e11c932a2196fd8b485a737 (commit)
via c2d2a53b14e6330281b2c519e1bdd129d4de86b5 (commit)
via 9672fb595c581044a01cb4836d33afe6b58f5ab3 (commit)
via 572d3b1ae55ebbca06289bc53035042472a50138 (commit)
via 70f71c5413f70d9cf5716911101e48face70d080 (commit)
via 92ac412b79d7b8c9d802530b9019f4c918d6fdd8 (commit)
via 7631aa8f7c4eeb998deabfdd60a9ee6eeb0d05dc (commit)
via 160677ea7d08e14bd2fc736f2d7b6763ceb2366a (commit)
via 3b1f845a12b4b30ae1cc4c1bdf2af8923995dfca (commit)
via c129951474788781d54007380769ff3eed0f15cf (commit)
via f4f1c1f0006d665f2e2216e3872d82b5ac25334b (commit)
via f77ed1ab54bc60e08292d58fbc4cfc635cd1ef42 (commit)
via 9e8813efff273e390680ccfd1e8893c06a4b5461 (commit)
via 85c5f47252f0db064ece1a00c121cca9519d3b42 (commit)
via 1ba16e4d72f4923946981997fed48eccb786a0e0 (commit)
via d7b4201a3b8daa0937883569b86085c42a8dbe1a (commit)
via 3b1307a0711edb6adb6e2e5532e302b5ce898537 (commit)
via 27597c6b64f541464113088eeac038b33d794096 (commit)
via 612e52448e93d3d5f0645117a0263428a4d5c7ae (commit)
via 1261088d77d3be53d8bc088abe4d4c5d9253dc40 (commit)
via d5137a32591ee4e832354607dea8627ebe1e089c (commit)
via 80de8b943cba0596032073ed443c573b341106af (commit)
via 2f505102370abac68e4b5dd52c39aecbfda41852 (commit)
via 63cce9fa516b2a36e13515013d45e95407ffce36 (commit)
via e6898f852cbff7dc11eecb74bac36d632628c639 (commit)
via ec661eb924e484b0591e155302b1cca5ccda3234 (commit)
via ab0db5a96545dece318f354fcb3317d1358060eb (commit)
via 2edd97ec54d5a3df9e11e5e74188558606e2e3bd (commit)
via b70d80fca2146f8adca9b5c36e0806911097d2d2 (commit)
via 3a2ccbf78e869817a411d735e28425713c220ffa (commit)
via cc62eeca9e859daf93603bc2421f3f2988870d1c (commit)
via e5fb484fbabf454dc0fea14ed4564061555af275 (commit)
via 03911f1000649e0db11d1bbd956b2df5732a5a44 (commit)
via 22d72fe82da9313ecd73bae3efa61788f0b8c7dd (commit)
via f2a0e7ce76ed227a7067919a1f44cb33ccf1e826 (commit)
via e6d402802cf16fb0d3c183ea32658e4e7b6e278b (commit)
via 44f835de6b8c19c7b6ffe755d956d24da061559e (commit)
via 2f3467a4eaeea16afe3119ab6f6628ed1a7f941a (commit)
via 9ea3182d49d0ad15571ea962ae34b68bcf5a200f (commit)
via 3da9d6198bdedd9317b290f70c9bbe613894037b (commit)
via 549e44164f1e4203bf1acb8d6c137f1de5a48f5a (commit)
via fd7f3a84f391957a09996ab869d079b6fe53a9fd (commit)
via 5ec0945ea8abd8ce3aa59aa851421269d9f807d4 (commit)
via 11ed5b5ca1fb48c7754c1d85b65fa00b00630d78 (commit)
via ad9807ad75f8b76413de4ab0478cff9611a2817a (commit)
via 0f6b84e5523df12f5017ef7615bd0bb25359cc5f (commit)
via 42b0cb7bc7423e9f78199ea2f60a449dd98a2843 (commit)
via 2894c45545298103feef9dd0a5f06405d88d67ea (commit)
via 24c515276e5a15558824fa12b8fefc9b80c315d3 (commit)
via cbffb4ac5bf27888553a102ac6ee2a1fbf07642b (commit)
via b548f4ed6cc20a5d8bb802aed646af007c0653b8 (commit)
via c90033f1d91fd82c7bafbe645de95281c46ff46f (commit)
via 7e5b7f352db7ef0778b85dbf73be66210b739b46 (commit)
via 92226343e053027d4abc7a9f2406016d6adfc112 (commit)
via 57fda3f1db7ebbc966ae1ab980409a923196ba5e (commit)
via 8545674c14771700ce0aa611f3fa734082d6e444 (commit)
via 3814969790ec02dceaee88372a977a52bc210199 (commit)
via e4ecc70f8d016e19fb3274a8d2e802cb22b76231 (commit)
via 3a81d2d941bb7f8be0219cc2ec4176c894634237 (commit)
via 425e18f7045e7300230bb2876d69a1ec9837a6bd (commit)
from 550a5e0da25f7b3fa8051d988d70c116490b0f74 (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 ce492ecf70bdd3fe483a7f4282e98443f72b6989
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Dec 13 12:02:05 2012 +0100
[2378] Fix ZoneLoader after merge
There were some small changes in the behaviour of MasterLoader as a
result of review, this is update do ZoneLoader and its tests to
incorporate that.
commit fd3ff10fe28782177dff77b15293bbb3306522b3
Merge: 91d77e0 9672fb5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Dec 13 11:34:55 2012 +0100
Merge doxygen tweaks
Reviewed as part of #2378, but merged as a separate branch.
commit 91d77e0da5203fe0d925d297d448258f40f21099
Merge: 70f71c5 27033b5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Dec 13 11:34:22 2012 +0100
Merge #2378
The Zone loader class (glue class between zone updater and MasterLoader).
commit 27033b59dcaf34216802401f19ec0b51e572b098
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Dec 7 14:09:05 2012 +0100
[2378] Simplify the loadIncremental code
Some of the code can be shared between the variants, saving some code.
commit af1da46eef54e96be6765922f42a786b84db2014
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Dec 7 14:00:49 2012 +0100
[2378] Note about late detection of end
commit b8fde1ab760f06e76c06e795b127f66784eb6aa7
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Dec 5 23:42:31 2012 +0100
[2378] minor doc and comment fixes
commit 01461d51fa2a533092b135604b33747908891792
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Dec 4 13:57:50 2012 +0100
[2378] Fixes of ZoneLoader and tests
After the rebase on top of working 2377. The most significant - don't
access updater if it doesn't exist.
commit a6709a421381c61dae6208d3cc503ef14fbebd43
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Nov 29 15:26:42 2012 +0100
[2378] Implement the master file loading
commit 807b5a13c25760f09f10bb8ea9242277b8928fdb
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Nov 29 15:25:49 2012 +0100
[2378] It would throw at load(), not constructor
There's no way to know the master file would be broken in the
constructor. So update the documentation to say it'd throw from the
load() and loadIncremental().
commit c1ba429f5eb098d7b1a9498fe11b354bca8283bd
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Nov 29 15:21:40 2012 +0100
[2378] Detect class mismatch with copy mode
commit 235a1870910da0a8b567bf47c5fc8467d4bcb102
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 14:36:47 2012 +0100
[2378] Tests for the loading from file
They are similar to the ones for copy mode. Should they be unified in
some way?
commit a8326a6fcae7f3b0fb708323750e781221511ffc
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 14:14:10 2012 +0100
[2378] Consider masterfile errors in ZoneLoader docs
commit c9825a5714cebba054619150cc6dc74dee8f94f5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 14:03:44 2012 +0100
[2378] Test throwing when missing zone
commit c842187ad91270660a91ac054953649d3f011d54
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 13:35:29 2012 +0100
[2378] Test loading signed zone
commit 86233a2049f66fc932915367dc7f26e499b0303c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 13:34:41 2012 +0100
[2378] Fix InMemory iterator
Not directly related, but it breaks tests of the ZoneLoader. The NSEC3
namespace and all RRSIGs were missing from the returned data.
commit 62df1d46455dc5cef85adc07031a07fb3d0e4b6b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 11:34:56 2012 +0100
[2378] Basic test for incremental loading
commit 8743e25c800ac5994e11c932a2196fd8b485a737
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 11:28:23 2012 +0100
[2378] Check attempt to load past the end
commit c2d2a53b14e6330281b2c519e1bdd129d4de86b5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 11:22:21 2012 +0100
[2378] The copy mode of ZoneLoader
At least its basic version. Error handling must still be tested and done.
commit 9672fb595c581044a01cb4836d33afe6b58f5ab3
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 10:39:09 2012 +0100
[Dox] Run doxygen -u
To update the Doxyfile. It no longer complains about obsolete options.
Conflicts:
doc/Doxyfile
commit 572d3b1ae55ebbca06289bc53035042472a50138
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Nov 27 10:33:37 2012 +0100
[Dox] Some Doxyfile tweaks
commit 70f71c5413f70d9cf5716911101e48face70d080
Merge: 550a5e0 92ac412
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Dec 13 11:30:39 2012 +0100
Merge #2377
The isc::dns::MasterLoader class and its basic implementation. Further handling
is going to be added in future branches, this handles just the simplest form of
master files.
-----------------------------------------------------------------------
Summary of changes:
doc/Doxyfile | 623 +++++++++++++++-----
src/lib/datasrc/Makefile.am | 1 +
src/lib/datasrc/master_loader_callbacks.cc | 20 +-
src/lib/datasrc/master_loader_callbacks.h | 2 +-
src/lib/datasrc/memory/memory_client.cc | 55 +-
src/lib/datasrc/tests/Makefile.am | 1 +
.../datasrc/tests/master_loader_callbacks_test.cc | 38 +-
.../datasrc/tests/memory/memory_client_unittest.cc | 19 +
src/lib/datasrc/tests/zone_loader_unittest.cc | 395 +++++++++++++
src/lib/datasrc/zone_loader.cc | 132 +++++
src/lib/datasrc/zone_loader.h | 158 +++++
src/lib/dns/Makefile.am | 1 +
src/lib/dns/master_loader.cc | 278 +++++++++
src/lib/dns/master_loader.h | 133 ++++-
src/lib/dns/master_loader_callbacks.h | 28 +-
src/lib/dns/rrset.h | 3 -
src/lib/dns/tests/Makefile.am | 1 +
src/lib/dns/tests/master_loader_unittest.cc | 341 +++++++++++
src/lib/dns/tests/testdata/Makefile.am | 1 +
src/lib/dns/tests/testdata/example.org | 15 +
20 files changed, 2053 insertions(+), 192 deletions(-)
create mode 100644 src/lib/datasrc/tests/zone_loader_unittest.cc
create mode 100644 src/lib/datasrc/zone_loader.cc
create mode 100644 src/lib/datasrc/zone_loader.h
create mode 100644 src/lib/dns/master_loader.cc
create mode 100644 src/lib/dns/tests/master_loader_unittest.cc
create mode 100644 src/lib/dns/tests/testdata/example.org
-----------------------------------------------------------------------
diff --git a/doc/Doxyfile b/doc/Doxyfile
index fbd082f..5c071c1 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -1,14 +1,14 @@
-# Doxyfile 1.6.1
+# Doxyfile 1.8.2
# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
+# doxygen (www.doxygen.org) for a project.
#
-# All text after a hash (#) is considered a comment and will be ignored
+# All text after a hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
+# Values that contain spaces should be placed between quotes (" ").
#---------------------------------------------------------------------------
# Project related configuration options
@@ -22,8 +22,9 @@
DOXYFILE_ENCODING = UTF-8
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
PROJECT_NAME = BIND10
@@ -31,12 +32,21 @@ PROJECT_NAME = BIND10
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-# Currently this variable is overwritten (see devel target in Makefile.am)
-# If the number of parameters to overwrite increases, we should generate
-# Doxyfile (rename it to Doxyfile.in and generate during configure phase)
-
PROJECT_NUMBER =
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
@@ -61,7 +71,7 @@ CREATE_SUBDIRS = YES
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
@@ -116,7 +126,9 @@ FULL_PATH_NAMES = No
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
STRIP_FROM_PATH =
@@ -130,7 +142,7 @@ STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
+# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
@@ -185,6 +197,13 @@ TAB_SIZE = 4
ALIASES =
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
@@ -211,25 +230,43 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
-# Doxygen selects the parser to use depending on the extension of the files it parses.
-# With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this tag.
-# The format is ext=language, where ext is a file extension, and language is one of
-# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
-# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
-# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
-# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
EXTENSION_MAPPING =
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
+# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
-BUILTIN_STL_SUPPORT = NO
+BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
@@ -242,12 +279,7 @@ CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen to replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = YES
@@ -266,6 +298,22 @@ DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
@@ -282,16 +330,27 @@ TYPEDEF_HIDES_STRUCT = NO
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
+# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
+# corresponding to a cache size of 2^16 = 65536 symbols.
SYMBOL_CACHE_SIZE = 0
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -308,6 +367,11 @@ EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
@@ -330,7 +394,7 @@ EXTRACT_LOCAL_METHODS = NO
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
-# anonymous namespace are hidden.
+# anonymous namespaces are hidden.
EXTRACT_ANON_NSPACES = NO
@@ -376,7 +440,7 @@ INTERNAL_DOCS = NO
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
-CASE_SENSE_NAMES = NO
+CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
@@ -388,12 +452,18 @@ HIDE_SCOPE_NAMES = NO
# will put a list of the files that are included by a file in the documentation
# of that file.
-SHOW_INCLUDE_FILES = NO
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
-INLINE_INFO = NO
+INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
@@ -407,17 +477,23 @@ SORT_MEMBER_DOCS = YES
# by member name. If set to NO (the default) the members will appear in
# declaration order.
-SORT_BRIEF_DOCS = NO
+SORT_BRIEF_DOCS = YES
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-SORT_MEMBERS_CTORS_1ST = NO
+SORT_MEMBERS_CTORS_1ST = YES
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
-SORT_GROUP_NAMES = NO
+SORT_GROUP_NAMES = YES
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to
@@ -429,6 +505,15 @@ SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
@@ -459,10 +544,10 @@ GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
+# the initial value of a variable or macro consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
+# The appearance of the initializer of individual variables and macros in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
@@ -474,12 +559,6 @@ MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES = NO
-
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
@@ -503,15 +582,25 @@ SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
-# doxygen. The layout file controls the global structure of the generated output files
-# in an output format independent way. The create the layout file that represents
-# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
-# file name after the option, if omitted DoxygenLayout.xml will be used as the name
-# of the layout file.
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
@@ -519,7 +608,7 @@ LAYOUT_FILE =
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
-QUIET = NO
+QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
@@ -540,7 +629,7 @@ WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
@@ -572,16 +661,36 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../src/lib/exceptions ../src/lib/cc \
- ../src/lib/config ../src/lib/cryptolink ../src/lib/dns \
- ../src/lib/datasrc ../src/lib/datasrc/memory \
- ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log \
- ../src/lib/log/compiler ../src/lib/asiolink/ ../src/lib/nsas \
- ../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/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/lib/dhcpsrv \
- ../src/bin/dhcp4 ../tests/tools/perfdhcp devel
+INPUT = ../src/lib/exceptions \
+ ../src/lib/cc \
+ ../src/lib/config \
+ ../src/lib/cryptolink \
+ ../src/lib/dns \
+ ../src/lib/datasrc \
+ ../src/lib/datasrc/memory \
+ ../src/bin/auth \
+ ../src/bin/resolver \
+ ../src/lib/bench \
+ ../src/lib/log \
+ ../src/lib/log/compiler \
+ ../src/lib/asiolink/ \
+ ../src/lib/nsas \
+ ../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/lib/statistics \
+ ../src/bin/dhcp6 \
+ ../src/lib/dhcp \
+ ../src/lib/dhcpsrv \
+ ../src/bin/dhcp4 \
+ ../tests/tools/perfdhcp \
+ devel
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -595,10 +704,15 @@ INPUT_ENCODING = UTF-8
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
-FILE_PATTERNS = *.c *.cc *.h *.hpp *.dox
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.h \
+ *.hpp \
+ *.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@@ -606,14 +720,16 @@ FILE_PATTERNS = *.c *.cc *.h *.hpp *.dox
RECURSIVE = NO
-# The EXCLUDE tag can be used to specify files and/or directories that should
+# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
EXCLUDE =
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
@@ -624,7 +740,8 @@ EXCLUDE_SYMLINKS = NO
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
-EXCLUDE_PATTERNS = */*-placeholder.* */cpp/*.py
+EXCLUDE_PATTERNS = */*-placeholder.* \
+ */cpp/*.py
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@@ -677,8 +794,8 @@ INPUT_FILTER =
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
@@ -688,6 +805,14 @@ FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
@@ -697,7 +822,7 @@ FILTER_SOURCE_FILES = NO
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
-SOURCE_BROWSER = NO
+SOURCE_BROWSER = YES
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
@@ -706,7 +831,7 @@ INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
STRIP_CODE_COMMENTS = YES
@@ -790,7 +915,14 @@ HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
HTML_HEADER =
@@ -802,26 +934,79 @@ HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
HTML_STYLESHEET =
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
-HTML_ALIGN_MEMBERS = YES
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
-HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
@@ -831,7 +1016,8 @@ HTML_DYNAMIC_SECTIONS = NO
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
GENERATE_DOCSET = NO
@@ -849,6 +1035,16 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
@@ -893,10 +1089,10 @@ BINARY_TOC = NO
TOC_EXPAND = NO
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
-# are set, an additional index file will be generated that can be used as input for
-# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
-# HTML documentation.
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = NO
@@ -918,20 +1114,24 @@ QHP_NAMESPACE =
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
-# For more information please see
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
@@ -942,16 +1142,30 @@ QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
-DISABLE_INDEX = NO
+GENERATE_ECLIPSEHELP = NO
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
-ENUM_VALUES_PER_LINE = 4
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
@@ -960,13 +1174,17 @@ ENUM_VALUES_PER_LINE = 4
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
GENERATE_TREEVIEW = YES
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
-USE_INLINE_TREES = NO
+ENUM_VALUES_PER_LINE = 4
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
@@ -974,6 +1192,11 @@ USE_INLINE_TREES = NO
TREEVIEW_WIDTH = 180
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
@@ -982,13 +1205,60 @@ TREEVIEW_WIDTH = 180
FORMULA_FONTSIZE = 10
-# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
-# there is already a search function so this one should typically
-# be disabled.
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = NO
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
@@ -1006,6 +1276,9 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
@@ -1022,7 +1295,7 @@ MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
+# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
@@ -1039,6 +1312,13 @@ EXTRA_PACKAGES =
LATEX_HEADER =
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
@@ -1065,10 +1345,19 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -1100,7 +1389,7 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# Load style sheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
@@ -1245,7 +1534,7 @@ MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
SEARCH_INCLUDES = YES
@@ -1275,15 +1564,15 @@ PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = YES
@@ -1291,22 +1580,18 @@ SKIP_FUNCTION_MACROS = YES
# Configuration::additions related to external references
#---------------------------------------------------------------------------
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
#
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
TAGFILES =
@@ -1339,9 +1624,8 @@ PERL_PATH = /usr/bin/perl
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
CLASS_DIAGRAMS = YES
@@ -1367,14 +1651,20 @@ HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
DOT_FONTNAME = FreeSans
@@ -1383,17 +1673,16 @@ DOT_FONTNAME = FreeSans
DOT_FONTSIZE = 10
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
DOT_FONTPATH =
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
+# CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
@@ -1415,6 +1704,15 @@ GROUP_GRAPHS = YES
UML_LOOK = NO
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
@@ -1451,11 +1749,11 @@ CALL_GRAPH = NO
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
+# will generate a graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
@@ -1463,11 +1761,22 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
DOT_IMAGE_FORMAT = png
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
@@ -1479,6 +1788,12 @@ DOT_PATH =
DOTFILE_DIRS =
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index f4e768a..340c4f4 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -38,6 +38,7 @@ libb10_datasrc_la_SOURCES += client_list.h client_list.cc
libb10_datasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
libb10_datasrc_la_SOURCES += master_loader_callbacks.h
libb10_datasrc_la_SOURCES += master_loader_callbacks.cc
+libb10_datasrc_la_SOURCES += zone_loader.h zone_loader.cc
nodist_libb10_datasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
libb10_datasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
diff --git a/src/lib/datasrc/master_loader_callbacks.cc b/src/lib/datasrc/master_loader_callbacks.cc
index 54e4d0e..04b8940 100644
--- a/src/lib/datasrc/master_loader_callbacks.cc
+++ b/src/lib/datasrc/master_loader_callbacks.cc
@@ -48,6 +48,19 @@ logWarning(const isc::dns::Name& name, const isc::dns::RRClass& rrclass,
arg(name).arg(rrclass).arg(reason);
}
+void
+addRR(const isc::dns::Name& name, const isc::dns::RRClass& rrclass,
+ const isc::dns::RRType& type, const isc::dns::RRTTL& ttl,
+ const isc::dns::rdata::RdataPtr& data, ZoneUpdater* updater)
+{
+ // We get description of one RR. The updater takes RRset, so we
+ // wrap it up and push there. It should collate the RRsets of the
+ // same name and type together, since the addRRset should "merge".
+ isc::dns::BasicRRset rrset(name, rrclass, type, ttl);
+ rrset.addRdata(data);
+ updater->addRRset(rrset);
+}
+
}
isc::dns::MasterLoaderCallbacks
@@ -61,12 +74,9 @@ createMasterLoaderCallbacks(const isc::dns::Name& name,
rrclass, _1, _2, _3)));
}
-isc::dns::AddRRsetCallback
+isc::dns::AddRRCallback
createMasterLoaderAddCallback(ZoneUpdater& updater) {
- return (boost::bind(&ZoneUpdater::addRRset, &updater,
- // The callback provides a shared pointer, we
- // need the object. This bind unpacks the object.
- boost::bind(&isc::dns::RRsetPtr::operator*, _1)));
+ return (boost::bind(addRR, _1, _2, _3, _4, _5, &updater));
}
}
diff --git a/src/lib/datasrc/master_loader_callbacks.h b/src/lib/datasrc/master_loader_callbacks.h
index c258303..ae827c9 100644
--- a/src/lib/datasrc/master_loader_callbacks.h
+++ b/src/lib/datasrc/master_loader_callbacks.h
@@ -58,7 +58,7 @@ createMasterLoaderCallbacks(const isc::dns::Name& name,
/// \param updater The zone updater to use.
/// \return The callback to be passed to MasterLoader.
/// \throw std::bad_alloc when allocation fails.
-isc::dns::AddRRsetCallback
+isc::dns::AddRRCallback
createMasterLoaderAddCallback(ZoneUpdater& updater);
}
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 65e1e3b..66e61a2 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -209,14 +209,20 @@ private:
RdataIteratorPtr rdata_iterator_;
bool separate_rrs_;
bool ready_;
+ bool examined_rrsigs_;
+ // In case there's nsec3 namespace in the zone, it is represented the same
+ // way as the usual namespace. So we reuse the iterator implementation for
+ // it.
+ ZoneIteratorPtr nsec3_namespace_;
public:
MemoryIterator(const RRClass& rrclass,
- const ZoneTree& tree, const Name& origin,
- bool separate_rrs) :
+ const ZoneTree& tree, const NSEC3Data* nsec3_data,
+ const Name& origin, bool separate_rrs) :
rrclass_(rrclass),
tree_(tree),
separate_rrs_(separate_rrs),
- ready_(true)
+ ready_(true),
+ examined_rrsigs_(false)
{
// Find the first node (origin) and preserve the node chain for future
// searches
@@ -235,10 +241,25 @@ public:
rdata_iterator_ = rrset_->getRdataIterator();
}
}
+
+ // If we have the NSEC3 namespace, get an iterator for it so we can
+ // delegate to it later.
+ if (nsec3_data != NULL) {
+ nsec3_namespace_ =
+ ZoneIteratorPtr(new MemoryIterator(rrclass,
+ nsec3_data->getNSEC3Tree(),
+ NULL, origin,
+ separate_rrs));
+ }
}
virtual ConstRRsetPtr getNextRRset() {
if (!ready_) {
+ // We are done iterating. But in case there's the nsec3 one,
+ // iterate through that one.
+ if (nsec3_namespace_ != ZoneIteratorPtr()) {
+ return (nsec3_namespace_->getNextRRset());
+ }
isc_throw(Unexpected, "Iterating past the zone end");
}
/*
@@ -259,13 +280,19 @@ public:
rrset_.reset(new TreeNodeRRset(rrclass_,
node_, set_node_, true));
rdata_iterator_ = rrset_->getRdataIterator();
+ examined_rrsigs_ = false;
}
}
}
if (node_ == NULL) {
// That's all, folks
ready_ = false;
- return (ConstRRsetPtr());
+ if (nsec3_namespace_ != ZoneIteratorPtr()) {
+ // In case we have the NSEC3 namespace, get one from there.
+ return (nsec3_namespace_->getNextRRset());
+ } else {
+ return (ConstRRsetPtr());
+ }
}
if (separate_rrs_) {
@@ -273,10 +300,24 @@ public:
// 'current' rdata
RRsetPtr result(new RRset(rrset_->getName(),
rrset_->getClass(),
- rrset_->getType(),
+ // If we are looking into the signature,
+ // we need to adjust the type too.
+ examined_rrsigs_ ? RRType::RRSIG() :
+ rrset_->getType(),
rrset_->getTTL()));
result->addRdata(rdata_iterator_->getCurrent());
rdata_iterator_->next();
+ if (!examined_rrsigs_ && rdata_iterator_->isLast()) {
+ // We got to the last RR of the RRset, but we need to look at
+ // the signatures too, if there are any.
+ examined_rrsigs_ = true;
+ const ConstRRsetPtr rrsig = rrset_->getRRsig();
+ if (rrsig != ConstRRsetPtr()) {
+ rrset_ = rrsig;
+ rdata_iterator_ = rrsig->getRdataIterator();
+ } // else - no RRSIG. rdata_iterator_ stays at last, next
+ // condition applies
+ }
if (rdata_iterator_->isLast()) {
// all used up, next.
set_node_ = set_node_->getNext();
@@ -286,6 +327,7 @@ public:
rrset_.reset(new TreeNodeRRset(rrclass_,
node_, set_node_, true));
rdata_iterator_ = rrset_->getRdataIterator();
+ examined_rrsigs_ = false;
}
}
return (result);
@@ -317,7 +359,8 @@ InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
return (ZoneIteratorPtr(new MemoryIterator(
getClass(),
- result.zone_data->getZoneTree(), name,
+ result.zone_data->getZoneTree(),
+ result.zone_data->getNSEC3Data(), name,
separate_rrs)));
}
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index d3ef3bf..61858bd 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -60,6 +60,7 @@ run_unittests_SOURCES += zone_finder_context_unittest.cc
run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
run_unittests_SOURCES += client_list_unittest.cc
run_unittests_SOURCES += master_loader_callbacks_test.cc
+run_unittests_SOURCES += zone_loader_unittest.cc
# We need the actual module implementation in the tests (they are not part
# of libdatasrc)
diff --git a/src/lib/datasrc/tests/master_loader_callbacks_test.cc b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
index f814288..19ec4d2 100644
--- a/src/lib/datasrc/tests/master_loader_callbacks_test.cc
+++ b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
@@ -18,6 +18,9 @@
#include <dns/rrset.h>
#include <dns/rrclass.h>
#include <dns/rrttl.h>
+#include <dns/rdata.h>
+
+#include <testutils/dnsmessage_test.h>
#include <exceptions/exceptions.h>
@@ -40,8 +43,21 @@ public:
// the correct ones, according to a predefined set in a list.
virtual void addRRset(const isc::dns::AbstractRRset& rrset) {
ASSERT_FALSE(expected_rrsets_.empty());
- // In our tests, pointer equality is enough.
- EXPECT_EQ(expected_rrsets_.front().get(), &rrset);
+
+ // As the rrsetCheck requires a shared pointer, we need to create
+ // a copy.
+ isc::dns::RRsetPtr copy(new isc::dns::BasicRRset(rrset.getName(),
+ rrset.getClass(),
+ rrset.getType(),
+ rrset.getTTL()));
+ EXPECT_FALSE(rrset.getRRsig()) << "Unexpected RRSIG on rrset, not "
+ "copying. Following check will likely fail as a result.";
+ for (isc::dns::RdataIteratorPtr it(rrset.getRdataIterator());
+ !it->isLast(); it->next()) {
+ copy->addRdata(it->getCurrent());
+ }
+
+ isc::testutils::rrsetCheck(expected_rrsets_.front(), copy);
// And remove this RRset, as it has been used.
expected_rrsets_.pop_front();
}
@@ -67,14 +83,22 @@ protected:
isc::dns::RRClass::IN(), &ok_))
{}
// Generate a new RRset, put it to the updater and return it.
- isc::dns::RRsetPtr generateRRset() {
+ void generateRRset(isc::dns::AddRRCallback callback) {
const isc::dns::RRsetPtr
result(new isc::dns::RRset(isc::dns::Name("example.org"),
isc::dns::RRClass::IN(),
isc::dns::RRType::A(),
isc::dns::RRTTL(3600)));
+ const isc::dns::rdata::RdataPtr
+ data(isc::dns::rdata::createRdata(isc::dns::RRType::A(),
+ isc::dns::RRClass::IN(),
+ "192.0.2.1"));
+
+ result->addRdata(data);
updater_.expected_rrsets_.push_back(result);
- return (result);
+
+ callback(result->getName(), result->getClass(), result->getType(),
+ result->getTTL(), data);
}
// An updater to be passed to the context
MockUpdater updater_;
@@ -112,11 +136,11 @@ TEST_F(MasterLoaderCallbackTest, callbacks) {
// Try adding some RRsets.
TEST_F(MasterLoaderCallbackTest, addRRset) {
- isc::dns::AddRRsetCallback
+ isc::dns::AddRRCallback
callback(createMasterLoaderAddCallback(updater_));
// Put some of them in.
- EXPECT_NO_THROW(callback(generateRRset()));
- EXPECT_NO_THROW(callback(generateRRset()));
+ EXPECT_NO_THROW(generateRRset(callback));
+ EXPECT_NO_THROW(generateRRset(callback));
// They all get pushed there right away, so there are none in the queue
EXPECT_TRUE(updater_.expected_rrsets_.empty());
}
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 2a9a35d..0a03645 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -690,6 +690,25 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
EXPECT_EQ(ConstRRsetPtr(), iterator2->getNextRRset());
}
+// Test we get RRSIGs and NSEC3s too for iterating with separate RRs
+TEST_F(MemoryClientTest, getIteratorSeparateSigned) {
+ client_->load(Name("example.org"),
+ TEST_DATA_DIR "/example.org-nsec3-signed.zone");
+ ZoneIteratorPtr iterator(client_->getIterator(Name("example.org"), true));
+ bool seen_rrsig = false, seen_nsec3 = false;
+ for (ConstRRsetPtr rrset = iterator->getNextRRset();
+ rrset != ConstRRsetPtr(); rrset = iterator->getNextRRset()) {
+ if (rrset->getType() == RRType::RRSIG()) {
+ seen_rrsig = true;
+ } else if (rrset->getType() == RRType::NSEC3()) {
+ seen_nsec3 = true;
+ }
+ }
+
+ EXPECT_TRUE(seen_rrsig);
+ EXPECT_TRUE(seen_nsec3);
+}
+
TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
diff --git a/src/lib/datasrc/tests/zone_loader_unittest.cc b/src/lib/datasrc/tests/zone_loader_unittest.cc
new file mode 100644
index 0000000..b19a843
--- /dev/null
+++ b/src/lib/datasrc/tests/zone_loader_unittest.cc
@@ -0,0 +1,395 @@
+// 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/zone_loader.h>
+#include <datasrc/data_source.h>
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/memory_client.h>
+
+#include <dns/rrclass.h>
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <util/memory_segment_local.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+using isc::dns::RRClass;
+using isc::dns::Name;
+using isc::dns::RRType;
+using isc::dns::ConstRRsetPtr;
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+using namespace isc::datasrc;
+
+namespace {
+
+class MockClient : public DataSourceClient {
+public:
+ MockClient() :
+ commit_called_(false),
+ missing_zone_(false),
+ rrclass_(RRClass::IN())
+ {}
+ virtual FindResult findZone(const Name&) const {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ };
+ virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
+ getJournalReader(const Name&, uint32_t, uint32_t) const
+ {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ virtual ZoneUpdaterPtr getUpdater(const Name& name, bool replace,
+ bool journaling) const;
+ // We store some information about what was happening here.
+ // It is publicly accessible, since this is private testing class
+ // anyway, so no need to dress it fancy into getters. Some are mutable,
+ // since many client methods are const, but we still want to know they
+ // were called.
+ mutable vector<Name> provided_updaters_;
+ // We store string representations of the RRsets. This is simpler than
+ // copying them and we can't really put them into shared pointers, because
+ // we get them as references.
+ vector<string> rrsets_;
+ bool commit_called_;
+ // If set to true, getUpdater returns NULL
+ bool missing_zone_;
+ // The pretended class of the client. Usualy IN, but can be overriden.
+ RRClass rrclass_;
+};
+
+// The updater isn't really correct according to the API. For example,
+// the whole client can be committed only once in its lifetime. The
+// updaters would influence each other if there were more. But we
+// don't need more updaters in the same test, so it doesn't matter
+// and this way, it is much simpler.
+class Updater : public ZoneUpdater {
+public:
+ Updater(MockClient* client) :
+ client_(client),
+ finder_(client_->rrclass_)
+ {}
+ virtual ZoneFinder& getFinder() {
+ return (finder_);
+ }
+ virtual void addRRset(const isc::dns::AbstractRRset& rrset) {
+ if (client_->commit_called_) {
+ isc_throw(DataSourceError, "Add after commit");
+ }
+ client_->rrsets_.push_back(rrset.toText());
+ }
+ virtual void deleteRRset(const isc::dns::AbstractRRset&) {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ virtual void commit() {
+ client_->commit_called_ = true;
+ }
+private:
+ MockClient* client_;
+ class Finder : public ZoneFinder {
+ public:
+ Finder(const RRClass& rrclass) :
+ class_(rrclass)
+ {}
+ virtual RRClass getClass() const {
+ return (class_);
+ }
+ virtual Name getOrigin() const {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ virtual shared_ptr<Context> find(const Name&, const RRType&,
+ const FindOptions)
+ {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ virtual shared_ptr<Context> findAll(const Name&,
+ vector<ConstRRsetPtr>&,
+ const FindOptions)
+ {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ virtual FindNSEC3Result findNSEC3(const Name&, bool) {
+ isc_throw(isc::NotImplemented, "Method not used in tests");
+ }
+ private:
+ const RRClass class_;
+ } finder_;
+};
+
+ZoneUpdaterPtr
+MockClient::getUpdater(const Name& name, bool replace, bool journaling) const {
+ if (missing_zone_) {
+ return (ZoneUpdaterPtr());
+ }
+ EXPECT_TRUE(replace);
+ EXPECT_FALSE(journaling);
+ provided_updaters_.push_back(name);
+ // const_cast is bad. But the const on getUpdater seems wrong in the first
+ // place, since updater will be modifying the data there. And the updater
+ // wants to store data into the client so we can examine it later.
+ return (ZoneUpdaterPtr(new Updater(const_cast<MockClient*>(this))));
+}
+
+class ZoneLoaderTest : public ::testing::Test {
+protected:
+ ZoneLoaderTest() :
+ rrclass_(RRClass::IN()),
+ ztable_segment_(memory::ZoneTableSegment::
+ create(isc::data::NullElement(), rrclass_)),
+ source_client_(ztable_segment_, rrclass_)
+ {}
+ void prepareSource(const Name& zone, const char* filename) {
+ // TODO:
+ // Currently, load uses an urelated implementation. In the long term,
+ // the method will probably be deprecated. At that time, we should
+ // probably prepare the data in some other way (using sqlite3 or
+ // something). This is simpler for now.
+ source_client_.load(zone, string(TEST_DATA_DIR) + "/" + filename);
+ }
+private:
+ const RRClass rrclass_;
+ // This is because of the in-memory client. We use it to read data
+ // from. It is still easier than setting up sqlite3 client, since
+ // we have this one in the linked library.
+
+ // FIXME: We should be destroying it by ZoneTableSegment::destroy.
+ // But the shared pointer won't let us, will it?
+ shared_ptr<memory::ZoneTableSegment> ztable_segment_;
+protected:
+ memory::InMemoryClient source_client_;
+ // This one is mocked. It will help us see what is happening inside.
+ // Also, mocking it is simpler than setting up an sqlite3 client.
+ MockClient destination_client_;
+};
+
+// Use the loader to load an unsigned zone.
+TEST_F(ZoneLoaderTest, copyUnsigned) {
+ prepareSource(Name::ROOT_NAME(), "root.zone");
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(), source_client_);
+ // It gets the updater directly in the constructor
+ ASSERT_EQ(1, destination_client_.provided_updaters_.size());
+ EXPECT_EQ(Name::ROOT_NAME(), destination_client_.provided_updaters_[0]);
+ // Now load the whole zone
+ loader.load();
+ EXPECT_TRUE(destination_client_.commit_called_);
+ // We don't check the whole zone. We check the first and last and the
+ // count, which should be enough.
+
+ // The count is 34 because we expect the RRs to be separated.
+ EXPECT_EQ(34, destination_client_.rrsets_.size());
+ // Ensure known order.
+ std::sort(destination_client_.rrsets_.begin(),
+ destination_client_.rrsets_.end());
+ EXPECT_EQ(". 518400 IN NS a.root-servers.net.\n",
+ destination_client_.rrsets_.front());
+ EXPECT_EQ("m.root-servers.net. 3600000 IN AAAA 2001:dc3::35\n",
+ destination_client_.rrsets_.back());
+
+ // It isn't possible to try again now
+ EXPECT_THROW(loader.load(), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
+ // Even 0, which should load nothing, returns the error
+ EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
+}
+
+// Try loading incrementally.
+TEST_F(ZoneLoaderTest, copyUnsignedIncremental) {
+ prepareSource(Name::ROOT_NAME(), "root.zone");
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(), source_client_);
+
+ // Try loading few RRs first.
+ loader.loadIncremental(10);
+ // We should get the 10 we asked for
+ EXPECT_EQ(10, destination_client_.rrsets_.size());
+ // Not committed yet, we didn't complete the loading
+ EXPECT_FALSE(destination_client_.commit_called_);
+
+ // This is unusual, but allowed. Check it doesn't do anything
+ loader.loadIncremental(0);
+ EXPECT_EQ(10, destination_client_.rrsets_.size());
+ EXPECT_FALSE(destination_client_.commit_called_);
+
+ // We can finish the rest
+ loader.loadIncremental(30);
+ EXPECT_EQ(34, destination_client_.rrsets_.size());
+ EXPECT_TRUE(destination_client_.commit_called_);
+
+ // No more loading now
+ EXPECT_THROW(loader.load(), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
+}
+
+// Check we can load RRSIGs and NSEC3 (which could break due to them being
+// in separate namespace)
+TEST_F(ZoneLoaderTest, copySigned) {
+ prepareSource(Name("example.org"), "example.org.nsec3-signed");
+ ZoneLoader loader(destination_client_, Name("example.org"),
+ source_client_);
+ loader.load();
+
+ // All the RRs are there, including the ones in NSEC3 namespace
+ EXPECT_EQ(14, destination_client_.rrsets_.size());
+ EXPECT_TRUE(destination_client_.commit_called_);
+ // Same trick with sorting to know where they are
+ std::sort(destination_client_.rrsets_.begin(),
+ destination_client_.rrsets_.end());
+ // Due to the R at the beginning, this one should be last
+ EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
+ "1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG\n",
+ destination_client_.rrsets_[0]);
+ EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
+ "NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
+ " EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
+ "KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
+ "/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=\n",
+ destination_client_.rrsets_[1]);
+}
+
+// If the destination zone does not exist, it throws
+TEST_F(ZoneLoaderTest, copyMissingDestination) {
+ destination_client_.missing_zone_ = true;
+ prepareSource(Name::ROOT_NAME(), "root.zone");
+ EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
+ source_client_), DataSourceError);
+}
+
+// If the source zone does not exist, it throws
+TEST_F(ZoneLoaderTest, copyMissingSource) {
+ EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
+ source_client_), DataSourceError);
+}
+
+// The class of the source and destination are different
+TEST_F(ZoneLoaderTest, classMismatch) {
+ destination_client_.rrclass_ = RRClass::CH();
+ prepareSource(Name::ROOT_NAME(), "root.zone");
+ EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
+ source_client_), isc::InvalidParameter);
+}
+
+// Load an unsigned zone, all at once
+TEST_F(ZoneLoaderTest, loadUnsigned) {
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
+ TEST_DATA_DIR "/root.zone");
+ // It gets the updater directly in the constructor
+ ASSERT_EQ(1, destination_client_.provided_updaters_.size());
+ EXPECT_EQ(Name::ROOT_NAME(), destination_client_.provided_updaters_[0]);
+ // Now load the whole zone
+ loader.load();
+ EXPECT_TRUE(destination_client_.commit_called_);
+ // We don't check the whole zone. We check the first and last and the
+ // count, which should be enough.
+
+ // The count is 34 because we expect the RRs to be separated.
+ EXPECT_EQ(34, destination_client_.rrsets_.size());
+ // Ensure known order.
+ std::sort(destination_client_.rrsets_.begin(),
+ destination_client_.rrsets_.end());
+ EXPECT_EQ(". 518400 IN NS a.root-servers.net.\n",
+ destination_client_.rrsets_.front());
+ EXPECT_EQ("m.root-servers.net. 3600000 IN AAAA 2001:dc3::35\n",
+ destination_client_.rrsets_.back());
+
+ // It isn't possible to try again now
+ EXPECT_THROW(loader.load(), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
+ // Even 0, which should load nothing, returns the error
+ EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
+}
+
+// Try loading from master file incrementally.
+TEST_F(ZoneLoaderTest, loadUnsignedIncremental) {
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
+ TEST_DATA_DIR "/root.zone");
+
+ // Try loading few RRs first.
+ loader.loadIncremental(10);
+ // We should get the 10 we asked for
+ EXPECT_EQ(10, destination_client_.rrsets_.size());
+ // Not committed yet, we didn't complete the loading
+ EXPECT_FALSE(destination_client_.commit_called_);
+
+ EXPECT_EQ(10, destination_client_.rrsets_.size());
+ EXPECT_FALSE(destination_client_.commit_called_);
+
+ // We can finish the rest
+ loader.loadIncremental(30);
+ EXPECT_EQ(34, destination_client_.rrsets_.size());
+ EXPECT_TRUE(destination_client_.commit_called_);
+
+ // No more loading now
+ EXPECT_THROW(loader.load(), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
+ EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
+}
+
+// If the destination zone does not exist, it throws
+TEST_F(ZoneLoaderTest, loadMissingDestination) {
+ destination_client_.missing_zone_ = true;
+ EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
+ TEST_DATA_DIR "/root.zone"), DataSourceError);
+}
+
+// Check we can load RRSIGs and NSEC3 (which could break due to them being
+// in separate namespace)
+TEST_F(ZoneLoaderTest, loadSigned) {
+ ZoneLoader loader(destination_client_, Name("example.org"),
+ TEST_DATA_DIR "/example.org.nsec3-signed");
+ loader.load();
+
+ // All the RRs are there, including the ones in NSEC3 namespace
+ EXPECT_EQ(14, destination_client_.rrsets_.size());
+ EXPECT_TRUE(destination_client_.commit_called_);
+ // Same trick with sorting to know where they are
+ std::sort(destination_client_.rrsets_.begin(),
+ destination_client_.rrsets_.end());
+ // Due to the R at the beginning, this one should be last
+ EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
+ "1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG\n",
+ destination_client_.rrsets_[0]);
+ EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
+ "NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
+ " EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
+ "KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
+ "/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=\n",
+ destination_client_.rrsets_[1]);
+}
+
+// Test it throws when there's no such file
+TEST_F(ZoneLoaderTest, loadNoSuchFile) {
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
+ "This file does not exist");
+ EXPECT_THROW(loader.load(), MasterFileError);
+ EXPECT_FALSE(destination_client_.commit_called_);
+}
+
+// And it also throws when there's a syntax error in the master file
+TEST_F(ZoneLoaderTest, loadSyntaxError) {
+ ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
+ // This is not a master file for sure
+ // (misusing a file that happens to be there
+ // already).
+ TEST_DATA_DIR "/example.org.sqlite3");
+ EXPECT_THROW(loader.load(), MasterFileError);
+ EXPECT_FALSE(destination_client_.commit_called_);
+}
+
+}
diff --git a/src/lib/datasrc/zone_loader.cc b/src/lib/datasrc/zone_loader.cc
new file mode 100644
index 0000000..01f216e
--- /dev/null
+++ b/src/lib/datasrc/zone_loader.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 <datasrc/zone_loader.h>
+#include <datasrc/master_loader_callbacks.h>
+
+#include <datasrc/client.h>
+#include <datasrc/data_source.h>
+#include <datasrc/iterator.h>
+#include <datasrc/zone.h>
+
+#include <dns/rrset.h>
+
+using isc::dns::Name;
+using isc::dns::ConstRRsetPtr;
+using isc::dns::MasterLoader;
+
+namespace isc {
+namespace datasrc {
+
+ZoneLoader::ZoneLoader(DataSourceClient& destination, const Name& zone_name,
+ DataSourceClient& source) :
+ // Separate the RRsets as that is possibly faster (the data source doesn't
+ // have to aggregate them) and also because our limit semantics.
+ iterator_(source.getIterator(zone_name, true)),
+ updater_(destination.getUpdater(zone_name, true, false)),
+ complete_(false)
+{
+ // The getIterator should never return NULL. So we check it.
+ // Or should we throw instead?
+ assert(iterator_ != ZoneIteratorPtr());
+ // In case the zone doesn't exist in the destination, throw
+ if (updater_ == ZoneUpdaterPtr()) {
+ isc_throw(DataSourceError, "Zone " << zone_name << " not found in "
+ "destination data source, can't fill it with data");
+ }
+ // The dereference of zone_finder is safe, if we can get iterator, we can
+ // get a finder.
+ //
+ // TODO: We probably need a getClass on the data source itself.
+ if (source.findZone(zone_name).zone_finder->getClass() !=
+ updater_->getFinder().getClass()) {
+ isc_throw(isc::InvalidParameter,
+ "Source and destination class mismatch");
+ }
+}
+
+ZoneLoader::ZoneLoader(DataSourceClient& destination, const Name& zone_name,
+ const char* filename) :
+ updater_(destination.getUpdater(zone_name, true, false)),
+ complete_(false),
+ loaded_ok_(true)
+{
+ if (updater_ == ZoneUpdaterPtr()) {
+ isc_throw(DataSourceError, "Zone " << zone_name << " not found in "
+ "destination data source, can't fill it with data");
+ } else {
+ loader_.reset(new
+ MasterLoader(filename, zone_name,
+ // TODO: Maybe we should have getClass()
+ // on the data source?
+ updater_->getFinder().getClass(),
+ createMasterLoaderCallbacks(zone_name,
+ updater_->getFinder().getClass(),
+ &loaded_ok_),
+ createMasterLoaderAddCallback(*updater_)));
+ }
+}
+
+namespace {
+
+// Copy up to limit RRsets from source to destination
+bool
+copyRRsets(const ZoneUpdaterPtr& destination, const ZoneIteratorPtr& source,
+ size_t limit)
+{
+ size_t loaded = 0;
+ while (loaded < limit) {
+ const ConstRRsetPtr rrset(source->getNextRRset());
+ if (rrset == ConstRRsetPtr()) {
+ // Done loading, no more RRsets in the input.
+ return (true);
+ } else {
+ destination->addRRset(*rrset);
+ }
+ ++loaded;
+ }
+ return (false); // Not yet, there may be more
+}
+
+} // end unnamed namespace
+
+bool
+ZoneLoader::loadIncremental(size_t limit) {
+ if (complete_) {
+ isc_throw(isc::InvalidOperation,
+ "Loading has been completed previously");
+ }
+
+ if (iterator_ == ZoneIteratorPtr()) {
+ assert(loader_.get() != NULL);
+ try {
+ complete_ = loader_->loadIncremental(limit);
+ } catch (const isc::dns::MasterLoaderError& e) {
+ isc_throw(MasterFileError, e.getMessage().c_str());
+ }
+ if (complete_ && !loaded_ok_) {
+ isc_throw(MasterFileError, "Error while loading master file");
+ }
+ } else {
+ complete_ = copyRRsets(updater_, iterator_, limit);
+ }
+
+ if (complete_) {
+ updater_->commit();
+ }
+ return (complete_);
+}
+
+} // end namespace datasrc
+} // end namespace isc
diff --git a/src/lib/datasrc/zone_loader.h b/src/lib/datasrc/zone_loader.h
new file mode 100644
index 0000000..2946116
--- /dev/null
+++ b/src/lib/datasrc/zone_loader.h
@@ -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.
+
+#ifndef DATASRC_ZONE_LOADER_H
+#define DATASRC_ZONE_LOADER_H
+
+#include <datasrc/data_source.h>
+
+#include <dns/master_loader.h>
+
+#include <cstdlib> // For size_t
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+
+namespace isc {
+namespace dns {
+// Forward declaration
+class Name;
+}
+namespace datasrc {
+
+// Forward declarations
+class DataSourceClient;
+class ZoneIterator;
+typedef boost::shared_ptr<ZoneIterator> ZoneIteratorPtr;
+class ZoneUpdater;
+typedef boost::shared_ptr<ZoneUpdater> ZoneUpdaterPtr;
+
+/// \brief Exception thrown when there's a problem with master file.
+///
+/// This is thrown by the ZoneLoader when there's a fatal problem with
+/// a master file being loaded.
+class MasterFileError : public DataSourceError {
+public:
+ MasterFileError(const char* file, size_t line, const char* what) :
+ DataSourceError(file, line, what)
+ {}
+};
+
+/// \brief Class to load data into a data source client.
+///
+/// This is a small wrapper class that is able to load data into a data source.
+/// It can load either from another data source or from a master file. The
+/// purpose of the class is only to hold the state for incremental loading.
+///
+/// The old content of zone is discarded and no journal is stored.
+class ZoneLoader {
+public:
+ /// \brief Constructor from master file.
+ ///
+ /// This initializes the zone loader to load from a master file.
+ ///
+ /// \param destination The data source into which the loaded data should
+ /// go.
+ /// \param zone_name The origin of the zone. The class is implicit in the
+ /// destination.
+ /// \param master_file Path to the master file to read data from.
+ /// \throw DataSourceError in case the zone does not exist in destination.
+ /// This class does not support creating brand new zones, only loading
+ /// data into them. In case a new zone is needed, it must be created
+ /// beforehand.
+ /// \throw DataSourceError in case of other (possibly low-level) errors,
+ /// such as read-only data source or database error.
+ ZoneLoader(DataSourceClient& destination, const isc::dns::Name& zone_name,
+ const char* master_file);
+
+ /// \brief Constructor from another data source.
+ ///
+ /// This initializes the zone loader to read from another data source.
+ /// It'll effectively copy data from one data source to another.
+ ///
+ /// \param destination The data source into which the loaded data should
+ /// go.
+ /// \param zone_name The origin of the zone.
+ /// \param source The data source from which the data would be read.
+ /// \throw InvalidParameter in case the class of destination and source
+ /// differs.
+ /// \throw NotImplemented in case the source data source client doesn't
+ /// provide an iterator.
+ /// \throw DataSourceError in case the zone does not exist in destination.
+ /// This class does not support creating brand new zones, only loading
+ /// data into them. In case a new zone is needed, it must be created
+ /// beforehand.
+ /// \throw DataSourceError in case the zone does not exist in the source.
+ /// \throw DataSourceError in case of other (possibly low-level) errors,
+ /// such as read-only data source or database error.
+ ZoneLoader(DataSourceClient& destination, const isc::dns::Name& zone_name,
+ DataSourceClient& source);
+
+ /// \brief Perform the whole load.
+ ///
+ /// This performs the whole loading operation. It may take a long time.
+ ///
+ /// \throw InvalidOperation in case the loading was already completed
+ /// before this call.
+ /// \throw DataSourceError in case some error (possibly low-level) happens.
+ /// \throw MasterFileError when the master_file is badly formatted or some
+ /// similar problem is found when loading the master file.
+ void load() {
+ while (!loadIncremental(1000)) { // 1000 is arbitrary largish number
+ // Body intentionally left blank.
+ }
+ }
+
+ /// \brief Load up to limit RRs.
+ ///
+ /// This performs a part of the loading. In case there's enough data in the
+ /// source, it copies limit RRs. It can copy less RRs during the final call
+ /// (when there's less than limit left).
+ ///
+ /// This can be called repeatedly until the whole zone is loaded, having
+ /// pauses in the loading for some purposes (for example reporting
+ /// progress).
+ ///
+ /// \param limit The maximum allowed number of RRs to be loaded during this
+ /// call.
+ /// \return True in case the loading is completed, false if there's more
+ /// to load.
+ /// \throw InvalidOperation in case the loading was already completed
+ /// before this call (by load() or by a loadIncremental that returned
+ /// true).
+ /// \throw DataSourceError in case some error (possibly low-level) happens.
+ /// \throw MasterFileError when the master_file is badly formatted or some
+ /// similar problem is found when loading the master file.
+ /// \note If the limit is exactly the number of RRs available to be loaded,
+ /// the method still returns false and true'll be returned on the next
+ /// call (which will load 0 RRs). This is because the end of iterator or
+ /// master file is detected when reading past the end, not when the last
+ /// one is read.
+ bool loadIncremental(size_t limit);
+private:
+ /// \brief The iterator used as source of data in case of the copy mode.
+ const ZoneIteratorPtr iterator_;
+ /// \brief The destination zone updater
+ const ZoneUpdaterPtr updater_;
+ /// \brief The master loader (for the master file mode)
+ boost::scoped_ptr<isc::dns::MasterLoader> loader_;
+ /// \brief Indicator if loading was completed
+ bool complete_;
+ /// \brief Was the loading successful?
+ bool loaded_ok_;
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 15f3421..7778b58 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -102,6 +102,7 @@ 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 += master_lexer_state.h
+libb10_dns___la_SOURCES += master_loader.h master_loader.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
diff --git a/src/lib/dns/master_loader.cc b/src/lib/dns/master_loader.cc
new file mode 100644
index 0000000..941a100
--- /dev/null
+++ b/src/lib/dns/master_loader.cc
@@ -0,0 +1,278 @@
+// 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_loader.h>
+#include <dns/master_lexer.h>
+#include <dns/name.h>
+#include <dns/rrttl.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rdata.h>
+
+#include <string>
+#include <memory>
+
+using std::string;
+using std::auto_ptr;
+
+namespace isc {
+namespace dns {
+
+class MasterLoader::MasterLoaderImpl {
+public:
+ MasterLoaderImpl(const char* master_file,
+ const Name& zone_origin,
+ const RRClass& zone_class,
+ const MasterLoaderCallbacks& callbacks,
+ const AddRRCallback& add_callback,
+ MasterLoader::Options options) :
+ lexer_(),
+ zone_origin_(zone_origin),
+ zone_class_(zone_class),
+ callbacks_(callbacks),
+ add_callback_(add_callback),
+ options_(options),
+ master_file_(master_file),
+ initialized_(false),
+ ok_(true),
+ many_errors_((options & MANY_ERRORS) != 0),
+ complete_(false),
+ seen_error_(false)
+ {}
+
+ void reportError(const std::string& filename, size_t line,
+ const std::string& reason)
+ {
+ seen_error_ = true;
+ callbacks_.error(filename, line, reason);
+ if (!many_errors_) {
+ // In case we don't have the lenient mode, every error is fatal
+ // and we throw
+ ok_ = false;
+ complete_ = true;
+ isc_throw(MasterLoaderError, reason.c_str());
+ }
+ }
+
+ void pushSource(const std::string& filename) {
+ std::string error;
+ if (!lexer_.pushSource(filename.c_str(), &error)) {
+ if (initialized_) {
+ // $INCLUDE file
+ reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
+ error);
+ } else {
+ // Top-level file
+ reportError("", 0, error);
+ ok_ = false;
+ }
+ }
+ initialized_ = true;
+ }
+
+ void pushStreamSource(std::istream& stream) {
+ lexer_.pushSource(stream);
+ initialized_ = true;
+ }
+
+ // Get a string token. Handle it as error if it is not string.
+ const string getString() {
+ lexer_.getNextToken(MasterToken::STRING).getString(string_token_);
+ return (string_token_);
+ }
+
+ bool loadIncremental(size_t count_limit);
+
+private:
+ MasterLexer lexer_;
+ const Name zone_origin_;
+ const RRClass zone_class_;
+ MasterLoaderCallbacks callbacks_;
+ AddRRCallback add_callback_;
+ const MasterLoader::Options options_;
+ const std::string master_file_;
+ std::string string_token_;
+ bool initialized_;
+ bool ok_; // Is it OK to continue loading?
+ const bool many_errors_; // Are many errors allowed (or should we abort
+ // on the first)
+public:
+ bool complete_; // All work done.
+ bool seen_error_; // Was there at least one error during the
+ // load?
+};
+
+bool
+MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
+ if (count_limit == 0) {
+ isc_throw(isc::InvalidParameter, "Count limit set to 0");
+ }
+ if (complete_) {
+ isc_throw(isc::InvalidOperation,
+ "Trying to load when already loaded");
+ }
+ if (!initialized_) {
+ pushSource(master_file_);
+ }
+ size_t count = 0;
+ while (ok_ && count < count_limit) {
+ try {
+ // Skip all EOLNs (empty lines) and finish on EOF
+ bool empty = true;
+ do {
+ const MasterToken& empty_token(lexer_.getNextToken());
+ if (empty_token.getType() == MasterToken::END_OF_FILE) {
+ // TODO: Check if this is the last source, possibly pop
+ return (true);
+ }
+ empty = empty_token.getType() == MasterToken::END_OF_LINE;
+ } while (empty);
+ // Return the last token, as it was not empty
+ lexer_.ungetToken();
+
+ const MasterToken::StringRegion&
+ name_string(lexer_.getNextToken(MasterToken::QSTRING).
+ getStringRegion());
+ // TODO $ handling
+ const Name name(name_string.beg, name_string.len,
+ &zone_origin_);
+ // TODO: Some more flexibility. We don't allow omitting
+ // anything yet
+
+ // The parameters
+ const RRTTL ttl(getString());
+ const RRClass rrclass(getString());
+ const RRType rrtype(getString());
+
+ // TODO: Some more validation?
+ if (rrclass != zone_class_) {
+ // It doesn't really matter much what type of exception
+ // we throw, we catch it just below.
+ isc_throw(isc::BadValue, "Class mismatch: " << rrclass <<
+ "vs. " << zone_class_);
+ }
+ // TODO: Check if it is SOA, it should be at the origin.
+
+ const rdata::RdataPtr data(rdata::createRdata(rrtype, rrclass,
+ lexer_,
+ &zone_origin_,
+ options_,
+ callbacks_));
+ // In case we get NULL, it means there was error creating
+ // the Rdata. The errors should have been reported by
+ // callbacks_ already. We need to decide if we want to continue
+ // or not.
+ if (data) {
+ add_callback_(name, rrclass, rrtype, ttl, data);
+
+ // Good, we loaded another one
+ ++count;
+ } else {
+ seen_error_ = true;
+ if (!many_errors_) {
+ ok_ = false;
+ complete_ = true;
+ // We don't have the exact error here, but it was reported
+ // by the error callback.
+ isc_throw(MasterLoaderError, "Invalid RR data");
+ }
+ }
+ } catch (const MasterLoaderError&) {
+ // This is a hack. We exclude the MasterLoaderError from the
+ // below case. Once we restrict the below to some smaller
+ // exception, we should remove this.
+ throw;
+ } catch (const isc::Exception& e) {
+ // TODO: Once we do #2518, catch only the DNSTextError here,
+ // not isc::Exception. The rest should be just simply
+ // propagated.
+ reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
+ e.what());
+ // We want to continue. Try to read until the end of line
+ bool end = false;
+ do {
+ const MasterToken& token(lexer_.getNextToken());
+ switch (token.getType()) {
+ case MasterToken::END_OF_FILE:
+ callbacks_.warning(lexer_.getSourceName(),
+ lexer_.getSourceLine(),
+ "File does not end with newline");
+ // TODO: Try pop in case this is not the only
+ // source
+ return (true);
+ case MasterToken::END_OF_LINE:
+ end = true;
+ break;
+ default:
+ // Do nothing. This is just to make compiler
+ // happy
+ break;
+ }
+ } while (!end);
+ }
+ }
+ // When there was a fatal error and ok is false, we say we are done.
+ return (!ok_);
+}
+
+MasterLoader::MasterLoader(const char* master_file,
+ const Name& zone_origin,
+ const RRClass& zone_class,
+ const MasterLoaderCallbacks& callbacks,
+ const AddRRCallback& add_callback,
+ Options options)
+{
+ if (add_callback.empty()) {
+ isc_throw(isc::InvalidParameter, "Empty add RR callback");
+ }
+ impl_ = new MasterLoaderImpl(master_file, zone_origin,
+ zone_class, callbacks, add_callback, options);
+}
+
+MasterLoader::MasterLoader(std::istream& stream,
+ const Name& zone_origin,
+ const RRClass& zone_class,
+ const MasterLoaderCallbacks& callbacks,
+ const AddRRCallback& add_callback,
+ Options options)
+{
+ if (add_callback.empty()) {
+ isc_throw(isc::InvalidParameter, "Empty add RR callback");
+ }
+ auto_ptr<MasterLoaderImpl> impl(new MasterLoaderImpl("", zone_origin,
+ zone_class, callbacks,
+ add_callback,
+ options));
+ impl->pushStreamSource(stream);
+ impl_ = impl.release();
+}
+
+MasterLoader::~MasterLoader() {
+ delete impl_;
+}
+
+bool
+MasterLoader::loadIncremental(size_t count_limit) {
+ const bool result = impl_->loadIncremental(count_limit);
+ impl_->complete_ = result;
+ return (result);
+}
+
+bool
+MasterLoader::loadedSucessfully() const {
+ return (impl_->complete_ && !impl_->seen_error_);
+}
+
+} // end namespace dns
+} // end namespace isc
diff --git a/src/lib/dns/master_loader.h b/src/lib/dns/master_loader.h
index 5ecdd77..9d8a755 100644
--- a/src/lib/dns/master_loader.h
+++ b/src/lib/dns/master_loader.h
@@ -15,20 +15,139 @@
#ifndef MASTER_LOADER_H
#define MASTER_LOADER_H
+#include <dns/master_loader_callbacks.h>
+
+#include <boost/noncopyable.hpp>
+
namespace isc {
namespace dns {
-// Placeholder introduced by #2497. The real class should be updated in
-// #2377.
-class MasterLoader {
+class Name;
+class RRClass;
+
+/// \brief Error while loading by MasterLoader without specifying the
+/// MANY_ERRORS option.
+class MasterLoaderError : public isc::Exception {
public:
+ MasterLoaderError(const char* file, size_t line, const char* what) :
+ Exception(file, line, what)
+ {}
+};
+
+/// \brief A class able to load DNS master files
+///
+/// This class is able to produce a stream of RRs from a master file.
+/// It is able to load all of the master file at once, or by blocks
+/// incrementally.
+///
+/// It reports the loaded RRs and encountered errors by callbacks.
+class MasterLoader : boost::noncopyable {
+public:
+ /// \brief Options how the parsing should work.
enum Options {
- MANY_ERRORS, // lenient mode
- // also eventually some check policies like "check NS name"
+ DEFAULT = 0, ///< Nothing special.
+ MANY_ERRORS = 1 ///< Lenient mode (see documentation of MasterLoader
+ /// constructor).
};
+
+ /// \brief Constructor
+ ///
+ /// This creates a master loader and provides it with all
+ /// relevant information.
+ ///
+ /// Except for the exceptions listed below, the constructor doesn't
+ /// throw. Most errors (like non-existent master file) are reported
+ /// by the callbacks during load() or loadIncremental().
+ ///
+ /// \param master_file Path to the file to load.
+ /// \param zone_origin The origin of zone to be expected inside
+ /// the master file. Currently unused, but it is expected to
+ /// be used for some validation.
+ /// \param zone_class The class of zone to be expected inside the
+ /// master file.
+ /// \param callbacks The callbacks by which it should report problems.
+ /// Usually, the callback carries a filename and line number of the
+ /// input where the problem happens. There's a special case of empty
+ /// filename and zero line in case the opening of the top-level master
+ /// file fails.
+ /// \param add_callback The callback which would be called with each
+ /// loaded RR.
+ /// \param options Options for the parsing, which is bitwise-or of
+ /// the Options values or DEFAULT. If the MANY_ERRORS option is
+ /// included, the parser tries to continue past errors. If it
+ /// is not included, it stops at first encountered error.
+ /// \throw std::bad_alloc when there's not enough memory.
+ /// \throw isc::InvalidParameter if add_callback is empty.
+ MasterLoader(const char* master_file,
+ const Name& zone_origin,
+ const RRClass& zone_class,
+ const MasterLoaderCallbacks& callbacks,
+ const AddRRCallback& add_callback,
+ Options options = DEFAULT);
+
+ /// \brief Constructor from a stream
+ ///
+ /// This is a constructor very similar to the previous one. The only
+ /// difference is it doesn't take a filename, but an input stream
+ /// to read the data from. It is expected to be mostly used in tests,
+ /// but it is public as it may possibly be useful for other currently
+ /// unknown purposes.
+ MasterLoader(std::istream& input,
+ const Name& zone_origin,
+ const RRClass& zone_class,
+ const MasterLoaderCallbacks& callbacks,
+ const AddRRCallback& add_callback,
+ Options options = DEFAULT);
+
+ /// \brief Destructor
+ ~MasterLoader();
+
+ /// \brief Load some RRs
+ ///
+ /// This method loads at most count_limit RRs and reports them. In case
+ /// an error (either fatal or without MANY_ERRORS) or end of file is
+ /// encountered, they may be less.
+ ///
+ /// \param count_limit Upper limit on the number of RRs loaded.
+ /// \return In case it stops because of the count limit, it returns false.
+ /// It returns true if the loading is done.
+ /// \throw isc::InvalidOperation when called after loading was done
+ /// already.
+ /// \throw MasterLoaderError when there's an error in the input master
+ /// file and the MANY_ERRORS is not specified. It never throws this
+ /// in case MANY_ERRORS is specified.
+ bool loadIncremental(size_t count_limit);
+
+ /// \brief Load everything
+ ///
+ /// This simply calls loadIncremental until the loading is done.
+ /// \throw isc::InvalidOperation when called after loading was done
+ /// already.
+ /// \throw MasterLoaderError when there's an error in the input master
+ /// file and the MANY_ERRORS is not specified. It never throws this
+ /// in case MANY_ERRORS is specified.
+ void load() {
+ while (!loadIncremental(1000)) { // 1000 = arbitrary largish number
+ // Body intentionally left blank
+ }
+ }
+
+ /// \brief Was the loading successful?
+ ///
+ /// \return true if and only if the loading was complete (after a call of
+ /// load or after loadIncremental returned true) and there was no
+ /// error. In other cases, return false.
+ /// \note While this method works even before the loading is complete (by
+ /// returning false in that case), it is meant to be called only after
+ /// finishing the load.
+ bool loadedSucessfully() const;
+
+private:
+ class MasterLoaderImpl;
+ MasterLoaderImpl* impl_;
};
-}
-}
+} // end namespace dns
+} // end namespace isc
#endif // MASTER_LOADER_H
diff --git a/src/lib/dns/master_loader_callbacks.h b/src/lib/dns/master_loader_callbacks.h
index 77d9ac5..f572194 100644
--- a/src/lib/dns/master_loader_callbacks.h
+++ b/src/lib/dns/master_loader_callbacks.h
@@ -23,20 +23,30 @@
namespace isc {
namespace dns {
+class Name;
+class RRClass;
+class RRType;
+class RRTTL;
+namespace rdata {
+class Rdata;
+typedef boost::shared_ptr<Rdata> RdataPtr;
+}
-class AbstractRRset;
-typedef boost::shared_ptr<AbstractRRset> RRsetPtr;
-
-/// \brief Type of callback to add a RRset.
+/// \brief Type of callback to add a RR.
///
/// This type of callback is used by the loader to report another loaded
-/// RRset. The RRset is no longer preserved by the loader and is fully
+/// RR. The Rdata is no longer preserved by the loader and is fully
/// owned by the callback.
///
-/// \param RRset The rrset to add. It does not contain the accompanying
-/// RRSIG (if the zone is signed), they are reported with separate
-/// calls to the callback.
-typedef boost::function<void(const RRsetPtr& rrset)> AddRRsetCallback;
+/// \param name The domain name where the RR belongs.
+/// \param rrclass The class of the RR.
+/// \param rrtype Type of the RR.
+/// \param rrttl Time to live of the RR.
+/// \param rdata The actual carried data of the RR.
+typedef boost::function<void(const Name& name, const RRClass& rrclass,
+ const RRType& rrtype, const RRTTL& rrttl,
+ const rdata::RdataPtr& rdata)>
+ AddRRCallback;
/// \brief Set of issue callbacks for a loader.
///
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index 9c1715b..395cbdd 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -770,9 +770,6 @@ public:
//@{
/// \brief Return pointer to this RRset's RRSIG RRset
///
- /// \exception NotImplemented Always thrown. Associated RRSIG RRsets are
- /// not supported in this class.
- ///
/// \return Null pointer, as this class does not support RRSIG records.
virtual RRsetPtr getRRsig() const {
return (RRsetPtr());
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index d5690d4..5f2ae5c 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -27,6 +27,7 @@ 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 += master_loader_unittest.cc
run_unittests_SOURCES += master_lexer_state_unittest.cc
run_unittests_SOURCES += name_unittest.cc
run_unittests_SOURCES += nsec3hash_unittest.cc
diff --git a/src/lib/dns/tests/master_loader_unittest.cc b/src/lib/dns/tests/master_loader_unittest.cc
new file mode 100644
index 0000000..70e3249
--- /dev/null
+++ b/src/lib/dns/tests/master_loader_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 <dns/master_loader_callbacks.h>
+#include <dns/master_loader.h>
+#include <dns/rrtype.h>
+#include <dns/rrset.h>
+#include <dns/rrclass.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+
+#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <sstream>
+
+using namespace isc::dns;
+using std::vector;
+using std::string;
+using std::list;
+using std::stringstream;
+using std::endl;
+
+namespace {
+class MasterLoaderTest : public ::testing::Test {
+public:
+ MasterLoaderTest() :
+ callbacks_(boost::bind(&MasterLoaderTest::callback, this,
+ &errors_, _1, _2, _3),
+ boost::bind(&MasterLoaderTest::callback, this,
+ &warnings_, _1, _2, _3))
+ {}
+
+ /// Concatenate file, line, and reason, and add it to either errors
+ /// or warnings
+ void callback(vector<string>* target, const std::string& file, size_t line,
+ const std::string& reason)
+ {
+ std::stringstream ss;
+ ss << reason << " [" << file << ":" << line << "]";
+ target->push_back(ss.str());
+ }
+
+ void addRRset(const Name& name, const RRClass& rrclass,
+ const RRType& rrtype, const RRTTL& rrttl,
+ const rdata::RdataPtr& data) {
+ const RRsetPtr rrset(new BasicRRset(name, rrclass, rrtype, rrttl));
+ rrset->addRdata(data);
+ rrsets_.push_back(rrset);
+ }
+
+ void setLoader(const char* file, const Name& origin,
+ const RRClass& rrclass, const MasterLoader::Options options)
+ {
+ loader_.reset(new MasterLoader(file, origin, rrclass, callbacks_,
+ boost::bind(&MasterLoaderTest::addRRset,
+ this, _1, _2, _3, _4, _5),
+ options));
+ }
+
+ void setLoader(std::istream& stream, const Name& origin,
+ const RRClass& rrclass, const MasterLoader::Options options)
+ {
+ loader_.reset(new MasterLoader(stream, origin, rrclass, callbacks_,
+ boost::bind(&MasterLoaderTest::addRRset,
+ this, _1, _2, _3, _4, _5),
+ options));
+ }
+
+ static string prepareZone(const string& line, bool include_last) {
+ string result;
+ result += "example.org. 3600 IN SOA ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200\n";
+ result += line;
+ if (include_last) {
+ result += "\n";
+ result += "correct 3600 IN A 192.0.2.2\n";
+ }
+ return (result);
+ }
+
+ void clear() {
+ warnings_.clear();
+ errors_.clear();
+ rrsets_.clear();
+ }
+
+ // Check the next RR in the ones produced by the loader
+ // Other than passed arguments are checked to be the default for the tests
+ void checkRR(const string& name, const RRType& type, const string& data) {
+ ASSERT_FALSE(rrsets_.empty());
+ RRsetPtr current = rrsets_.front();
+ rrsets_.pop_front();
+
+ EXPECT_EQ(Name(name), current->getName());
+ EXPECT_EQ(type, current->getType());
+ EXPECT_EQ(RRClass::IN(), current->getClass());
+ ASSERT_EQ(1, current->getRdataCount());
+ EXPECT_EQ(0, isc::dns::rdata::createRdata(type, RRClass::IN(), data)->
+ compare(current->getRdataIterator()->getCurrent()));
+ }
+
+ MasterLoaderCallbacks callbacks_;
+ boost::scoped_ptr<MasterLoader> loader_;
+ vector<string> errors_;
+ vector<string> warnings_;
+ list<RRsetPtr> rrsets_;
+};
+
+// Test simple loading. The zone file contains no tricky things, and nothing is
+// omitted. No RRset contains more than one RR Also no errors or warnings.
+TEST_F(MasterLoaderTest, basicLoad) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSucessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("example.org", RRType::SOA(),
+ "ns1.example.org. admin.example.org. "
+ "1234 3600 1800 2419200 7200");
+ checkRR("example.org", RRType::NS(), "ns1.example.org.");
+ checkRR("www.example.org", RRType::A(), "192.0.2.1");
+}
+
+// Check it works the same when created based on a stream, not filename
+TEST_F(MasterLoaderTest, streamConstructor) {
+ stringstream zone_stream(prepareZone("", true));
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSucessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ checkRR("correct.example.org", RRType::A(), "192.0.2.2");
+}
+
+// Try loading data incrementally.
+TEST_F(MasterLoaderTest, incrementalLoad) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_FALSE(loader_->loadIncremental(2));
+ EXPECT_FALSE(loader_->loadedSucessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("example.org", RRType::SOA(),
+ "ns1.example.org. admin.example.org. "
+ "1234 3600 1800 2419200 7200");
+ checkRR("example.org", RRType::NS(), "ns1.example.org.");
+
+ // The third one is not loaded yet
+ EXPECT_TRUE(rrsets_.empty());
+
+ // Load the rest.
+ EXPECT_TRUE(loader_->loadIncremental(20));
+ EXPECT_TRUE(loader_->loadedSucessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("www.example.org", RRType::A(), "192.0.2.1");
+}
+
+// Try loading from file that doesn't exist. There should be single error
+// saying so.
+TEST_F(MasterLoaderTest, invalidFile) {
+ setLoader("This file doesn't exist at all",
+ Name("exmaple.org."), RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ // Nothing yet. The loader is dormant until invoked.
+ // Is it really what we want?
+ EXPECT_TRUE(errors_.empty());
+
+ loader_->load();
+
+ EXPECT_TRUE(warnings_.empty());
+ EXPECT_TRUE(rrsets_.empty());
+ ASSERT_EQ(1, errors_.size());
+ EXPECT_EQ(0, errors_[0].find("Error opening the input source file: ")) <<
+ "Different error: " << errors_[0];
+}
+
+struct ErrorCase {
+ const char* const line; // The broken line in master file
+ const char* const problem; // Description of the problem for SCOPED_TRACE
+} const error_cases[] = {
+ { "www... 3600 IN A 192.0.2.1", "Invalid name" },
+ { "www FORTNIGHT IN A 192.0.2.1", "Invalid TTL" },
+ { "www 3600 XX A 192.0.2.1", "Invalid class" },
+ { "www 3600 IN A bad_ip", "Invalid Rdata" },
+ { "www 3600 IN", "Unexpected EOLN" },
+ { "www 3600 CH TXT nothing", "Class mismatch" },
+ { "www \"3600\" IN A 192.0.2.1", "Quoted TTL" },
+ { "www 3600 \"IN\" A 192.0.2.1", "Quoted class" },
+ { "www 3600 IN \"A\" 192.0.2.1", "Quoted type" },
+ { "unbalanced)paren 3600 IN A 192.0.2.1", "Token error 1" },
+ { "www 3600 unbalanced)paren A 192.0.2.1", "Token error 2" },
+ { NULL, NULL }
+};
+
+// Test a broken zone is handled properly. We test several problems,
+// both in strict and lenient mode.
+TEST_F(MasterLoaderTest, brokenZone) {
+ for (const ErrorCase* ec = error_cases; ec->line != NULL; ++ec) {
+ SCOPED_TRACE(ec->problem);
+ const string zone(prepareZone(ec->line, true));
+
+ {
+ SCOPED_TRACE("Strict mode");
+ clear();
+ stringstream zone_stream(zone);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_THROW(loader_->load(), MasterLoaderError);
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_EQ(1, errors_.size()) << errors_[0];
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ // In the strict mode, it is aborted. The last RR is not
+ // even attempted.
+ EXPECT_TRUE(rrsets_.empty());
+ }
+
+ {
+ SCOPED_TRACE("Lenient mode");
+ clear();
+ stringstream zone_stream(zone);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_EQ(1, errors_.size());
+ EXPECT_TRUE(warnings_.empty());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ // This one is below the error one.
+ checkRR("correct.example.org", RRType::A(), "192.0.2.2");
+ EXPECT_TRUE(rrsets_.empty());
+ }
+
+ {
+ SCOPED_TRACE("Error at EOF");
+ // This case is interesting only in the lenient mode.
+ const string zoneEOF(prepareZone(ec->line, false));
+ clear();
+ stringstream zone_stream(zoneEOF);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSucessfully());
+ EXPECT_EQ(1, errors_.size());
+ // The unexpected EOF warning
+ EXPECT_EQ(1, warnings_.size());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ EXPECT_TRUE(rrsets_.empty());
+ }
+ }
+}
+
+// Test the constructor rejects empty add callback.
+TEST_F(MasterLoaderTest, emptyCallback) {
+ EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
+ Name("example.org"), RRClass::IN(), callbacks_,
+ AddRRCallback()), isc::InvalidParameter);
+ // And the same with the second constructor
+ stringstream ss("");
+ EXPECT_THROW(MasterLoader(ss, Name("example.org"), RRClass::IN(),
+ callbacks_, AddRRCallback()),
+ isc::InvalidParameter);
+}
+
+// Check it throws when we try to load after loading was complete.
+TEST_F(MasterLoaderTest, loadTwice) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_THROW(loader_->load(), isc::InvalidOperation);
+}
+
+// Load 0 items should be rejected
+TEST_F(MasterLoaderTest, loadZero) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+ EXPECT_THROW(loader_->loadIncremental(0), isc::InvalidParameter);
+}
+
+// Test there's a warning when the file terminates without end of
+// line.
+TEST_F(MasterLoaderTest, noEOLN) {
+ // No \n at the end
+ const string input("example.org. 3600 IN SOA ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSucessfully());
+ EXPECT_TRUE(errors_.empty()) << errors_[0];
+ // There should be one warning about the EOLN
+ EXPECT_EQ(1, warnings_.size());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+}
+
+}
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 94cadec..d312e07 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -170,6 +170,7 @@ EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
EXTRA_DIST += tsig_verify7.spec tsig_verify8.spec tsig_verify9.spec
EXTRA_DIST += tsig_verify10.spec
+EXTRA_DIST += example.org
.spec.wire:
$(PYTHON) $(top_builddir)/src/lib/util/python/gen_wiredata.py -o $@ $<
diff --git a/src/lib/dns/tests/testdata/example.org b/src/lib/dns/tests/testdata/example.org
new file mode 100644
index 0000000..2f2edf3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/example.org
@@ -0,0 +1,15 @@
+example.org. 3600 IN SOA ( ; The SOA, split across lines for testing
+ ns1.example.org.
+ admin.example.org.
+ 1234
+ 3600
+ 1800
+ 2419200
+ 7200
+ )
+; Check it accepts quoted name too
+"\101xample.org." 3600 IN NS ns1.example.org.
+
+
+; Some empty lines here. They are to make sure the loader can skip them.
+www 3600 IN A 192.0.2.1 ; Test a relative name as well.
More information about the bind10-changes
mailing list